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

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

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

Go to the source code of this file.

Data Structures

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

Macros

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

Enumerations

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

Functions

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

Variables

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

Detailed Description

True call queues with optional send URL on answer.

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

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

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

Patch Version 1.07 2003-12-24 01

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

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

Definition in file app_queue.c.

Macro Definition Documentation

◆ ANNOUNCEHOLDTIME_ALWAYS

#define ANNOUNCEHOLDTIME_ALWAYS   1

Definition at line 1771 of file app_queue.c.

◆ ANNOUNCEHOLDTIME_ONCE

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1772 of file app_queue.c.

◆ ANNOUNCEPOSITION_LIMIT

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1789 of file app_queue.c.

◆ ANNOUNCEPOSITION_MORE_THAN

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 1788 of file app_queue.c.

◆ ANNOUNCEPOSITION_NO

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1787 of file app_queue.c.

◆ ANNOUNCEPOSITION_YES

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1786 of file app_queue.c.

◆ AST_MAX_WATCHERS

#define AST_MAX_WATCHERS   256

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

◆ DEFAULT_RETRY

#define DEFAULT_RETRY   5

Definition at line 1553 of file app_queue.c.

◆ DEFAULT_TIMEOUT

#define DEFAULT_TIMEOUT   15

Definition at line 1554 of file app_queue.c.

◆ MAX_CALL_ATTEMPT_BUCKETS

#define MAX_CALL_ATTEMPT_BUCKETS   353

Definition at line 2512 of file app_queue.c.

◆ MAX_PERIODIC_ANNOUNCEMENTS

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 1556 of file app_queue.c.

◆ MAX_QUEUE_BUCKETS

#define MAX_QUEUE_BUCKETS   53

Definition at line 1563 of file app_queue.c.

◆ QUEUE_EVENT_VARIABLES

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1773 of file app_queue.c.

◆ QUEUE_PAUSED_DEVSTATE

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

Definition at line 3531 of file app_queue.c.

◆ queue_ref

#define queue_ref (   q)    ao2_bump(q)

Definition at line 2053 of file app_queue.c.

◆ queue_t_ref

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

Definition at line 2055 of file app_queue.c.

◆ queue_t_unref

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

Definition at line 2056 of file app_queue.c.

◆ QUEUE_UNKNOWN_PAUSED_DEVSTATE

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3533 of file app_queue.c.

◆ QUEUE_UNPAUSED_DEVSTATE

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3532 of file app_queue.c.

◆ queue_unref

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

Definition at line 2054 of file app_queue.c.

◆ queues_t_link

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

Definition at line 2057 of file app_queue.c.

◆ queues_t_unlink

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

Definition at line 2058 of file app_queue.c.

◆ RECHECK

#define RECHECK   1

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

Definition at line 1555 of file app_queue.c.

◆ RES_EXISTS

#define RES_EXISTS   (-1)

Entry already exists

Definition at line 1566 of file app_queue.c.

◆ RES_NOSUCHQUEUE

#define RES_NOSUCHQUEUE   (-3)

No such queue

Definition at line 1568 of file app_queue.c.

◆ RES_NOT_CALLER

#define RES_NOT_CALLER   (-5)

Caller not found

Definition at line 1570 of file app_queue.c.

◆ RES_NOT_DYNAMIC

#define RES_NOT_DYNAMIC   (-4)

Member is not dynamic

Definition at line 1569 of file app_queue.c.

◆ RES_OKAY

#define RES_OKAY   0

Action completed

Definition at line 1565 of file app_queue.c.

◆ RES_OUTOFMEMORY

#define RES_OUTOFMEMORY   (-2)

Out of memory

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

1446 {
1447 OPT_MARK_AS_ANSWERED = (1 << 0),
1448 OPT_GO_ON = (1 << 1),
1449 OPT_DATA_QUALITY = (1 << 2),
1450 OPT_CALLEE_GO_ON = (1 << 3),
1451 OPT_CALLEE_HANGUP = (1 << 4),
1452 OPT_CALLER_HANGUP = (1 << 5),
1453 OPT_IGNORE_CALL_FW = (1 << 6),
1454 OPT_IGNORE_CONNECTEDLINE = (1 << 7),
1455 OPT_CALLEE_PARK = (1 << 8),
1456 OPT_CALLER_PARK = (1 << 9),
1457 OPT_NO_RETRY = (1 << 10),
1458 OPT_RINGING = (1 << 11),
1459 OPT_RING_WHEN_RINGING = (1 << 12),
1460 OPT_CALLEE_TRANSFER = (1 << 13),
1461 OPT_CALLER_TRANSFER = (1 << 14),
1462 OPT_CALLEE_AUTOMIXMON = (1 << 15),
1463 OPT_CALLER_AUTOMIXMON = (1 << 16),
1464 OPT_CALLEE_AUTOMON = (1 << 17),
1465 OPT_CALLER_AUTOMON = (1 << 18),
1466 OPT_PREDIAL_CALLEE = (1 << 19),
1467 OPT_PREDIAL_CALLER = (1 << 20),
1468 OPT_MUSICONHOLD_CLASS = (1 << 21),
1469};
@ OPT_CALLER_AUTOMON
Definition: app_queue.c:1465
@ OPT_CALLEE_PARK
Definition: app_queue.c:1455
@ OPT_PREDIAL_CALLER
Definition: app_queue.c:1467
@ OPT_GO_ON
Definition: app_queue.c:1448
@ OPT_IGNORE_CONNECTEDLINE
Definition: app_queue.c:1454
@ OPT_CALLEE_AUTOMON
Definition: app_queue.c:1464
@ OPT_CALLEE_TRANSFER
Definition: app_queue.c:1460
@ OPT_CALLEE_GO_ON
Definition: app_queue.c:1450
@ OPT_MARK_AS_ANSWERED
Definition: app_queue.c:1447
@ OPT_IGNORE_CALL_FW
Definition: app_queue.c:1453
@ OPT_CALLER_PARK
Definition: app_queue.c:1456
@ OPT_NO_RETRY
Definition: app_queue.c:1457
@ OPT_DATA_QUALITY
Definition: app_queue.c:1449
@ OPT_CALLER_HANGUP
Definition: app_queue.c:1452
@ OPT_MUSICONHOLD_CLASS
Definition: app_queue.c:1468
@ OPT_CALLEE_AUTOMIXMON
Definition: app_queue.c:1462
@ OPT_CALLEE_HANGUP
Definition: app_queue.c:1451
@ OPT_CALLER_AUTOMIXMON
Definition: app_queue.c:1463
@ OPT_RINGING
Definition: app_queue.c:1458
@ OPT_CALLER_TRANSFER
Definition: app_queue.c:1461
@ OPT_PREDIAL_CALLEE
Definition: app_queue.c:1466
@ OPT_RING_WHEN_RINGING
Definition: app_queue.c:1459

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

1471 {
1476 /* note: this entry _MUST_ be the last one in the enum */
1478};
@ OPT_ARG_CALLEE_GO_ON
Definition: app_queue.c:1472
@ OPT_ARG_PREDIAL_CALLEE
Definition: app_queue.c:1473
@ OPT_ARG_MUSICONHOLD_CLASS
Definition: app_queue.c:1475
@ OPT_ARG_PREDIAL_CALLER
Definition: app_queue.c:1474
@ OPT_ARG_ARRAY_SIZE
Definition: app_queue.c:1477

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

1505 {
1514};
@ QUEUE_STRATEGY_RINGALL
Definition: app_queue.c:1506
@ QUEUE_STRATEGY_RRMEMORY
Definition: app_queue.c:1510
@ QUEUE_STRATEGY_LINEAR
Definition: app_queue.c:1511
@ QUEUE_STRATEGY_LEASTRECENT
Definition: app_queue.c:1507
@ QUEUE_STRATEGY_RANDOM
Definition: app_queue.c:1509
@ QUEUE_STRATEGY_FEWESTCALLS
Definition: app_queue.c:1508
@ QUEUE_STRATEGY_RRORDERED
Definition: app_queue.c:1513
@ QUEUE_STRATEGY_WRANDOM
Definition: app_queue.c:1512

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 1516 of file app_queue.c.

1516 {
1520};
@ QUEUE_AUTOPAUSE_ON
Definition: app_queue.c:1518
@ QUEUE_AUTOPAUSE_OFF
Definition: app_queue.c:1517
@ QUEUE_AUTOPAUSE_ALL
Definition: app_queue.c:1519

◆ agent_complete_reason

Enumerator
CALLER 
AGENT 
TRANSFER 

Definition at line 6117 of file app_queue.c.

6117 {
6118 CALLER,
6119 AGENT,
6120 TRANSFER
6121};
@ AGENT
Definition: app_queue.c:6119
@ CALLER
Definition: app_queue.c:6118
@ TRANSFER
Definition: app_queue.c:6120

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

1754 {
1755 QUEUE_EMPTY_PENALTY = (1 << 0),
1756 QUEUE_EMPTY_PAUSED = (1 << 1),
1757 QUEUE_EMPTY_INUSE = (1 << 2),
1758 QUEUE_EMPTY_RINGING = (1 << 3),
1759 QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
1760 QUEUE_EMPTY_INVALID = (1 << 5),
1761 QUEUE_EMPTY_UNKNOWN = (1 << 6),
1762 QUEUE_EMPTY_WRAPUP = (1 << 7),
1763};
@ QUEUE_EMPTY_INVALID
Definition: app_queue.c:1760
@ QUEUE_EMPTY_UNKNOWN
Definition: app_queue.c:1761
@ QUEUE_EMPTY_PENALTY
Definition: app_queue.c:1755
@ QUEUE_EMPTY_RINGING
Definition: app_queue.c:1758
@ QUEUE_EMPTY_INUSE
Definition: app_queue.c:1757
@ QUEUE_EMPTY_UNAVAILABLE
Definition: app_queue.c:1759
@ QUEUE_EMPTY_WRAPUP
Definition: app_queue.c:1762
@ QUEUE_EMPTY_PAUSED
Definition: app_queue.c:1756

◆ member_properties

Enumerator
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1765 of file app_queue.c.

1765 {
1766 MEMBER_PENALTY = 0,
1767 MEMBER_RINGINUSE = 1,
1768};
@ MEMBER_RINGINUSE
Definition: app_queue.c:1767
@ MEMBER_PENALTY
Definition: app_queue.c:1766

◆ queue_reload_mask

Enumerator
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 1522 of file app_queue.c.

1522 {
1523 QUEUE_RELOAD_PARAMETERS = (1 << 0),
1524 QUEUE_RELOAD_MEMBER = (1 << 1),
1525 QUEUE_RELOAD_RULES = (1 << 2),
1526 QUEUE_RESET_STATS = (1 << 3),
1527};
@ QUEUE_RELOAD_RULES
Definition: app_queue.c:1525
@ QUEUE_RELOAD_MEMBER
Definition: app_queue.c:1524
@ QUEUE_RESET_STATS
Definition: app_queue.c:1526
@ QUEUE_RELOAD_PARAMETERS
Definition: app_queue.c:1523

◆ queue_result

Enumerator
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 
QUEUE_WITHDRAW 

Definition at line 1625 of file app_queue.c.

1625 {
1626 QUEUE_UNKNOWN = 0,
1627 QUEUE_TIMEOUT = 1,
1628 QUEUE_JOINEMPTY = 2,
1629 QUEUE_LEAVEEMPTY = 3,
1632 QUEUE_FULL = 6,
1633 QUEUE_CONTINUE = 7,
1634 QUEUE_WITHDRAW = 8,
1635};
@ QUEUE_FULL
Definition: app_queue.c:1632
@ QUEUE_UNKNOWN
Definition: app_queue.c:1626
@ QUEUE_WITHDRAW
Definition: app_queue.c:1634
@ QUEUE_CONTINUE
Definition: app_queue.c:1633
@ QUEUE_LEAVEEMPTY
Definition: app_queue.c:1629
@ QUEUE_LEAVEUNAVAIL
Definition: app_queue.c:1631
@ QUEUE_JOINUNAVAIL
Definition: app_queue.c:1630
@ QUEUE_JOINEMPTY
Definition: app_queue.c:1628
@ QUEUE_TIMEOUT
Definition: app_queue.c:1627

◆ queue_timeout_priority

Enumerator
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1652 of file app_queue.c.

1652 {
1655};
@ TIMEOUT_PRIORITY_CONF
Definition: app_queue.c:1654
@ TIMEOUT_PRIORITY_APP
Definition: app_queue.c:1653

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

10131{
10132 struct call_queue *q;
10133 struct ast_str *out = ast_str_alloca(512);
10134 struct ao2_container *sorted_queues;
10135
10136 struct ao2_iterator queue_iter;
10137 int found = 0;
10138
10139 if (argc != 2 && argc != 3) {
10140 return CLI_SHOWUSAGE;
10141 }
10142
10143 if (argc == 3) { /* specific queue */
10144 if ((q = find_load_queue_rt_friendly(argv[2]))) {
10145 ao2_lock(q);
10146 print_queue(s, fd, q);
10147 ao2_unlock(q);
10148 queue_unref(q);
10149 } else {
10150 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
10151 do_print(s, fd, ast_str_buffer(out));
10152 }
10153 return CLI_SUCCESS;
10154 }
10155
10156 if (ast_check_realtime("queues")) {
10157 /* This block is to find any queues which are defined in realtime but
10158 * which have not yet been added to the in-core container
10159 */
10160 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10161 if (cfg) {
10162 char *category = NULL;
10163 while ((category = ast_category_browse(cfg, category))) {
10164 const char *queuename = ast_variable_retrieve(cfg, category, "name");
10165 if (ast_strlen_zero(queuename)) {
10166 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
10167 continue;
10168 }
10169 if ((q = find_load_queue_rt_friendly(queuename))) {
10170 queue_t_unref(q, "Done with temporary pointer");
10171 }
10172 }
10173 ast_config_destroy(cfg);
10174 }
10175 }
10176
10177 /*
10178 * Snapping a copy of the container prevents having to lock both the queues container
10179 * and the queue itself at the same time. It also allows us to sort the entries.
10180 */
10181 sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
10182 if (!sorted_queues) {
10183 return CLI_SUCCESS;
10184 }
10185 if (ao2_container_dup(sorted_queues, queues, 0)) {
10186 ao2_ref(sorted_queues, -1);
10187 return CLI_SUCCESS;
10188 }
10189
10190 /*
10191 * No need to lock the container since it's temporary and static.
10192 * We also unlink the entries as we use them so the container is
10193 * empty when the iterator finishes. We can then just unref the container.
10194 */
10195 queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
10196 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10197 struct call_queue *realtime_queue = NULL;
10198 ao2_lock(q);
10199 /* This check is to make sure we don't print information for realtime
10200 * queues which have been deleted from realtime but which have not yet
10201 * been deleted from the in-core container. Only do this if we're not
10202 * looking for a specific queue.
10203 */
10204 if (q->realtime) {
10205 realtime_queue = find_load_queue_rt_friendly(q->name);
10206 if (!realtime_queue) {
10207 ao2_unlock(q);
10208 queue_t_unref(q, "Done with iterator");
10209 continue;
10210 }
10211 queue_t_unref(realtime_queue, "Queue is already in memory");
10212 }
10213
10214 found = 1;
10215 print_queue(s, fd, q);
10216
10217 ao2_unlock(q);
10218 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
10219 }
10220 ao2_iterator_destroy(&queue_iter);
10221 ao2_ref(sorted_queues, -1);
10222 if (!found) {
10223 ast_str_set(&out, 0, "No queues.");
10224 do_print(s, fd, ast_str_buffer(out));
10225 }
10226 return CLI_SUCCESS;
10227}
static void print_queue(struct mansession *s, int fd, struct call_queue *q)
Print a single queue to AMI or the CLI.
Definition: app_queue.c:10022
static struct ao2_container * queues
Definition: app_queue.c:1899
#define queue_t_unref(q, tag)
Definition: app_queue.c:2056
#define queue_unref(q)
Definition: app_queue.c:2054
static void do_print(struct mansession *s, int fd, const char *str)
direct output to manager or cli with proper terminator
Definition: app_queue.c:10012
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3890
#define ast_log
Definition: astobj2.c:42
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1909
@ AO2_ITERATOR_UNLINK
Definition: astobj2.h:1863
@ AO2_ITERATOR_DONTLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1852
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
#define SENTINEL
Definition: compiler.h:87
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3622
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3530
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:783
#define LOG_WARNING
#define NULL
Definition: resample.c:96
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_alloca(init_len)
Definition: strings.h:848
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Support for dynamic strings.
Definition: strings.h:623
unsigned int realtime
Definition: app_queue.c:1845
unsigned int found
Definition: app_queue.c:1846
const ast_string_field name
Definition: app_queue.c:1829
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 11939 of file app_queue.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

7589{
7590 struct call_queue *q;
7591 struct member *new_member, *old_member;
7592 int res = RES_NOSUCHQUEUE;
7593
7594 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7595 * short-circuits if the queue is already in memory. */
7596 if (!(q = find_load_queue_rt_friendly(queuename))) {
7597 return res;
7598 }
7599
7600 ao2_lock(q);
7601 if ((old_member = interface_exists(q, interface)) == NULL) {
7603 new_member->dynamic = 1;
7604 if (reason_paused) {
7605 ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7606 }
7607 member_add_to_queue(q, new_member);
7608 queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7609
7610 if (is_member_available(q, new_member)) {
7612 }
7613
7614 ao2_ref(new_member, -1);
7615 new_member = NULL;
7616
7617 if (dump) {
7619 }
7620
7621 res = RES_OKAY;
7622 } else {
7623 res = RES_OUTOFMEMORY;
7624 }
7625 } else {
7626 ao2_ref(old_member, -1);
7627 res = RES_EXISTS;
7628 }
7629 ao2_unlock(q);
7630 queue_t_unref(q, "Expiring temporary reference");
7631
7632 return res;
7633}
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:2863
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7453
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:7480
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2604
#define RES_OUTOFMEMORY
Definition: app_queue.c:1567
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1568
#define RES_OKAY
Definition: app_queue.c:1565
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3541
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2393
#define RES_EXISTS
Definition: app_queue.c:1566
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2369
@ AST_DEVSTATE_CACHABLE
Definition: devicestate.h:70
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:510
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
unsigned int ringinuse
Definition: app_queue.c:1833
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1727
int dynamic
Definition: app_queue.c:1735
char membername[80]
Definition: app_queue.c:1732
int penalty
Definition: app_queue.c:1733
int paused
Definition: app_queue.c:1738
int wrapuptime
Definition: app_queue.c:1742
char reason_paused[80]
Definition: app_queue.c:1739
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1730

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

3723{
3724 struct call_queue *q;
3725
3726 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3727 if (ast_string_field_init(q, 64)) {
3728 queue_t_unref(q, "String field allocation failed");
3729 return NULL;
3730 }
3731 ast_string_field_set(q, name, queuename);
3732 }
3733 return q;
3734}
static void destroy_queue(void *obj)
Free queue's member list then its string fields.
Definition: app_queue.c:3707
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:407
static const char name[]
Definition: format_mp3.c:68
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359

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

Referenced by find_queue_by_name_rt(), and reload_single_queue().

◆ AO2_STRING_FIELD_SORT_FN()

AO2_STRING_FIELD_SORT_FN ( call_queue  ,
name   
)

◆ aqm_exec()

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

AddQueueMember application.

Definition at line 8349 of file app_queue.c.

8350{
8351 int res=-1;
8352 char *parse, *tmp, *temppos = NULL;
8354 AST_APP_ARG(queuename);
8355 AST_APP_ARG(interface);
8356 AST_APP_ARG(penalty);
8358 AST_APP_ARG(membername);
8359 AST_APP_ARG(state_interface);
8360 AST_APP_ARG(wrapuptime);
8361 );
8362 int penalty = 0;
8363 int wrapuptime;
8364
8365 if (ast_strlen_zero(data)) {
8366 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8367 return -1;
8368 }
8369
8370 parse = ast_strdupa(data);
8371
8373
8374 if (ast_strlen_zero(args.interface)) {
8375 args.interface = ast_strdupa(ast_channel_name(chan));
8376 temppos = strrchr(args.interface, '-');
8377 if (temppos) {
8378 *temppos = '\0';
8379 }
8380 }
8381
8382 if (!ast_strlen_zero(args.penalty)) {
8383 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8384 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8385 penalty = 0;
8386 }
8387 }
8388
8389 if (!ast_strlen_zero(args.wrapuptime)) {
8390 tmp = args.wrapuptime;
8391 ast_strip(tmp);
8392 wrapuptime = atoi(tmp);
8393 if (wrapuptime < 0) {
8394 wrapuptime = 0;
8395 }
8396 } else {
8397 wrapuptime = 0;
8398 }
8399
8400 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface, NULL, wrapuptime)) {
8401 case RES_OKAY:
8402 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8403 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", "");
8404 } else {
8405 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", "");
8406 }
8407 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8408 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8409 res = 0;
8410 break;
8411 case RES_EXISTS:
8412 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8413 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8414 res = 0;
8415 break;
8416 case RES_NOSUCHQUEUE:
8417 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8418 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8419 res = 0;
8420 break;
8421 case RES_OUTOFMEMORY:
8422 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8423 break;
8424 }
8425
8426 return res;
8427}
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1590
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1614
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:7588
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
static int tmp()
Definition: bt_open.c:389
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:953
#define LOG_ERROR
#define LOG_NOTICE
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
const char * args
static struct test_options options

References add_to_queue(), args, AST_APP_ARG, 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(), member::interface, LOG_ERROR, log_membername_as_agent, LOG_NOTICE, LOG_WARNING, member::membername, NULL, options, pbx_builtin_setvar_helper(), member::penalty, queue_persistent_members, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, member::state_interface, tmp(), and member::wrapuptime.

Referenced by load_module().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 11939 of file app_queue.c.

◆ autopause2int()

static int autopause2int ( const char *  autopause)
static

Definition at line 1946 of file app_queue.c.

1947{
1948 int x;
1949 /*This 'double check' that default value is OFF */
1951 return QUEUE_AUTOPAUSE_OFF;
1952 }
1953
1954 /*This 'double check' is to ensure old values works */
1955 if(ast_true(autopause)) {
1956 return QUEUE_AUTOPAUSE_ON;
1957 }
1958
1959 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
1960 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
1961 return autopausesmodes[x].autopause;
1962 }
1963 }
1964
1965 /*This 'double check' that default value is OFF */
1966 return QUEUE_AUTOPAUSE_OFF;
1967}
static const struct autopause autopausesmodes[]
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
int autopause
Definition: app_queue.c:1545
#define ARRAY_LEN(a)
Definition: utils.h:666

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

Referenced by queue_set_param().

◆ calc_metric()

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

Calculate the metric of each member in the outgoing callattempts.

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

Return values
-1if penalties are exceeded
0otherwise

Definition at line 6039 of file app_queue.c.

6040{
6041 /* disregarding penalty on too few members? */
6042 int membercount = ao2_container_count(q->members);
6043 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
6044 int penalty = mem->penalty;
6045
6046 if (usepenalty) {
6047 if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) {
6048 /* Low penalty is raised up to the current minimum */
6049 penalty = qe->raise_penalty;
6050 }
6051 if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
6052 (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6053 return -1;
6054 }
6055 } else {
6056 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
6057 membercount, q->penaltymemberslimit);
6058 }
6059
6060 switch (q->strategy) {
6062 /* Everyone equal, except for penalty */
6063 tmp->metric = penalty * 1000000 * usepenalty;
6064 break;
6066 if (pos < qe->linpos) {
6067 tmp->metric = 1000 + pos;
6068 } else {
6069 if (pos > qe->linpos) {
6070 /* Indicate there is another priority */
6071 qe->linwrapped = 1;
6072 }
6073 tmp->metric = pos;
6074 }
6075 tmp->metric += penalty * 1000000 * usepenalty;
6076 break;
6079 pos = mem->queuepos;
6080 if (pos < q->rrpos) {
6081 tmp->metric = 1000 + pos;
6082 } else {
6083 if (pos > q->rrpos) {
6084 /* Indicate there is another priority */
6085 q->wrapped = 1;
6086 }
6087 tmp->metric = pos;
6088 }
6089 tmp->metric += penalty * 1000000 * usepenalty;
6090 break;
6092 tmp->metric = ast_random() % 1000;
6093 tmp->metric += penalty * 1000000 * usepenalty;
6094 break;
6096 tmp->metric = ast_random() % ((1 + penalty) * 1000);
6097 break;
6099 tmp->metric = mem->calls;
6100 tmp->metric += penalty * 1000000 * usepenalty;
6101 break;
6103 if (!mem->lastcall) {
6104 tmp->metric = 0;
6105 } else {
6106 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
6107 }
6108 tmp->metric += penalty * 1000000 * usepenalty;
6109 break;
6110 default:
6111 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
6112 break;
6113 }
6114 return 0;
6115}
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:1885
int penaltymemberslimit
Definition: app_queue.c:1871
unsigned int wrapped
Definition: app_queue.c:1839
int strategy
Definition: app_queue.c:1844
int queuepos
Definition: app_queue.c:1740
time_t lastcall
Definition: app_queue.c:1744
int calls
Definition: app_queue.c:1734
int linpos
Definition: app_queue.c:1713
int max_penalty
Definition: app_queue.c:1710
int raise_penalty
Definition: app_queue.c:1712
int min_penalty
Definition: app_queue.c:1711
int linwrapped
Definition: app_queue.c:1714
long int ast_random(void)
Definition: utils.c:2312

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

Referenced by try_calling().

◆ callattempt_free()

static void callattempt_free ( struct callattempt doomed)
static

Definition at line 4442 of file app_queue.c.

4443{
4444 if (doomed->member) {
4445 ao2_ref(doomed->member, -1);
4446 }
4448 ast_free(doomed->orig_chan_name);
4449 ast_free(doomed);
4450}
#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:2072
struct ast_party_connected_line connected
Definition: app_queue.c:1677
char * orig_chan_name
Definition: app_queue.c:1688
struct member * member
Definition: app_queue.c:1675

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

4653{
4654 struct member *memberp = call->member;
4655 int wrapuptime;
4656
4657 if (memberp->paused) {
4658 ast_debug(1, "%s paused, can't receive call\n", call->interface);
4659 return 0;
4660 }
4661
4662 if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4663 ast_debug(1, "%s not available, can't receive call\n", call->interface);
4664 return 0;
4665 }
4666
4667 if (memberp->lastqueue) {
4668 wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4669 } else {
4670 wrapuptime = get_wrapuptime(qe->parent, memberp);
4671 }
4672 if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4673 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4674 (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4675 call->interface);
4676 return 0;
4677 }
4678
4679 if (use_weight && compare_weight(qe->parent, memberp)) {
4680 ast_debug(1, "Priority queue delaying call to %s:%s\n",
4681 qe->parent->name, call->interface);
4682 return 0;
4683 }
4684
4686 ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
4687 qe->parent->name, call->interface);
4688 return 0;
4689 }
4690
4691 if (!memberp->ringinuse) {
4692 struct member *mem;
4693
4695
4696 mem = ao2_find(pending_members, memberp,
4698 if (mem) {
4699 /*
4700 * If found that means this member is currently being attempted
4701 * from another calling thread, so stop trying from this thread
4702 */
4703 ast_debug(1, "%s has another call trying, can't receive call\n",
4704 call->interface);
4705 ao2_ref(mem, -1);
4707 return 0;
4708 }
4709
4710 /*
4711 * If not found add it to the container so another queue
4712 * won't attempt to call this member at the same time.
4713 */
4714 ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4715 ao2_link(pending_members, memberp);
4717
4718 /*
4719 * The queue member is available. Get current status to be sure
4720 * because the device state and extension state callbacks may
4721 * not have updated the status yet.
4722 */
4724 ast_debug(1, "%s actually not available, can't receive call\n",
4725 call->interface);
4726 pending_members_remove(memberp);
4727 return 0;
4728 }
4729 }
4730
4731 return 1;
4732}
static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
Definition: app_queue.c:4571
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:1989
static int compare_weight(struct call_queue *rq, struct member *member)
Definition: app_queue.c:4537
static struct ao2_container * pending_members
Definition: app_queue.c:2511
static int force_longest_waiting_caller
queues.conf [general] option
Definition: app_queue.c:1617
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2562
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:2848
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1593
static int member_status_available(int status)
Definition: app_queue.c:4638
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
static int call(void *data)
Definition: chan_pjsip.c:2391
int status
Definition: app_queue.c:1737
unsigned int ringinuse
Definition: app_queue.c:1751
struct call_queue * lastqueue
Definition: app_queue.c:1747
struct call_queue * parent
Definition: app_queue.c:1693

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

7642{
7643 struct call_queue *q;
7644 struct queue_ent *current, *prev = NULL, *caller_qe = NULL;
7645 int res = RES_NOSUCHQUEUE;
7646
7647 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7648 * short-circuits if the queue is already in memory. */
7649 if (!(q = find_load_queue_rt_friendly(queuename))) {
7650 return res;
7651 }
7652
7653 ao2_lock(q);
7654 res = RES_NOT_CALLER;
7655 for (current = q->head; current; current = current->next) {
7656 if (strcmp(ast_channel_name(current->chan), caller) == 0) {
7657 ast_debug(1, "%s Caller new priority %d in queue %s\n",
7658 caller, priority, queuename);
7659 current->prio = priority;
7660 if (immediate) {
7661 /* This caller is being immediately moved in the queue so remove them */
7662 if (prev) {
7663 prev->next = current->next;
7664 } else {
7665 q->head = current->next;
7666 }
7667 caller_qe = current;
7668 /* The position for all callers is not recalculated in here as it will
7669 * be updated when the moved caller is inserted back into the queue
7670 */
7671 }
7672 res = RES_OKAY;
7673 break;
7674 } else if (immediate) {
7675 prev = current;
7676 }
7677 }
7678
7679 if (caller_qe) {
7680 int inserted = 0, pos = 0;
7681
7682 /* If a caller queue entry exists, we are applying their priority immediately
7683 * and have to reinsert them at the correct position.
7684 */
7685 prev = NULL;
7686 current = q->head;
7687 while (current) {
7688 if (!inserted && (caller_qe->prio > current->prio)) {
7689 insert_entry(q, prev, caller_qe, &pos);
7690 inserted = 1;
7691 }
7692
7693 /* We always update the position as it may have changed */
7694 current->pos = ++pos;
7695
7696 /* Move to the next caller in the queue */
7697 prev = current;
7698 current = current->next;
7699 }
7700
7701 if (!inserted) {
7702 insert_entry(q, prev, caller_qe, &pos);
7703 }
7704 }
7705
7706 ao2_unlock(q);
7707 return res;
7708}
#define RES_NOT_CALLER
Definition: app_queue.c:1570
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:2087
static int priority
size_t current
Definition: main/cli.c:113
struct queue_ent * head
Definition: app_queue.c:1886
struct queue_ent * next
Definition: app_queue.c:1723

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

Referenced by handle_queue_change_priority_caller(), and manager_change_priority_caller_on_queue().

◆ clear_queue()

static void clear_queue ( struct call_queue q)
static

Definition at line 3048 of file app_queue.c.

3049{
3050 q->holdtime = 0;
3051 q->callscompleted = 0;
3052 q->callsabandoned = 0;
3053 q->callscompletedinsl = 0;
3054 q->callsabandonedinsl = 0;
3055 q->talktime = 0;
3056
3057 if (q->members) {
3058 struct member *mem;
3059 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3060 while ((mem = ao2_iterator_next(&mem_iter))) {
3061 mem->calls = 0;
3062 mem->callcompletedinsl = 0;
3063 mem->lastcall = 0;
3064 mem->starttime = 0;
3065 ao2_ref(mem, -1);
3066 }
3067 ao2_iterator_destroy(&mem_iter);
3068 }
3069}
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
int talktime
Definition: app_queue.c:1861
int callsabandoned
Definition: app_queue.c:1863
int callscompleted
Definition: app_queue.c:1862
int callsabandonedinsl
Definition: app_queue.c:1864
int callscompletedinsl
Definition: app_queue.c:1866
int holdtime
Definition: app_queue.c:1860
time_t starttime
Definition: app_queue.c:1743
int callcompletedinsl
Definition: app_queue.c:1741

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

9966{
9967 struct call_queue *q;
9968 struct ao2_iterator queue_iter;
9969
9970 queue_iter = ao2_iterator_init(queues, 0);
9971 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
9972 ao2_lock(q);
9973 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
9974 clear_queue(q);
9975 ao2_unlock(q);
9976 queue_t_unref(q, "Done with iterator");
9977 }
9978 ao2_iterator_destroy(&queue_iter);
9979 return 0;
9980}
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:3048

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

4538{
4539 struct call_queue *q;
4540 struct member *mem;
4541 int found = 0;
4542 struct ao2_iterator queue_iter;
4543
4544 queue_iter = ao2_iterator_init(queues, 0);
4545 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4546 if (q == rq) { /* don't check myself, could deadlock */
4547 queue_t_unref(q, "Done with iterator");
4548 continue;
4549 }
4550 ao2_lock(q);
4551 if (q->count && q->members) {
4552 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4553 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4554 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
4555 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);
4556 found = 1;
4557 }
4558 ao2_ref(mem, -1);
4559 }
4560 }
4561 ao2_unlock(q);
4562 queue_t_unref(q, "Done with iterator");
4563 if (found) {
4564 break;
4565 }
4566 }
4567 ao2_iterator_destroy(&queue_iter);
4568 return found;
4569}
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:4504
#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 10301 of file app_queue.c.

10302{
10303 struct call_queue *q;
10304 char *ret = NULL;
10305 int which = 0;
10306 int wordlen = strlen(word);
10307 struct ao2_iterator queue_iter;
10308 const char *word_list = NULL;
10309
10310 /* for certain commands, already completed items should be left out of
10311 * the list */
10312 if (word_list_offset && strlen(line) >= word_list_offset) {
10313 word_list = line + word_list_offset;
10314 }
10315
10316 queue_iter = ao2_iterator_init(queues, 0);
10317 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10318 if (!strncasecmp(word, q->name, wordlen) && ++which > state
10319 && (!word_list_offset || !word_in_list(word_list, q->name))) {
10320 ret = ast_strdup(q->name);
10321 queue_t_unref(q, "Done with iterator");
10322 break;
10323 }
10324 queue_t_unref(q, "Done with iterator");
10325 }
10326 ao2_iterator_destroy(&queue_iter);
10327
10328 /* Pretend "rules" is at the end of the queues list in certain
10329 * circumstances since it is an alternate command that should be
10330 * tab-completable for "queue show" */
10331 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
10332 ret = ast_strdup("rules");
10333 }
10334
10335 return ret;
10336}
static int word_in_list(const char *list, const char *word)
Check if a given word is in a space-delimited list.
Definition: app_queue.c:10242
#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 10807 of file app_queue.c.

10808{
10809 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
10810 switch (pos) {
10811 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
10812 return NULL;
10813 case 4: /* only one possible match, "to" */
10814 return state == 0 ? ast_strdup("to") : NULL;
10815 case 5: /* <queue> */
10816 return complete_queue(line, word, pos, state, 0);
10817 case 6: /* only one possible match, "penalty" */
10818 return state == 0 ? ast_strdup("penalty") : NULL;
10819 case 7:
10820 if (0 <= state && state < 100) { /* 0-99 */
10821 char *num;
10822 if ((num = ast_malloc(3))) {
10823 sprintf(num, "%d", state);
10824 }
10825 return num;
10826 } else {
10827 return NULL;
10828 }
10829 case 8: /* only one possible match, "as" */
10830 return state == 0 ? ast_strdup("as") : NULL;
10831 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
10832 return NULL;
10833 default:
10834 return NULL;
10835 }
10836}
static char * complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
Check if a given word is in a space-delimited list.
Definition: app_queue.c:10301
#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 11225 of file app_queue.c.

11226{
11227 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
11228 switch (pos) {
11229 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11230 return NULL;
11231 case 4: /* only one possible match, "queue" */
11232 return state == 0 ? ast_strdup("queue") : NULL;
11233 case 5: /* <queue> */
11234 return complete_queue(line, word, pos, state, 0);
11235 case 6: /* "reason" */
11236 return state == 0 ? ast_strdup("reason") : NULL;
11237 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
11238 return NULL;
11239 default:
11240 return NULL;
11241 }
11242}

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

11061{
11062 int which = 0;
11063 struct call_queue *q;
11064 struct member *m;
11065 struct ao2_iterator queue_iter;
11066 struct ao2_iterator mem_iter;
11067 int wordlen = strlen(word);
11068
11069 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
11070 if (pos > 5 || pos < 3) {
11071 return NULL;
11072 }
11073 if (pos == 4) { /* only one possible match, 'from' */
11074 return (state == 0 ? ast_strdup("from") : NULL);
11075 }
11076
11077 if (pos == 5) { /* No need to duplicate code */
11078 return complete_queue(line, word, pos, state, 0);
11079 }
11080
11081 /* here is the case for 3, <member> */
11082 queue_iter = ao2_iterator_init(queues, 0);
11083 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
11084 ao2_lock(q);
11085 mem_iter = ao2_iterator_init(q->members, 0);
11086 while ((m = ao2_iterator_next(&mem_iter))) {
11087 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
11088 char *tmp;
11089 tmp = ast_strdup(m->interface);
11090 ao2_ref(m, -1);
11091 ao2_iterator_destroy(&mem_iter);
11092 ao2_unlock(q);
11093 queue_t_unref(q, "Done with iterator, returning interface name");
11094 ao2_iterator_destroy(&queue_iter);
11095 return tmp;
11096 }
11097 ao2_ref(m, -1);
11098 }
11099 ao2_iterator_destroy(&mem_iter);
11100 ao2_unlock(q);
11101 queue_t_unref(q, "Done with iterator");
11102 }
11103 ao2_iterator_destroy(&queue_iter);
11104
11105 return NULL;
11106}

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

Referenced by handle_queue_remove_member().

◆ complete_queue_rule_show()

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

Definition at line 11420 of file app_queue.c.

11421{
11422 int which = 0;
11423 struct rule_list *rl_iter;
11424 int wordlen = strlen(word);
11425 char *ret = NULL;
11426 if (pos != 3) /* Wha? */ {
11427 return NULL;
11428 }
11429
11431 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11432 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11433 ret = ast_strdup(rl_iter->name);
11434 break;
11435 }
11436 }
11438
11439 return ret;
11440}
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
char name[80]
Definition: app_queue.c:1892
struct rule_list::@56 list

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

Referenced by handle_queue_rule_show().

◆ complete_queue_set_member_value()

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

Definition at line 11299 of file app_queue.c.

11300{
11301 /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
11302 switch (pos) {
11303 case 4:
11304 if (state == 0) {
11305 return ast_strdup("on");
11306 } else {
11307 return NULL;
11308 }
11309 case 6:
11310 if (state == 0) {
11311 return ast_strdup("in");
11312 } else {
11313 return NULL;
11314 }
11315 case 7:
11316 return complete_queue(line, word, pos, state, 0);
11317 default:
11318 return NULL;
11319 }
11320}

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

10339{
10340 if (pos == 2) {
10341 return complete_queue(line, word, pos, state, 0);
10342 }
10343 return NULL;
10344}

References complete_queue(), and NULL.

Referenced by queue_show().

◆ compress_char()

static int compress_char ( const char  c)
static

Definition at line 2908 of file app_queue.c.

2909{
2910 if (c < 32) {
2911 return 0;
2912 } else if (c > 96) {
2913 return c - 64;
2914 }
2915 return c - 32;
2916}
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 2775 of file app_queue.c.

2776{
2777 struct ast_context *c = NULL;
2778
2779 c = ast_context_find(parent);
2780 if (!c) {
2781 /* well, if parent doesn't exist, how can the child be included in it? */
2782 return 0;
2783 }
2784 if (!strcmp(ast_get_context_name(c), parent)) {
2785 /* found the context of the hint app_queue is using. Now, see
2786 if that context includes the one that just changed state */
2787 struct ast_include *inc = NULL;
2788
2789 while ((inc = (struct ast_include*) ast_walk_context_includes(c, inc))) {
2790 const char *includename = ast_get_include_name(inc);
2791 if (!strcasecmp(child, includename)) {
2792 return 1;
2793 }
2794 /* recurse on this context, for nested includes. The
2795 PBX extension parser will prevent infinite recursion. */
2796 if (context_included(includename, child)) {
2797 return 1;
2798 }
2799 }
2800 }
2801 return 0;
2802}
static int context_included(const char *parent, const char *child)
Returns if one context includes another context.
Definition: app_queue.c:2775
const struct ast_include * ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc)
Definition: pbx.c:8650
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: extconf.c:4172
const char * ast_get_include_name(const struct ast_include *include)
Definition: pbx_include.c:50
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
ast_context: An extension context
Definition: pbx.c:284
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37

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

Referenced by context_included(), and extension_state_cb().

◆ copy_rules()

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

Copy rule from global list into specified queue.

Definition at line 8464 of file app_queue.c.

8465{
8466 struct penalty_rule *pr_iter;
8467 struct rule_list *rl_iter;
8468 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8470 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8471 if (!strcasecmp(rl_iter->name, tmp)) {
8472 break;
8473 }
8474 }
8475 if (rl_iter) {
8476 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8477 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8478 if (!new_pr) {
8479 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8480 break;
8481 }
8482 new_pr->time = pr_iter->time;
8483 new_pr->max_value = pr_iter->max_value;
8484 new_pr->min_value = pr_iter->min_value;
8485 new_pr->raise_value = pr_iter->raise_value;
8486 new_pr->max_relative = pr_iter->max_relative;
8487 new_pr->min_relative = pr_iter->min_relative;
8488 new_pr->raise_relative = pr_iter->raise_relative;
8489 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8490 }
8491 }
8493}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
const ast_string_field defaultrule
Definition: app_queue.c:1829
int raise_relative
Definition: app_queue.c:1782
struct penalty_rule::@52 list
int min_relative
Definition: app_queue.c:1781
int max_relative
Definition: app_queue.c:1780
struct queue_ent::@51 qe_rules
struct rule_list::@55 rules

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

Referenced by queue_exec().

◆ create_queue_member()

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

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

Definition at line 2863 of file app_queue.c.

2864{
2865 struct member *cur;
2866
2867 if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
2868 cur->ringinuse = ringinuse;
2869 cur->penalty = penalty;
2870 cur->paused = paused;
2871 cur->wrapuptime = wrapuptime;
2872 if (paused) {
2873 time(&cur->lastpause); /* Update time of last pause */
2874 }
2875 time(&cur->logintime);
2876 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
2879 } else {
2881 }
2883 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
2884 } else {
2885 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
2886 }
2887 if (!strchr(cur->interface, '/')) {
2888 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
2889 }
2890 if (!strncmp(cur->state_interface, "hint:", 5)) {
2891 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
2892 char *exten = strsep(&context, "@") + 5;
2893
2894 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
2895 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
2896
2898 } else {
2899 cur->state_id = -1;
2900 }
2901 cur->status = get_queue_member_status(cur);
2902 }
2903
2904 return cur;
2905}
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: app_queue.c:2804
static void destroy_queue_member_cb(void *obj)
Definition: app_queue.c:2853
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
char * strsep(char **str, const char *delims)
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
Definition: pbx.c:3823
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
time_t logintime
Definition: app_queue.c:1746
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1728
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1729
int state_id
Definition: app_queue.c:1731
time_t lastpause
Definition: app_queue.c:1745

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

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

◆ destroy_queue()

static void destroy_queue ( void *  obj)
static

Free queue's member list then its string fields.

Definition at line 3707 of file app_queue.c.

3708{
3709 struct call_queue *q = obj;
3710 int i;
3711
3712 free_members(q, 1);
3714 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3715 if (q->sound_periodicannounce[i]) {
3717 }
3718 }
3719 ao2_ref(q->members, -1);
3720}
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1556
static void free_members(struct call_queue *q, int all)
Iterate through queue's member list and delete them.
Definition: app_queue.c:3691
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
struct ast_str * sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]
Definition: app_queue.c:1831

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

2854{
2855 struct member *mem = obj;
2856
2857 if (mem->state_id != -1) {
2859 }
2860}
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition: pbx.c:3856

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

Referenced by create_queue_member().

◆ device_state_cb()

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

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

Definition at line 2639 of file app_queue.c.

2640{
2641 struct ao2_iterator miter, qiter;
2642 struct ast_device_state_message *dev_state;
2643 struct member *m;
2644 struct call_queue *q;
2645 char interface[80], *slash_pos;
2646 int found = 0; /* Found this member in any queue */
2647 int found_member; /* Found this member in this queue */
2648 int avail = 0; /* Found an available member in this queue */
2649
2651 return;
2652 }
2653
2654 dev_state = stasis_message_data(msg);
2655 if (dev_state->eid) {
2656 /* ignore non-aggregate states */
2657 return;
2658 }
2659
2660 qiter = ao2_iterator_init(queues, 0);
2661 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
2662 ao2_lock(q);
2663
2664 avail = 0;
2665 found_member = 0;
2666 miter = ao2_iterator_init(q->members, 0);
2667 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2668 if (!found_member) {
2669 ast_copy_string(interface, m->state_interface, sizeof(interface));
2670
2671 if ((slash_pos = strchr(interface, '/'))) {
2672 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
2673 *slash_pos = '\0';
2674 }
2675 }
2676
2677 if (!strcasecmp(interface, dev_state->device)) {
2678 found_member = 1;
2679 update_status(q, m, dev_state->state);
2680 }
2681 }
2682
2683 /* check every member until we find one NOT_INUSE */
2684 if (!avail) {
2685 avail = is_member_available(q, m);
2686 }
2687 if (avail && found_member) {
2688 /* early exit as we've found an available member and the member of interest */
2689 ao2_ref(m, -1);
2690 break;
2691 }
2692 }
2693
2694 if (found_member) {
2695 found = 1;
2696 if (avail) {
2698 } else {
2700 }
2701 }
2702
2703 ao2_iterator_destroy(&miter);
2704
2705 ao2_unlock(q);
2706 queue_t_unref(q, "Done with iterator");
2707 }
2708 ao2_iterator_destroy(&qiter);
2709
2710 if (found) {
2711 ast_debug(1, "Device '%s' changed to state '%u' (%s)\n",
2712 dev_state->device,
2713 dev_state->state,
2714 ast_devstate2str(dev_state->state));
2715 } else {
2716 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",
2717 dev_state->device,
2718 dev_state->state,
2719 ast_devstate2str(dev_state->state));
2720 }
2721
2722 return;
2723}
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:2573
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Definition: devicestate.c:237
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
The structure that contains device state.
Definition: devicestate.h:238
enum ast_device_state state
Definition: devicestate.h:248
const struct ast_eid * eid
The EID of the server where this message originated.
Definition: devicestate.h:246

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

Referenced by load_module().

◆ do_hang()

static void do_hang ( struct callattempt o)
static

common hangup actions

Definition at line 4622 of file app_queue.c.

4623{
4624 o->stillgoing = 0;
4625 ast_hangup(o->chan);
4627 o->chan = NULL;
4628}
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2541
struct ast_channel * chan
Definition: app_queue.c:1672
unsigned int stillgoing
Definition: app_queue.c:1685

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

Referenced by ring_entry(), and wait_for_answer().

◆ do_print()

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

direct output to manager or cli with proper terminator

Definition at line 10012 of file app_queue.c.

10013{
10014 if (s) {
10015 astman_append(s, "%s\r\n", str);
10016 } else {
10017 ast_cli(fd, "%s\n", str);
10018 }
10019}
const char * str
Definition: app_jack.c:147
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3302

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

Definition at line 7480 of file app_queue.c.

7481{
7482 struct member *cur_member;
7483 struct ast_str *value;
7484 struct ao2_iterator mem_iter;
7485
7486 if (!pm_queue) {
7487 return;
7488 }
7489
7490 /* 4K is a reasonable default for most applications, but we grow to
7491 * accommodate more if necessary. */
7492 if (!(value = ast_str_create(4096))) {
7493 return;
7494 }
7495
7496 mem_iter = ao2_iterator_init(pm_queue->members, 0);
7497 while ((cur_member = ao2_iterator_next(&mem_iter))) {
7498 if (!cur_member->dynamic) {
7499 ao2_ref(cur_member, -1);
7500 continue;
7501 }
7502
7503 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
7504 ast_str_strlen(value) ? "|" : "",
7505 cur_member->interface,
7506 cur_member->penalty,
7507 cur_member->paused,
7508 cur_member->membername,
7509 cur_member->state_interface,
7510 cur_member->reason_paused,
7511 cur_member->wrapuptime);
7512
7513 ao2_ref(cur_member, -1);
7514 }
7515 ao2_iterator_destroy(&mem_iter);
7516
7517 if (ast_str_strlen(value) && !cur_member) {
7518 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
7519 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
7520 }
7521 } else {
7522 /* Delete the entry if the queue is empty or there is an error */
7523 ast_db_del(pm_family, pm_queue->name);
7524 }
7525
7526 ast_free(value);
7527}
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: main/db.c:342
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: main/db.c:476
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
int value
Definition: syslog.c:37

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

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

◆ end_bridge_callback()

static void end_bridge_callback ( void *  data)
static

Definition at line 6829 of file app_queue.c.

6830{
6831 struct queue_end_bridge *qeb = data;
6832 struct call_queue *q = qeb->q;
6833 struct ast_channel *chan = qeb->chan;
6834
6835 if (ao2_ref(qeb, -1) == 1) {
6836 set_queue_variables(q, chan);
6837 /* This unrefs the reference we made in try_calling when we allocated qeb */
6838 queue_t_unref(q, "Expire bridge_config reference");
6839 }
6840}
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:2061
Main Channel structure associated with a channel.
struct call_queue * q
Definition: app_queue.c:6818
struct ast_channel * chan
Definition: app_queue.c:6819

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

6823{
6824 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
6825 ao2_ref(qeb, +1);
6826 qeb->chan = originator;
6827}
void * end_bridge_callback_data
Definition: channel.h:1091

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

6871{
6872 const char *m = input;
6873 char escaped[size];
6874 char *p;
6875
6876 for (p = escaped; p < escaped + size - 1; p++, m++) {
6877 switch (*m) {
6878 case '^':
6879 if (*(m + 1) == '{') {
6880 *p = '$';
6881 }
6882 break;
6883 case ',':
6884 *p++ = '\\';
6885 /* Fall through */
6886 default:
6887 *p = *m;
6888 }
6889 if (*m == '\0')
6890 break;
6891 }
6892
6893 if (p == escaped + size) {
6894 escaped[size - 1] = '\0';
6895 }
6896
6897 pbx_substitute_variables_helper(chan, escaped, output, size - 1);
6898}
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1570
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211

References input(), and pbx_substitute_variables_helper().

Referenced by setup_mixmonitor().

◆ extension_state_cb()

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

Definition at line 2804 of file app_queue.c.

2805{
2806 struct ao2_iterator miter, qiter;
2807 struct member *m;
2808 struct call_queue *q;
2809 int state = info->exten_state;
2810 int found = 0, device_state = extensionstate2devicestate(state);
2811
2812 /* only interested in extension state updates involving device states */
2813 if (info->reason != AST_HINT_UPDATE_DEVICE) {
2814 return 0;
2815 }
2816
2817 qiter = ao2_iterator_init(queues, 0);
2818 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
2819 ao2_lock(q);
2820
2821 miter = ao2_iterator_init(q->members, 0);
2822 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2823 if (!strcmp(m->state_exten, exten) &&
2825 /* context could be included in m->state_context. We need to check. */
2826 found = 1;
2827 update_status(q, m, device_state);
2828 }
2829 }
2830 ao2_iterator_destroy(&miter);
2831
2832 ao2_unlock(q);
2833 queue_t_unref(q, "Done with iterator");
2834 }
2835 ao2_iterator_destroy(&qiter);
2836
2837 if (found) {
2838 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
2839 } else {
2840 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",
2841 exten, context, device_state, ast_devstate2str(device_state));
2842 }
2843
2844 return 0;
2845}
static int extensionstate2devicestate(int state)
Helper function which converts from extension state to device state values.
Definition: app_queue.c:2726
def info(msg)
@ AST_HINT_UPDATE_DEVICE
Definition: pbx.h:91

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

Referenced by create_queue_member(), and destroy_queue_member_cb().

◆ extensionstate2devicestate()

static int extensionstate2devicestate ( int  state)
static

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

Definition at line 2726 of file app_queue.c.

2727{
2728 switch (state) {
2731 break;
2734 break;
2735 case AST_EXTENSION_BUSY:
2737 break;
2740 break;
2743 break;
2746 break;
2749 break;
2752 break;
2755 default:
2757 break;
2758 }
2759
2760 return state;
2761}
enum cc_state state
Definition: ccss.c:393
@ AST_DEVICE_RINGINUSE
Definition: devicestate.h:60
@ AST_DEVICE_ONHOLD
Definition: devicestate.h:61
@ AST_DEVICE_RINGING
Definition: devicestate.h:59
@ AST_DEVICE_INVALID
Definition: devicestate.h:57
@ AST_DEVICE_BUSY
Definition: devicestate.h:56
@ AST_DEVICE_UNAVAILABLE
Definition: devicestate.h:58
@ AST_EXTENSION_REMOVED
Definition: pbx.h:62
@ AST_EXTENSION_RINGING
Definition: pbx.h:68
@ AST_EXTENSION_NOT_INUSE
Definition: pbx.h:64
@ AST_EXTENSION_INUSE
Definition: pbx.h:65
@ AST_EXTENSION_UNAVAILABLE
Definition: pbx.h:67
@ AST_EXTENSION_ONHOLD
Definition: pbx.h:69
@ AST_EXTENSION_BUSY
Definition: pbx.h:66
@ AST_EXTENSION_DEACTIVATED
Definition: pbx.h:63

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

Referenced by extension_state_cb(), and get_queue_member_status().

◆ find_best()

static struct callattempt * find_best ( struct callattempt outgoing)
static

find the entry with the best metric, or NULL

Definition at line 4880 of file app_queue.c.

4881{
4882 struct callattempt *best = NULL, *cur;
4883
4884 for (cur = outgoing; cur; cur = cur->q_next) {
4885 if (cur->stillgoing && /* Not already done */
4886 !cur->chan && /* Isn't already going */
4887 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
4888 best = cur;
4889 }
4890 }
4891
4892 return best;
4893}
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1669

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

3891{
3892 struct ast_variable *queue_vars;
3893 struct ast_config *member_config = NULL;
3894 struct call_queue *q = NULL, tmpq = {
3895 .name = queuename,
3896 };
3897 int prev_weight = 0;
3898
3899 /* Find the queue in the in-core list first. */
3900 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
3901
3902 if (!q || q->realtime) {
3903 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
3904 queue operations while waiting for the DB.
3905
3906 This will be two separate database transactions, so we might
3907 see queue parameters as they were before another process
3908 changed the queue and member list as it was after the change.
3909 Thus we might see an empty member list when a queue is
3910 deleted. In practise, this is unlikely to cause a problem. */
3911
3912 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
3913 if (queue_vars) {
3914 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
3915 if (!member_config) {
3916 ast_debug(1, "No queue_members defined in config extconfig.conf\n");
3917 member_config = ast_config_new();
3918 }
3919 }
3920 if (q) {
3921 prev_weight = q->weight ? 1 : 0;
3922 queue_t_unref(q, "Need to find realtime queue");
3923 }
3924
3925 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
3926 ast_config_destroy(member_config);
3927 ast_variables_destroy(queue_vars);
3928
3929 /* update the use_weight value if the queue's has gained or lost a weight */
3930 if (q) {
3931 if (!q->weight && prev_weight) {
3933 }
3934 if (q->weight && !prev_weight) {
3936 }
3937 }
3938 /* Other cases will end up with the proper value for use_weight */
3939 } else {
3941 }
3942 return q;
3943}
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:3746
static void update_realtime_members(struct call_queue *q)
Definition: app_queue.c:3995
#define ao2_t_find(container, arg, flags, tag)
Definition: astobj2.h:1734
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: extconf.c:3274
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3506
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
Structure for variables, used for configurations and for channel variables.

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

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

◆ find_member_by_queuename_and_interface()

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

Find a member by looking up queuename and interface.

Returns
member or NULL if member not found.

Definition at line 11919 of file app_queue.c.

11920{
11921 struct member *mem = NULL;
11922 struct call_queue *q;
11923
11924 if ((q = find_load_queue_rt_friendly(queuename))) {
11925 ao2_lock(q);
11926 mem = ao2_find(q->members, interface, OBJ_KEY);
11927 ao2_unlock(q);
11928 queue_t_unref(q, "Expiring temporary reference.");
11929 }
11930 return mem;
11931}
#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 3746 of file app_queue.c.

3747{
3748 struct ast_variable *v;
3749 struct call_queue *q, tmpq = {
3750 .name = queuename,
3751 };
3752 struct member *m;
3753 struct ao2_iterator mem_iter;
3754 char *category = NULL;
3755 const char *tmp_name;
3756 char *tmp;
3757 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
3758
3759 /* Static queues override realtime. */
3760 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
3761 ao2_lock(q);
3762 if (!q->realtime) {
3763 if (q->dead) {
3764 ao2_unlock(q);
3765 queue_t_unref(q, "Queue is dead; can't return it");
3766 return NULL;
3767 }
3768 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
3769 ao2_unlock(q);
3770 return q;
3771 }
3772 } else if (!member_config) {
3773 /* Not found in the list, and it's not realtime ... */
3774 return NULL;
3775 }
3776 /* Check if queue is defined in realtime. */
3777 if (!queue_vars) {
3778 /* Delete queue from in-core list if it has been deleted in realtime. */
3779 if (q) {
3780 /*! \note Hmm, can't seem to distinguish a DB failure from a not
3781 found condition... So we might delete an in-core queue
3782 in case of DB failure. */
3783 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
3784
3785 q->dead = 1;
3786 /* Delete if unused (else will be deleted when last caller leaves). */
3787 queues_t_unlink(queues, q, "Unused; removing from container");
3788 ao2_unlock(q);
3789 queue_t_unref(q, "Queue is dead; can't return it");
3790 }
3791 return NULL;
3792 }
3793
3794 /* Create a new queue if an in-core entry does not exist yet. */
3795 if (!q) {
3796 struct ast_variable *tmpvar = NULL;
3797 if (!(q = alloc_queue(queuename))) {
3798 return NULL;
3799 }
3800 ao2_lock(q);
3801 clear_queue(q);
3802 q->realtime = 1;
3803 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
3804 * will allocate the members properly
3805 */
3806 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
3807 if (!strcasecmp(tmpvar->name, "strategy")) {
3808 q->strategy = strat2int(tmpvar->value);
3809 if (q->strategy < 0) {
3810 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3811 tmpvar->value, q->name);
3813 }
3814 break;
3815 }
3816 }
3817 /* We traversed all variables and didn't find a strategy */
3818 if (!tmpvar) {
3820 }
3821 queues_t_link(queues, q, "Add queue to container");
3822 }
3823 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
3824
3825 memset(tmpbuf, 0, sizeof(tmpbuf));
3826 for (v = queue_vars; v; v = v->next) {
3827 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
3828 if (strchr(v->name, '_')) {
3829 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
3830 tmp_name = tmpbuf;
3831 tmp = tmpbuf;
3832 while ((tmp = strchr(tmp, '_'))) {
3833 *tmp++ = '-';
3834 }
3835 } else {
3836 tmp_name = v->name;
3837 }
3838
3839 /* NULL values don't get returned from realtime; blank values should
3840 * still get set. If someone doesn't want a value to be set, they
3841 * should set the realtime column to NULL, not blank. */
3842 queue_set_param(q, tmp_name, v->value, -1, 0);
3843 }
3844
3845 /* Temporarily set realtime members dead so we can detect deleted ones. */
3846 mem_iter = ao2_iterator_init(q->members, 0);
3847 while ((m = ao2_iterator_next(&mem_iter))) {
3848 if (m->realtime) {
3849 m->dead = 1;
3850 }
3851 ao2_ref(m, -1);
3852 }
3853 ao2_iterator_destroy(&mem_iter);
3854
3855 while ((category = ast_category_browse(member_config, category))) {
3856 rt_handle_member_record(q, category, member_config);
3857 }
3858
3859 /* Delete all realtime members that have been deleted in DB. */
3860 mem_iter = ao2_iterator_init(q->members, 0);
3861 while ((m = ao2_iterator_next(&mem_iter))) {
3862 if (m->dead) {
3864 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
3865 } else {
3866 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
3867 }
3869 }
3870 ao2_ref(m, -1);
3871 }
3872 ao2_iterator_destroy(&mem_iter);
3873
3874 ao2_unlock(q);
3875
3876 return q;
3877}
static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3557
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:3573
#define queues_t_unlink(c, q, tag)
Definition: app_queue.c:2058
#define queues_t_link(c, q, tag)
Definition: app_queue.c:2057
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:3329
static void init_queue(struct call_queue *q)
Initialize Queue default values.
Definition: app_queue.c:2947
static struct call_queue * alloc_queue(const char *queuename)
Definition: app_queue.c:3722
static int strat2int(const char *strategy)
Definition: app_queue.c:1933
struct ast_variable * next
unsigned int dead
Definition: app_queue.c:1832
unsigned int dead
Definition: app_queue.c:1748
int realtime
Definition: app_queue.c:1736

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

Referenced by find_load_queue_rt_friendly().

◆ free_members()

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

Iterate through queue's member list and delete them.

Definition at line 3691 of file app_queue.c.

3692{
3693 /* Free non-dynamic members */
3694 struct member *cur;
3695 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3696
3697 while ((cur = ao2_iterator_next(&mem_iter))) {
3698 if (all || !cur->dynamic) {
3700 }
3701 ao2_ref(cur, -1);
3702 }
3703 ao2_iterator_destroy(&mem_iter);
3704}

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

8980{
8981 struct member *m;
8982
8984 ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
8985 return NULL;
8986 }
8987
8989 if (!m) {
8990 ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
8991 interface, q->name);
8992 }
8993 return m;
8994}

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

8065{
8066 int foundqueue = 0, penalty;
8067 struct call_queue *q;
8068 struct member *mem;
8069
8070 if ((q = find_load_queue_rt_friendly(queuename))) {
8071 foundqueue = 1;
8072 ao2_lock(q);
8073 if ((mem = interface_exists(q, interface))) {
8074 penalty = mem->penalty;
8075 ao2_ref(mem, -1);
8076 ao2_unlock(q);
8077 queue_t_unref(q, "Search complete");
8078 return penalty;
8079 }
8080 ao2_unlock(q);
8081 queue_t_unref(q, "Search complete");
8082 }
8083
8084 /* some useful debugging */
8085 if (foundqueue) {
8086 ast_log (LOG_ERROR, "Invalid queuename\n");
8087 } else {
8088 ast_log (LOG_ERROR, "Invalid interface\n");
8089 }
8090
8091 return RESULT_FAILURE;
8092}
#define RESULT_FAILURE
Definition: cli.h:42

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

Referenced by queue_function_memberpenalty_read().

◆ get_member_status()

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

Check if members are available.

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

Definition at line 2420 of file app_queue.c.

2421{
2422 struct member *member;
2423 struct ao2_iterator mem_iter;
2424
2425 ao2_lock(q);
2426 mem_iter = ao2_iterator_init(q->members, 0);
2427 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
2428 int penalty = member->penalty;
2429 if (raise_penalty != INT_MAX && penalty < raise_penalty) {
2430 ast_debug(4, "%s is having his penalty raised up from %d to %d\n", member->membername, penalty, raise_penalty);
2431 penalty = raise_penalty;
2432 }
2433 if ((max_penalty != INT_MAX && penalty > max_penalty) || (min_penalty != INT_MAX && penalty < min_penalty)) {
2434 if (conditions & QUEUE_EMPTY_PENALTY) {
2435 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
2436 continue;
2437 }
2438 }
2439
2440 switch (devstate ? ast_device_state(member->state_interface) : member->status) {
2441 case AST_DEVICE_INVALID:
2442 if (conditions & QUEUE_EMPTY_INVALID) {
2443 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
2444 break;
2445 }
2446 goto default_case;
2448 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
2449 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
2450 break;
2451 }
2452 goto default_case;
2453 case AST_DEVICE_INUSE:
2454 if (conditions & QUEUE_EMPTY_INUSE) {
2455 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
2456 break;
2457 }
2458 goto default_case;
2459 case AST_DEVICE_RINGING:
2460 if (conditions & QUEUE_EMPTY_RINGING) {
2461 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
2462 break;
2463 }
2464 goto default_case;
2465 case AST_DEVICE_UNKNOWN:
2466 if (conditions & QUEUE_EMPTY_UNKNOWN) {
2467 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
2468 break;
2469 }
2470 /* Fall-through */
2471 default:
2472 default_case:
2473 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
2474 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
2475 break;
2476 } else if ((conditions & QUEUE_EMPTY_WRAPUP)
2477 && member->lastcall
2478 && get_wrapuptime(q, member)
2479 && (time(NULL) - get_wrapuptime(q, member) < member->lastcall)) {
2480 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n",
2481 member->membername, (int) (time(NULL) - member->lastcall), get_wrapuptime(q, member));
2482 break;
2483 } else {
2484 ao2_ref(member, -1);
2485 ao2_iterator_destroy(&mem_iter);
2486 ao2_unlock(q);
2487 ast_debug(4, "%s is available.\n", member->membername);
2488 return 0;
2489 }
2490 break;
2491 }
2492 }
2493 ao2_iterator_destroy(&mem_iter);
2494 ao2_unlock(q);
2495
2496 if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
2497 /* member state still may be RINGING due to lag in event message - check again with device state */
2498 return get_member_status(q, max_penalty, min_penalty, raise_penalty, conditions, 1);
2499 }
2500 return -1;
2501}
static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate)
Check if members are available.
Definition: app_queue.c:2420
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 2848 of file app_queue.c.

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

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

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

◆ get_wrapuptime()

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

Return wrapuptime.

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

Returns
integer value

Definition at line 1989 of file app_queue.c.

1990{
1991 if (member->wrapuptime) {
1992 return member->wrapuptime;
1993 }
1994 return q->wrapuptime;
1995}
int wrapuptime
Definition: app_queue.c:1870

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

6465{
6466 struct queue_stasis_data *queue_data = userdata;
6467 struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6468 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6469 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6470
6471 if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6473 return;
6474 }
6475
6476 ao2_lock(queue_data);
6477
6478 if (queue_data->dying) {
6479 ao2_unlock(queue_data);
6480 return;
6481 }
6482
6483 if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6484 ao2_unlock(queue_data);
6485 return;
6486 }
6487
6488 if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6489 atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6490 (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6492 ao2_unlock(queue_data);
6493 return;
6494 }
6495
6496 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6497 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6498
6499 ao2_unlock(queue_data);
6500
6501 ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6502 log_attended_transfer(queue_data, atxfer_msg);
6503
6504 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6505 queue_data->holdstart, queue_data->starttime, TRANSFER);
6506 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6507 queue_data->starttime);
6508 remove_stasis_subscriptions(queue_data);
6509}
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:6124
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:5967
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6271
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition: app_queue.c:6325
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition: bridge.h:1100
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
@ AST_ATTENDED_TRANSFER_DEST_THREEWAY
Message representing attended transfer.
enum ast_attended_transfer_dest_type dest_type
struct ast_bridge_channel_snapshot_pair to_transfer_target
enum ast_transfer_result result
struct ast_bridge_channel_snapshot_pair to_transferee
struct ast_bridge_snapshot * bridge_snapshot
const ast_string_field uniqueid
Definition: bridge.h:328
Structure representing a snapshot of channel state.
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:6217
const ast_string_field caller_uniqueid
Definition: app_queue.c:6225
const ast_string_field member_uniqueid
Definition: app_queue.c:6225
struct call_queue * queue
Definition: app_queue.c:6227
const ast_string_field bridge_uniqueid
Definition: app_queue.c:6225
struct member * member
Definition: app_queue.c:6229
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

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

Referenced by setup_stasis_subs().

◆ handle_blind_transfer()

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

Handle a blind transfer event.

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

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

Definition at line 6404 of file app_queue.c.

6406{
6407 struct queue_stasis_data *queue_data = userdata;
6408 struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
6409 const char *exten;
6410 const char *context;
6411 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6412 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6413
6414 if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
6415 return;
6416 }
6417
6418 ao2_lock(queue_data);
6419
6420 if (queue_data->dying) {
6421 ao2_unlock(queue_data);
6422 return;
6423 }
6424
6425 if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
6426 strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
6427 ao2_unlock(queue_data);
6428 return;
6429 }
6430
6431 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6432 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6433
6434 ao2_unlock(queue_data);
6435
6436 exten = transfer_msg->exten;
6437 context = transfer_msg->context;
6438
6439 ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
6440 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6441 "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
6442 exten, context,
6443 (long) (queue_data->starttime - queue_data->holdstart),
6444 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6445
6446 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6447 queue_data->holdstart, queue_data->starttime, TRANSFER);
6448 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6449 queue_data->starttime);
6450 remove_stasis_subscriptions(queue_data);
6451}
Message published during a blind transfer.
char exten[AST_MAX_EXTENSION]
struct ast_bridge_snapshot * bridge
enum ast_transfer_result result
char context[AST_MAX_CONTEXT]

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

Referenced by setup_stasis_subs().

◆ handle_bridge_enter()

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

Definition at line 6371 of file app_queue.c.

6373{
6374 struct queue_stasis_data *queue_data = userdata;
6375 struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6376 SCOPED_AO2LOCK(lock, queue_data);
6377
6378 if (queue_data->dying) {
6379 return;
6380 }
6381
6382 if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6383 return;
6384 }
6385
6386 if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6387 ast_string_field_set(queue_data, bridge_uniqueid,
6388 enter_blob->bridge->uniqueid);
6389 ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6390 enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6391 }
6392}
ast_mutex_t lock
Definition: app_sla.c:331
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:604
Blob of data associated with a bridge.
struct ast_bridge_snapshot * bridge
struct ast_channel_snapshot * channel
const ast_string_field uniqueid
const ast_string_field name
struct ast_channel_snapshot_base * base

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

Referenced by setup_stasis_subs().

◆ handle_hangup()

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

Definition at line 6652 of file app_queue.c.

6654{
6655 struct queue_stasis_data *queue_data = userdata;
6656 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6657 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6658 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6659 RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
6660 enum agent_complete_reason reason;
6661
6662 ao2_lock(queue_data);
6663
6664 if (queue_data->dying) {
6665 ao2_unlock(queue_data);
6666 return;
6667 }
6668
6669 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6670 reason = CALLER;
6671 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6672 reason = AGENT;
6673 } else {
6674 ao2_unlock(queue_data);
6675 return;
6676 }
6677
6678 chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
6679 if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
6680 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
6681 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
6682 /* Channel that is hanging up is doing it as part of a transfer.
6683 * We'll get a transfer event later
6684 */
6685 ao2_unlock(queue_data);
6686 return;
6687 }
6688
6689 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6690 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6691
6692 ao2_unlock(queue_data);
6693
6694 ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
6695 channel_blob->snapshot->base->name);
6696
6697 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6698 reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
6699 (long) (queue_data->starttime - queue_data->holdstart),
6700 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6701
6702 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6703 queue_data->holdstart, queue_data->starttime, reason);
6704 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6705 queue_data->starttime);
6706 remove_stasis_subscriptions(queue_data);
6707}
agent_complete_reason
Definition: app_queue.c:6117
#define AST_TRANSFERER_ROLE_NAME
Definition: bridge_basic.h:36
int ast_channel_has_role(struct ast_channel *channel, const char *role_name)
Check if a role exists on a channel.
Definition: bridge_roles.c:394
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
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 6537 of file app_queue.c.

6539{
6540 struct queue_stasis_data *queue_data = userdata;
6541 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6542 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6543 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6544 struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6545 struct local_optimization *optimization;
6546 unsigned int id;
6547 SCOPED_AO2LOCK(lock, queue_data);
6548
6549 if (queue_data->dying) {
6550 return;
6551 }
6552
6553 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6554 optimization = &queue_data->member_optimize;
6555 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6556 optimization = &queue_data->caller_optimize;
6557 } else {
6558 return;
6559 }
6560
6561 /* We only allow move-swap optimizations, so there had BETTER be a source */
6562 ast_assert(source != NULL);
6563
6564 optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6565 if (!optimization->source_chan_uniqueid) {
6566 ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6567 return;
6568 }
6570
6571 optimization->id = id;
6572 optimization->in_progress = 1;
6573}
enum queue_result id
Definition: app_queue.c:1638
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:6193
const char * source_chan_uniqueid
Definition: app_queue.c:6195
unsigned int id
Definition: app_queue.c:6199
struct local_optimization member_optimize
Definition: app_queue.c:6247
struct local_optimization caller_optimize
Definition: app_queue.c:6245
#define ast_assert(a)
Definition: utils.h:739

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

Referenced by setup_stasis_subs().

◆ handle_local_optimization_end()

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

Definition at line 6588 of file app_queue.c.

6590{
6591 struct queue_stasis_data *queue_data = userdata;
6592 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6593 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6594 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6595 struct local_optimization *optimization;
6596 int is_caller;
6597 unsigned int id;
6598 SCOPED_AO2LOCK(lock, queue_data);
6599
6600 if (queue_data->dying) {
6601 return;
6602 }
6603
6604 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6605 optimization = &queue_data->member_optimize;
6606 is_caller = 0;
6607 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6608 optimization = &queue_data->caller_optimize;
6609 is_caller = 1;
6610 } else {
6611 return;
6612 }
6613
6615
6616 if (!optimization->in_progress) {
6617 ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
6618 return;
6619 }
6620
6621 if (id != optimization->id) {
6622 ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
6623 id, optimization->id);
6624 return;
6625 }
6626
6627 if (is_caller) {
6628 ast_debug(3, "Local optimization: Changing queue caller uniqueid from %s to %s\n",
6629 queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
6630 ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
6631 } else {
6632 ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
6633 queue_data->member_uniqueid, optimization->source_chan_uniqueid);
6634 ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
6635 }
6636
6637 optimization->in_progress = 0;
6638}

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

6711{
6712 struct queue_stasis_data *queue_data = userdata;
6713 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6714 const char *new_channel_id;
6715
6716 new_channel_id = ast_json_string_get(ast_json_object_get(channel_blob->blob, "newchanneluniqueid"));
6717
6718 ao2_lock(queue_data);
6719
6720 if (queue_data->dying) {
6721 ao2_unlock(queue_data);
6722 return;
6723 }
6724
6725 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6726 ast_debug(1, "Replacing caller channel %s with %s due to masquerade\n", queue_data->caller_uniqueid, new_channel_id);
6727 ast_string_field_set(queue_data, caller_uniqueid, new_channel_id);
6728 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6729 ast_debug(1, "Replacing member channel %s with %s due to masquerade\n", queue_data->member_uniqueid, new_channel_id);
6730 ast_string_field_set(queue_data, member_uniqueid, new_channel_id);
6731 }
6732
6733 ao2_unlock(queue_data);
6734}
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 10982 of file app_queue.c.

10983{
10984 const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
10985 int penalty;
10986
10987 switch ( cmd ) {
10988 case CLI_INIT:
10989 e->command = "queue add member";
10990 e->usage =
10991 "Usage: queue add member <dial string> to <queue> [penalty <penalty> [as <membername> [state_interface <interface>]]]\n"
10992 " 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";
10993 return NULL;
10994 case CLI_GENERATE:
10995 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
10996 }
10997
10998 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
10999 return CLI_SHOWUSAGE;
11000 } else if (strcmp(a->argv[4], "to")) {
11001 return CLI_SHOWUSAGE;
11002 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
11003 return CLI_SHOWUSAGE;
11004 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
11005 return CLI_SHOWUSAGE;
11006 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
11007 return CLI_SHOWUSAGE;
11008 }
11009
11010 queuename = a->argv[5];
11011 interface = a->argv[3];
11012 if (a->argc >= 8) {
11013 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
11014 if (penalty < 0) {
11015 ast_cli(a->fd, "Penalty must be >= 0\n");
11016 penalty = 0;
11017 }
11018 } else {
11019 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
11020 penalty = 0;
11021 }
11022 } else {
11023 penalty = 0;
11024 }
11025
11026 if (a->argc >= 10) {
11027 membername = a->argv[9];
11028 }
11029
11030 if (a->argc >= 12) {
11031 state_interface = a->argv[11];
11032 }
11033
11034 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface, NULL, 0)) {
11035 case RES_OKAY:
11036 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
11037 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
11038 } else {
11039 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", "");
11040 }
11041 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
11042 return CLI_SUCCESS;
11043 case RES_EXISTS:
11044 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
11045 return CLI_FAILURE;
11046 case RES_NOSUCHQUEUE:
11047 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
11048 return CLI_FAILURE;
11049 case RES_OUTOFMEMORY:
11050 ast_cli(a->fd, "Out of memory\n");
11051 return CLI_FAILURE;
11052 case RES_NOT_DYNAMIC:
11053 ast_cli(a->fd, "Member not dynamic\n");
11054 return CLI_FAILURE;
11055 default:
11056 return CLI_FAILURE;
11057 }
11058}
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1569
static char * complete_queue_add_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10807
@ 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 11171 of file app_queue.c.

11172{
11173 const char *queuename, *caller;
11174 int priority, immediate = 0;
11175 char *res = CLI_FAILURE;
11176
11177 switch (cmd) {
11178 case CLI_INIT:
11179 e->command = "queue priority caller";
11180 e->usage =
11181 "Usage: queue priority caller <channel> on <queue> to <priority> [immediate]\n"
11182 " Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
11183 return NULL;
11184 case CLI_GENERATE:
11185 return NULL;
11186 }
11187
11188 if (a->argc < 8) {
11189 return CLI_SHOWUSAGE;
11190 } else if (strcmp(a->argv[4], "on")) {
11191 return CLI_SHOWUSAGE;
11192 } else if (strcmp(a->argv[6], "to")) {
11193 return CLI_SHOWUSAGE;
11194 } else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
11195 ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
11196 return CLI_SHOWUSAGE;
11197 } else if (a->argc == 9) {
11198 if (strcmp(a->argv[8], "immediate")) {
11199 return CLI_SHOWUSAGE;
11200 }
11201 immediate = 1;
11202 }
11203
11204 caller = a->argv[3];
11205 queuename = a->argv[5];
11206
11207 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11208 case RES_OKAY:
11209 res = CLI_SUCCESS;
11210 break;
11211 case RES_NOSUCHQUEUE:
11212 ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename);
11213 break;
11214 case RES_NOT_CALLER:
11215 ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename);
11216
11217 break;
11218 }
11219
11220 return res;
11221}
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:7641

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

11245{
11246 const char *queuename, *interface, *reason;
11247 int paused;
11248
11249 switch (cmd) {
11250 case CLI_INIT:
11251 e->command = "queue {pause|unpause} member";
11252 e->usage =
11253 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
11254 " Pause or unpause a queue member. Not specifying a particular queue\n"
11255 " will pause or unpause a member across all queues to which the member\n"
11256 " belongs.\n";
11257 return NULL;
11258 case CLI_GENERATE:
11259 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
11260 }
11261
11262 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
11263 return CLI_SHOWUSAGE;
11264 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
11265 return CLI_SHOWUSAGE;
11266 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
11267 return CLI_SHOWUSAGE;
11268 }
11269
11270
11271 interface = a->argv[3];
11272 queuename = a->argc >= 6 ? a->argv[5] : NULL;
11273 reason = a->argc == 8 ? a->argv[7] : NULL;
11274 paused = !strcasecmp(a->argv[1], "pause");
11275
11276 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
11277 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
11278 if (!ast_strlen_zero(queuename)) {
11279 ast_cli(a->fd, " in queue '%s'", queuename);
11280 }
11281 if (!ast_strlen_zero(reason)) {
11282 ast_cli(a->fd, " for reason '%s'", reason);
11283 }
11284 ast_cli(a->fd, "\n");
11285 return CLI_SUCCESS;
11286 } else {
11287 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
11288 if (!ast_strlen_zero(queuename)) {
11289 ast_cli(a->fd, " in queue '%s'", queuename);
11290 }
11291 if (!ast_strlen_zero(reason)) {
11292 ast_cli(a->fd, " for reason '%s'", reason);
11293 }
11294 ast_cli(a->fd, "\n");
11295 return CLI_FAILURE;
11296 }
11297}
static char * complete_queue_pause_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11225
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:7847
#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 11516 of file app_queue.c.

11517{
11518 struct ast_flags mask = {0,};
11519 int i;
11520
11521 switch (cmd) {
11522 case CLI_INIT:
11523 e->command = "queue reload {parameters|members|rules|all}";
11524 e->usage =
11525 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
11526 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
11527 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
11528 "specified in order to know what information to reload. Below is an explanation\n"
11529 "of each of these qualifiers.\n"
11530 "\n"
11531 "\t'members' - reload queue members from queues.conf\n"
11532 "\t'parameters' - reload all queue options except for queue members\n"
11533 "\t'rules' - reload the queuerules.conf file\n"
11534 "\t'all' - reload queue rules, parameters, and members\n"
11535 "\n"
11536 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
11537 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
11538 "one queue is specified when using this command, reloading queue rules may cause\n"
11539 "other queues to be affected\n";
11540 return NULL;
11541 case CLI_GENERATE:
11542 if (a->pos >= 3) {
11543 /* find the point at which the list of queue names starts */
11544 const char *command_end = a->line + strlen("queue reload ");
11545 command_end = strchr(command_end, ' ');
11546 if (!command_end) {
11547 command_end = a->line + strlen(a->line);
11548 }
11549 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
11550 } else {
11551 return NULL;
11552 }
11553 }
11554
11555 if (a->argc < 3)
11556 return CLI_SHOWUSAGE;
11557
11558 if (!strcasecmp(a->argv[2], "rules")) {
11560 } else if (!strcasecmp(a->argv[2], "members")) {
11562 } else if (!strcasecmp(a->argv[2], "parameters")) {
11564 } else if (!strcasecmp(a->argv[2], "all")) {
11566 }
11567
11568 if (a->argc == 3) {
11569 reload_handler(1, &mask, NULL);
11570 return CLI_SUCCESS;
11571 }
11572
11573 for (i = 3; i < a->argc; ++i) {
11574 reload_handler(1, &mask, a->argv[i]);
11575 }
11576
11577 return CLI_SUCCESS;
11578}
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:9995
Structure used to handle boolean flags.
Definition: utils.h:199
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_FLAGS_ALL
Definition: utils.h:196

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

◆ handle_queue_remove_member()

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

Definition at line 11108 of file app_queue.c.

11109{
11110 const char *queuename, *interface;
11111 struct member *mem = NULL;
11112 char *res = CLI_FAILURE;
11113
11114 switch (cmd) {
11115 case CLI_INIT:
11116 e->command = "queue remove member";
11117 e->usage =
11118 "Usage: queue remove member <channel> from <queue>\n"
11119 " Remove a specific channel from a queue.\n";
11120 return NULL;
11121 case CLI_GENERATE:
11122 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
11123 }
11124
11125 if (a->argc != 6) {
11126 return CLI_SHOWUSAGE;
11127 } else if (strcmp(a->argv[4], "from")) {
11128 return CLI_SHOWUSAGE;
11129 }
11130
11131 queuename = a->argv[5];
11132 interface = a->argv[3];
11133
11135 mem = find_member_by_queuename_and_interface(queuename, interface);
11136 }
11137
11138 switch (remove_from_queue(queuename, interface)) {
11139 case RES_OKAY:
11140 if (!mem || ast_strlen_zero(mem->membername)) {
11141 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
11142 } else {
11143 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
11144 }
11145 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
11146 res = CLI_SUCCESS;
11147 break;
11148 case RES_EXISTS:
11149 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
11150 break;
11151 case RES_NOSUCHQUEUE:
11152 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
11153 break;
11154 case RES_OUTOFMEMORY:
11155 ast_cli(a->fd, "Out of memory\n");
11156 break;
11157 case RES_NOT_DYNAMIC:
11158 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
11159 break;
11160 }
11161
11162 if (mem) {
11163 ao2_ref(mem, -1);
11164 }
11165
11166 return res;
11167}
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:7535
static struct member * find_member_by_queuename_and_interface(const char *queuename, const char *interface)
Find a member by looking up queuename and interface.
Definition: app_queue.c:11919
static char * complete_queue_remove_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11060

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

11478{
11479 struct ast_flags mask = {QUEUE_RESET_STATS,};
11480 int i;
11481
11482 switch (cmd) {
11483 case CLI_INIT:
11484 e->command = "queue reset stats";
11485 e->usage =
11486 "Usage: queue reset stats [<queuenames>]\n"
11487 "\n"
11488 "Issuing this command will reset statistics for\n"
11489 "<queuenames>, or for all queues if no queue is\n"
11490 "specified.\n";
11491 return NULL;
11492 case CLI_GENERATE:
11493 if (a->pos >= 3) {
11494 return complete_queue(a->line, a->word, a->pos, a->n, 17);
11495 } else {
11496 return NULL;
11497 }
11498 }
11499
11500 if (a->argc < 3) {
11501 return CLI_SHOWUSAGE;
11502 }
11503
11504 if (a->argc == 3) {
11505 reload_handler(1, &mask, NULL);
11506 return CLI_SUCCESS;
11507 }
11508
11509 for (i = 3; i < a->argc; ++i) {
11510 reload_handler(1, &mask, a->argv[i]);
11511 }
11512
11513 return CLI_SUCCESS;
11514}

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

11443{
11444 const char *rule;
11445 struct rule_list *rl_iter;
11446 struct penalty_rule *pr_iter;
11447 switch (cmd) {
11448 case CLI_INIT:
11449 e->command = "queue show rules";
11450 e->usage =
11451 "Usage: queue show rules [rulename]\n"
11452 " Show the list of rules associated with rulename. If no\n"
11453 " rulename is specified, list all rules defined in queuerules.conf\n";
11454 return NULL;
11455 case CLI_GENERATE:
11456 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
11457 }
11458
11459 if (a->argc != 3 && a->argc != 4) {
11460 return CLI_SHOWUSAGE;
11461 }
11462
11463 rule = a->argc == 4 ? a->argv[3] : "";
11465 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11466 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
11467 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
11468 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
11469 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);
11470 }
11471 }
11472 }
11474 return CLI_SUCCESS;
11475}
static char * complete_queue_rule_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11420

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

11380{
11381 const char *queuename = NULL, *interface;
11382 int penalty = 0;
11383
11384 switch (cmd) {
11385 case CLI_INIT:
11386 e->command = "queue set penalty";
11387 e->usage =
11388 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
11389 " Set a member's penalty in the queue specified. If no queue is specified\n"
11390 " then that interface's penalty is set in all queues to which that interface is a member\n";
11391 return NULL;
11392 case CLI_GENERATE:
11393 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11394 }
11395
11396 if (a->argc != 6 && a->argc != 8) {
11397 return CLI_SHOWUSAGE;
11398 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11399 return CLI_SHOWUSAGE;
11400 }
11401
11402 if (a->argc == 8) {
11403 queuename = a->argv[7];
11404 }
11405 interface = a->argv[5];
11406 penalty = atoi(a->argv[3]);
11407
11408 switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
11409 case RESULT_SUCCESS:
11410 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11411 return CLI_SUCCESS;
11412 case RESULT_FAILURE:
11413 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11414 return CLI_FAILURE;
11415 default:
11416 return CLI_FAILURE;
11417 }
11418}
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:7995
static char * complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11299

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

11323{
11324 const char *queuename = NULL, *interface;
11325 int ringinuse;
11326
11327 switch (cmd) {
11328 case CLI_INIT:
11329 e->command = "queue set ringinuse";
11330 e->usage =
11331 "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
11332 " Set a member's ringinuse in the queue specified. If no queue is specified\n"
11333 " then that interface's penalty is set in all queues to which that interface is a member.\n";
11334 break;
11335 return NULL;
11336 case CLI_GENERATE:
11337 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11338 }
11339
11340 /* Sensible argument counts */
11341 if (a->argc != 6 && a->argc != 8) {
11342 return CLI_SHOWUSAGE;
11343 }
11344
11345 /* Uses proper indicational words */
11346 if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11347 return CLI_SHOWUSAGE;
11348 }
11349
11350 /* Set the queue name if applicable */
11351 if (a->argc == 8) {
11352 queuename = a->argv[7];
11353 }
11354
11355 /* Interface being set */
11356 interface = a->argv[5];
11357
11358 /* Check and set the ringinuse value */
11359 if (ast_true(a->argv[3])) {
11360 ringinuse = 1;
11361 } else if (ast_false(a->argv[3])) {
11362 ringinuse = 0;
11363 } else {
11364 return CLI_SHOWUSAGE;
11365 }
11366
11367 switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11368 case RESULT_SUCCESS:
11369 ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11370 return CLI_SUCCESS;
11371 case RESULT_FAILURE:
11372 ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11373 return CLI_FAILURE;
11374 default:
11375 return CLI_FAILURE;
11376 }
11377}
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2216

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

◆ hangupcalls()

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

Hang up a list of outgoing calls.

Definition at line 4464 of file app_queue.c.

4465{
4466 struct callattempt *oo;
4467
4468 while (outgoing) {
4469 /* If someone else answered the call we should indicate this in the CANCEL */
4470 /* Hangup any existing lines we have open */
4471 if (outgoing->chan && (outgoing->chan != exception)) {
4472 if (exception || cancel_answered_elsewhere) {
4474 }
4475 ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
4476
4477 /* When dialing channels it is possible that they may not ever
4478 * leave the not in use state (Local channels in particular) by
4479 * the time we cancel them. If this occurs but we know they were
4480 * dialed we explicitly remove them from the pending members
4481 * container so that subsequent call attempts occur.
4482 */
4483 if (outgoing->member->status == AST_DEVICE_NOT_INUSE) {
4485 }
4486
4487 ast_hangup(outgoing->chan);
4488 }
4489 oo = outgoing;
4490 outgoing = outgoing->q_next;
4492 callattempt_free(oo);
4493 }
4494}
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:307
static void callattempt_free(struct callattempt *doomed)
Definition: app_queue.c:4442
#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:1686
struct ast_channel * chan
Definition: app_queue.c:1720

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

2948{
2949 int i;
2950 struct penalty_rule *pr_iter;
2951
2952 q->dead = 0;
2953 q->retry = DEFAULT_RETRY;
2955 q->maxlen = 0;
2956
2957 ast_string_field_set(q, announce, "");
2959 ast_string_field_set(q, membergosub, "");
2960 ast_string_field_set(q, defaultrule, "");
2961
2962 q->announcefrequency = 0;
2964 q->announceholdtime = 1;
2966 q->announcepositionlimit = 10; /* Default 10 positions */
2967 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
2968 q->roundingseconds = 0; /* Default - don't announce seconds */
2969 q->servicelevel = 0;
2970 q->ringinuse = 1;
2972 q->setinterfacevar = 0;
2973 q->setqueuevar = 0;
2974 q->setqueueentryvar = 0;
2976 q->monfmt[0] = '\0';
2977 q->reportholdtime = 0;
2978 q->wrapuptime = 0;
2979 q->penaltymemberslimit = 0;
2980 q->joinempty = 0;
2981 q->leavewhenempty = 0;
2982 q->memberdelay = 0;
2983 q->weight = 0;
2984 q->timeoutrestart = 0;
2988 q->numperiodicannounce = 0;
2991 q->autopausebusy = 0;
2992 q->autopauseunavail = 0;
2994 q->autopausedelay = 0;
2995 if (!q->members) {
2997 /* linear strategy depends on order, so we have to place all members in a list */
2999 } else {
3002 }
3003 }
3004 q->found = 1;
3005
3006 ast_string_field_set(q, moh, "");
3007 ast_string_field_set(q, sound_next, "queue-youarenext");
3008 ast_string_field_set(q, sound_thereare, "queue-thereare");
3009 ast_string_field_set(q, sound_calls, "queue-callswaiting");
3010 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3011 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3012 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3013 ast_string_field_set(q, sound_minutes, "queue-minutes");
3014 ast_string_field_set(q, sound_minute, "queue-minute");
3015 ast_string_field_set(q, sound_seconds, "queue-seconds");
3016 ast_string_field_set(q, sound_thanks, "queue-thankyou");
3017 ast_string_field_set(q, sound_callerannounce, "");
3018 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3019
3020 if (!q->sound_periodicannounce[0]) {
3022 }
3023
3024 if (q->sound_periodicannounce[0]) {
3025 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3026 }
3027
3028 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3029 if (q->sound_periodicannounce[i]) {
3030 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3031 }
3032 }
3033
3034 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3035 ast_free(pr_iter);
3036 }
3037
3038 /* On restart assume no members are available.
3039 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3040 *
3041 * This seems counter intuitive, but is required to light a BLF
3042 * AST_DEVICE_INUSE indicates no members are available.
3043 * AST_DEVICE_NOT_INUSE indicates a member is available.
3044 */
3046}
#define DEFAULT_RETRY
Definition: app_queue.c:1553
static int member_hash_fn(const void *obj, const int flags)
Definition: app_queue.c:2918
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition: app_queue.c:2934
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition: app_queue.c:1561
#define DEFAULT_TIMEOUT
Definition: app_queue.c:1554
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1596
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1786
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
unsigned int autopauseunavail
Definition: app_queue.c:1849
unsigned int setinterfacevar
Definition: app_queue.c:1835
int announcefrequency
Definition: app_queue.c:1853
unsigned int announceholdtime
Definition: app_queue.c:1841
unsigned int reportholdtime
Definition: app_queue.c:1838
unsigned int setqueueentryvar
Definition: app_queue.c:1837
unsigned int timeoutrestart
Definition: app_queue.c:1840
int periodicannouncefrequency
Definition: app_queue.c:1856
unsigned int announceposition_only_up
Definition: app_queue.c:1843
unsigned int setqueuevar
Definition: app_queue.c:1836
int announcepositionlimit
Definition: app_queue.c:1852
unsigned int announce_to_first_user
Definition: app_queue.c:1834
int randomperiodicannounce
Definition: app_queue.c:1858
int autopause
Definition: app_queue.c:1876
int periodicannouncestartdelay
Definition: app_queue.c:1855
struct call_queue::@54 rules
int servicelevel
Definition: app_queue.c:1865
int autofill
Definition: app_queue.c:1883
int minannouncefrequency
Definition: app_queue.c:1854
enum empty_conditions leavewhenempty
Definition: app_queue.c:1851
int roundingseconds
Definition: app_queue.c:1859
int numperiodicannounce
Definition: app_queue.c:1857
unsigned int announceposition
Definition: app_queue.c:1842
char monfmt[8]
Definition: app_queue.c:1867
enum empty_conditions joinempty
Definition: app_queue.c:1850
int memberdelay
Definition: app_queue.c:1882
unsigned int autopausebusy
Definition: app_queue.c:1848
int autopausedelay
Definition: app_queue.c:1877
int timeoutpriority
Definition: app_queue.c:1878
unsigned int relativeperiodicannounce
Definition: app_queue.c:1847

References call_queue::announce_to_first_user, call_queue::announcefrequency, call_queue::announceholdtime, call_queue::announceposition, call_queue::announceposition_only_up, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ao2_container_alloc_list, AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_free, AST_LIST_REMOVE_HEAD, ast_str_create, ast_str_set(), ast_string_field_set, call_queue::autofill, autofill_default, call_queue::autopause, call_queue::autopausebusy, call_queue::autopausedelay, call_queue::autopauseunavail, voicemailpwcheck::context, call_queue::dead, DEFAULT_MIN_ANNOUNCE_FREQUENCY, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, penalty_rule::list, 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 2087 of file app_queue.c.

2088{
2089 struct queue_ent *cur;
2090
2091 if (!q || !new)
2092 return;
2093 if (prev) {
2094 cur = prev->next;
2095 prev->next = new;
2096 } else {
2097 cur = q->head;
2098 q->head = new;
2099 }
2100 new->next = cur;
2101
2102 /* every queue_ent must have a reference to it's parent call_queue, this
2103 * reference does not go away until the end of the queue_ent's life, meaning
2104 * that even when the queue_ent leaves the call_queue this ref must remain. */
2105 if (!new->parent) {
2106 queue_ref(q);
2107 new->parent = q;
2108 }
2109 new->pos = ++(*pos);
2110 new->opos = *pos;
2111}
#define queue_ref(q)
Definition: app_queue.c:2053

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

3081{
3082 char *timestr, *maxstr, *minstr, *raisestr, *contentdup;
3083 struct penalty_rule *rule = NULL, *rule_iter;
3084 struct rule_list *rl_iter;
3085 int penaltychangetime, inserted = 0;
3086
3087 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
3088 return -1;
3089 }
3090
3091 contentdup = ast_strdupa(content);
3092
3093 if (!(maxstr = strchr(contentdup, ','))) {
3094 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
3095 ast_free(rule);
3096 return -1;
3097 }
3098
3099 *maxstr++ = '\0';
3100 if ((minstr = strchr(maxstr,','))) {
3101 *minstr++ = '\0';
3102 if ((raisestr = strchr(minstr,','))) {
3103 *raisestr++ = '\0';
3104 }
3105 } else {
3106 raisestr = NULL;
3107 }
3108
3109 timestr = contentdup;
3110 if ((penaltychangetime = atoi(timestr)) < 0) {
3111 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
3112 ast_free(rule);
3113 return -1;
3114 }
3115
3116 rule->time = penaltychangetime;
3117
3118 /* The last check will evaluate true if either no penalty change is indicated for a given rule
3119 * OR if a min penalty change is indicated but no max penalty change is */
3120 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
3121 rule->max_relative = 1;
3122 }
3123
3124 rule->max_value = atoi(maxstr);
3125
3126 if (!ast_strlen_zero(minstr)) {
3127 if (*minstr == '+' || *minstr == '-') {
3128 rule->min_relative = 1;
3129 }
3130 rule->min_value = atoi(minstr);
3131 } else { /*there was no minimum specified, so assume this means no change*/
3132 rule->min_relative = 1;
3133 }
3134
3135 if (!ast_strlen_zero(raisestr)) {
3136 if (*raisestr == '+' || *raisestr == '-') {
3137 rule->raise_relative = 1;
3138 }
3139 rule->raise_value = atoi(raisestr);
3140 } else { /*there was no raise specified, so assume this means no change*/
3141 rule->raise_relative = 1;
3142 }
3143
3144 /*We have the rule made, now we need to insert it where it belongs*/
3145 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
3146 if (strcasecmp(rl_iter->name, list_name)) {
3147 continue;
3148 }
3149
3150 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
3151 if (rule->time < rule_iter->time) {
3153 inserted = 1;
3154 break;
3155 }
3156 }
3158
3159 if (!inserted) {
3160 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
3161 inserted = 1;
3162 }
3163
3164 break;
3165 }
3166
3167 if (!inserted) {
3168 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
3169 ast_free(rule);
3170 return -1;
3171 }
3172 return 0;
3173}
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:599
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529

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

Referenced by reload_queue_rules().

◆ int2strat()

static const char * int2strat ( int  strategy)
static

Definition at line 1920 of file app_queue.c.

1921{
1922 int x;
1923
1924 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1925 if (strategy == strategies[x].strategy) {
1926 return strategies[x].name;
1927 }
1928 }
1929
1930 return "<unknown>";
1931}
static const struct strategy strategies[]
const char * name
Definition: app_queue.c:1531

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

7454{
7455 struct member *mem;
7456 struct ao2_iterator mem_iter;
7457
7458 if (!q) {
7459 return NULL;
7460 }
7461 mem_iter = ao2_iterator_init(q->members, 0);
7462 while ((mem = ao2_iterator_next(&mem_iter))) {
7463 if (!strcasecmp(interface, mem->interface)) {
7464 ao2_iterator_destroy(&mem_iter);
7465 return mem;
7466 }
7467 ao2_ref(mem, -1);
7468 }
7469 ao2_iterator_destroy(&mem_iter);
7470
7471 return NULL;
7472}

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

4572{
4573 struct call_queue *q;
4574 struct member *mem;
4575 int is_longest_waiting = 1;
4576 struct ao2_iterator queue_iter;
4577 struct queue_ent *ch;
4578
4579 queue_iter = ao2_iterator_init(queues, 0);
4580 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4581 if (q == caller->parent) { /* don't check myself, could deadlock */
4582 queue_t_unref(q, "Done with iterator");
4583 continue;
4584 }
4585 ao2_lock(q);
4586 /*
4587 * If the other queue has equal weight, see if we should let that handle
4588 * their call first. If weights are not equal, compare_weights will step in.
4589 */
4590 if (q->weight == caller->parent->weight && q->count && q->members) {
4591 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4592 ast_debug(2, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4593
4594 /* Does this queue have a caller that's been waiting longer? */
4595 ch = q->head;
4596 while (ch) {
4597 /* If ch->pending, the other call (which may be waiting for a longer period of time),
4598 * is already ringing at another agent. Ignore such callers; otherwise, all agents
4599 * will be unused until the first caller is picked up.
4600 */
4601 if (ch->start < caller->start && !ch->pending) {
4602 ast_debug(1, "Queue %s has a call at position %i that's been waiting longer (%li vs %li)\n",
4603 q->name, ch->pos, ch->start, caller->start);
4604 is_longest_waiting = 0;
4605 break;
4606 }
4607 ch = ch->next;
4608 }
4609 }
4610 }
4611 ao2_unlock(q);
4612 queue_t_unref(q, "Done with iterator");
4613 if (!is_longest_waiting) {
4614 break;
4615 }
4616 }
4617 ao2_iterator_destroy(&queue_iter);
4618 return is_longest_waiting;
4619}
int pending
Definition: app_queue.c:1709
time_t start
Definition: app_queue.c:1715

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

Referenced by can_ring_entry().

◆ is_member_available()

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

Definition at line 2604 of file app_queue.c.

2605{
2606 int available = 0;
2607 int wrapuptime;
2608
2609 switch (mem->status) {
2610 case AST_DEVICE_INVALID:
2612 break;
2613 case AST_DEVICE_INUSE:
2614 case AST_DEVICE_BUSY:
2615 case AST_DEVICE_RINGING:
2617 case AST_DEVICE_ONHOLD:
2618 if (!mem->ringinuse) {
2619 break;
2620 }
2621 /* else fall through */
2623 case AST_DEVICE_UNKNOWN:
2624 if (!mem->paused) {
2625 available = 1;
2626 }
2627 break;
2628 }
2629
2630 /* Let wrapuptimes override device state availability */
2631 wrapuptime = get_wrapuptime(q, mem);
2632 if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {
2633 available = 0;
2634 }
2635 return available;
2636}
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13472

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

5741{
5742 struct queue_ent *ch;
5743 int res;
5744 int avl;
5745 int idx = 0;
5746 /* This needs a lock. How many members are available to be served? */
5747 ao2_lock(qe->parent);
5748
5749 avl = num_available_members(qe->parent);
5750
5751 ch = qe->parent->head;
5752
5753 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
5754
5755 while ((idx < avl) && (ch) && (ch != qe)) {
5756 if (!ch->pending) {
5757 idx++;
5758 }
5759 ch = ch->next;
5760 }
5761
5762 ao2_unlock(qe->parent);
5763 /* If the queue entry is within avl [the number of available members] calls from the top ...
5764 * Autofill and position check added to support autofill=no (as only calls
5765 * from the front of the queue are valid when autofill is disabled)
5766 */
5767 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
5768 ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
5769 res = 1;
5770 } else {
5771 ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
5772 res = 0;
5773 }
5774
5775 /* Update realtime members if this is the first call and number of avalable members is 0 */
5776 if (avl == 0 && qe->pos == 1) {
5778 }
5779
5780 return res;
5781}

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

Referenced by queue_exec(), and wait_our_turn().

◆ join_queue()

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

Definition at line 4054 of file app_queue.c.

4055{
4056 struct call_queue *q;
4057 struct queue_ent *cur, *prev = NULL;
4058 int res = -1;
4059 int pos = 0;
4060 int inserted = 0;
4061
4062 if (!(q = find_load_queue_rt_friendly(queuename))) {
4063 return res;
4064 }
4065 ao2_lock(q);
4066
4067 /* This is our one */
4068 if (q->joinempty) {
4069 int status = 0;
4070 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, qe->raise_penalty, q->joinempty, 0))) {
4071 *reason = QUEUE_JOINEMPTY;
4072 ao2_unlock(q);
4073 queue_t_unref(q, "Done with realtime queue");
4074 return res;
4075 }
4076 }
4077 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
4078 *reason = QUEUE_FULL;
4079 } else if (*reason == QUEUE_UNKNOWN) {
4080 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4081
4082 /* There's space for us, put us at the right position inside
4083 * the queue.
4084 * Take into account the priority of the calling user */
4085 inserted = 0;
4086 prev = NULL;
4087 cur = q->head;
4088 while (cur) {
4089 /* We have higher priority than the current user, enter
4090 * before him, after all the other users with priority
4091 * higher or equal to our priority. */
4092 if ((!inserted) && (qe->prio > cur->prio)) {
4093 insert_entry(q, prev, qe, &pos);
4094 inserted = 1;
4095 }
4096 /* <= is necessary for the position comparison because it may not be possible to enter
4097 * at our desired position since higher-priority callers may have taken the position we want
4098 */
4099 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
4100 insert_entry(q, prev, qe, &pos);
4101 inserted = 1;
4102 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
4103 if (position < pos) {
4104 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
4105 }
4106 }
4107 cur->pos = ++pos;
4108 prev = cur;
4109 cur = cur->next;
4110 }
4111 /* No luck, join at the end of the queue */
4112 if (!inserted) {
4113 insert_entry(q, prev, qe, &pos);
4114 }
4115 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
4116 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
4117 ast_copy_string(qe->context, q->context, sizeof(qe->context));
4118 q->count++;
4119 if (q->count == 1) {
4121 }
4122
4123 res = 0;
4124
4125 blob = ast_json_pack("{s: s, s: i, s: i}",
4126 "Queue", q->name,
4127 "Position", qe->pos,
4128 "Count", q->count);
4129 ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
4130 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
4131 }
4132 ao2_unlock(q);
4133 queue_t_unref(q, "Done with realtime queue");
4134
4135 return res;
4136}
jack_status_t status
Definition: app_jack.c:146
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:1829
const ast_string_field context
Definition: app_queue.c:1829
const ast_string_field announce
Definition: app_queue.c:1829
char announce[PATH_MAX]
Definition: app_queue.c:1695
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1694
char context[AST_MAX_CONTEXT]
Definition: app_queue.c:1696

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

Referenced by queue_exec().

◆ kill_dead_members()

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

Definition at line 9729 of file app_queue.c.

9730{
9731 struct member *member = obj;
9732
9733 if (!member->delme) {
9735 return 0;
9736 } else {
9737 return CMP_MATCH;
9738 }
9739}
@ CMP_MATCH
Definition: astobj2.h:1027
unsigned int delme
Definition: app_queue.c:1749

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

9885{
9886 struct call_queue *q = obj;
9887 char *queuename = arg;
9888 if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
9889 q->dead = 1;
9890 return CMP_MATCH;
9891 } else {
9892 return 0;
9893 }
9894}

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

4368{
4369 struct call_queue *q;
4370 struct queue_ent *current, *prev = NULL;
4371 struct penalty_rule *pr_iter;
4372 int pos = 0;
4373
4374 if (!(q = qe->parent)) {
4375 return;
4376 }
4377 queue_t_ref(q, "Copy queue pointer from queue entry");
4378 ao2_lock(q);
4379
4380 prev = NULL;
4381 for (current = q->head; current; current = current->next) {
4382 if (current == qe) {
4383 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4384 char posstr[20];
4385 q->count--;
4386 if (!q->count) {
4388 }
4389
4390 blob = ast_json_pack("{s: s, s: i, s: i}",
4391 "Queue", q->name,
4392 "Position", qe->pos,
4393 "Count", q->count);
4394 ast_channel_publish_cached_blob(qe->chan, queue_caller_leave_type(), blob);
4395 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
4396 /* Take us out of the queue */
4397 if (prev) {
4398 prev->next = current->next;
4399 } else {
4400 q->head = current->next;
4401 }
4402 /* Free penalty rules */
4403 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
4404 ast_free(pr_iter);
4405 }
4406 qe->pr = NULL;
4407 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
4408 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
4409 } else {
4410 /* Renumber the people after us in the queue based on a new count */
4411 current->pos = ++pos;
4412 prev = current;
4413 }
4414 }
4415 ao2_unlock(q);
4416
4417 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
4418 if (q->realtime) {
4419 struct ast_variable *var;
4420 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
4421 q->dead = 1;
4422 } else {
4424 }
4425 }
4426
4427 if (q->dead) {
4428 /* It's dead and nobody is in it, so kill it */
4429 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
4430 }
4431 /* unref the explicit ref earlier in the function */
4432 queue_t_unref(q, "Expire copied reference");
4433}
#define queue_t_ref(q, tag)
Definition: app_queue.c:2055
#define var
Definition: ast_expr2f.c:605
struct penalty_rule * pr
Definition: app_queue.c:1722

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

11752{
11753 int err = 0;
11754 struct ast_flags mask = {AST_FLAGS_ALL, };
11755 struct ast_config *member_config;
11756 struct stasis_topic *queue_topic;
11758
11761 if (!queues) {
11763 }
11764
11767 if (!pending_members) {
11768 unload_module();
11770 }
11771
11772 use_weight = 0;
11773
11774 if (reload_handler(0, &mask, NULL)) {
11775 unload_module();
11777 }
11778
11779 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, "reason_paused", RQ_CHAR, 80, SENTINEL);
11780
11781 /*
11782 * This section is used to determine which name for 'ringinuse' to use in realtime members
11783 * Necessary for supporting older setups.
11784 *
11785 * It also checks if 'reason_paused' exists in the realtime backend
11786 */
11787 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
11788 if (!member_config) {
11789 realtime_ringinuse_field = "ringinuse";
11790 } else {
11791 const char *config_val;
11792
11793 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
11794 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
11795 realtime_ringinuse_field = "ringinuse";
11796 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
11797 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
11798 realtime_ringinuse_field = "ignorebusy";
11799 } else {
11800 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
11801 realtime_ringinuse_field = "ringinuse";
11802 }
11803
11804 if (ast_variable_retrieve(member_config, NULL, "reason_paused")) {
11806 }
11807 }
11808 ast_config_destroy(member_config);
11809
11812 }
11813
11822 err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
11823 err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
11830 err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
11831 err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
11832 err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
11833 err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
11843
11844 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
11846 if (!device_state_sub) {
11847 err = -1;
11848 }
11851
11853 queue_topic = ast_queue_topic_all();
11854 if (!manager_topic || !queue_topic) {
11855 unload_module();
11857 }
11859 if (!topic_forwarder) {
11860 unload_module();
11862 }
11863
11866 unload_module();
11868 }
11870 if (!agent_router) {
11871 unload_module();
11873 }
11877 NULL);
11881 NULL);
11882
11883 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
11884 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
11885 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
11886
11887 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
11888 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
11889 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
11890 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
11891 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
11892 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
11893
11894 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
11895 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
11896 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
11897 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
11898 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
11899
11900 if (err) {
11901 unload_module();
11903 }
11905}
static struct ast_custom_function queuevar_function
Definition: app_queue.c:9445
static int manager_queue_reset(struct mansession *s, const struct message *m)
Definition: app_queue.c:10792
static int pending_members_cmp(void *obj, void *arg, int flags)
Definition: app_queue.c:2534
static struct ast_custom_function queuemembercount_function
Definition: app_queue.c:9450
static struct ast_custom_function queuewaitingcount_function
Definition: app_queue.c:9466
static char * app_pqm
Definition: app_queue.c:1578
static struct ast_custom_function queuememberlist_function
Definition: app_queue.c:9471
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition: app_queue.c:1620
static int manager_add_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10603
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition: app_queue.c:8349
#define MAX_QUEUE_BUCKETS
Definition: app_queue.c:1563
static int upqm_exec(struct ast_channel *chan, const char *data)
UnpauseQueueMember application.
Definition: app_queue.c:8242
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6155
static char * app_ql
Definition: app_queue.c:1582
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition: app_queue.c:8095
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition: app_queue.c:8278
#define MAX_CALL_ATTEMPT_BUCKETS
Definition: app_queue.c:2512
static char * app_rqm
Definition: app_queue.c:1576
static int manager_queue_rule_show(struct mansession *s, const struct message *m)
Definition: app_queue.c:10362
static int manager_queue_reload(struct mansession *s, const struct message *m)
Definition: app_queue.c:10760
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition: app_queue.c:8206
static int qupd_exec(struct ast_channel *chan, const char *data)
Update Queue with data of an outgoing call.
Definition: app_queue.c:11583
static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
Definition: app_queue.c:10838
static char * app_qupd
Definition: app_queue.c:1584
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
Definition: app_queue.c:10872
static char * app_upqm
Definition: app_queue.c:1580
static struct ast_custom_function queuememberpenalty_function
Definition: app_queue.c:9476
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition: app_queue.c:1976
static int manager_request_withdraw_caller_from_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:10945
static char * app
Definition: app_queue.c:1572
static int queue_hash_cb(const void *obj, const int flags)
Definition: app_queue.c:1969
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition: app_queue.c:8507
static int pending_members_hash(const void *obj, const int flags)
Definition: app_queue.c:2514
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10714
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition: app_queue.c:8430
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10667
static struct stasis_message_router * agent_router
Definition: app_queue.c:11673
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:2639
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition: app_queue.c:1608
static int manager_queues_summary(struct mansession *s, const struct message *m)
Summary of queue info via the AMI.
Definition: app_queue.c:10398
static int unload_module(void)
Definition: app_queue.c:11676
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
Definition: app_queue.c:10480
static int realtime_reason_paused
does realtime backend support reason_paused
Definition: app_queue.c:1623
static struct ast_custom_function queuemembercount_dep
Definition: app_queue.c:9456
static char * app_aqm
Definition: app_queue.c:1574
static struct ast_cli_entry cli_queue[]
Definition: app_queue.c:11660
static struct ast_custom_function queuegetchannel_function
Definition: app_queue.c:9461
static struct stasis_forward * topic_forwarder
Definition: app_queue.c:11674
static struct ast_custom_function queueexists_function
Definition: app_queue.c:9440
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:10898
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
Definition: app_queue.c:10739
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
Definition: devicestate.c:668
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1872
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition: manager.c:1636
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:3334
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3549
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
#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:626
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
@ 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:1023
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:1077
#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:1578
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:649
#define stasis_message_router_create(topic)
Create a new message router object.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.

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

◆ load_realtime_queues()

static void load_realtime_queues ( const char *  queuename)
static

Definition at line 3951 of file app_queue.c.

3952{
3953 struct ast_config *cfg = NULL;
3954 char *category = NULL;
3955 const char *name = NULL;
3956 struct call_queue *q = NULL;
3957
3958 if (!ast_check_realtime("queues")) {
3959 return;
3960 }
3961
3962 if (ast_strlen_zero(queuename)) {
3963 if ((cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL))) {
3964 while ((category = ast_category_browse(cfg, category))) {
3965 name = ast_variable_retrieve(cfg, category, "name");
3967 queue_unref(q);
3968 }
3969 }
3970 ast_config_destroy(cfg);
3971 }
3972 } else {
3973 if ((q = find_load_queue_rt_friendly(queuename))) {
3974 queue_unref(q);
3975 }
3976 }
3977}

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

3185{
3186 struct ast_config *cfg;
3187 struct rule_list *rl_iter, *new_rl;
3188 struct penalty_rule *pr_iter;
3189 char *rulecat = NULL;
3190
3191 if (!ast_check_realtime("queue_rules")) {
3192 ast_log(LOG_WARNING, "Missing \"queue_rules\" in extconfig.conf\n");
3193 return 0;
3194 }
3195 if (!(cfg = ast_load_realtime_multientry("queue_rules", "rule_name LIKE", "%", SENTINEL))) {
3196 ast_log(LOG_WARNING, "Failed to load queue rules from realtime\n");
3197 return 0;
3198 }
3199 while ((rulecat = ast_category_browse(cfg, rulecat))) {
3200 const char *timestr, *maxstr, *minstr, *raisestr, *rule_name;
3201 int penaltychangetime, rule_exists = 0, inserted = 0;
3202 int max_penalty = 0, min_penalty = 0, raise_penalty = 0;
3203 int min_relative = 0, max_relative = 0, raise_relative = 0;
3204 struct penalty_rule *new_penalty_rule = NULL;
3205
3206 rule_name = ast_variable_retrieve(cfg, rulecat, "rule_name");
3207 if (ast_strlen_zero(rule_name)) {
3208 continue;
3209 }
3210
3211 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
3212 if (!(strcasecmp(rl_iter->name, rule_name))) {
3213 rule_exists = 1;
3214 new_rl = rl_iter;
3215 break;
3216 }
3217 }
3218 if (!rule_exists) {
3219 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
3220 ast_config_destroy(cfg);
3221 return -1;
3222 }
3223 ast_copy_string(new_rl->name, rule_name, sizeof(new_rl->name));
3225 }
3226 timestr = ast_variable_retrieve(cfg, rulecat, "time");
3227 if (!(timestr) || sscanf(timestr, "%30d", &penaltychangetime) != 1) {
3228 ast_log(LOG_NOTICE, "Failed to parse time (%s) for one of the %s rules, skipping it\n",
3229 (ast_strlen_zero(timestr) ? "invalid value" : timestr), rule_name);
3230 continue;
3231 }
3232 if (!(new_penalty_rule = ast_calloc(1, sizeof(*new_penalty_rule)))) {
3233 ast_config_destroy(cfg);
3234 return -1;
3235 }
3236 if (!(maxstr = ast_variable_retrieve(cfg, rulecat, "max_penalty")) ||
3237 ast_strlen_zero(maxstr) || sscanf(maxstr, "%30d", &max_penalty) != 1) {
3238 max_penalty = 0;
3239 max_relative = 1;
3240 } else {
3241 if (*maxstr == '+' || *maxstr == '-') {
3242 max_relative = 1;
3243 }
3244 }
3245 if (!(minstr = ast_variable_retrieve(cfg, rulecat, "min_penalty")) ||
3246 ast_strlen_zero(minstr) || sscanf(minstr, "%30d", &min_penalty) != 1) {
3247 min_penalty = 0;
3248 min_relative = 1;
3249 } else {
3250 if (*minstr == '+' || *minstr == '-') {
3251 min_relative = 1;
3252 }
3253 }
3254 if (!(raisestr = ast_variable_retrieve(cfg, rulecat, "raise_penalty")) ||
3255 ast_strlen_zero(raisestr) || sscanf(raisestr, "%30d", &raise_penalty) != 1) {
3256 raise_penalty = 0;
3257 raise_relative = 1;
3258 } else {
3259 if (*raisestr == '+' || *raisestr == '-') {
3260 raise_relative = 1;
3261 }
3262 }
3263 new_penalty_rule->time = penaltychangetime;
3264 new_penalty_rule->max_relative = max_relative;
3265 new_penalty_rule->max_value = max_penalty;
3266 new_penalty_rule->min_relative = min_relative;
3267 new_penalty_rule->min_value = min_penalty;
3268 new_penalty_rule->raise_relative = raise_relative;
3269 new_penalty_rule->raise_value = raise_penalty;
3270 AST_LIST_TRAVERSE_SAFE_BEGIN(&new_rl->rules, pr_iter, list) {
3271 if (new_penalty_rule->time < pr_iter->time) {
3272 AST_LIST_INSERT_BEFORE_CURRENT(new_penalty_rule, list);
3273 inserted = 1;
3274 }
3275 }
3277 if (!inserted) {
3278 AST_LIST_INSERT_TAIL(&new_rl->rules, new_penalty_rule, list);
3279 }
3280 }
3281
3282 ast_config_destroy(cfg);
3283 return 0;
3284}

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

Referenced by reload_queue_rules().

◆ log_attended_transfer()

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

Definition at line 6325 of file app_queue.c.

6327{
6328 RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
6329
6330 if (!transfer_str) {
6331 ast_log(LOG_WARNING, "Unable to log attended transfer to queue log\n");
6332 return;
6333 }
6334
6335 switch (atxfer_msg->dest_type) {
6337 ast_str_set(&transfer_str, 0, "BRIDGE|%s", atxfer_msg->dest.bridge);
6338 break;
6341 ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
6342 break;
6344 ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
6345 atxfer_msg->dest.links[1]->base->name);
6346 break;
6349 /* Threeways are headed off and should not be logged here */
6350 ast_assert(0);
6351 return;
6352 }
6353
6354 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
6355 ast_str_buffer(transfer_str),
6356 (long) (queue_data->starttime - queue_data->holdstart),
6357 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6358}
@ AST_ATTENDED_TRANSFER_DEST_FAIL
@ AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE
@ AST_ATTENDED_TRANSFER_DEST_LOCAL_APP
@ AST_ATTENDED_TRANSFER_DEST_LINK
@ AST_ATTENDED_TRANSFER_DEST_APP
union ast_attended_transfer_message::@284 dest
struct ast_channel_snapshot * links[2]
char bridge[AST_UUID_STR_LEN]

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

Referenced by handle_attended_transfer().

◆ manager_add_queue_member()

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

Definition at line 10603 of file app_queue.c.

10604{
10605 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface, *wrapuptime_s;
10606 int paused, penalty, wrapuptime = 0;
10607
10608 queuename = astman_get_header(m, "Queue");
10609 interface = astman_get_header(m, "Interface");
10610 penalty_s = astman_get_header(m, "Penalty");
10611 paused_s = astman_get_header(m, "Paused");
10612 membername = astman_get_header(m, "MemberName");
10613 state_interface = astman_get_header(m, "StateInterface");
10614 wrapuptime_s = astman_get_header(m, "Wrapuptime");
10615
10616 if (ast_strlen_zero(queuename)) {
10617 astman_send_error(s, m, "'Queue' not specified.");
10618 return 0;
10619 }
10620
10621 if (ast_strlen_zero(interface)) {
10622 astman_send_error(s, m, "'Interface' not specified.");
10623 return 0;
10624 }
10625
10626 if (ast_strlen_zero(penalty_s)) {
10627 penalty = 0;
10628 } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
10629 penalty = 0;
10630 }
10631
10632 if (ast_strlen_zero(wrapuptime_s)) {
10633 wrapuptime = 0;
10634 } else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
10635 wrapuptime = 0;
10636 }
10637
10638 if (ast_strlen_zero(paused_s)) {
10639 paused = 0;
10640 } else {
10641 paused = abs(ast_true(paused_s));
10642 }
10643
10644 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, NULL, wrapuptime)) {
10645 case RES_OKAY:
10646 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10647 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10648 } else {
10649 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10650 }
10651 astman_send_ack(s, m, "Added interface to queue");
10652 break;
10653 case RES_EXISTS:
10654 astman_send_error(s, m, "Unable to add interface: Already there");
10655 break;
10656 case RES_NOSUCHQUEUE:
10657 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
10658 break;
10659 case RES_OUTOFMEMORY:
10660 astman_send_error(s, m, "Out of memory");
10661 break;
10662 }
10663
10664 return 0;
10665}
#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:3381
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3413
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3042

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

10899{
10900 const char *queuename, *caller, *priority_s, *immediate_s;
10901 int priority = 0, immediate = 0;
10902
10903 queuename = astman_get_header(m, "Queue");
10904 caller = astman_get_header(m, "Caller");
10905 priority_s = astman_get_header(m, "Priority");
10906 immediate_s = astman_get_header(m, "Immediate");
10907
10908 if (ast_strlen_zero(queuename)) {
10909 astman_send_error(s, m, "'Queue' not specified.");
10910 return 0;
10911 }
10912
10913 if (ast_strlen_zero(caller)) {
10914 astman_send_error(s, m, "'Caller' not specified.");
10915 return 0;
10916 }
10917
10918 if (ast_strlen_zero(priority_s)) {
10919 astman_send_error(s, m, "'Priority' not specified.");
10920 return 0;
10921 } else if (sscanf(priority_s, "%30d", &priority) != 1) {
10922 astman_send_error(s, m, "'Priority' need integer.");
10923 return 0;
10924 }
10925
10926 if (!ast_strlen_zero(immediate_s)) {
10927 immediate = ast_true(immediate_s);
10928 }
10929
10930 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
10931 case RES_OKAY:
10932 astman_send_ack(s, m, "Priority change for caller on queue");
10933 break;
10934 case RES_NOSUCHQUEUE:
10935 astman_send_error(s, m, "Unable to change priority caller on queue: No such queue");
10936 break;
10937 case RES_NOT_CALLER:
10938 astman_send_error(s, m, "Unable to change priority caller on queue: No such caller");
10939 break;
10940 }
10941
10942 return 0;
10943}

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

10715{
10716 const char *queuename, *interface, *paused_s, *reason;
10717 int paused;
10718
10719 interface = astman_get_header(m, "Interface");
10720 paused_s = astman_get_header(m, "Paused");
10721 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
10722 reason = astman_get_header(m, "Reason"); /* Optional */
10723
10724 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
10725 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
10726 return 0;
10727 }
10728
10729 paused = abs(ast_true(paused_s));
10730
10731 if (set_member_paused(queuename, interface, reason, paused)) {
10732 astman_send_error(s, m, "Interface not found");
10733 } else {
10734 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
10735 }
10736 return 0;
10737}

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

10740{
10741 const char *queuename, *event, *message, *interface, *uniqueid;
10742
10743 queuename = astman_get_header(m, "Queue");
10744 uniqueid = astman_get_header(m, "UniqueId");
10745 interface = astman_get_header(m, "Interface");
10746 event = astman_get_header(m, "Event");
10747 message = astman_get_header(m, "Message");
10748
10749 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
10750 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
10751 return 0;
10752 }
10753
10754 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
10755 astman_send_ack(s, m, "Event added successfully");
10756
10757 return 0;
10758}
Definition: astman.c:222

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

Referenced by load_module().

◆ manager_queue_member_penalty()

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

Definition at line 10872 of file app_queue.c.

10873{
10874 const char *queuename, *interface, *penalty_s;
10875 int penalty;
10876
10877 interface = astman_get_header(m, "Interface");
10878 penalty_s = astman_get_header(m, "Penalty");
10879 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
10880 queuename = astman_get_header(m, "Queue");
10881
10882 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
10883 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
10884 return 0;
10885 }
10886
10887 penalty = atoi(penalty_s);
10888
10889 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
10890 astman_send_error(s, m, "Invalid interface, queuename or penalty");
10891 } else {
10892 astman_send_ack(s, m, "Interface penalty set successfully");
10893 }
10894
10895 return 0;
10896}

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

10839{
10840 const char *queuename, *interface, *ringinuse_s;
10841 int ringinuse;
10842
10843 interface = astman_get_header(m, "Interface");
10844 ringinuse_s = astman_get_header(m, "RingInUse");
10845
10846 /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
10847 queuename = astman_get_header(m, "Queue");
10848
10849 if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
10850 astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
10851 return 0;
10852 }
10853
10854 if (ast_true(ringinuse_s)) {
10855 ringinuse = 1;
10856 } else if (ast_false(ringinuse_s)) {
10857 ringinuse = 0;
10858 } else {
10859 astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
10860 return 0;
10861 }
10862
10863 if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
10864 astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
10865 } else {
10866 astman_send_ack(s, m, "Interface ringinuse set successfully");
10867 }
10868
10869 return 0;
10870}

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

10761{
10762 struct ast_flags mask = {0,};
10763 const char *queuename = NULL;
10764 int header_found = 0;
10765
10766 queuename = astman_get_header(m, "Queue");
10767 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
10769 header_found = 1;
10770 }
10771 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
10773 header_found = 1;
10774 }
10775 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
10777 header_found = 1;
10778 }
10779
10780 if (!header_found) {
10782 }
10783
10784 if (!reload_handler(1, &mask, queuename)) {
10785 astman_send_ack(s, m, "Queue reloaded successfully");
10786 } else {
10787 astman_send_error(s, m, "Error encountered while reloading queue");
10788 }
10789 return 0;
10790}

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

10793{
10794 const char *queuename = NULL;
10795 struct ast_flags mask = {QUEUE_RESET_STATS,};
10796
10797 queuename = astman_get_header(m, "Queue");
10798
10799 if (!reload_handler(1, &mask, queuename)) {
10800 astman_send_ack(s, m, "Queue stats reset successfully");
10801 } else {
10802 astman_send_error(s, m, "Error encountered while resetting queue stats");
10803 }
10804 return 0;
10805}

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

10363{
10364 const char *rule = astman_get_header(m, "Rule");
10365 const char *id = astman_get_header(m, "ActionID");
10366 struct rule_list *rl_iter;
10367 struct penalty_rule *pr_iter;
10368
10369 astman_append(s, "Response: Success\r\n");
10370 if (!ast_strlen_zero(id)) {
10371 astman_append(s, "ActionID: %s\r\n", id);
10372 }
10373
10375 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10376 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
10377 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
10378 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10379 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 );
10380 }
10381 if (!ast_strlen_zero(rule)) {
10382 break;
10383 }
10384 }
10385 }
10387
10388 /*
10389 * Two blank lines instead of one because the Response and
10390 * ActionID headers used to not be present.
10391 */
10392 astman_append(s, "\r\n\r\n");
10393
10394 return RESULT_SUCCESS;
10395}

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

10481{
10482 time_t now;
10483 int pos;
10484 int q_items = 0;
10485 const char *id = astman_get_header(m,"ActionID");
10486 const char *queuefilter = astman_get_header(m,"Queue");
10487 const char *memberfilter = astman_get_header(m,"Member");
10488 char idText[256];
10489 struct call_queue *q;
10490 struct queue_ent *qe;
10491 float sl = 0;
10492 float sl2 = 0;
10493 struct member *mem;
10494 struct ao2_iterator queue_iter;
10495 struct ao2_iterator mem_iter;
10496
10497 if (ast_check_realtime("queues")) {
10498 load_realtime_queues(queuefilter);
10499 }
10500
10501 astman_send_listack(s, m, "Queue status will follow", "start");
10502 time(&now);
10503 idText[0] = '\0';
10504 if (!ast_strlen_zero(id)) {
10505 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10506 }
10507
10508 queue_iter = ao2_iterator_init(queues, 0);
10509 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10510 ao2_lock(q);
10511
10512 /* List queue properties */
10513 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10514 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
10515 sl2 = (((q->callscompleted + q->callsabandoned) > 0) ? 100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)) : 0);
10516
10517 astman_append(s, "Event: QueueParams\r\n"
10518 "Queue: %s\r\n"
10519 "Max: %d\r\n"
10520 "Strategy: %s\r\n"
10521 "Calls: %d\r\n"
10522 "Holdtime: %d\r\n"
10523 "TalkTime: %d\r\n"
10524 "Completed: %d\r\n"
10525 "Abandoned: %d\r\n"
10526 "ServiceLevel: %d\r\n"
10527 "ServicelevelPerf: %2.1f\r\n"
10528 "ServicelevelPerf2: %2.1f\r\n"
10529 "Weight: %d\r\n"
10530 "%s"
10531 "\r\n",
10532 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
10533 q->callsabandoned, q->servicelevel, sl, sl2, q->weight, idText);
10534 ++q_items;
10535
10536 /* List Queue Members */
10537 mem_iter = ao2_iterator_init(q->members, 0);
10538 while ((mem = ao2_iterator_next(&mem_iter))) {
10539 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
10540 astman_append(s, "Event: QueueMember\r\n"
10541 "Queue: %s\r\n"
10542 "Name: %s\r\n"
10543 "Location: %s\r\n"
10544 "StateInterface: %s\r\n"
10545 "Membership: %s\r\n"
10546 "Penalty: %d\r\n"
10547 "CallsTaken: %d\r\n"
10548 "LastCall: %d\r\n"
10549 "LastPause: %d\r\n"
10550 "LoginTime: %d\r\n"
10551 "InCall: %d\r\n"
10552 "Status: %d\r\n"
10553 "Paused: %d\r\n"
10554 "PausedReason: %s\r\n"
10555 "Wrapuptime: %d\r\n"
10556 "%s"
10557 "\r\n",
10558 q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
10559 mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, (int)mem->logintime, mem->starttime ? 1 : 0, mem->status,
10560 mem->paused, mem->reason_paused, mem->wrapuptime, idText);
10561 ++q_items;
10562 }
10563 ao2_ref(mem, -1);
10564 }
10565 ao2_iterator_destroy(&mem_iter);
10566
10567 /* List Queue Entries */
10568 pos = 1;
10569 for (qe = q->head; qe; qe = qe->next) {
10570 astman_append(s, "Event: QueueEntry\r\n"
10571 "Queue: %s\r\n"
10572 "Position: %d\r\n"
10573 "Channel: %s\r\n"
10574 "Uniqueid: %s\r\n"
10575 "CallerIDNum: %s\r\n"
10576 "CallerIDName: %s\r\n"
10577 "ConnectedLineNum: %s\r\n"
10578 "ConnectedLineName: %s\r\n"
10579 "Wait: %ld\r\n"
10580 "Priority: %d\r\n"
10581 "%s"
10582 "\r\n",
10583 q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
10588 (long) (now - qe->start), qe->prio, idText);
10589 ++q_items;
10590 }
10591 }
10592 ao2_unlock(q);
10593 queue_t_unref(q, "Done with iterator");
10594 }
10595 ao2_iterator_destroy(&queue_iter);
10596
10597 astman_send_list_complete_start(s, m, "QueueStatusComplete", q_items);
10599
10600 return RESULT_SUCCESS;
10601}
static void load_realtime_queues(const char *queuename)
Definition: app_queue.c:3951
static const char * int2strat(int strategy)
Definition: app_queue.c:1920
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:3423
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:3459
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3467
#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:420
struct ast_party_id id
Connected party ID.
Definition: channel.h:458
struct ast_party_name name
Subscriber name.
Definition: channel.h:340
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:342
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:279
char * str
Subscriber name (Malloced)
Definition: channel.h:264
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:297
char * str
Subscriber phone number (Malloced)
Definition: channel.h:291

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

10399{
10400 time_t now;
10401 int qmemcount = 0;
10402 int qmemavail = 0;
10403 int qchancount = 0;
10404 int qlongestholdtime = 0;
10405 int qsummaries = 0;
10406 const char *id = astman_get_header(m, "ActionID");
10407 const char *queuefilter = astman_get_header(m, "Queue");
10408 char idText[256];
10409 struct call_queue *q;
10410 struct queue_ent *qe;
10411 struct member *mem;
10412 struct ao2_iterator queue_iter;
10413 struct ao2_iterator mem_iter;
10414
10415 if (ast_check_realtime("queues")) {
10416 load_realtime_queues(queuefilter);
10417 }
10418
10419 astman_send_listack(s, m, "Queue summary will follow", "start");
10420 time(&now);
10421 idText[0] = '\0';
10422 if (!ast_strlen_zero(id)) {
10423 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10424 }
10425 queue_iter = ao2_iterator_init(queues, 0);
10426 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10427 ao2_lock(q);
10428
10429 /* List queue properties */
10430 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10431 /* Reset the necessary local variables if no queuefilter is set*/
10432 qmemcount = 0;
10433 qmemavail = 0;
10434 qchancount = 0;
10435 qlongestholdtime = 0;
10436
10437 /* List Queue Members */
10438 mem_iter = ao2_iterator_init(q->members, 0);
10439 while ((mem = ao2_iterator_next(&mem_iter))) {
10440 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
10441 ++qmemcount;
10442 if (member_status_available(mem->status) && !mem->paused) {
10443 ++qmemavail;
10444 }
10445 }
10446 ao2_ref(mem, -1);
10447 }
10448 ao2_iterator_destroy(&mem_iter);
10449 for (qe = q->head; qe; qe = qe->next) {
10450 if ((now - qe->start) > qlongestholdtime) {
10451 qlongestholdtime = now - qe->start;
10452 }
10453 ++qchancount;
10454 }
10455 astman_append(s, "Event: QueueSummary\r\n"
10456 "Queue: %s\r\n"
10457 "LoggedIn: %d\r\n"
10458 "Available: %d\r\n"
10459 "Callers: %d\r\n"
10460 "HoldTime: %d\r\n"
10461 "TalkTime: %d\r\n"
10462 "LongestHoldTime: %d\r\n"
10463 "%s"
10464 "\r\n",
10465 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
10466 ++qsummaries;
10467 }
10468 ao2_unlock(q);
10469 queue_t_unref(q, "Done with iterator");
10470 }
10471 ao2_iterator_destroy(&queue_iter);
10472
10473 astman_send_list_complete_start(s, m, "QueueSummaryComplete", qsummaries);
10475
10476 return RESULT_SUCCESS;
10477}

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

10668{
10669 const char *queuename, *interface;
10670 struct member *mem = NULL;
10671
10672 queuename = astman_get_header(m, "Queue");
10673 interface = astman_get_header(m, "Interface");
10674
10675 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
10676 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
10677 return 0;
10678 }
10679
10681 mem = find_member_by_queuename_and_interface(queuename, interface);
10682 }
10683
10684 switch (remove_from_queue(queuename, interface)) {
10685 case RES_OKAY:
10686 if (!mem || ast_strlen_zero(mem->membername)) {
10687 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
10688 } else {
10689 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
10690 }
10691 astman_send_ack(s, m, "Removed interface from queue");
10692 break;
10693 case RES_EXISTS:
10694 astman_send_error(s, m, "Unable to remove interface: Not there");
10695 break;
10696 case RES_NOSUCHQUEUE:
10697 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
10698 break;
10699 case RES_OUTOFMEMORY:
10700 astman_send_error(s, m, "Out of memory");
10701 break;
10702 case RES_NOT_DYNAMIC:
10703 astman_send_error(s, m, "Member not dynamic");
10704 break;
10705 }
10706
10707 if (mem) {
10708 ao2_ref(mem, -1);
10709 }
10710
10711 return 0;
10712}

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

10946{
10947 const char *queuename, *caller, *withdraw_info;
10948
10949 queuename = astman_get_header(m, "Queue");
10950 caller = astman_get_header(m, "Caller");
10951 withdraw_info = astman_get_header(m, "WithdrawInfo");
10952
10953 if (ast_strlen_zero(queuename)) {
10954 astman_send_error(s, m, "'Queue' not specified.");
10955 return 0;
10956 }
10957
10958 if (ast_strlen_zero(caller)) {
10959 astman_send_error(s, m, "'Caller' not specified.");
10960 return 0;
10961 }
10962
10963 switch (request_withdraw_caller_from_queue(queuename, caller, withdraw_info)) {
10964 case RES_OKAY:
10965 astman_send_ack(s, m, "Withdraw requested successfully");
10966 break;
10967 case RES_NOSUCHQUEUE:
10968 astman_send_error(s, m, "Unable to request withdraw from queue: No such queue");
10969 break;
10970 case RES_NOT_CALLER:
10971 astman_send_error(s, m, "Unable to request withdraw from queue: No such caller");
10972 break;
10973 case RES_EXISTS:
10974 astman_send_error(s, m, "Unable to request withdraw from queue: Already requested");
10975 break;
10976 }
10977
10978 return 0;
10979}
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:7717

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

9721{
9722 struct member *member = obj;
9723 if (!member->dynamic && !member->realtime) {
9724 member->delme = 1;
9725 }
9726 return 0;
9727}

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

9875{
9876 struct call_queue *q = obj;
9877 char *queuename = arg;
9878 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
9879 q->found = 0;
9880 }
9881 return 0;
9882}

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

2935{
2936 struct member *mem1 = obj1;
2937 struct member *mem2 = obj2;
2938 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
2939
2940 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
2941}
@ 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 2918 of file app_queue.c.

2919{
2920 const struct member *mem = obj;
2921 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
2922 const char *chname = strchr(interface, '/');
2923 int ret = 0, i;
2924
2925 if (!chname) {
2926 chname = interface;
2927 }
2928 for (i = 0; i < 5 && chname[i]; i++) {
2929 ret += compress_char(chname[i]) << (i * 6);
2930 }
2931 return ret;
2932}
static int compress_char(const char c)
Definition: app_queue.c:2908

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

3558{
3560 ao2_lock(queue->members);
3563 ao2_unlink(queue->members, mem);
3564 ao2_unlock(queue->members);
3565}
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:2040
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition: app_queue.c:3533
#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 4638 of file app_queue.c.

4639{
4641}

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

4505{
4506 struct member *mem;
4507 int avl = 0;
4508 struct ao2_iterator mem_iter;
4509
4510 mem_iter = ao2_iterator_init(q->members, 0);
4511 while ((mem = ao2_iterator_next(&mem_iter))) {
4512
4513 avl += is_member_available(q, mem);
4514 ao2_ref(mem, -1);
4515
4516 /* If autofill is not enabled or if the queue's strategy is ringall, then
4517 * we really don't care about the number of available members so much as we
4518 * do that there is at least one available.
4519 *
4520 * In fact, we purposely will return from this function stating that only
4521 * one member is available if either of those conditions hold. That way,
4522 * functions which determine what action to take based on the number of available
4523 * members will operate properly. The reasoning is that even if multiple
4524 * members are available, only the head caller can actually be serviced.
4525 */
4526 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
4527 break;
4528 }
4529 }
4530 ao2_iterator_destroy(&mem_iter);
4531
4532 return avl;
4533}

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

3287{
3288 char *value_copy = ast_strdupa(value);
3289 char *option = NULL;
3290 while ((option = strsep(&value_copy, ","))) {
3291 if (!strcasecmp(option, "paused")) {
3292 *empty |= QUEUE_EMPTY_PAUSED;
3293 } else if (!strcasecmp(option, "penalty")) {
3294 *empty |= QUEUE_EMPTY_PENALTY;
3295 } else if (!strcasecmp(option, "inuse")) {
3296 *empty |= QUEUE_EMPTY_INUSE;
3297 } else if (!strcasecmp(option, "ringing")) {
3298 *empty |= QUEUE_EMPTY_RINGING;
3299 } else if (!strcasecmp(option, "invalid")) {
3300 *empty |= QUEUE_EMPTY_INVALID;
3301 } else if (!strcasecmp(option, "wrapup")) {
3302 *empty |= QUEUE_EMPTY_WRAPUP;
3303 } else if (!strcasecmp(option, "unavailable")) {
3304 *empty |= QUEUE_EMPTY_UNAVAILABLE;
3305 } else if (!strcasecmp(option, "unknown")) {
3306 *empty |= QUEUE_EMPTY_UNKNOWN;
3307 } else if (!strcasecmp(option, "loose")) {
3309 } else if (!strcasecmp(option, "strict")) {
3311 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
3313 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
3314 *empty = 0;
3315 } else {
3316 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
3317 }
3318 }
3319}

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

2535{
2536 const struct member *object_left = obj;
2537 const struct member *object_right = arg;
2538 const char *right_key = arg;
2539 int cmp;
2540
2541 switch (flags & OBJ_SEARCH_MASK) {
2542 case OBJ_SEARCH_OBJECT:
2543 right_key = object_right->interface;
2544 /* Fall through */
2545 case OBJ_SEARCH_KEY:
2546 cmp = strcasecmp(object_left->interface, right_key);
2547 break;
2549 /* Not supported by container. */
2550 ast_assert(0);
2551 return 0;
2552 default:
2553 cmp = 0;
2554 break;
2555 }
2556 if (cmp) {
2557 return 0;
2558 }
2559 return CMP_MATCH;
2560}
@ 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 2514 of file app_queue.c.

2515{
2516 const struct member *object;
2517 const char *key;
2518
2519 switch (flags & OBJ_SEARCH_MASK) {
2520 case OBJ_SEARCH_KEY:
2521 key = obj;
2522 break;
2523 case OBJ_SEARCH_OBJECT:
2524 object = obj;
2525 key = object->interface;
2526 break;
2527 default:
2528 ast_assert(0);
2529 return 0;
2530 }
2531 return ast_str_case_hash(key);
2532}
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1303

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

Referenced by load_module().

◆ pending_members_remove()

static void pending_members_remove ( struct member mem)
static

Definition at line 2562 of file app_queue.c.

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

4139{
4140 int res;
4141
4142 if (ast_strlen_zero(filename)) {
4143 return 0;
4144 }
4145
4146 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
4147 return 0;
4148 }
4149
4150 ast_stopstream(chan);
4151
4152 res = ast_streamfile(chan, filename, ast_channel_language(chan));
4153 if (!res) {
4154 res = ast_waitstream(chan, AST_DIGIT_ANY);
4155 }
4156
4157 ast_stopstream(chan);
4158
4159 return res;
4160}
const char * ast_channel_language(const struct ast_channel *chan)
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1293
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1129
#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:1840

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

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

◆ pqm_exec()

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

PauseQueueMember application.

Definition at line 8206 of file app_queue.c.

8207{
8208 char *parse;
8210 AST_APP_ARG(queuename);
8211 AST_APP_ARG(interface);
8213 AST_APP_ARG(reason);
8214 );
8215
8216 if (ast_strlen_zero(data)) {
8217 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
8218 return -1;
8219 }
8220
8221 parse = ast_strdupa(data);
8222
8224
8225 if (ast_strlen_zero(args.interface)) {
8226 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
8227 return -1;
8228 }
8229
8230 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
8231 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
8232 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
8233 return 0;
8234 }
8235
8236 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
8237
8238 return 0;
8239}

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

10023{
10024 float sl;
10025 float sl2;
10026 struct ao2_iterator mem_iter;
10027 struct ast_str *out = ast_str_alloca(512);
10028 time_t now = time(NULL);
10029
10030 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
10031 if (q->maxlen) {
10032 ast_str_append(&out, 0, "%d", q->maxlen);
10033 } else {
10034 ast_str_append(&out, 0, "unlimited");
10035 }
10036 sl = 0;
10037 sl2 = 0;
10038 if (q->callscompleted > 0) {
10039 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
10040 }
10041 if (q->callscompleted + q->callsabandoned > 0) {
10042 sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted));
10043 }
10044
10045 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",
10047 do_print(s, fd, ast_str_buffer(out));
10048 if (!ao2_container_count(q->members)) {
10049 do_print(s, fd, " No Members");
10050 } else {
10051 struct member *mem;
10052
10053 do_print(s, fd, " Members: ");
10054 mem_iter = ao2_iterator_init(q->members, 0);
10055 while ((mem = ao2_iterator_next(&mem_iter))) {
10056 ast_str_set(&out, 0, " %s", mem->membername);
10057 if (strcasecmp(mem->membername, mem->interface)) {
10058 ast_str_append(&out, 0, " (%s", mem->interface);
10060 && strcmp(mem->state_interface, mem->interface)) {
10061 ast_str_append(&out, 0, " from %s", mem->state_interface);
10062 }
10063 ast_str_append(&out, 0, ")");
10064 }
10065 if (mem->penalty) {
10066 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
10067 }
10068
10069 ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
10070
10071 ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s",
10072 mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
10073 mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
10074 mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
10075
10076 if (mem->paused) {
10077 ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
10079 ast_strlen_zero(mem->reason_paused) ? "" : ":",
10081 (long) (now - mem->lastpause),
10082 ast_term_reset());
10083 }
10084
10085 ast_str_append(&out, 0, " (%s%s%s)",
10090 if (mem->calls) {
10091 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
10092 mem->calls, (long) (now - mem->lastcall));
10093 } else {
10094 ast_str_append(&out, 0, " has taken no calls yet");
10095 }
10096 ast_str_append(&out, 0, " %s(login was %ld secs ago)%s",
10098 (long) (now - mem->logintime),
10099 ast_term_reset());
10100 do_print(s, fd, ast_str_buffer(out));
10101 ao2_ref(mem, -1);
10102 }
10103 ao2_iterator_destroy(&mem_iter);
10104 }
10105 if (!q->head) {
10106 do_print(s, fd, " No Callers");
10107 } else {
10108 struct queue_ent *qe;
10109 int pos = 1;
10110
10111 do_print(s, fd, " Callers: ");
10112 for (qe = q->head; qe; qe = qe->next) {
10113 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
10114 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
10115 (long) (now - qe->start) % 60, qe->prio);
10116 do_print(s, fd, ast_str_buffer(out));
10117 }
10118 }
10119 do_print(s, fd, ""); /* blank line between entries */
10120}
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:357
#define COLOR_CYAN
Definition: term.h:62
#define COLOR_MAGENTA
Definition: term.h:60
#define COLOR_BROWN
Definition: term.h:56
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition: term.c:341
#define COLOR_BLACK
Definition: term.h:50
#define COLOR_RED
Definition: term.h:52
#define COLOR_GREEN
Definition: term.h:54

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

Referenced by __queues_show().

◆ publish_dial_end_event()

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

Definition at line 4452 of file app_queue.c.

4453{
4454 struct callattempt *cur;
4455
4456 for (cur = outgoing; cur; cur = cur->q_next) {
4457 if (cur->chan && cur->chan != exception) {
4459 }
4460 }
4461}
struct callattempt * q_next
Definition: app_queue.c:1670
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 7756 of file app_queue.c.

7757{
7758 struct ast_json *json_blob = queue_member_blob_create(q, member);
7759
7760 if (!json_blob) {
7761 return -1;
7762 }
7763
7764 queue_publish_member_blob(queue_member_pause_type(), json_blob);
7765
7766 return 0;
7767}

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

8431{
8432 char *parse;
8433
8435 AST_APP_ARG(queuename);
8436 AST_APP_ARG(uniqueid);
8437 AST_APP_ARG(membername);
8439 AST_APP_ARG(params);
8440 );
8441
8442 if (ast_strlen_zero(data)) {
8443 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
8444 return -1;
8445 }
8446
8447 parse = ast_strdupa(data);
8448
8450
8451 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
8452 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
8453 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
8454 return -1;
8455 }
8456
8457 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
8458 "%s", args.params ? args.params : "");
8459
8460 return 0;
8461}

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

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

2263{
2264 return queue_multi_channel_to_ami("AgentCalled", message);
2265}
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2221

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

6157{
6158 struct ast_channel_blob *agent_blob;
6159
6160 agent_blob = stasis_message_data(msg);
6161
6163 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6164 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6165 "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
6167 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6168 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6169 "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
6170 (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
6171 }
6172}

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

Referenced by load_module().

◆ queue_agent_complete_to_ami()

static struct ast_manager_event_blob * queue_agent_complete_to_ami ( struct stasis_message message)
static

Definition at line 2272 of file app_queue.c.

2273{
2274 return queue_multi_channel_to_ami("AgentComplete", message);
2275}

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

2268{
2269 return queue_multi_channel_to_ami("AgentConnect", message);
2270}

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

2278{
2279 return queue_multi_channel_to_ami("AgentDump", message);
2280}

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

2283{
2284 return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2285}

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

6520{
6522 ao2_cleanup(userdata);
6523 }
6524}
struct stasis_forward * sub
Definition: res_corosync.c:240
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition: stasis.c:1174

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

2143{
2144 return queue_channel_to_ami("QueueCallerAbandon", message);
2145}
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2113

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

2133{
2134 return queue_channel_to_ami("QueueCallerJoin", message);
2135}

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

2138{
2139 return queue_channel_to_ami("QueueCallerLeave", message);
2140}

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

6745{
6747 ao2_cleanup(userdata);
6748 }
6749}

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

2114{
2116 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
2117 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2118
2119 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
2120 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
2121 if (!channel_string || !event_string) {
2122 return NULL;
2123 }
2124
2126 "%s"
2127 "%s",
2128 ast_str_buffer(channel_string),
2129 ast_str_buffer(event_string));
2130}
static const char type[]
Definition: chan_ooh323.c:109
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:1973
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:10548

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

1977{
1978 struct call_queue *q = obj, *q2 = arg;
1979 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
1980}

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

2023{
2024 struct member *mem = obj;
2025 struct call_queue *queue = arg;
2026 int rrpos = mem->queuepos;
2027
2028 if (mem->delme) {
2030 }
2031
2032 return 0;
2033}
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2003
#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 8507 of file app_queue.c.

8508{
8509 int res=-1;
8510 int ringing=0;
8511 const char *user_priority;
8512 const char *max_penalty_str;
8513 const char *min_penalty_str;
8514 const char *raise_penalty_str;
8515 int prio;
8516 int qcontinue = 0;
8517 int max_penalty, min_penalty, raise_penalty;
8518 enum queue_result reason = QUEUE_UNKNOWN;
8519 /* whether to exit Queue application after the timeout hits */
8520 int tries = 0;
8521 int noption = 0;
8522 char *parse;
8523 int makeannouncement = 0;
8524 int position = 0;
8526 AST_APP_ARG(queuename);
8529 AST_APP_ARG(announceoverride);
8530 AST_APP_ARG(queuetimeoutstr);
8531 AST_APP_ARG(agi);
8532 AST_APP_ARG(gosub);
8534 AST_APP_ARG(position);
8535 );
8536 /* Our queue entry */
8537 struct queue_ent qe = { 0 };
8538 struct ast_flags opts = { 0, };
8539 char *opt_args[OPT_ARG_ARRAY_SIZE];
8540 int max_forwards;
8541
8542 if (ast_strlen_zero(data)) {
8543 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,gosub[,rule[,position]]]]]]]]\n");
8544 return -1;
8545 }
8546
8547 ast_channel_lock(chan);
8549 ast_channel_unlock(chan);
8550
8551 if (max_forwards <= 0) {
8552 ast_log(LOG_WARNING, "Channel '%s' cannot enter queue. Max forwards exceeded\n", ast_channel_name(chan));
8553 return -1;
8554 }
8555
8556 parse = ast_strdupa(data);
8558
8559 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, timeout: %s, agi: %s, gosub: %s, rule: %s, position: %s\n",
8560 args.queuename,
8561 S_OR(args.options, ""),
8562 S_OR(args.url, ""),
8563 S_OR(args.announceoverride, ""),
8564 S_OR(args.queuetimeoutstr, ""),
8565 S_OR(args.agi, ""),
8566 S_OR(args.gosub, ""),
8567 S_OR(args.rule, ""),
8568 S_OR(args.position, ""));
8569
8570 if (!ast_strlen_zero(args.options)) {
8571 ast_app_parse_options(queue_exec_options, &opts, opt_args, args.options);
8572 }
8573
8574 /* Setup our queue entry */
8575 qe.start = time(NULL);
8576
8577 pbx_builtin_setvar_helper(chan, "ABANDONED", NULL);
8578
8579 /* set the expire time based on the supplied timeout; */
8580 if (!ast_strlen_zero(args.queuetimeoutstr)) {
8581 qe.expire = qe.start + atoi(args.queuetimeoutstr);
8582 } else {
8583 qe.expire = 0;
8584 }
8585
8586 /* Get the priority from the variable ${QUEUE_PRIO} */
8587 ast_channel_lock(chan);
8588 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
8589 if (user_priority) {
8590 if (sscanf(user_priority, "%30d", &prio) == 1) {
8591 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", ast_channel_name(chan), prio);
8592 } else {
8593 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
8594 user_priority, ast_channel_name(chan));
8595 prio = 0;
8596 }
8597 } else {
8598 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
8599 prio = 0;
8600 }
8601
8602 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
8603
8604 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
8605 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
8606 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", ast_channel_name(chan), max_penalty);
8607 } else {
8608 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
8609 max_penalty_str, ast_channel_name(chan));
8610 max_penalty = INT_MAX;
8611 }
8612 } else {
8613 max_penalty = INT_MAX;
8614 }
8615
8616 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
8617 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
8618 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", ast_channel_name(chan), min_penalty);
8619 } else {
8620 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
8621 min_penalty_str, ast_channel_name(chan));
8622 min_penalty = INT_MAX;
8623 }
8624 } else {
8625 min_penalty = INT_MAX;
8626 }
8627
8628 if ((raise_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_RAISE_PENALTY"))) {
8629 if (sscanf(raise_penalty_str, "%30d", &raise_penalty) == 1) {
8630 ast_debug(1, "%s: Got raise penalty %d from ${QUEUE_RAISE_PENALTY}.\n", ast_channel_name(chan), raise_penalty);
8631 } else {
8632 ast_log(LOG_WARNING, "${QUEUE_RAISE_PENALTY}: Invalid value (%s), channel %s.\n",
8633 raise_penalty_str, ast_channel_name(chan));
8634 raise_penalty = INT_MAX;
8635 }
8636 } else {
8637 raise_penalty = INT_MAX;
8638 }
8639 ast_channel_unlock(chan);
8640
8641 if (ast_test_flag(&opts, OPT_RINGING)) {
8642 ringing = 1;
8643 }
8644
8645 if (ringing != 1 && ast_test_flag(&opts, OPT_RING_WHEN_RINGING)) {
8646 qe.ring_when_ringing = 1;
8647 }
8648
8649 if (ast_test_flag(&opts, OPT_GO_ON)) {
8650 qcontinue = 1;
8651 }
8652
8653 if (args.position) {
8654 position = atoi(args.position);
8655 if (position < 0) {
8656 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
8657 position = 0;
8658 }
8659 }
8660
8661 ast_debug(1, "queue: %s, expires: %ld, priority: %d\n",
8662 args.queuename, (long)qe.expire, prio);
8663
8664 qe.chan = chan;
8665 qe.prio = prio;
8666 qe.max_penalty = max_penalty;
8667 qe.min_penalty = min_penalty;
8668 qe.raise_penalty = raise_penalty;
8669 qe.last_pos_said = 0;
8670 qe.last_pos = 0;
8673 qe.valid_digits = 0;
8674 if (join_queue(args.queuename, &qe, &reason, position)) {
8675 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
8676 set_queue_result(chan, reason);
8677 return 0;
8678 }
8679 ast_assert(qe.parent != NULL);
8680
8681 if (qe.parent->periodicannouncestartdelay >= 0) {
8684 }
8685
8686 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d",
8687 S_OR(args.url, ""),
8688 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
8689 qe.opos);
8690
8691 /* PREDIAL: Preprocess any callee gosub arguments. */
8693 && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])) {
8696 }
8697
8698 /* PREDIAL: Run gosub on the caller's channel */
8700 && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) {
8702 ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER], 0);
8703 }
8704
8705 /* Music on hold class override */
8708 ast_copy_string(qe.moh, opt_args[OPT_ARG_MUSICONHOLD_CLASS], sizeof(qe.moh));
8709 }
8710
8711 copy_rules(&qe, args.rule);
8712 qe.pr = AST_LIST_FIRST(&qe.qe_rules);
8713check_turns:
8714 if (ringing) {
8716 } else {
8717 ast_moh_start(chan, qe.moh, NULL);
8718 }
8719
8720 /* This is the wait loop for callers 2 through maxlen */
8721 res = wait_our_turn(&qe, ringing, &reason);
8722 if (res) {
8723 goto stop;
8724 }
8725
8726 makeannouncement = qe.parent->announce_to_first_user;
8727
8728 for (;;) {
8729 /* This is the wait loop for the head caller*/
8730 /* To exit, they may get their call answered; */
8731 /* they may dial a digit from the queue context; */
8732 /* or, they may timeout. */
8733
8734 /* A request to withdraw this call from the queue arrived */
8735 if (qe.withdraw) {
8736 reason = QUEUE_WITHDRAW;
8737 res = 1;
8738 break;
8739 }
8740
8741 /* Leave if we have exceeded our queuetimeout */
8742 if (qe.expire && (time(NULL) >= qe.expire)) {
8743 record_abandoned(&qe);
8744 reason = QUEUE_TIMEOUT;
8745 res = 0;
8746 ast_queue_log(args.queuename, ast_channel_uniqueid(chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
8747 qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8748 break;
8749 }
8750
8751 if (makeannouncement) {
8752 /* Make a position announcement, if enabled */
8753 if (qe.parent->announcefrequency) {
8754 if ((res = say_position(&qe, ringing))) {
8755 goto stop;
8756 }
8757 }
8758 }
8759 makeannouncement = 1;
8760
8761 /* Make a periodic announcement, if enabled */
8763 if ((res = say_periodic_announcement(&qe, ringing))) {
8764 goto stop;
8765 }
8766 }
8767
8768 /* A request to withdraw this call from the queue arrived */
8769 if (qe.withdraw) {
8770 reason = QUEUE_WITHDRAW;
8771 res = 1;
8772 break;
8773 }
8774
8775 /* Leave if we have exceeded our queuetimeout */
8776 if (qe.expire && (time(NULL) >= qe.expire)) {
8777 record_abandoned(&qe);
8778 reason = QUEUE_TIMEOUT;
8779 res = 0;
8780 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
8781 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8782 break;
8783 }
8784
8785 /* see if we need to move to the next penalty level for this queue */
8786 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
8787 update_qe_rule(&qe);
8788 }
8789
8790 /* Try calling all queue members for 'timeout' seconds */
8791 res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.gosub, ringing);
8792 if (res) {
8793 goto stop;
8794 }
8795
8796 if (qe.parent->leavewhenempty) {
8797 int status = 0;
8799 record_abandoned(&qe);
8800 reason = QUEUE_LEAVEEMPTY;
8801 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
8802 res = 0;
8803 break;
8804 }
8805 }
8806
8807 /* exit after 'timeout' cycle if 'n' option enabled */
8808 if (noption && tries >= ao2_container_count(qe.parent->members)) {
8809 ast_verb(3, "Exiting on time-out cycle\n");
8810 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
8811 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8812 record_abandoned(&qe);
8813 reason = QUEUE_TIMEOUT;
8814 res = 0;
8815 break;
8816 }
8817
8818
8819 /* Leave if we have exceeded our queuetimeout */
8820 if (qe.expire && (time(NULL) >= qe.expire)) {
8821 record_abandoned(&qe);
8822 reason = QUEUE_TIMEOUT;
8823 res = 0;
8824 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));
8825 break;
8826 }
8827
8828 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
8829 res = wait_a_bit(&qe);
8830 if (res) {
8831 goto stop;
8832 }
8833
8834 /* If using dynamic realtime members, we should regenerate the member list for this queue */
8836
8837 /* Since this is a priority queue and
8838 * it is not sure that we are still at the head
8839 * of the queue, go and check for our turn again.
8840 */
8841 if (!is_our_turn(&qe)) {
8842 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", ast_channel_name(qe.chan));
8843 goto check_turns;
8844 }
8845 }
8846
8847stop:
8848 if (res) {
8849 if (reason == QUEUE_WITHDRAW) {
8850 record_abandoned(&qe);
8851 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 : "");
8852 if (qe.withdraw_info) {
8853 pbx_builtin_setvar_helper(qe.chan, "QUEUE_WITHDRAW_INFO", qe.withdraw_info);
8854 }
8855 res = 0;
8856 } else if (res < 0) {
8857 if (!qe.handled) {
8858 record_abandoned(&qe);
8859 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ABANDON",
8860 "%d|%d|%ld", qe.pos, qe.opos,
8861 (long) (time(NULL) - qe.start));
8862 res = -1;
8863 } else if (reason == QUEUE_LEAVEEMPTY) {
8864 /* Return back to dialplan, don't hang up */
8865 res = 0;
8866 } else if (qcontinue) {
8867 reason = QUEUE_CONTINUE;
8868 res = 0;
8869 }
8870 } else if (qe.valid_digits) {
8871 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY",
8872 "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8873 }
8874 }
8875
8876 /* Free the optional withdraw info if present */
8877 /* This is done here to catch all cases. e.g. if the call eventually wasn't withdrawn, e.g. answered */
8878 if (qe.withdraw_info) {
8880 qe.withdraw_info = NULL;
8881 }
8882
8883 /* Don't allow return code > 0 */
8884 if (res >= 0) {
8885 res = 0;
8886 if (ringing) {
8887 ast_indicate(chan, -1);
8888 } else {
8889 ast_moh_stop(chan);
8890 }
8891 ast_stopstream(chan);
8892 }
8893
8895
8896 leave_queue(&qe);
8897 if (reason != QUEUE_UNKNOWN)
8898 set_queue_result(chan, reason);
8899
8900 /*
8901 * every queue_ent is given a reference to it's parent
8902 * call_queue when it joins the queue. This ref must be taken
8903 * away right before the queue_ent is destroyed. In this case
8904 * the queue_ent is about to be returned on the stack
8905 */
8906 qe.parent = queue_unref(qe.parent);
8907
8908 return res;
8909}
static int is_our_turn(struct queue_ent *qe)
Check if we should start attempting to call queue members.
Definition: app_queue.c:5740
static void record_abandoned(struct queue_ent *qe)
Record that a caller gave up on waiting in queue.
Definition: app_queue.c:5074
static void set_queue_result(struct ast_channel *chan, enum queue_result res)
sets the QUEUESTATUS channel variable
Definition: app_queue.c:1908
static void leave_queue(struct queue_ent *qe)
Caller leaving queue.
Definition: app_queue.c:4367
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
Playback announcement to queued members if period has elapsed.
Definition: app_queue.c:5013
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:5879
static void copy_rules(struct queue_ent *qe, const char *rulename)
Copy rule from global list into specified queue.
Definition: app_queue.c:8464
static const struct ast_app_option queue_exec_options[128]
Definition: app_queue.c:1503
queue_result
Definition: app_queue.c:1625
static void update_qe_rule(struct queue_ent *qe)
update rules for queues
Definition: app_queue.c:5789
static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
Definition: app_queue.c:4054
static int say_position(struct queue_ent *qe, int ringing)
Definition: app_queue.c:4202
static int wait_a_bit(struct queue_ent *qe)
Definition: app_queue.c:7440
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:6973
unsigned int stop
Definition: app_sla.c:336
static void ringing(struct ast_channel *chan)
Helper method to send a ringing indication to a channel in a bridge.
#define ast_channel_lock(chan)
Definition: channel.h:2922
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4277
#define ast_channel_unlock(chan)
Definition: channel.h:2923
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
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:3056
@ AST_CONTROL_RINGING
#define ast_verb(level,...)
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
int ast_max_forwards_get(struct ast_channel *chan)
Get the current max forwards for a particular channel.
Definition: max_forwards.c:121
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7766
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7776
static char url[512]
Channel datastore data for max forwards.
Definition: max_forwards.c:29
Number structure.
Definition: app_followme.c:154
char digits[AST_MAX_EXTENSION]
Definition: app_queue.c:1697
int valid_digits
Definition: app_queue.c:1699
time_t last_pos
Definition: app_queue.c:1706
time_t last_periodic_announce_time
Definition: app_queue.c:1704
time_t expire
Definition: app_queue.c:1716
unsigned int withdraw
Definition: app_queue.c:1718
int ring_when_ringing
Definition: app_queue.c:1703
char * withdraw_info
Definition: app_queue.c:1719
int handled
Definition: app_queue.c:1708
int last_pos_said
Definition: app_queue.c:1702
int last_periodic_announce_sound
Definition: app_queue.c:1705
const char * predial_callee
Definition: app_queue.c:1698
#define ast_test_flag(p, flag)
Definition: utils.h:63
void ast_replace_subargument_delimiter(char *s)
Replace '^' in a string with ','.
Definition: utils.c:2343

References call_queue::announce_to_first_user, call_queue::announcefrequency, ao2_container_count(), args, AST_APP_ARG, ast_app_exec_sub(), ast_app_parse_options(), ast_assert, ast_channel_caller(), ast_channel_lock, ast_channel_name(), ast_channel_uniqueid(), ast_channel_unlock, AST_CONTROL_RINGING, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_free, ast_indicate(), AST_LIST_FIRST, ast_log, ast_max_forwards_get(), ast_moh_start(), ast_moh_stop(), ast_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, 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_WARNING, queue_ent::max_penalty, call_queue::members, queue_ent::min_penalty, queue_ent::moh, call_queue::name, NULL, queue_ent::opos, OPT_ARG_ARRAY_SIZE, OPT_ARG_MUSICONHOLD_CLASS, OPT_ARG_PREDIAL_CALLEE, OPT_ARG_PREDIAL_CALLER, OPT_GO_ON, OPT_MUSICONHOLD_CLASS, OPT_PREDIAL_CALLEE, OPT_PREDIAL_CALLER, OPT_RING_WHEN_RINGING, OPT_RINGING, options, queue_ent::parent, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), call_queue::periodicannouncefrequency, call_queue::periodicannouncestartdelay, queue_ent::pos, queue_ent::pr, queue_ent::predial_callee, queue_ent::prio, queue_ent::qe_rules, QUEUE_CONTINUE, queue_exec_options, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, QUEUE_UNKNOWN, queue_unref, QUEUE_WITHDRAW, queue_ent::raise_penalty, record_abandoned(), queue_ent::ring_when_ringing, ringing(), S_COR, S_OR, say_periodic_announcement(), say_position(), set_queue_result(), set_queue_variables(), queue_ent::start, status, stop, penalty_rule::time, try_calling(), update_qe_rule(), update_realtime_members(), url, 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 8960 of file app_queue.c.

8961{
8962 struct call_queue *q;
8963
8964 buf[0] = '\0';
8965
8966 if (ast_strlen_zero(data)) {
8967 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
8968 return -1;
8969 }
8971 snprintf(buf, len, "%d", q != NULL? 1 : 0);
8972 if (q) {
8973 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
8974 }
8975
8976 return 0;
8977}
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 9002 of file app_queue.c.

9003{
9004 int count = 0;
9005 struct member *m;
9006 struct ao2_iterator mem_iter;
9007 struct call_queue *q;
9008
9010 AST_APP_ARG(queuename);
9011 AST_APP_ARG(option);
9012 AST_APP_ARG(interface);
9013 );
9014 /* Make sure the returned value on error is zero length string. */
9015 buf[0] = '\0';
9016
9017 if (ast_strlen_zero(data)) {
9019 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9020 cmd);
9021 return -1;
9022 }
9023
9025
9026 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) {
9028 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9029 cmd);
9030 return -1;
9031 }
9032
9033 if ((q = find_load_queue_rt_friendly(args.queuename))) {
9034 ao2_lock(q);
9035 if (!strcasecmp(args.option, "logged")) {
9036 mem_iter = ao2_iterator_init(q->members, 0);
9037 while ((m = ao2_iterator_next(&mem_iter))) {
9038 /* Count the agents who are logged in and presently answering calls */
9039 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9040 count++;
9041 }
9042 ao2_ref(m, -1);
9043 }
9044 ao2_iterator_destroy(&mem_iter);
9045 } else if (!strcasecmp(args.option, "free")) {
9046 mem_iter = ao2_iterator_init(q->members, 0);
9047 while ((m = ao2_iterator_next(&mem_iter))) {
9048 /* Count the agents who are logged in and presently answering calls */
9049 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
9050 count++;
9051 }
9052 ao2_ref(m, -1);
9053 }
9054 ao2_iterator_destroy(&mem_iter);
9055 } else if (!strcasecmp(args.option, "ready")) {
9056 time_t now;
9057 time(&now);
9058 mem_iter = ao2_iterator_init(q->members, 0);
9059 while ((m = ao2_iterator_next(&mem_iter))) {
9060 /* Count the agents who are logged in, not paused and not wrapping up */
9061 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
9062 !(m->lastcall && get_wrapuptime(q, m) && ((now - get_wrapuptime(q, m)) < m->lastcall))) {
9063 count++;
9064 }
9065 ao2_ref(m, -1);
9066 }
9067 ao2_iterator_destroy(&mem_iter);
9068 } else if (!strcasecmp(args.option, "count")) {
9070 } else if (!strcasecmp(args.option, "penalty")) {
9071 m = get_interface_helper(q, args.interface);
9072 if (m) {
9073 count = m->penalty;
9074 ao2_ref(m, -1);
9075 }
9076 } else if (!strcasecmp(args.option, "paused")) {
9077 m = get_interface_helper(q, args.interface);
9078 if (m) {
9079 count = m->paused;
9080 ao2_ref(m, -1);
9081 }
9082 } else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9083 || !strcasecmp(args.option, "ringinuse"))) {
9084 m = get_interface_helper(q, args.interface);
9085 if (m) {
9086 count = m->ringinuse;
9087 ao2_ref(m, -1);
9088 }
9089 } else {
9090 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9091 }
9092 ao2_unlock(q);
9093 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
9094 } else {
9095 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9096 }
9097
9098 snprintf(buf, len, "%d", count);
9099
9100 return 0;
9101}
static struct member * get_interface_helper(struct call_queue *q, const char *interface)
Definition: app_queue.c:8979

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

9105{
9106 int memvalue;
9107
9109 AST_APP_ARG(queuename);
9110 AST_APP_ARG(option);
9111 AST_APP_ARG(interface);
9112 );
9113
9114 if (ast_strlen_zero(data)) {
9116 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9117 cmd);
9118 return -1;
9119 }
9120
9122
9123 if (ast_strlen_zero(args.option)
9124 || ast_strlen_zero(args.interface)) {
9126 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9127 cmd);
9128 return -1;
9129 }
9130
9131 /*
9132 * If queuename is empty then the option will be
9133 * set for the interface in all queues.
9134 */
9135
9136 memvalue = atoi(value);
9137 if (!strcasecmp(args.option, "penalty")) {
9138 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
9139 ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
9140 return -1;
9141 }
9142 } else if (!strcasecmp(args.option, "paused")) {
9143 memvalue = (memvalue <= 0) ? 0 : 1;
9144 if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
9145 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9146 return -1;
9147 }
9148 } else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9149 || !strcasecmp(args.option, "ringinuse")) {
9150 memvalue = (memvalue <= 0) ? 0 : 1;
9151 if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
9152 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9153 return -1;
9154 }
9155 } else {
9156 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9157 return -1;
9158 }
9159 return 0;
9160}

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

9373{
9374 int penalty;
9376 AST_APP_ARG(queuename);
9377 AST_APP_ARG(interface);
9378 );
9379 /* Make sure the returned value on error is NULL. */
9380 buf[0] = '\0';
9381
9382 if (ast_strlen_zero(data)) {
9383 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9384 return -1;
9385 }
9386
9388
9389 if (args.argc < 2) {
9390 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9391 return -1;
9392 }
9393
9394 penalty = get_member_penalty (args.queuename, args.interface);
9395
9396 if (penalty >= 0) { /* remember that buf is already '\0' */
9397 snprintf (buf, len, "%d", penalty);
9398 }
9399
9400 return 0;
9401}
static int get_member_penalty(char *queuename, char *interface)
Gets members penalty.
Definition: app_queue.c:8064

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

9405{
9406 int penalty;
9408 AST_APP_ARG(queuename);
9409 AST_APP_ARG(interface);
9410 );
9411
9412 if (ast_strlen_zero(data)) {
9413 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9414 return -1;
9415 }
9416
9418
9419 if (args.argc < 2) {
9420 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9421 return -1;
9422 }
9423
9424 penalty = atoi(value);
9425
9426 if (ast_strlen_zero(args.interface)) {
9427 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9428 return -1;
9429 }
9430
9431 /* if queuename = NULL then penalty will be set for interface in all the queues. */
9432 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9433 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9434 return -1;
9435 }
9436
9437 return 0;
9438}

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

◆ queue_function_qac_dep()

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

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

Return values
numberof members
-1on error

Definition at line 9167 of file app_queue.c.

9168{
9169 int count = 0;
9170 struct member *m;
9171 struct call_queue *q;
9172 struct ao2_iterator mem_iter;
9173 static int depflag = 1;
9174
9175 if (depflag) {
9176 depflag = 0;
9177 ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
9178 }
9179
9180 if (ast_strlen_zero(data)) {
9181 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9182 return -1;
9183 }
9184
9185 if ((q = find_load_queue_rt_friendly(data))) {
9186 ao2_lock(q);
9187 mem_iter = ao2_iterator_init(q->members, 0);
9188 while ((m = ao2_iterator_next(&mem_iter))) {
9189 /* Count the agents who are logged in and presently answering calls */
9190 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9191 count++;
9192 }
9193 ao2_ref(m, -1);
9194 }
9195 ao2_iterator_destroy(&mem_iter);
9196 ao2_unlock(q);
9197 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
9198 } else {
9199 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9200 }
9201
9202 snprintf(buf, len, "%d", count);
9203
9204 return 0;
9205}

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

◆ queue_function_queuegetchannel()

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

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

Definition at line 9208 of file app_queue.c.

9209{
9210 int position;
9211 char *parse;
9212 struct call_queue *q;
9213 struct ast_variable *var;
9214
9216 AST_APP_ARG(queuename);
9217 AST_APP_ARG(position);
9218 );
9219
9220 buf[0] = '\0';
9221
9222 if (ast_strlen_zero(data)) {
9223 ast_log(LOG_ERROR, "Missing argument. QUEUE_GET_CHANNEL(<queuename>,<position>)\n");
9224 return -1;
9225 }
9226
9227 parse = ast_strdupa(data);
9229
9230 if (ast_strlen_zero(args.queuename)) {
9231 ast_log (LOG_ERROR, "The <queuename> parameter is required.\n");
9232 return -1;
9233 }
9234
9235 if (ast_strlen_zero(args.position)) {
9236 position = 1;
9237 } else {
9238 if (sscanf(args.position, "%30d", &position) != 1) {
9239 ast_log (LOG_ERROR, "<position> parameter must be an integer.\n");
9240 return -1;
9241 }
9242 if (position < 1) {
9243 ast_log (LOG_ERROR, "<position> parameter must be an integer greater than zero.\n");
9244 return -1;
9245 }
9246 }
9247
9248 {
9249 struct call_queue tmpq = {
9250 .name = args.queuename,
9251 };
9252
9253 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_GET_CHANNEL()");
9254 }
9255 if (q) {
9256 ao2_lock(q);
9257 if (q->count >= position) {
9258 struct queue_ent *qe;
9259
9260 for (qe = q->head; qe; qe = qe->next) {
9261 if (qe->pos == position) {
9263 break;
9264 }
9265 }
9266 }
9267 ao2_unlock(q);
9268 queue_t_unref(q, "Done with reference in QUEUE_GET_CHANNEL()");
9269 return 0;
9270 }
9271
9272 var = ast_load_realtime("queues", "name", args.queuename, SENTINEL);
9273 if (var) {
9274 /* if the queue is realtime but was not found in memory, this
9275 * means that the queue had been deleted from memory since it was
9276 * "dead."
9277 */
9279 return 0;
9280 }
9281
9282 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9283 return 0;
9284}

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

◆ queue_function_queuememberlist()

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

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

Definition at line 9324 of file app_queue.c.

9325{
9326 struct call_queue *q;
9327 struct member *m;
9328
9329 /* Ensure an otherwise empty list doesn't return garbage */
9330 buf[0] = '\0';
9331
9332 if (ast_strlen_zero(data)) {
9333 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
9334 return -1;
9335 }
9336
9337 if ((q = find_load_queue_rt_friendly(data))) {
9338 int buflen = 0, count = 0;
9339 struct ao2_iterator mem_iter;
9340
9341 ao2_lock(q);
9342 mem_iter = ao2_iterator_init(q->members, 0);
9343 while ((m = ao2_iterator_next(&mem_iter))) {
9344 /* strcat() is always faster than printf() */
9345 if (count++) {
9346 strncat(buf + buflen, ",", len - buflen - 1);
9347 buflen++;
9348 }
9349 strncat(buf + buflen, m->interface, len - buflen - 1);
9350 buflen += strlen(m->interface);
9351 /* Safeguard against overflow (negative length) */
9352 if (buflen >= len - 2) {
9353 ao2_ref(m, -1);
9354 ast_log(LOG_WARNING, "Truncating list\n");
9355 break;
9356 }
9357 ao2_ref(m, -1);
9358 }
9359 ao2_iterator_destroy(&mem_iter);
9360 ao2_unlock(q);
9361 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
9362 } else
9363 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9364
9365 /* We should already be terminated, but let's make sure. */
9366 buf[len - 1] = '\0';
9367
9368 return 0;
9369}

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

9288{
9289 int count = 0;
9290 struct call_queue *q, tmpq = {
9291 .name = data,
9292 };
9293 struct ast_variable *var = NULL;
9294
9295 buf[0] = '\0';
9296
9297 if (ast_strlen_zero(data)) {
9298 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
9299 return -1;
9300 }
9301
9302 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
9303 ao2_lock(q);
9304 count = q->count;
9305 ao2_unlock(q);
9306 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
9307 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
9308 /* if the queue is realtime but was not found in memory, this
9309 * means that the queue had been deleted from memory since it was
9310 * "dead." This means it has a 0 waiting count
9311 */
9312 count = 0;
9314 } else {
9315 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9316 }
9317
9318 snprintf(buf, len, "%d", count);
9319
9320 return 0;
9321}

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

8917{
8918 int res = -1;
8919 struct call_queue *q;
8920 char interfacevar[256] = "";
8921 float sl = 0;
8922
8923 if (ast_strlen_zero(data)) {
8924 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
8925 return -1;
8926 }
8927
8928 if ((q = find_load_queue_rt_friendly(data))) {
8929 ao2_lock(q);
8930 if (q->setqueuevar) {
8931 sl = 0;
8932 res = 0;
8933
8934 if (q->callscompleted > 0) {
8935 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
8936 }
8937
8938 snprintf(interfacevar, sizeof(interfacevar),
8939 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
8941
8942 pbx_builtin_setvar_multiple(chan, interfacevar);
8943 }
8944
8945 ao2_unlock(q);
8946 queue_t_unref(q, "Done with QUEUE() function");
8947 } else {
8948 ast_log(LOG_WARNING, "queue %s was not found\n", data);
8949 }
8950
8951 snprintf(buf, len, "%d", res);
8952
8953 return 0;
8954}
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 1969 of file app_queue.c.

1970{
1971 const struct call_queue *q = obj;
1972
1973 return ast_str_case_hash(q->name);
1974}

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

2178{
2179 return queue_member_to_ami("QueueMemberAdded", message);
2180}
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2157

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

2394{
2395 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}",
2396 "Queue", q->name,
2397 "MemberName", mem->membername,
2398 "Interface", mem->interface,
2399 "StateInterface", mem->state_interface,
2400 "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
2401 "Penalty", mem->penalty,
2402 "CallsTaken", mem->calls,
2403 "LastCall", (int)mem->lastcall,
2404 "LastPause", (int)mem->lastpause,
2405 "LoginTime", (int)mem->logintime,
2406 "InCall", mem->starttime ? 1 : 0,
2407 "Status", mem->status,
2408 "Paused", mem->paused,
2409 "PausedReason", mem->reason_paused,
2410 "Ringinuse", mem->ringinuse,
2411 "Wrapuptime", mem->wrapuptime);
2412}

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

2004{
2005 struct member *mem = obj;
2006 int *decrement_followers_after = arg;
2007
2008 if (mem->queuepos > *decrement_followers_after) {
2009 mem->queuepos--;
2010 }
2011
2012 return 0;
2013}

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

2041{
2042 int pos = mem->queuepos;
2043
2044 /* 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
2045 * who would have been next otherwise. */
2046 if (pos < queue->rrpos) {
2047 queue->rrpos--;
2048 }
2049
2051}

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

2188{
2189 return queue_member_to_ami("QueueMemberPause", message);
2190}

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

2193{
2194 return queue_member_to_ami("QueueMemberPenalty", message);
2195}

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

2183{
2184 return queue_member_to_ami("QueueMemberRemoved", message);
2185}

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

2198{
2199 return queue_member_to_ami("QueueMemberRinginuse", message);
2200}

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

2173{
2174 return queue_member_to_ami("QueueMemberStatus", message);
2175}

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

2222{
2225 struct ast_channel_snapshot *agent;
2226 RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2227 RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2228 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2229
2231 if (caller) {
2232 caller_event_string = ast_manager_build_channel_state_string(caller);
2233 if (!caller_event_string) {
2234 ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2235 return NULL;
2236 }
2237 }
2238
2239 agent = ast_multi_channel_blob_get_channel(obj, "agent");
2240 if (agent) {
2241 agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2242 if (!agent_event_string) {
2243 ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2244 return NULL;
2245 }
2246 }
2247
2249 if (!event_string) {
2250 return NULL;
2251 }
2252
2254 "%s"
2255 "%s"
2256 "%s",
2257 caller_event_string ? ast_str_buffer(caller_event_string) : "",
2258 agent_event_string ? ast_str_buffer(agent_event_string) : "",
2259 ast_str_buffer(event_string));
2260}
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 2369 of file app_queue.c.

2370{
2371 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2372 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2373
2374 if (!blob || !type) {
2375 ast_json_unref(blob);
2376 return;
2377 }
2378
2379 payload = ast_json_payload_create(blob);
2380 ast_json_unref(blob);
2381 if (!payload) {
2382 return;
2383 }
2384
2385 msg = stasis_message_create(type, payload);
2386 if (!msg) {
2387 return;
2388 }
2389
2391}
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:1511

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

2340{
2341 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2342 RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2343
2344 ast_channel_lock(caller);
2345 caller_snapshot = ast_channel_snapshot_create(caller);
2346 ast_channel_unlock(caller);
2347 ast_channel_lock(agent);
2348 agent_snapshot = ast_channel_snapshot_create(agent);
2349 ast_channel_unlock(agent);
2350
2351 if (!caller_snapshot || !agent_snapshot) {
2352 return;
2353 }
2354
2356 agent_snapshot, type, blob);
2357}
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:2303
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 2303 of file app_queue.c.

2307{
2308 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
2309 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2310
2311 if (!type) {
2312 return;
2313 }
2314
2315 payload = ast_multi_channel_blob_create(blob);
2316 if (!payload) {
2317 return;
2318 }
2319
2320 if (caller_snapshot) {
2321 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
2322 } else {
2323 ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
2324 }
2325
2326 if (agent_snapshot) {
2327 ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
2328 }
2329
2330 msg = stasis_message_create(type, payload);
2331 if (!msg) {
2332 return;
2333 }
2334
2335 stasis_publish(topic, msg);
2336}
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 9562 of file app_queue.c.

9563{
9565 autofill_default = 0;
9566 montype_default = 0;
9567 shared_lastcall = 0;
9571}
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1599
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1611
static int shared_lastcall
queues.conf [general] option
Definition: app_queue.c:1602

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

Referenced by reload_queues().

◆ queue_rules_reset_global_params()

static void queue_rules_reset_global_params ( void  )
static

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

Definition at line 9483 of file app_queue.c.

9484{
9485 realtime_rules = 0;
9486}
static int realtime_rules
queuerules.conf [general] option
Definition: app_queue.c:1605

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

9490{
9491 const char *general_val = NULL;
9492 if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9493 realtime_rules = ast_true(general_val);
9494 }
9495}

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

9575{
9576 const char *general_val = NULL;
9577 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
9578 queue_persistent_members = ast_true(general_val);
9579 }
9580 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
9581 autofill_default = ast_true(general_val);
9582 }
9583 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
9584 if (!strcasecmp(general_val, "mixmonitor"))
9585 montype_default = 1;
9586 }
9587 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
9588 shared_lastcall = ast_true(general_val);
9589 }
9590 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
9591 negative_penalty_invalid = ast_true(general_val);
9592 }
9593 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
9594 log_membername_as_agent = ast_true(general_val);
9595 }
9596 if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
9598 }
9599}

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

Referenced by reload_queues().

◆ queue_set_param()

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

Configure a queue parameter.

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

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

Definition at line 3329 of file app_queue.c.

3330{
3331 if (!strcasecmp(param, "musicclass") ||
3332 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
3333 ast_string_field_set(q, moh, val);
3334 } else if (!strcasecmp(param, "announce")) {
3335 ast_string_field_set(q, announce, val);
3336 } else if (!strcasecmp(param, "context")) {
3338 } else if (!strcasecmp(param, "timeout")) {
3339 q->timeout = atoi(val);
3340 if (q->timeout < 0) {
3342 }
3343 } else if (!strcasecmp(param, "ringinuse")) {
3344 q->ringinuse = ast_true(val);
3345 } else if (!strcasecmp(param, "setinterfacevar")) {
3347 } else if (!strcasecmp(param, "setqueuevar")) {
3348 q->setqueuevar = ast_true(val);
3349 } else if (!strcasecmp(param, "setqueueentryvar")) {
3351 } else if (!strcasecmp(param, "monitor-format")) {
3352 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
3353 } else if (!strcasecmp(param, "membergosub")) {
3354 ast_string_field_set(q, membergosub, val);
3355 } else if (!strcasecmp(param, "queue-youarenext")) {
3356 ast_string_field_set(q, sound_next, val);
3357 } else if (!strcasecmp(param, "queue-thereare")) {
3358 ast_string_field_set(q, sound_thereare, val);
3359 } else if (!strcasecmp(param, "queue-callswaiting")) {
3360 ast_string_field_set(q, sound_calls, val);
3361 } else if (!strcasecmp(param, "queue-quantity1")) {
3362 ast_string_field_set(q, queue_quantity1, val);
3363 } else if (!strcasecmp(param, "queue-quantity2")) {
3364 ast_string_field_set(q, queue_quantity2, val);
3365 } else if (!strcasecmp(param, "queue-holdtime")) {
3366 ast_string_field_set(q, sound_holdtime, val);
3367 } else if (!strcasecmp(param, "queue-minutes")) {
3368 ast_string_field_set(q, sound_minutes, val);
3369 } else if (!strcasecmp(param, "queue-minute")) {
3370 ast_string_field_set(q, sound_minute, val);
3371 } else if (!strcasecmp(param, "queue-seconds")) {
3372 ast_string_field_set(q, sound_seconds, val);
3373 } else if (!strcasecmp(param, "queue-thankyou")) {
3374 ast_string_field_set(q, sound_thanks, val);
3375 } else if (!strcasecmp(param, "queue-callerannounce")) {
3376 ast_string_field_set(q, sound_callerannounce, val);
3377 } else if (!strcasecmp(param, "queue-reporthold")) {
3378 ast_string_field_set(q, sound_reporthold, val);
3379 } else if (!strcasecmp(param, "announce-frequency")) {
3380 q->announcefrequency = atoi(val);
3381 } else if (!strcasecmp(param, "announce-to-first-user")) {
3383 } else if (!strcasecmp(param, "min-announce-frequency")) {
3384 q->minannouncefrequency = atoi(val);
3385 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
3386 } else if (!strcasecmp(param, "announce-round-seconds")) {
3387 q->roundingseconds = atoi(val);
3388 /* Rounding to any other values just doesn't make sense... */
3389 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
3390 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
3391 if (linenum >= 0) {
3392 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3393 "using 0 instead for queue '%s' at line %d of queues.conf\n",
3394 val, param, q->name, linenum);
3395 } else {
3396 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3397 "using 0 instead for queue '%s'\n", val, param, q->name);
3398 }
3399 q->roundingseconds=0;
3400 }
3401 } else if (!strcasecmp(param, "announce-holdtime")) {
3402 if (!strcasecmp(val, "once")) {
3404 } else if (ast_true(val)) {
3406 } else {
3407 q->announceholdtime = 0;
3408 }
3409 } else if (!strcasecmp(param, "announce-position")) {
3410 if (!strcasecmp(val, "limit")) {
3412 } else if (!strcasecmp(val, "more")) {
3414 } else if (ast_true(val)) {
3416 } else {
3418 }
3419 } else if (!strcasecmp(param, "announce-position-only-up")) {
3421 } else if (!strcasecmp(param, "announce-position-limit")) {
3422 q->announcepositionlimit = atoi(val);
3423 } else if (!strcasecmp(param, "periodic-announce")) {
3424 if (strchr(val, ',')) {
3425 char *s, *buf = ast_strdupa(val);
3426 unsigned int i = 0;
3427
3428 while ((s = strsep(&buf, ",|"))) {
3429 if (!q->sound_periodicannounce[i]) {
3431 }
3432 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
3433 i++;
3434 if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
3435 break;
3436 }
3437 }
3438 q->numperiodicannounce = i;
3439 } else {
3440 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
3441 q->numperiodicannounce = 1;
3442 }
3443 } else if (!strcasecmp(param, "periodic-announce-startdelay")) {
3445 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
3446 q->periodicannouncefrequency = atoi(val);
3447 } else if (!strcasecmp(param, "relative-periodic-announce")) {
3449 } else if (!strcasecmp(param, "random-periodic-announce")) {
3451 } else if (!strcasecmp(param, "retry")) {
3452 q->retry = atoi(val);
3453 if (q->retry <= 0) {
3454 q->retry = DEFAULT_RETRY;
3455 }
3456 } else if (!strcasecmp(param, "wrapuptime")) {
3457 q->wrapuptime = atoi(val);
3458 } else if (!strcasecmp(param, "penaltymemberslimit")) {
3459 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
3460 q->penaltymemberslimit = 0;
3461 }
3462 } else if (!strcasecmp(param, "autofill")) {
3463 q->autofill = ast_true(val);
3464 } else if (!strcasecmp(param, "autopause")) {
3466 } else if (!strcasecmp(param, "autopausedelay")) {
3467 q->autopausedelay = atoi(val);
3468 } else if (!strcasecmp(param, "autopausebusy")) {
3470 } else if (!strcasecmp(param, "autopauseunavail")) {
3472 } else if (!strcasecmp(param, "maxlen")) {
3473 q->maxlen = atoi(val);
3474 if (q->maxlen < 0) {
3475 q->maxlen = 0;
3476 }
3477 } else if (!strcasecmp(param, "servicelevel")) {
3478 q->servicelevel= atoi(val);
3479 } else if (!strcasecmp(param, "strategy")) {
3480 int strategy;
3481
3482 /* We are a static queue and already have set this, no need to do it again */
3483 if (failunknown) {
3484 return;
3485 }
3487 if (strategy < 0) {
3488 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3489 val, q->name);
3491 }
3492 if (strategy == q->strategy) {
3493 return;
3494 }
3496 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
3497 return;
3498 }
3499 q->strategy = strategy;
3500 } else if (!strcasecmp(param, "joinempty")) {
3502 } else if (!strcasecmp(param, "leavewhenempty")) {
3504 } else if (!strcasecmp(param, "reportholdtime")) {
3506 } else if (!strcasecmp(param, "memberdelay")) {
3507 q->memberdelay = atoi(val);
3508 } else if (!strcasecmp(param, "weight")) {
3509 q->weight = atoi(val);
3510 } else if (!strcasecmp(param, "timeoutrestart")) {
3512 } else if (!strcasecmp(param, "defaultrule")) {
3513 ast_string_field_set(q, defaultrule, val);
3514 } else if (!strcasecmp(param, "timeoutpriority")) {
3515 if (!strcasecmp(val, "conf")) {
3517 } else {
3519 }
3520 } else if (failunknown) {
3521 if (linenum >= 0) {
3522 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
3523 q->name, param, linenum);
3524 } else {
3525 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
3526 }
3527 }
3528}
#define ANNOUNCEPOSITION_MORE_THAN
Definition: app_queue.c:1788
static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
Definition: app_queue.c:3286
#define ANNOUNCEPOSITION_NO
Definition: app_queue.c:1787
#define ANNOUNCEHOLDTIME_ALWAYS
Definition: app_queue.c:1771
#define ANNOUNCEPOSITION_LIMIT
Definition: app_queue.c:1789
#define ANNOUNCEHOLDTIME_ONCE
Definition: app_queue.c:1772
static int autopause2int(const char *autopause)
Definition: app_queue.c:1946
Definition: ast_expr2.c:325

References call_queue::announce_to_first_user, call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_NO, call_queue::announceposition_only_up, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, ast_copy_string(), ast_debug, ast_log, ast_str_create, ast_str_set(), ast_strdupa, ast_string_field_set, ast_true(), call_queue::autofill, call_queue::autopause, autopause2int(), call_queue::autopausebusy, call_queue::autopausedelay, call_queue::autopauseunavail, buf, voicemailpwcheck::context, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::joinempty, call_queue::leavewhenempty, 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 10346 of file app_queue.c.

10347{
10348 switch ( cmd ) {
10349 case CLI_INIT:
10350 e->command = "queue show";
10351 e->usage =
10352 "Usage: queue show\n"
10353 " Provides summary information on a specified queue.\n";
10354 return NULL;
10355 case CLI_GENERATE:
10356 return complete_queue_show(a->line, a->word, a->pos, a->n);
10357 }
10358
10359 return __queues_show(NULL, a->fd, a->argc, a->argv);
10360}
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10338
static char * __queues_show(struct mansession *s, int fd, int argc, const char *const *argv)
Show queue(s) status and statistics.
Definition: app_queue.c:10130

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

6289{
6290 struct queue_stasis_data *queue_data;
6291
6292 queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
6293 if (!queue_data) {
6294 return NULL;
6295 }
6296
6297 if (ast_string_field_init(queue_data, 64)) {
6298 ao2_cleanup(queue_data);
6299 return NULL;
6300 }
6301
6304 queue_data->queue = queue_ref(qe->parent);
6305 queue_data->starttime = starttime;
6306 queue_data->holdstart = holdstart;
6308 queue_data->caller_pos = qe->opos;
6309 ao2_ref(mem, +1);
6310 queue_data->member = mem;
6311
6312 return queue_data;
6313}
static void queue_stasis_data_destructor(void *obj)
Definition: app_queue.c:6254

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

6255{
6256 struct queue_stasis_data *queue_data = obj;
6257
6258 /* This can only happen if refcounts for this object have got severely messed up */
6259 ast_assert(queue_data->bridge_router == NULL);
6260 ast_assert(queue_data->channel_router == NULL);
6261
6262 ao2_cleanup(queue_data->member);
6263 queue_unref(queue_data->queue);
6264 ast_string_field_free_memory(queue_data);
6265}
struct stasis_message_router * channel_router
Definition: app_queue.c:6243
struct stasis_message_router * bridge_router
Definition: app_queue.c:6241

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

11584{
11585 int oldtalktime;
11586 char *parse;
11587 struct call_queue *q;
11588 struct member *mem;
11589 int newtalktime = 0;
11590
11592 AST_APP_ARG(queuename);
11593 AST_APP_ARG(uniqueid);
11594 AST_APP_ARG(agent);
11596 AST_APP_ARG(talktime);
11597 AST_APP_ARG(params););
11598
11599 if (ast_strlen_zero(data)) {
11600 ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n");
11601 return -1;
11602 }
11603
11604 parse = ast_strdupa(data);
11605
11607
11608 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) {
11609 ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n");
11610 return -1;
11611 }
11612
11613 if (!ast_strlen_zero(args.talktime)) {
11614 newtalktime = atoi(args.talktime);
11615 }
11616
11617 q = find_load_queue_rt_friendly(args.queuename);
11618 if (!q) {
11619 ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename);
11620 return 0;
11621 }
11622
11623 ao2_lock(q);
11624 if (q->members) {
11625 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
11626 while ((mem = ao2_iterator_next(&mem_iter))) {
11627 if (!strcasecmp(mem->membername, args.agent)) {
11628 if (!strcasecmp(args.status, "ANSWER")) {
11629 oldtalktime = q->talktime;
11630 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
11631 time(&mem->lastcall);
11632 mem->calls++;
11633 mem->lastqueue = q;
11634 q->callscompleted++;
11635
11636 if (newtalktime <= q->servicelevel) {
11637 q->callscompletedinsl++;
11638 }
11639 } else {
11640
11641 time(&mem->lastcall);
11642 q->callsabandoned++;
11643 }
11644
11645 ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params);
11646 }
11647
11648 ao2_ref(mem, -1);
11649 }
11650
11651 ao2_iterator_destroy(&mem_iter);
11652 }
11653
11654 ao2_unlock(q);
11655 queue_t_unref(q, "Done with temporary pointer");
11656
11657 return 0;
11658}

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

4345{
4346 int oldvalue;
4347
4348 /* Calculate holdtime using an exponential average */
4349 /* Thanks to SRT for this contribution */
4350 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
4351
4352 ao2_lock(qe->parent);
4353 if ((qe->parent->callscompleted + qe->parent->callsabandoned) == 0) {
4354 qe->parent->holdtime = newholdtime;
4355 } else {
4356 oldvalue = qe->parent->holdtime;
4357 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
4358 }
4359 ao2_unlock(qe->parent);
4360}

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

Referenced by try_calling().

◆ record_abandoned()

static void record_abandoned ( struct queue_ent qe)
static

Record that a caller gave up on waiting in queue.

Definition at line 5074 of file app_queue.c.

5075{
5076 int callabandonedinsl = 0;
5077 time_t now;
5078
5079 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5080
5081 pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE");
5082
5084 ao2_lock(qe->parent);
5085 blob = ast_json_pack("{s: s, s: i, s: i, s: i}",
5086 "Queue", qe->parent->name,
5087 "Position", qe->pos,
5088 "OriginalPosition", qe->opos,
5089 "HoldTime", (int)(time(NULL) - qe->start));
5090
5091
5092 time(&now);
5093 callabandonedinsl = ((now - qe->start) <= qe->parent->servicelevel);
5094 if (callabandonedinsl) {
5096 }
5097
5098 qe->parent->callsabandoned++;
5099 ao2_unlock(qe->parent);
5100
5101 ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
5102}

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

11908{
11909 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
11910 ast_unload_realtime("queue_members");
11911 reload_handler(1, &mask, NULL);
11912 return 0;
11913}
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3576

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

9996{
9997 int res = 0;
9998
9999 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
10000 res |= reload_queue_rules(reload);
10001 }
10002 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
10003 res |= clear_stats(queuename);
10004 }
10006 res |= reload_queues(reload, mask, queuename);
10007 }
10008 return res;
10009}
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
Definition: app_queue.c:9908
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition: app_queue.c:9503
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
Definition: app_queue.c:9965
static int reload(void)
Definition: app_queue.c:11907

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

8096{
8097 char *cur_ptr;
8098 const char *queue_name;
8099 char *member;
8100 char *interface;
8101 char *membername = NULL;
8102 char *state_interface;
8103 char *penalty_tok;
8104 int penalty = 0;
8105 char *paused_tok;
8106 int paused = 0;
8107 char *wrapuptime_tok;
8108 int wrapuptime = 0;
8109 char *reason_paused;
8110 struct ast_db_entry *db_tree;
8111 struct ast_db_entry *entry;
8112 struct call_queue *cur_queue;
8113 char *queue_data;
8114
8115 /* Each key in 'pm_family' is the name of a queue */
8116 db_tree = ast_db_gettree(pm_family, NULL);
8117 for (entry = db_tree; entry; entry = entry->next) {
8118
8119 queue_name = entry->key + strlen(pm_family) + 2;
8120
8121 {
8122 struct call_queue tmpq = {
8123 .name = queue_name,
8124 };
8125 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
8126 }
8127
8128 if (!cur_queue) {
8129 cur_queue = find_load_queue_rt_friendly(queue_name);
8130 }
8131
8132 if (!cur_queue) {
8133 /* If the queue no longer exists, remove it from the
8134 * database */
8135 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
8136 ast_db_del(pm_family, queue_name);
8137 continue;
8138 }
8139
8140 if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
8141 queue_t_unref(cur_queue, "Expire reload reference");
8142 continue;
8143 }
8144
8145 cur_ptr = queue_data;
8146 while ((member = strsep(&cur_ptr, ",|"))) {
8147 if (ast_strlen_zero(member)) {
8148 continue;
8149 }
8150
8151 interface = strsep(&member, ";");
8152 penalty_tok = strsep(&member, ";");
8153 paused_tok = strsep(&member, ";");
8154 membername = strsep(&member, ";");
8155 state_interface = strsep(&member, ";");
8156 reason_paused = strsep(&member, ";");
8157 wrapuptime_tok = strsep(&member, ";");
8158
8159 if (!penalty_tok) {
8160 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
8161 break;
8162 }
8163 penalty = strtol(penalty_tok, NULL, 10);
8164 if (errno == ERANGE) {
8165 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
8166 break;
8167 }
8168
8169 if (!paused_tok) {
8170 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
8171 break;
8172 }
8173 paused = strtol(paused_tok, NULL, 10);
8174 if ((errno == ERANGE) || paused < 0 || paused > 1) {
8175 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
8176 break;
8177 }
8178
8179 if (!ast_strlen_zero(wrapuptime_tok)) {
8180 wrapuptime = strtol(wrapuptime_tok, NULL, 10);
8181 if (errno == ERANGE) {
8182 ast_log(LOG_WARNING, "Error converting wrapuptime: %s: Out of range.\n", wrapuptime_tok);
8183 break;
8184 }
8185 }
8186
8187 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s Wrapuptime: %d\n",
8188 queue_name, interface, membername, penalty, paused, reason_paused, wrapuptime);
8189
8190 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused, wrapuptime) == RES_OUTOFMEMORY) {
8191 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
8192 break;
8193 }
8194 }
8195 queue_t_unref(cur_queue, "Expire reload reference");
8196 ast_free(queue_data);
8197 }
8198
8199 if (db_tree) {
8200 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
8201 ast_db_freetree(db_tree);
8202 }
8203}
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: main/db.c:437
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
Definition: main/db.c:610
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition: main/db.c:677
int errno
Definition: astdb.h:31
Definition: search.h:40
char * key
Definition: search.h:41

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, entry::key, LOG_ERROR, LOG_NOTICE, LOG_WARNING, member::membername, call_queue::name, 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 9503 of file app_queue.c.

9504{
9505 struct ast_config *cfg;
9506 struct rule_list *rl_iter, *new_rl;
9507 struct penalty_rule *pr_iter;
9508 char *rulecat = NULL;
9509 struct ast_variable *rulevar = NULL;
9510 struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9511
9512 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
9513 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
9515 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9516 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
9518 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9519 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
9521 }
9522
9524 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
9525 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
9526 ast_free(pr_iter);
9527 ast_free(rl_iter);
9528 }
9530 while ((rulecat = ast_category_browse(cfg, rulecat))) {
9531 if (!strcasecmp(rulecat, "general")) {
9533 continue;
9534 }
9535 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
9537 ast_config_destroy(cfg);
9539 } else {
9540 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
9541 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
9542 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
9543 if(!strcasecmp(rulevar->name, "penaltychange"))
9544 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
9545 else
9546 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
9547 }
9548 }
9549
9550 ast_config_destroy(cfg);
9551
9555 }
9556
9559}
static int load_realtime_rules(void)
Load queue rules from realtime.
Definition: app_queue.c:3184
static void queue_rules_reset_global_params(void)
Definition: app_queue.c:9483
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition: app_queue.c:3080
static void queue_rules_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9489
#define ast_config_load(filename, flags)
Load a config file.
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
@ CONFIG_FLAG_FILEUNCHANGED

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

9909{
9910 struct ast_config *cfg;
9911 char *cat;
9912 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9913 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
9914
9915 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
9916 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
9917 return -1;
9918 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9919 return 0;
9920 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9921 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
9922 return -1;
9923 }
9924
9925 /* We've made it here, so it looks like we're doing operations on all queues. */
9927
9928 /* Mark non-realtime queues not found at the beginning. */
9929 ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
9930
9931 /* Chug through config file. */
9932 cat = NULL;
9934 while ((cat = ast_category_browse(cfg, cat)) ) {
9935 if (!strcasecmp(cat, "general") && queue_reload) {
9937 continue;
9938 }
9939 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
9940 reload_single_queue(cfg, mask, cat);
9941 }
9942
9943 ast_config_destroy(cfg);
9944 if (queue_reload) {
9945 /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
9947 }
9949 return 0;
9950}
static void queue_reset_global_params(void)
Definition: app_queue.c:9562
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:9751
static void queue_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9574
static int mark_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:9874
static int kill_if_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:9884

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

9610{
9611 char *membername, *interface, *state_interface, *tmp;
9612 char *parse;
9613 struct member *cur, *newm;
9614 struct member tmpmem;
9615 int penalty;
9616 int ringinuse;
9617 int wrapuptime;
9625 );
9626
9627 if (ast_strlen_zero(memberdata)) {
9628 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
9629 return;
9630 }
9631
9632 /* Add a new member */
9633 parse = ast_strdupa(memberdata);
9634
9636
9637 interface = args.interface;
9638 if (!ast_strlen_zero(args.penalty)) {
9639 tmp = args.penalty;
9640 ast_strip(tmp);
9641 penalty = atoi(tmp);
9642 if (penalty < 0) {
9643 penalty = 0;
9644 }
9645 } else {
9646 penalty = 0;
9647 }
9648
9649 if (!ast_strlen_zero(args.membername)) {
9650 membername = args.membername;
9651 ast_strip(membername);
9652 } else {
9653 membername = interface;
9654 }
9655
9656 if (!ast_strlen_zero(args.state_interface)) {
9657 state_interface = args.state_interface;
9658 ast_strip(state_interface);
9659 } else {
9660 state_interface = interface;
9661 }
9662
9663 if (!ast_strlen_zero(args.ringinuse)) {
9664 tmp = args.ringinuse;
9665 ast_strip(tmp);
9666 if (ast_true(tmp)) {
9667 ringinuse = 1;
9668 } else if (ast_false(tmp)) {
9669 ringinuse = 0;
9670 } else {
9671 ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n",
9672 membername, q->name);
9673 ringinuse = q->ringinuse;
9674 }
9675 } else {
9676 ringinuse = q->ringinuse;
9677 }
9678
9679 if (!ast_strlen_zero(args.wrapuptime)) {
9680 tmp = args.wrapuptime;
9681 ast_strip(tmp);
9682 wrapuptime = atoi(tmp);
9683 if (wrapuptime < 0) {
9684 wrapuptime = 0;
9685 }
9686 } else {
9687 wrapuptime = 0;
9688 }
9689
9690 /* Find the old position in the list */
9691 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
9692 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
9693
9694 if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface, ringinuse, wrapuptime))) {
9695 newm->wrapuptime = wrapuptime;
9696 if (cur) {
9697 ao2_lock(q->members);
9698 /* Round Robin Queue Position must be copied if this is replacing an existing member */
9699 newm->queuepos = cur->queuepos;
9700 /* Don't reset agent stats either */
9701 newm->calls = cur->calls;
9702 newm->lastcall = cur->lastcall;
9703
9704 ao2_link(q->members, newm);
9705 ao2_unlink(q->members, cur);
9706 ao2_unlock(q->members);
9707 } else {
9708 /* Otherwise we need to add using the function that will apply a round robin queue position manually. */
9709 member_add_to_queue(q, newm);
9710 }
9711 ao2_ref(newm, -1);
9712 }
9713 newm = NULL;
9714
9715 if (cur) {
9716 ao2_ref(cur, -1);
9717 }
9718}

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

9752{
9753 int new;
9754 struct call_queue *q = NULL;
9755 struct member *member;
9756 /*We're defining a queue*/
9757 struct call_queue tmpq = {
9758 .name = queuename,
9759 };
9760 const char *tmpvar;
9761 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
9762 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
9763 int prev_weight = 0;
9764 struct ast_variable *var;
9765 struct ao2_iterator mem_iter;
9766
9767 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
9768 if (queue_reload) {
9769 /* Make one then */
9770 if (!(q = alloc_queue(queuename))) {
9771 return;
9772 }
9773 } else {
9774 /* Since we're not reloading queues, this means that we found a queue
9775 * in the configuration file which we don't know about yet. Just return.
9776 */
9777 return;
9778 }
9779 new = 1;
9780 } else {
9781 new = 0;
9782 }
9783
9784 if (!new) {
9785 ao2_lock(q);
9786 prev_weight = q->weight ? 1 : 0;
9787 }
9788 /* Check if we already found a queue with this name in the config file */
9789 if (q->found) {
9790 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
9791 if (!new) {
9792 /* It should be impossible to *not* hit this case*/
9793 ao2_unlock(q);
9794 }
9795 queue_t_unref(q, "We exist! Expiring temporary pointer");
9796 return;
9797 }
9798 /* Due to the fact that the "linear" strategy will have a different allocation
9799 * scheme for queue members, we must devise the queue's strategy before other initializations.
9800 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
9801 * container used will have only a single bucket instead of the typical number.
9802 */
9803 if (queue_reload) {
9804 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
9805 q->strategy = strat2int(tmpvar);
9806 if (q->strategy < 0) {
9807 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
9808 tmpvar, q->name);
9810 }
9811 } else {
9813 }
9814 init_queue(q);
9815 }
9816 if (member_reload) {
9818 q->found = 1;
9819 }
9820
9821 /* On the first pass we just read the parameters of the queue */
9822 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
9823 if (queue_reload && strcasecmp(var->name, "member")) {
9824 queue_set_param(q, var->name, var->value, var->lineno, 1);
9825 }
9826 }
9827
9828 /* On the second pass, we read members */
9829 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
9830 if (member_reload && !strcasecmp(var->name, "member")) {
9831 reload_single_member(var->value, q);
9832 }
9833 }
9834
9835 /* Update ringinuse for dynamic members */
9836 if (member_reload) {
9837 ao2_lock(q->members);
9839 while ((member = ao2_iterator_next(&mem_iter))) {
9840 if (member->dynamic) {
9842 }
9843 ao2_ref(member, -1);
9844 }
9845 ao2_iterator_destroy(&mem_iter);
9846 ao2_unlock(q->members);
9847 }
9848
9849 /* At this point, we've determined if the queue has a weight, so update use_weight
9850 * as appropriate
9851 */
9852 if (!q->weight && prev_weight) {
9854 } else if (q->weight && !prev_weight) {
9856 }
9857
9858 /* Free remaining members marked as delme */
9859 if (member_reload) {
9860 ao2_lock(q->members);
9863 ao2_unlock(q->members);
9864 }
9865
9866 if (new) {
9867 queues_t_link(queues, q, "Add queue to container");
9868 } else {
9869 ao2_unlock(q);
9870 }
9871 queue_t_unref(q, "Expiring creation reference");
9872}
static int mark_member_dead(void *obj, void *arg, int flags)
Definition: app_queue.c:9720
static void reload_single_member(const char *memberdata, struct call_queue *q)
reload information pertaining to a single member
Definition: app_queue.c:9609
static int kill_dead_members(void *obj, void *arg, int flags)
Definition: app_queue.c:9729
static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2022

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

Referenced by reload_queues().

◆ remove_from_queue()

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

Remove member from queue.

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

Definition at line 7535 of file app_queue.c.

7536{
7537 struct call_queue *q, tmpq = {
7538 .name = queuename,
7539 };
7540 struct member *mem, tmpmem;
7541 int res = RES_NOSUCHQUEUE;
7542
7543 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7544 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
7545 ao2_lock(q);
7546 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
7547 /* XXX future changes should beware of this assumption!! */
7548 /*Change Penalty on realtime users*/
7550 update_realtime_member_field(mem, q->name, "penalty", "-1");
7551 } else if (!mem->dynamic) {
7552 ao2_ref(mem, -1);
7553 ao2_unlock(q);
7554 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
7555 return RES_NOT_DYNAMIC;
7556 }
7557 queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
7558
7560 ao2_ref(mem, -1);
7561
7564 }
7565
7566 if (!num_available_members(q)) {
7568 }
7569
7570 res = RES_OKAY;
7571 } else {
7572 res = RES_EXISTS;
7573 }
7574 ao2_unlock(q);
7575 queue_t_unref(q, "Expiring temporary reference");
7576 }
7577
7578 return res;
7579}
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:3979
char rt_uniqueid[80]
Definition: app_queue.c:1750

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

6272{
6273 SCOPED_AO2LOCK(lock, queue_data);
6274
6275 queue_data->dying = 1;
6277 queue_data->bridge_router = NULL;
6279 queue_data->channel_router = NULL;
6280}
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 7717 of file app_queue.c.

7718{
7719 struct call_queue *q;
7720 struct queue_ent *qe;
7721 int res = RES_NOSUCHQUEUE;
7722
7723 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7724 * short-circuits if the queue is already in memory. */
7725 if (!(q = find_load_queue_rt_friendly(queuename))) {
7726 return res;
7727 }
7728
7729 ao2_lock(q);
7730 res = RES_NOT_CALLER;
7731 for (qe = q->head; qe; qe = qe->next) {
7732 if (!strcmp(ast_channel_name(qe->chan), caller)) {
7733 if (qe->withdraw) {
7734 ast_debug(1, "Ignoring duplicate withdraw request of caller %s from queue %s\n", caller, queuename);
7735 res = RES_EXISTS;
7736 } else {
7737 ast_debug(1, "Requested withdraw of caller %s from queue %s\n", caller, queuename);
7738 /* It is not possible to change the withdraw info by further withdraw requests for this caller (channel)
7739 in this queue, so we do not need to worry about a memory leak here. */
7740 if (withdraw_info) {
7742 }
7743 qe->withdraw = 1;
7744 res = RES_OKAY;
7745 }
7746 break;
7747 }
7748 }
7749 ao2_unlock(q);
7750 queue_unref(q);
7751
7752 return res;
7753}

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

Referenced by manager_request_withdraw_caller_from_queue().

◆ ring_entry()

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

Part 2 of ring_one.

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

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

Definition at line 4748 of file app_queue.c.

4749{
4750 int res;
4751 int status;
4752 char tech[256];
4753 char *location;
4754 struct ast_format_cap *nativeformats;
4755 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4756
4757 /* on entry here, we know that tmp->chan == NULL */
4758 if (!can_ring_entry(qe, tmp)) {
4759 tmp->stillgoing = 0;
4760 ++*busies;
4761 return 0;
4762 }
4763
4764 ast_copy_string(tech, tmp->interface, sizeof(tech));
4765 if ((location = strchr(tech, '/'))) {
4766 *location++ = '\0';
4767 } else {
4768 location = "";
4769 }
4770
4772 nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
4774
4775 /* Request the peer */
4776 tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
4777 ao2_cleanup(nativeformats);
4778 if (!tmp->chan) { /* If we can't, just go on to the next call */
4779 ao2_lock(qe->parent);
4780 qe->parent->rrpos++;
4781 qe->linpos++;
4782 ao2_unlock(qe->parent);
4783
4784 pending_members_remove(tmp->member);
4785
4786 publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
4787 tmp->stillgoing = 0;
4788 ++*busies;
4789 return 0;
4790 }
4791
4792 ast_channel_lock_both(tmp->chan, qe->chan);
4793
4796 if (qe->cancel_answered_elsewhere) {
4798 }
4799 ast_channel_appl_set(tmp->chan, "AppQueue");
4800 ast_channel_data_set(tmp->chan, "(Outgoing Line)");
4801 memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
4802
4803 /* If the new channel has no callerid, try to guess what it should be */
4804 if (!ast_channel_caller(tmp->chan)->id.number.valid) {
4806 struct ast_party_caller caller;
4807
4809 caller.id = ast_channel_connected(qe->chan)->id;
4810 caller.ani = ast_channel_connected(qe->chan)->ani;
4811 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
4812 } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
4814 } else if (!ast_strlen_zero(ast_channel_exten(qe->chan))) {
4816 }
4817 tmp->dial_callerid_absent = 1;
4818 }
4819
4821
4823
4825
4826 /* Inherit specially named variables from parent channel */
4830
4831 /* Presense of ADSI CPE on outgoing channel follows ours */
4833
4834 /* Inherit context and extension */
4835 ast_channel_dialcontext_set(tmp->chan, ast_channel_context(qe->chan));
4837
4838 /* Save the original channel name to detect call pickup masquerading in. */
4839 tmp->orig_chan_name = ast_strdup(ast_channel_name(tmp->chan));
4840
4841 ast_channel_unlock(tmp->chan);
4843
4844 /* location is tmp->interface where tech/ has been stripped, so it follow the same syntax as DIALEDPEERNUMBER in app_dial.c */
4845 pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", strlen(location) ? location : tmp->interface);
4846
4847 /* PREDIAL: Run gosub on the callee's channel */
4848 if (qe->predial_callee) {
4849 ast_pre_call(tmp->chan, qe->predial_callee);
4850 }
4851
4852 /* Place the call, but don't wait on the answer */
4853 if ((res = ast_call(tmp->chan, location, 0))) {
4854 /* Again, keep going even if there's an error */
4855 ast_verb(3, "Couldn't call %s\n", tmp->interface);
4856 do_hang(tmp);
4857 ++*busies;
4858 return 0;
4859 }
4860
4861 ast_channel_lock_both(tmp->chan, qe->chan);
4862
4863 blob = ast_json_pack("{s: s, s: s, s: s}",
4864 "Queue", qe->parent->name,
4865 "Interface", tmp->interface,
4866 "MemberName", tmp->member->membername);
4867 queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
4868
4869 ast_channel_publish_dial(qe->chan, tmp->chan, tmp->interface, NULL);
4870
4871 ast_channel_unlock(tmp->chan);
4873
4874 ast_verb(3, "Called %s\n", tmp->interface);
4875
4876 return 1;
4877}
static void do_hang(struct callattempt *o)
common hangup actions
Definition: app_queue.c:4622
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition: app_queue.c:4652
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:2338
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition: app_queue.c:4452
#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:6461
@ AST_CHANNEL_REQUESTOR_BRIDGE_PEER
Definition: channel.h:1477
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:7372
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:2929
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2368
const char * ast_channel_context(const struct ast_channel *chan)
ast_channel_adsicpe
Definition: channel.h:868
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:1999
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:7334
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:8293
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:6439
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:6444
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:6354
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:2135
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Definition: max_forwards.c:135
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Caller Party information.
Definition: channel.h:418
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:465
struct ast_party_dialed::@208 number
Dialed/Called number.
char * str
Subscriber phone number (Malloced)
Definition: channel.h:386
int transit_network_select
Transit Network Select.
Definition: channel.h:397
int cancel_answered_elsewhere
Definition: app_queue.c:1717

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, queue_ent::chan, do_hang(), ast_party_caller::id, ast_party_connected_line::id, queue_ent::linpos, call_queue::name, NULL, ast_party_id::number, ast_party_dialed::number, 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, ast_party_dialed::str, tmp(), 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 4905 of file app_queue.c.

4906{
4907 int ret = 0;
4908 struct callattempt *cur;
4909
4910 if (qe->predial_callee) {
4912 for (cur = outgoing; cur; cur = cur->q_next) {
4913 if (cur->stillgoing && cur->chan) {
4915 }
4916 }
4917 }
4918
4919 while (ret == 0) {
4920 struct callattempt *best = find_best(outgoing);
4921 if (!best) {
4922 ast_debug(1, "Nobody left to try ringing in queue\n");
4923 break;
4924 }
4926 /* Ring everyone who shares this best metric (for ringall) */
4927 for (cur = outgoing; cur; cur = cur->q_next) {
4928 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
4929 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
4930 ret |= ring_entry(qe, cur, busies);
4931 if (qe->predial_callee && cur->chan) {
4933 }
4934 }
4935 }
4936 } else {
4937 /* Ring just the best channel */
4938 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
4939 ret = ring_entry(qe, best, busies);
4940 if (qe->predial_callee && best->chan) {
4942 }
4943 }
4944
4945 /* If we have timed out, break out */
4946 if (qe->expire && (time(NULL) >= qe->expire)) {
4947 ast_debug(1, "Queue timed out while ringing members.\n");
4948 ret = 0;
4949 break;
4950 }
4951 }
4952 if (qe->predial_callee) {
4953 for (cur = outgoing; cur; cur = cur->q_next) {
4954 if (cur->stillgoing && cur->chan) {
4956 }
4957 }
4959 }
4960
4961 return ret;
4962}
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
Part 2 of ring_one.
Definition: app_queue.c:4748
static struct callattempt * find_best(struct callattempt *outgoing)
find the entry with the best metric, or NULL
Definition: app_queue.c:4880
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
char interface[256]
Definition: app_queue.c:1673

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

5106{
5107 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5108
5109 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
5110
5111 /* Stop ringing, and resume MOH if specified */
5112 if (qe->ring_when_ringing) {
5113 ast_indicate(qe->chan, -1);
5114 ast_moh_start(qe->chan, qe->moh, NULL);
5115 }
5116
5117 blob = ast_json_pack("{s: s, s: s, s: s, s: i}",
5118 "Queue", qe->parent->name,
5119 "Interface", interface,
5120 "MemberName", membername,
5121 "RingTime", rnatime);
5122 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_ringnoanswer_type(), blob);
5123
5124 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime);
5126 if (qe->parent->autopausedelay > 0) {
5127 struct member *mem;
5128 ao2_lock(qe->parent);
5129 if ((mem = interface_exists(qe->parent, interface))) {
5130 time_t idletime = time(&idletime)-mem->lastcall;
5131 if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
5132 ao2_unlock(qe->parent);
5133 ao2_ref(mem, -1);
5134 return;
5135 }
5136 ao2_ref(mem, -1);
5137 }
5138 ao2_unlock(qe->parent);
5139 }
5140 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
5141 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
5142 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
5143 interface, qe->parent->name);
5144 } else {
5145 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
5146 }
5147 } else {
5148 /* If queue autopause is mode all, just don't send any queue to stop.
5149 * the function will stop in all queues */
5150 if (!set_member_paused("", interface, "Auto-Pause", 1)) {
5151 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
5152 interface, qe->parent->name);
5153 } else {
5154 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
5155 }
5156 }
5157 }
5158 return;
5159}

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

8279{
8280 int res=-1;
8281 char *parse, *temppos = NULL;
8282 struct member *mem = NULL;
8283
8285 AST_APP_ARG(queuename);
8287 );
8288
8289
8290 if (ast_strlen_zero(data)) {
8291 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
8292 return -1;
8293 }
8294
8295 parse = ast_strdupa(data);
8296
8298
8299 if (ast_strlen_zero(args.interface)) {
8300 args.interface = ast_strdupa(ast_channel_name(chan));
8301 temppos = strrchr(args.interface, '-');
8302 if (temppos) {
8303 *temppos = '\0';
8304 }
8305 }
8306
8307 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
8308
8310 mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
8311 }
8312
8313 switch (remove_from_queue(args.queuename, args.interface)) {
8314 case RES_OKAY:
8315 if (!mem || ast_strlen_zero(mem->membername)) {
8316 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
8317 } else {
8318 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
8319 }
8320 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
8321 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
8322 res = 0;
8323 break;
8324 case RES_EXISTS:
8325 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
8326 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
8327 res = 0;
8328 break;
8329 case RES_NOSUCHQUEUE:
8330 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
8331 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
8332 res = 0;
8333 break;
8334 case RES_NOT_DYNAMIC:
8335 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
8336 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
8337 res = 0;
8338 break;
8339 }
8340
8341 if (mem) {
8342 ao2_ref(mem, -1);
8343 }
8344
8345 return res;
8346}

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

3574{
3575 struct member *m;
3576 struct ao2_iterator mem_iter;
3577 int penalty = 0;
3578 int paused = 0;
3579 int found = 0;
3580 int wrapuptime = 0;
3581 int ringinuse = q->ringinuse;
3582
3583 const char *config_val;
3584 const char *interface = ast_variable_retrieve(member_config, category, "interface");
3585 const char *rt_uniqueid = ast_variable_retrieve(member_config, category, "uniqueid");
3586 const char *membername = S_OR(ast_variable_retrieve(member_config, category, "membername"), interface);
3587 const char *state_interface = S_OR(ast_variable_retrieve(member_config, category, "state_interface"), interface);
3588 const char *penalty_str = ast_variable_retrieve(member_config, category, "penalty");
3589 const char *paused_str = ast_variable_retrieve(member_config, category, "paused");
3590 const char *wrapuptime_str = ast_variable_retrieve(member_config, category, "wrapuptime");
3591 const char *reason_paused = ast_variable_retrieve(member_config, category, "reason_paused");
3592
3593 if (ast_strlen_zero(rt_uniqueid)) {
3594 ast_log(LOG_WARNING, "Realtime field 'uniqueid' is empty for member %s\n",
3595 S_OR(membername, "NULL"));
3596 return;
3597 }
3598
3599 if (ast_strlen_zero(interface)) {
3600 ast_log(LOG_WARNING, "Realtime field 'interface' is empty for member %s\n",
3601 S_OR(membername, "NULL"));
3602 return;
3603 }
3604
3605 if (penalty_str) {
3606 penalty = atoi(penalty_str);
3607 if ((penalty < 0) && negative_penalty_invalid) {
3608 return;
3609 } else if (penalty < 0) {
3610 penalty = 0;
3611 }
3612 }
3613
3614 if (paused_str) {
3615 paused = atoi(paused_str);
3616 if (paused < 0) {
3617 paused = 0;
3618 }
3619 }
3620
3621 if (wrapuptime_str) {
3622 wrapuptime = atoi(wrapuptime_str);
3623 if (wrapuptime < 0) {
3624 wrapuptime = 0;
3625 }
3626 }
3627
3628 if ((config_val = ast_variable_retrieve(member_config, category, realtime_ringinuse_field))) {
3629 if (ast_true(config_val)) {
3630 ringinuse = 1;
3631 } else if (ast_false(config_val)) {
3632 ringinuse = 0;
3633 } else {
3634 ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name);
3635 }
3636 }
3637
3638 /* Find member by realtime uniqueid and update */
3639 mem_iter = ao2_iterator_init(q->members, 0);
3640 while ((m = ao2_iterator_next(&mem_iter))) {
3641 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
3642 m->dead = 0; /* Do not delete this one. */
3643 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3644 if (paused_str) {
3645 m->paused = paused;
3646 if (paused && m->lastpause == 0) {
3647 time(&m->lastpause); /* XXX: Should this come from realtime? */
3648 }
3650 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, m->interface);
3651 }
3652 if (strcasecmp(state_interface, m->state_interface)) {
3653 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
3654 }
3655 m->penalty = penalty;
3656 m->ringinuse = ringinuse;
3657 m->wrapuptime = wrapuptime;
3659 ast_copy_string(m->reason_paused, S_OR(reason_paused, ""), sizeof(m->reason_paused));
3660 }
3661 found = 1;
3662 ao2_ref(m, -1);
3663 break;
3664 }
3665 ao2_ref(m, -1);
3666 }
3667 ao2_iterator_destroy(&mem_iter);
3668
3669 /* Create a new member */
3670 if (!found) {
3671 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
3672 m->dead = 0;
3673 m->realtime = 1;
3674 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3675 if (!ast_strlen_zero(reason_paused)) {
3676 ast_copy_string(m->reason_paused, reason_paused, sizeof(m->reason_paused));
3677 }
3679 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3680 } else {
3681 ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3682 }
3683 member_add_to_queue(q, m);
3684 ao2_ref(m, -1);
3685 m = NULL;
3686 }
3687 }
3688}

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

5014{
5015 int res = 0;
5016 time_t now;
5017
5018 /* Get the current time */
5019 time(&now);
5020
5021 /* Check to see if it is time to announce */
5023 return 0;
5024 }
5025
5026 /* Stop the music on hold so we can play our own file */
5027 if (ringing) {
5028 ast_indicate(qe->chan,-1);
5029 } else {
5030 ast_moh_stop(qe->chan);
5031 }
5032
5033 ast_verb(3, "Playing periodic announcement\n");
5034
5036 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
5040 }
5041
5042 /* play the announcement */
5044
5045 if (res > 0 && !valid_exit(qe, res)) {
5046 res = 0;
5047 }
5048
5049 /* Resume Music on Hold if the caller is going to stay in the queue */
5050 if (!res) {
5051 if (ringing) {
5053 } else {
5054 ast_moh_start(qe->chan, qe->moh, NULL);
5055 }
5056 }
5057
5058 /* update last_periodic_announce_time */
5060 time(&qe->last_periodic_announce_time);
5061 } else {
5063 }
5064
5065 /* Update the current periodic announcement to the next announcement */
5066 if (!qe->parent->randomperiodicannounce) {
5068 }
5069
5070 return res;
5071}
static int play_file(struct ast_channel *chan, const char *filename)
Definition: app_queue.c:4138
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:4167

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

4203{
4204 int res = 0, say_thanks = 0;
4205 long avgholdmins, avgholdsecs;
4206 time_t now;
4207
4208 /* Let minannouncefrequency seconds pass between the start of each position announcement */
4209 time(&now);
4210 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) {
4211 return 0;
4212 }
4213
4214 /* If either our position has changed, or we are over the freq timer, say position */
4215 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) {
4216 return 0;
4217 }
4218
4219 /* Only announce if the caller's queue position has improved since last time */
4220 if (qe->parent->announceposition_only_up && qe->last_pos_said <= qe->pos) {
4221 return 0;
4222 }
4223
4224 if (ringing) {
4225 ast_indicate(qe->chan,-1);
4226 } else {
4227 ast_moh_stop(qe->chan);
4228 }
4229
4233 qe->pos <= qe->parent->announcepositionlimit)) {
4234 say_thanks = 1;
4235 /* Say we're next, if we are */
4236 if (qe->pos == 1) {
4237 res = play_file(qe->chan, qe->parent->sound_next);
4238 if (!res) {
4239 goto posout;
4240 }
4241 /* Say there are more than N callers */
4243 res = (
4244 play_file(qe->chan, qe->parent->queue_quantity1) ||
4246 ast_channel_language(qe->chan), NULL) || /* Needs gender */
4248 /* Say there are currently N callers waiting */
4249 } else {
4250 res = (
4251 play_file(qe->chan, qe->parent->sound_thereare) ||
4253 ast_channel_language(qe->chan), "n") || /* Needs gender */
4254 play_file(qe->chan, qe->parent->sound_calls));
4255 }
4256 if (res) {
4257 goto playout;
4258 }
4259 }
4260 /* Round hold time to nearest minute */
4261 avgholdmins = labs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
4262
4263 /* If they have specified a rounding then round the seconds as well */
4264 if (qe->parent->roundingseconds) {
4265 avgholdsecs = (labs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
4266 avgholdsecs *= qe->parent->roundingseconds;
4267 } else {
4268 avgholdsecs = 0;
4269 }
4270
4271 ast_verb(3, "Hold time for %s is %ld minute(s) %ld seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
4272
4273 /* If the hold time is >1 min, if it's enabled, and if it's not
4274 supposed to be only once and we have already said it, say it */
4275 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
4278 say_thanks = 1;
4279 res = play_file(qe->chan, qe->parent->sound_holdtime);
4280 if (res) {
4281 goto playout;
4282 }
4283
4284 if (avgholdmins >= 1) {
4285 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4286 if (res) {
4287 goto playout;
4288 }
4289
4290 if (avgholdmins == 1) {
4291 res = play_file(qe->chan, qe->parent->sound_minute);
4292 if (res) {
4293 goto playout;
4294 }
4295 } else {
4296 res = play_file(qe->chan, qe->parent->sound_minutes);
4297 if (res) {
4298 goto playout;
4299 }
4300 }
4301 }
4302 if (avgholdsecs >= 1) {
4303 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4304 if (res) {
4305 goto playout;
4306 }
4307
4308 res = play_file(qe->chan, qe->parent->sound_seconds);
4309 if (res) {
4310 goto playout;
4311 }
4312 }
4313 }
4314
4315posout:
4316 if (qe->parent->announceposition) {
4317 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
4318 ast_channel_name(qe->chan), qe->parent->name, qe->pos);
4319 }
4320 if (say_thanks) {
4321 res = play_file(qe->chan, qe->parent->sound_thanks);
4322 }
4323playout:
4324
4325 if ((res > 0 && !valid_exit(qe, res))) {
4326 res = 0;
4327 }
4328
4329 /* Set our last_pos indicators */
4330 qe->last_pos = now;
4331 qe->last_pos_said = qe->pos;
4332
4333 /* Don't restart music on hold if we're about to exit the caller from the queue */
4334 if (!res) {
4335 if (ringing) {
4337 } else {
4338 ast_moh_start(qe->chan, qe->moh, NULL);
4339 }
4340 }
4341 return res;
4342}
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:8235
const ast_string_field sound_thereare
Definition: app_queue.c:1829
const ast_string_field sound_holdtime
Definition: app_queue.c:1829
const ast_string_field sound_seconds
Definition: app_queue.c:1829
const ast_string_field sound_thanks
Definition: app_queue.c:1829
const ast_string_field queue_quantity2
Definition: app_queue.c:1829
const ast_string_field sound_calls
Definition: app_queue.c:1829
const ast_string_field sound_minute
Definition: app_queue.c:1829
const ast_string_field sound_minutes
Definition: app_queue.c:1829
const ast_string_field queue_quantity1
Definition: app_queue.c:1829
const ast_string_field sound_next
Definition: app_queue.c:1829

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

Referenced by queue_exec(), and wait_our_turn().

◆ send_agent_complete()

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

Send out AMI message with member call completion status information.

Definition at line 6124 of file app_queue.c.

6127{
6128 const char *reason = NULL; /* silence dumb compilers */
6129 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
6130
6131 switch (rsn) {
6132 case CALLER:
6133 reason = "caller";
6134 break;
6135 case AGENT:
6136 reason = "agent";
6137 break;
6138 case TRANSFER:
6139 reason = "transfer";
6140 break;
6141 }
6142
6143 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
6144 "Queue", queuename,
6145 "Interface", member->interface,
6146 "MemberName", member->membername,
6147 "HoldTime", (ast_json_int_t)(callstart - holdstart),
6148 "TalkTime", (ast_json_int_t)(time(NULL) - callstart),
6149 "Reason", reason ?: "");
6150
6152 queue_agent_complete_type(), blob);
6153}
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:3339
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 7847 of file app_queue.c.

7848{
7849 int found = 0;
7850 struct call_queue *q;
7851 struct ao2_iterator queue_iter;
7852
7853 if (ast_check_realtime("queues")) {
7854 load_realtime_queues(queuename);
7855 }
7856
7857 queue_iter = ao2_iterator_init(queues, 0);
7858 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
7859 ao2_lock(q);
7860 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
7861 struct member *mem;
7862
7863 if ((mem = interface_exists(q, interface))) {
7864 /*
7865 * Before we do the PAUSE/UNPAUSE, log if this was a
7866 * PAUSEALL/UNPAUSEALL but only on the first found entry.
7867 */
7868 ++found;
7869 if (found == 1
7870 && ast_strlen_zero(queuename)) {
7871 /*
7872 * XXX In all other cases, we use the queue name,
7873 * but since this affects all queues, we cannot.
7874 */
7875 ast_queue_log("NONE", "NONE", mem->membername,
7876 (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", S_OR(reason, ""));
7877 }
7878
7879 set_queue_member_pause(q, mem, reason, paused);
7880 ao2_ref(mem, -1);
7881 }
7882
7883 if (!ast_strlen_zero(queuename)) {
7884 ao2_unlock(q);
7885 queue_t_unref(q, "Done with iterator");
7886 break;
7887 }
7888 }
7889
7890 ao2_unlock(q);
7891 queue_t_unref(q, "Done with iterator");
7892 }
7893 ao2_iterator_destroy(&queue_iter);
7894
7895 return found ? RESULT_SUCCESS : RESULT_FAILURE;
7896}
static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
Definition: app_queue.c:7780

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

7908{
7909 struct member *mem;
7910 int foundinterface = 0;
7911
7912 ao2_lock(q);
7913 if ((mem = interface_exists(q, interface))) {
7914 foundinterface++;
7915 if (mem->realtime) {
7916 char rtpenalty[80];
7917
7918 sprintf(rtpenalty, "%i", penalty);
7919 update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
7920 }
7921
7922 mem->penalty = penalty;
7923
7924 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
7925 queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem));
7926 ao2_ref(mem, -1);
7927 }
7928 ao2_unlock(q);
7929
7930 return foundinterface;
7931}

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

7957{
7958 struct member *mem;
7959 int foundinterface = 0;
7960
7961 ao2_lock(q);
7962 if ((mem = interface_exists(q, interface))) {
7963 foundinterface++;
7965 ao2_ref(mem, -1);
7966 }
7967 ao2_unlock(q);
7968
7969 return foundinterface;
7970}
static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
Definition: app_queue.c:7943

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

7996{
7997 int foundinterface = 0, foundqueue = 0;
7998 struct call_queue *q;
7999 struct ast_config *queue_config = NULL;
8000 struct ao2_iterator queue_iter;
8001
8002 /* property dependent restrictions on values should be checked in this switch */
8003 switch (property) {
8004 case MEMBER_PENALTY:
8005 if (value < 0 && !negative_penalty_invalid) {
8006 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value);
8007 return RESULT_FAILURE;
8008 }
8009 }
8010
8011 if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */
8012 if (ast_check_realtime("queues")) {
8013 queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
8014 if (queue_config) {
8015 char *category = NULL;
8016 while ((category = ast_category_browse(queue_config, category))) {
8017 const char *name = ast_variable_retrieve(queue_config, category, "name");
8018 if (ast_strlen_zero(name)) {
8019 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
8020 continue;
8021 }
8022 if ((q = find_load_queue_rt_friendly(name))) {
8023 foundqueue++;
8024 foundinterface += set_member_value_help_members(q, interface, property, value);
8025 queue_unref(q);
8026 }
8027 }
8028
8029 ast_config_destroy(queue_config);
8030 }
8031 }
8032
8033 /* After hitting realtime queues, go back and get the regular ones. */
8034 queue_iter = ao2_iterator_init(queues, 0);
8035 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8036 foundqueue++;
8037 foundinterface += set_member_value_help_members(q, interface, property, value);
8038 queue_unref(q);
8039 }
8040 ao2_iterator_destroy(&queue_iter);
8041 } else { /* We actually have a queuename, so we can just act on the single queue. */
8042 if ((q = find_load_queue_rt_friendly(queuename))) {
8043 foundqueue++;
8044 foundinterface += set_member_value_help_members(q, interface, property, value);
8045 queue_unref(q);
8046 }
8047 }
8048
8049 if (foundinterface) {
8050 return RESULT_SUCCESS;
8051 } else if (!foundqueue) {
8052 ast_log (LOG_ERROR, "Invalid queuename\n");
8053 } else {
8054 ast_log (LOG_ERROR, "Invalid interface\n");
8055 }
8056
8057 return RESULT_FAILURE;
8058}
static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
Definition: app_queue.c:7972

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

7973{
7974 switch(property) {
7975 case MEMBER_PENALTY:
7976 return set_member_penalty_help_members(q, interface, value);
7977
7978 case MEMBER_RINGINUSE:
7979 return set_member_ringinuse_help_members(q, interface, value);
7980
7981 default:
7982 ast_log(LOG_ERROR, "Attempted to set invalid property\n");
7983 return 0;
7984 }
7985}
static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
Definition: app_queue.c:7956
static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
Definition: app_queue.c:7907

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

7781{
7782 if (mem->paused == paused) {
7783 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
7784 (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
7785 }
7786
7787 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid)) {
7789 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "reason_paused", S_OR(reason, ""), "paused", paused ? "1" : "0", SENTINEL) < 0) {
7790 ast_log(LOG_WARNING, "Failed update of realtime queue member %s:%s %spause and reason '%s'\n",
7791 q->name, mem->interface, (paused ? "" : "un"), S_OR(reason, ""));
7792 }
7793 } else {
7794 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "paused", paused ? "1" : "0", SENTINEL) < 0) {
7795 ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
7796 (paused ? "" : "un"), q->name, mem->interface);
7797 }
7798 }
7799 }
7800
7801 mem->paused = paused;
7802 if (paused) {
7803 time(&mem->lastpause); /* update last pause field */
7804 }
7805 if (paused && !ast_strlen_zero(reason)) {
7806 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7807 } else {
7808 /* We end up filling this in again later (temporarily) but we need it
7809 * empty for now so that the intervening code - specifically
7810 * dump_queue_members() - has the correct view of things. */
7811 mem->reason_paused[0] = '\0';
7812 }
7813
7815 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
7816
7819 }
7820
7821 if (is_member_available(q, mem)) {
7823 "Queue:%s_avail", q->name);
7824 } else if (!num_available_members(q)) {
7826 "Queue:%s_avail", q->name);
7827 }
7828
7829 if (!paused && !ast_strlen_zero(reason)) {
7830 /* Because we've been unpaused with a 'reason' we need to ensure that
7831 * that reason is emitted when the subsequent PauseQueueMember event
7832 * is raised. So temporarily set it on the member and clear it out
7833 * again right after. */
7834 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7835 }
7836
7837 ast_queue_log(q->name, "NONE", mem->membername, paused ? "PAUSE" : "UNPAUSE",
7838 "%s", mem->reason_paused);
7839
7841
7842 if (!paused) {
7843 mem->reason_paused[0] = '\0';
7844 }
7845}
static int publish_queue_member_pause(struct call_queue *q, struct member *member)
Definition: app_queue.c:7756
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3659

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

Referenced by set_member_paused().

◆ set_queue_member_ringinuse()

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

Definition at line 7943 of file app_queue.c.

7944{
7945 if (mem->realtime) {
7947 ringinuse ? "1" : "0");
7948 }
7949
7950 mem->ringinuse = ringinuse;
7951
7952 ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
7953 queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
7954}

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

1909{
1910 int i;
1911
1912 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
1913 if (queue_results[i].id == res) {
1914 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
1915 return;
1916 }
1917 }
1918}
static const struct @50 queue_results[]
char * text
Definition: app_queue.c:1639

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

2062{
2063 char interfacevar[256]="";
2064 float sl = 0;
2065
2066 ao2_lock(q);
2067
2068 if (q->setqueuevar) {
2069 sl = 0;
2070 if (q->callscompleted > 0) {
2071 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
2072 }
2073
2074 snprintf(interfacevar, sizeof(interfacevar),
2075 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
2077
2078 ao2_unlock(q);
2079
2080 pbx_builtin_setvar_multiple(chan, interfacevar);
2081 } else {
2082 ao2_unlock(q);
2083 }
2084}

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

6901{
6902 char escaped_filename[256];
6903 char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
6904 char mixmonargs[1512];
6905 char escaped_monitor_exec[1024];
6906 const char *monitor_options;
6907 const char *monitor_exec;
6908
6909 escaped_monitor_exec[0] = '\0';
6910
6911 if (filename) {
6912 escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
6913 } else {
6914 ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
6915 }
6916
6918 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
6919 monitor_exec = ast_strdupa(monitor_exec);
6920 }
6921 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
6922 monitor_options = ast_strdupa(monitor_options);
6923 } else {
6924 monitor_options = "";
6925 }
6927
6928 if (monitor_exec) {
6929 escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
6930 }
6931
6932 snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
6933
6934 if (!ast_strlen_zero(escaped_monitor_exec)) {
6935 snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
6936 } else {
6937 snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
6938 }
6939
6940 ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
6941
6942 if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
6943 ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
6944 }
6945}
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition: app_queue.c:6869
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 6852 of file app_queue.c.

6853{
6854 const char *context;
6855 const char *extension;
6856 int priority;
6857
6858 if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
6859 ast_channel_lock(chan);
6863 ast_channel_unlock(chan);
6865 opt_args[OPT_ARG_CALLEE_GO_ON]);
6866 }
6867}
void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
Set channel to go on in the dialplan after the bridge.
Definition: bridge_after.c:622
int ast_channel_priority(const struct ast_channel *chan)
structure to hold extensions

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

Referenced by try_calling().

◆ setup_stasis_subs()

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

Definition at line 6768 of file app_queue.c.

6770{
6771 struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6772
6773 if (!queue_data) {
6774 return -1;
6775 }
6776
6778 if (!queue_data->bridge_router) {
6779 ao2_ref(queue_data, -1);
6780 return -1;
6781 }
6782
6784 handle_bridge_enter, queue_data);
6786 handle_blind_transfer, queue_data);
6788 handle_attended_transfer, queue_data);
6790 queue_bridge_cb, queue_data);
6791
6793 if (!queue_data->channel_router) {
6794 /* Unsubscribing from the bridge router will remove the only ref of queue_data,
6795 * thus beginning the destruction process
6796 */
6798 queue_data->bridge_router = NULL;
6799 return -1;
6800 }
6801
6802 ao2_ref(queue_data, +1);
6806 handle_local_optimization_end, queue_data);
6808 handle_hangup, queue_data);
6810 handle_masquerade, queue_data);
6812 queue_channel_cb, queue_data);
6813
6814 return 0;
6815}
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6371
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6518
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition: app_queue.c:6463
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6709
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6537
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6588
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:6286
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6743
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6652
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition: app_queue.c:6404
struct stasis_message_type * ast_local_optimization_end_type(void)
Message type for when a local channel optimization completes.
struct stasis_message_type * ast_local_optimization_begin_type(void)
Message type for when a local channel optimization begins.
struct stasis_message_type * ast_channel_masquerade_type(void)
Message type for when a channel is being masqueraded.
struct stasis_message_type * ast_channel_hangup_request_type(void)
Message type for when a hangup is requested on a channel.
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for ast_channel enter bridge blob messages.
struct stasis_message_type * ast_blind_transfer_type(void)
Message type for ast_blind_transfer_message.
struct stasis_message_type * ast_attended_transfer_type(void)
Message type for ast_attended_transfer_message.
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
#define stasis_message_router_create_pool(topic)
Create a new message router object.
int stasis_message_router_set_default(struct stasis_message_router *router, stasis_subscription_cb callback, void *data)
Sets the default route of a router.

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

Referenced by try_calling().

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [1/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_called_type  ,
to_ami = queue_agent_called_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [2/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_complete_type  ,
to_ami = queue_agent_complete_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [3/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_connect_type  ,
to_ami = queue_agent_connect_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [4/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_dump_type  ,
to_ami = queue_agent_dump_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [5/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_ringnoanswer_type  ,
to_ami = queue_agent_ringnoanswer_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [6/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_abandon_type  ,
to_ami = queue_caller_abandon_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [7/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_join_type  ,
to_ami = queue_caller_join_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [8/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_leave_type  ,
to_ami = queue_caller_leave_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [9/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_added_type  ,
to_ami = queue_member_added_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [10/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_pause_type  ,
to_ami = queue_member_pause_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [11/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_penalty_type  ,
to_ami = queue_member_penalty_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [12/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_removed_type  ,
to_ami = queue_member_removed_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [13/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_ringinuse_type  ,
to_ami = queue_member_ringinuse_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [14/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_status_type  ,
to_ami = queue_member_status_to_ami 
)

◆ store_next_lin()

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

Search for best metric and add to Linear queue.

Definition at line 4989 of file app_queue.c.

4990{
4991 struct callattempt *best = find_best(outgoing);
4992
4993 if (best) {
4994 /* Ring just the best channel */
4995 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
4996 qe->linpos = best->metric % 1000;
4997 } else {
4998 /* Just increment rrpos */
4999 if (qe->linwrapped) {
5000 /* No more channels, start over */
5001 qe->linpos = 0;
5002 } else {
5003 /* Prioritize next entry */
5004 qe->linpos++;
5005 }
5006 }
5007 qe->linwrapped = 0;
5008
5009 return 0;
5010}

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

4966{
4967 struct callattempt *best = find_best(outgoing);
4968
4969 if (best) {
4970 /* Ring just the best channel */
4971 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
4972 qe->parent->rrpos = best->metric % 1000;
4973 } else {
4974 /* Just increment rrpos */
4975 if (qe->parent->wrapped) {
4976 /* No more channels, start over */
4977 qe->parent->rrpos = 0;
4978 } else {
4979 /* Prioritize next entry */
4980 qe->parent->rrpos++;
4981 }
4982 }
4983 qe->parent->wrapped = 0;
4984
4985 return 0;
4986}

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

1934{
1935 int x;
1936
1937 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1938 if (!strcasecmp(strategy, strategies[x].name)) {
1939 return strategies[x].strategy;
1940 }
1941 }
1942
1943 return -1;
1944}
int strategy
Definition: app_queue.c:1530

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

6974{
6975 struct member *cur;
6976 struct callattempt *outgoing = NULL; /* the list of calls we are building */
6977 int to, orig;
6978 char oldexten[AST_MAX_EXTENSION]="";
6979 char oldcontext[AST_MAX_CONTEXT]="";
6980 char queuename[256]="";
6981 struct ast_channel *peer;
6982 struct callattempt *lpeer;
6983 struct member *member;
6984 struct ast_app *application;
6985 int res = 0, bridge = 0;
6986 int numbusies = 0;
6987 int x=0;
6988 char *announce = NULL;
6989 char digit = 0;
6990 time_t now = time(NULL);
6991 struct ast_bridge_config bridge_config;
6992 char nondataquality = 1;
6993 char *agiexec = NULL;
6994 char *gosubexec = NULL;
6995 const char *monitorfilename;
6996 int forwardsallowed = 1;
6997 int block_connected_line = 0;
6998 struct ao2_iterator memi;
7000 int callcompletedinsl;
7001 time_t starttime;
7002
7003 memset(&bridge_config, 0, sizeof(bridge_config));
7004 time(&now);
7005
7006 /* If we've already exceeded our timeout, then just stop
7007 * This should be extremely rare. queue_exec will take care
7008 * of removing the caller and reporting the timeout as the reason.
7009 */
7010 if (qe->expire && now >= qe->expire) {
7011 res = 0;
7012 goto out;
7013 }
7014
7015 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) {
7016 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
7017 }
7018 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) {
7019 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
7020 }
7021 if (ast_test_flag(&opts, OPT_CALLEE_AUTOMON)) {
7022 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
7023 }
7024 if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
7025 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
7026 }
7027 if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
7028 nondataquality = 0;
7029 }
7030 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) {
7031 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
7032 }
7033 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) {
7034 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
7035 }
7036 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) {
7037 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
7038 }
7039 if (ast_test_flag(&opts, OPT_CALLER_PARK)) {
7040 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
7041 }
7042 if (ast_test_flag(&opts, OPT_NO_RETRY)) {
7045 (*tries)++;
7046 } else {
7047 *tries = ao2_container_count(qe->parent->members);
7048 }
7049 *noption = 1;
7050 }
7051 if (ast_test_flag(&opts, OPT_IGNORE_CALL_FW)) {
7052 forwardsallowed = 0;
7053 }
7055 block_connected_line = 1;
7056 }
7058 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
7059 }
7061 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
7062 }
7063 if (ast_test_flag(&opts, OPT_MARK_AS_ANSWERED)) {
7065 }
7066
7067 /* if the calling channel has AST_CAUSE_ANSWERED_ELSEWHERE set, make sure this is inherited.
7068 (this is mainly to support unreal/local channels)
7069 */
7072 }
7073
7074 ao2_lock(qe->parent);
7075 ast_debug(1, "%s is trying to call a queue member.\n",
7076 ast_channel_name(qe->chan));
7077 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
7078 if (!ast_strlen_zero(qe->announce)) {
7079 announce = qe->announce;
7080 }
7081 if (!ast_strlen_zero(announceoverride)) {
7082 announce = announceoverride;
7083 }
7084
7085 memi = ao2_iterator_init(qe->parent->members, 0);
7086 while ((cur = ao2_iterator_next(&memi))) {
7087 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
7088 if (!tmp) {
7089 ao2_ref(cur, -1);
7090 ao2_iterator_destroy(&memi);
7091 ao2_unlock(qe->parent);
7092 goto out;
7093 }
7094
7095 /*
7096 * Seed the callattempt's connected line information with previously
7097 * acquired connected line info from the queued channel. The
7098 * previously acquired connected line info could have been set
7099 * through the CONNECTED_LINE dialplan function.
7100 */
7104
7105 tmp->block_connected_update = block_connected_line;
7106 tmp->stillgoing = 1;
7107 tmp->member = cur; /* Place the reference for cur into callattempt. */
7108 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
7109 /* Calculate the metric for the appropriate strategy. */
7110 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
7111 /* Put them in the list of outgoing thingies... We're ready now.
7112 XXX If we're forcibly removed, these outgoing calls won't get
7113 hung up XXX */
7114 tmp->q_next = outgoing;
7115 outgoing = tmp;
7116 } else {
7118 }
7119 }
7120 ao2_iterator_destroy(&memi);
7121
7123 /* Application arguments have higher timeout priority (behaviour for <=1.6) */
7124 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) {
7125 to = (qe->expire - now) * 1000;
7126 } else {
7127 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
7128 }
7129 } else {
7130 /* Config timeout is higher priority thatn application timeout */
7131 if (qe->expire && qe->expire<=now) {
7132 to = 0;
7133 } else if (qe->parent->timeout) {
7134 to = qe->parent->timeout * 1000;
7135 } else {
7136 to = -1;
7137 }
7138 }
7139 orig = to;
7140 ++qe->pending;
7141 ao2_unlock(qe->parent);
7142 /* Call the queue members with the best metric now. */
7143 ring_one(qe, outgoing, &numbusies);
7144 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
7145 ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT),
7146 forwardsallowed);
7147
7148 ao2_lock(qe->parent);
7151
7152 }
7155 }
7156 ao2_unlock(qe->parent);
7157 peer = lpeer ? lpeer->chan : NULL;
7158 if (!peer) {
7159 qe->pending = 0;
7160 if (to) {
7161 /* Must gotten hung up */
7162 res = -1;
7163 } else {
7164 /* User exited by pressing a digit */
7165 res = digit;
7166 }
7167 if (res == -1) {
7168 ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
7169 }
7170 } else { /* peer is valid */
7171 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
7172 RAII_VAR(struct ast_str *, interfacevar, ast_str_create(325), ast_free);
7173 /* Ah ha! Someone answered within the desired timeframe. Of course after this
7174 we will always return with -1 so that it is hung up properly after the
7175 conversation. */
7176 if (!strcmp(ast_channel_tech(qe->chan)->type, "DAHDI")) {
7177 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
7178 }
7179 if (!strcmp(ast_channel_tech(peer)->type, "DAHDI")) {
7180 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
7181 }
7182 /* Update parameters for the queue */
7183 time(&now);
7184 recalc_holdtime(qe, (now - qe->start));
7185 member = lpeer->member;
7186 ao2_lock(qe->parent);
7187 callcompletedinsl = member->callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
7188 ao2_unlock(qe->parent);
7189 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
7190 ao2_ref(member, 1);
7192 outgoing = NULL;
7193 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
7194 int res2;
7195
7196 res2 = ast_autoservice_start(qe->chan);
7197 if (!res2) {
7198 if (qe->parent->memberdelay) {
7199 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
7200 res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
7201 }
7202 if (!res2 && announce) {
7203 char *front;
7204 char *announcefiles = ast_strdupa(announce);
7205 while ((front = ast_strsep(&announcefiles, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
7206 if (play_file(peer, front) < 0) {
7207 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", front, ast_channel_name(peer));
7208 }
7209 }
7210 }
7211 if (!res2 && qe->parent->reportholdtime) {
7212 if (!play_file(peer, qe->parent->sound_reporthold)) {
7213 long holdtime, holdtimesecs;
7214
7215 time(&now);
7216 holdtime = labs((now - qe->start) / 60);
7217 holdtimesecs = labs((now - qe->start) % 60);
7218 if (holdtime > 0) {
7219 ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), "n");
7220 if (play_file(peer, qe->parent->sound_minutes) < 0) {
7221 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, ast_channel_name(peer));
7222 }
7223 }
7224 if (holdtimesecs > 1) {
7225 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), "n");
7226 if (play_file(peer, qe->parent->sound_seconds) < 0) {
7227 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, ast_channel_name(peer));
7228 }
7229 }
7230 }
7231 }
7233 }
7234 if (ast_check_hangup(peer)) {
7235 /* Agent must have hung up */
7236 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer));
7237 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", "");
7238
7239 blob = ast_json_pack("{s: s, s: s, s: s}",
7240 "Queue", queuename,
7241 "Interface", member->interface,
7242 "MemberName", member->membername);
7243 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_dump_type(), blob);
7244
7248 ao2_ref(member, -1);
7249 goto out;
7250 } else if (ast_check_hangup(qe->chan)) {
7251 /* Caller must have hung up just before being connected */
7252 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer));
7253 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
7254 record_abandoned(qe);
7255 qe->handled = -1;
7259 ao2_ref(member, -1);
7260 return -1;
7261 }
7262 }
7263 /* Stop music on hold */
7264 if (ringing) {
7265 ast_indicate(qe->chan,-1);
7266 } else {
7267 ast_moh_stop(qe->chan);
7268 }
7269
7270 /* Make sure channels are compatible */
7271 res = ast_channel_make_compatible(qe->chan, peer);
7272 if (res < 0) {
7273 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", "");
7274 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));
7275 record_abandoned(qe);
7279 ao2_ref(member, -1);
7280 return -1;
7281 }
7282
7283 /* Play announcement to the caller telling it's his turn if defined */
7285 if (play_file(qe->chan, qe->parent->sound_callerannounce)) {
7286 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
7287 }
7288 }
7289
7290 ao2_lock(qe->parent);
7291 /* if setinterfacevar is defined, make member variables available to the channel */
7292 /* use pbx_builtin_setvar to set a load of variables with one call */
7293 if (qe->parent->setinterfacevar && interfacevar) {
7294 ast_str_set(&interfacevar, 0, "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
7297 pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7298 }
7299
7300 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
7301 /* use pbx_builtin_setvar to set a load of variables with one call */
7302 if (qe->parent->setqueueentryvar && interfacevar) {
7303 ast_str_set(&interfacevar, 0, "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
7304 (long) (time(NULL) - qe->start), qe->opos);
7306 pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7307 }
7308
7309 ao2_unlock(qe->parent);
7310
7311 /* try to set queue variables if configured to do so*/
7313 set_queue_variables(qe->parent, peer);
7314
7315 setup_peer_after_bridge_goto(qe->chan, peer, &opts, opt_args);
7317 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
7318 monitorfilename = ast_strdupa(monitorfilename);
7319 }
7321
7322 /* Begin Monitoring */
7323 if (*qe->parent->monfmt) {
7324 setup_mixmonitor(qe, monitorfilename);
7325 }
7326 /* Drop out of the queue at this point, to prepare for next caller */
7327 leave_queue(qe);
7329 ast_debug(1, "app_queue: sendurl=%s.\n", url);
7330 ast_channel_sendurl(peer, url);
7331 }
7332
7333 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
7334 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
7335 if (!ast_strlen_zero(gosub)) {
7336 gosubexec = ast_strdupa(gosub);
7337 } else {
7338 if (qe->parent->membergosub) {
7339 gosubexec = ast_strdupa(qe->parent->membergosub);
7340 }
7341 }
7342
7343 if (!ast_strlen_zero(gosubexec)) {
7344 char *gosub_args = NULL;
7345 char *gosub_argstart;
7346
7347 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
7348
7349 gosub_argstart = strchr(gosubexec, ',');
7350 if (gosub_argstart) {
7351 const char *what_is_s = "s";
7352 *gosub_argstart = 0;
7353 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)) &&
7354 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7355 what_is_s = "~~s~~";
7356 }
7357 if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
7358 gosub_args = NULL;
7359 }
7360 *gosub_argstart = ',';
7361 } else {
7362 const char *what_is_s = "s";
7363 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)) &&
7364 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7365 what_is_s = "~~s~~";
7366 }
7367 if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
7368 gosub_args = NULL;
7369 }
7370 }
7371 if (gosub_args) {
7372 ast_app_exec_sub(qe->chan, peer, gosub_args, 0);
7373 ast_free(gosub_args);
7374 } else {
7375 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
7376 }
7377 }
7378
7379 if (!ast_strlen_zero(agi)) {
7380 ast_debug(1, "app_queue: agi=%s.\n", agi);
7381 application = pbx_findapp("agi");
7382 if (application) {
7383 agiexec = ast_strdupa(agi);
7384 pbx_exec(qe->chan, application, agiexec);
7385 } else {
7386 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
7387 }
7388 }
7389 qe->handled++;
7390
7391 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
7392 (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
7393
7394 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I}",
7395 "Queue", queuename,
7396 "Interface", member->interface,
7397 "MemberName", member->membername,
7398 "HoldTime", (ast_json_int_t)(time(NULL) - qe->start),
7399 "RingTime", (ast_json_int_t)(orig - to > 0 ? (orig - to) / 1000 : 0));
7400 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_connect_type(), blob);
7401
7402 ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
7403 ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten));
7404
7405 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
7406 queue_end_bridge->q = qe->parent;
7407 queue_end_bridge->chan = qe->chan;
7408 bridge_config.end_bridge_callback = end_bridge_callback;
7409 bridge_config.end_bridge_callback_data = queue_end_bridge;
7410 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
7411 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
7412 * to make sure to increase the refcount of this queue so it cannot be freed until we
7413 * are done with it. We remove this reference in end_bridge_callback.
7414 */
7415 queue_t_ref(qe->parent, "For bridge_config reference");
7416 }
7417
7418 ao2_lock(qe->parent);
7419 time(&member->starttime);
7420 starttime = member->starttime;
7421 ao2_unlock(qe->parent);
7422 /* As a queue member may end up in multiple calls at once if a transfer occurs with
7423 * a Local channel in the mix we pass the current call information (starttime) to the
7424 * Stasis subscriptions so when they update the queue member data it becomes a noop
7425 * if this call is no longer between the caller and the queue member.
7426 */
7427 setup_stasis_subs(qe, peer, member, qe->start, starttime, callcompletedinsl);
7428 bridge = ast_bridge_call_with_flags(qe->chan, peer, &bridge_config,
7430
7431 res = bridge ? bridge : 1;
7432 ao2_ref(member, -1);
7433 }
7434out:
7436
7437 return res;
7438}
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:6768
static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
Definition: app_queue.c:6900
static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
Definition: app_queue.c:4344
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:4464
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:6039
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:4989
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:5200
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:4965
static void end_bridge_callback(void *data)
Definition: app_queue.c:6829
static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
Definition: app_queue.c:6822
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:6852
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
Place a call to a queue member.
Definition: app_queue.c:4905
#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:6720
@ AST_FEATURE_AUTOMIXMON
Definition: channel.h:1069
@ AST_FEATURE_REDIRECT
Definition: channel.h:1064
@ AST_FEATURE_PARKCALL
Definition: channel.h:1068
@ AST_FEATURE_AUTOMON
Definition: channel.h:1067
@ AST_FEATURE_DISCONNECT
Definition: channel.h:1065
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:2031
int ast_channel_supports_html(struct ast_channel *channel)
Checks for HTML support on a channel.
Definition: channel.c:6623
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:6635
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7422
void ast_autoservice_chan_hangup_peer(struct ast_channel *chan, struct ast_channel *peer)
Put chan into autoservice while hanging up peer.
Definition: autoservice.c:342
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1574
#define AST_MAX_EXTENSION
Definition: channel.h:134
const char * ast_hangup_cause_to_dial_status(int hangup_cause)
Convert a hangup cause to a publishable dial status.
Definition: dial.c:749
int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags)
Bridge a call, and add additional flags to the bridge.
Definition: features.c:595
#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:4175
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
@ AST_STRSEP_TRIM
Definition: strings.h:256
@ AST_STRSEP_STRIP
Definition: strings.h:255
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition: utils.c:1835
ast_app: A registered application
Definition: pbx_app.c:45
bridge configuration
Definition: channel.h:1076
const char *const type
Definition: channel.h:629
const ast_string_field sound_callerannounce
Definition: app_queue.c:1829
const ast_string_field sound_reporthold
Definition: app_queue.c:1829
const ast_string_field membergosub
Definition: app_queue.c:1829

References queue_ent::announce, ao2_alloc, ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_app_exec_sub(), ast_asprintf, ast_autoservice_chan_hangup_peer(), ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call_with_flags(), AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO, AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM, ast_calloc, AST_CAUSE_ANSWERED_ELSEWHERE, ast_channel_caller(), ast_channel_connected(), ast_channel_context(), ast_channel_exten(), ast_channel_hangupcause(), ast_channel_language(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_name(), ast_channel_publish_dial(), ast_channel_sendurl(), ast_channel_setoption(), ast_channel_supports_html(), ast_channel_tech(), ast_channel_uniqueid(), ast_channel_unlock, ast_check_hangup(), ast_copy_string(), ast_debug, AST_DIGIT_ANY, ast_exists_extension(), AST_FEATURE_AUTOMIXMON, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_free, ast_hangup_cause_to_dial_status(), ast_indicate(), ast_json_pack(), ast_json_unref(), ast_log, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_moh_stop(), AST_OPTION_TONE_VERIFY, ast_party_connected_line_copy(), ast_queue_log(), ast_safe_sleep(), ast_say_number(), ast_set_flag, ast_str_buffer(), ast_str_create, ast_str_set(), ast_strdupa, ast_strlen_zero(), ast_strsep(), AST_STRSEP_STRIP, AST_STRSEP_TRIM, ast_test_flag, calc_metric(), callattempt_free(), member::callcompletedinsl, member::calls, queue_ent::cancel_answered_elsewhere, callattempt::chan, queue_ent::chan, queue_end_bridge::chan, 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(), 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, 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, store_next_lin(), store_next_rr(), call_queue::strategy, call_queue::timeout, TIMEOUT_PRIORITY_APP, call_queue::timeoutpriority, tmp(), 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 11676 of file app_queue.c.

11677{
11680
11682
11683 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
11684 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
11685 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
11686
11687 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
11688 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
11689 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
11690 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
11691 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
11692 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
11693
11694 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
11695 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
11696 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
11697 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
11698 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
11699
11701 ast_manager_unregister("QueueStatus");
11702 ast_manager_unregister("QueueRule");
11703 ast_manager_unregister("QueueSummary");
11704 ast_manager_unregister("QueueAdd");
11705 ast_manager_unregister("QueueRemove");
11706 ast_manager_unregister("QueuePause");
11707 ast_manager_unregister("QueueLog");
11708 ast_manager_unregister("QueueUpdate");
11709 ast_manager_unregister("QueuePenalty");
11710 ast_manager_unregister("QueueReload");
11711 ast_manager_unregister("QueueReset");
11712 ast_manager_unregister("QueueMemberRingInUse");
11713 ast_manager_unregister("QueueChangePriorityCaller");
11714 ast_manager_unregister("QueueWithdrawCaller");
11730
11732
11733 ast_unload_realtime("queue_members");
11736
11737 queues = NULL;
11738 return 0;
11739}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8041
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:1548
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1134
void stasis_message_router_unsubscribe_and_join(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic, blocking until the final message has been processed.

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

Referenced by load_module().

◆ update_connected_line_from_peer()

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

Definition at line 5170 of file app_queue.c.

5171{
5172 struct ast_party_connected_line connected_caller;
5173
5174 ast_party_connected_line_init(&connected_caller);
5175
5176 ast_channel_lock(peer);
5178 ast_channel_unlock(peer);
5179 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
5180 if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
5181 ast_channel_update_connected_line(chan, &connected_caller, NULL);
5182 }
5183 ast_party_connected_line_free(&connected_caller);
5184}
@ 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:10338
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:9093
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:2022
Connected Line/Party information.
Definition: channel.h:456

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

5790{
5791 int max_penalty = INT_MAX;
5792
5793 if (qe->max_penalty != INT_MAX) {
5794 char max_penalty_str[20];
5795
5796 if (qe->pr->max_relative) {
5797 max_penalty = qe->max_penalty + qe->pr->max_value;
5798 } else {
5799 max_penalty = qe->pr->max_value;
5800 }
5801
5802 /* a relative change to the penalty could put it below 0 */
5803 if (max_penalty < 0) {
5804 max_penalty = 0;
5805 }
5806
5807 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
5808 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
5809 qe->max_penalty = max_penalty;
5810 ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n",
5811 qe->max_penalty, ast_channel_name(qe->chan), qe->pr->time);
5812 }
5813
5814 if (qe->min_penalty != INT_MAX) {
5815 char min_penalty_str[20];
5816 int min_penalty;
5817
5818 if (qe->pr->min_relative) {
5819 min_penalty = qe->min_penalty + qe->pr->min_value;
5820 } else {
5821 min_penalty = qe->pr->min_value;
5822 }
5823
5824 /* a relative change to the penalty could put it below 0 */
5825 if (min_penalty < 0) {
5826 min_penalty = 0;
5827 }
5828
5829 if (max_penalty != INT_MAX && min_penalty > max_penalty) {
5830 min_penalty = max_penalty;
5831 }
5832
5833 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
5834 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
5835 qe->min_penalty = min_penalty;
5836 ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n",
5837 qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time);
5838 }
5839
5840 if (qe->raise_penalty != INT_MAX) {
5841 char raise_penalty_str[20];
5842 int raise_penalty;
5843
5844 if (qe->pr->raise_relative) {
5845 raise_penalty = qe->raise_penalty + qe->pr->raise_value;
5846 } else {
5847 raise_penalty = qe->pr->raise_value;
5848 }
5849
5850 /* a relative change to the penalty could put it below 0 */
5851 if (raise_penalty < 0) {
5852 raise_penalty = 0;
5853 }
5854
5855 if (max_penalty != INT_MAX && raise_penalty > max_penalty) {
5856 raise_penalty = max_penalty;
5857 }
5858
5859 snprintf(raise_penalty_str, sizeof(raise_penalty_str), "%d", raise_penalty);
5860 pbx_builtin_setvar_helper(qe->chan, "QUEUE_RAISE_PENALTY", raise_penalty_str);
5861 qe->raise_penalty = raise_penalty;
5862 ast_debug(3, "Setting raised penalty to %d for caller %s since %d seconds have elapsed\n",
5863 qe->raise_penalty, ast_channel_name(qe->chan), qe->pr->time);
5864 }
5865
5866 qe->pr = AST_LIST_NEXT(qe->pr, list);
5867}
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439

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

Referenced by queue_exec(), and wait_our_turn().

◆ update_queue()

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

update the queue status

Return values
0always

Definition at line 5967 of file app_queue.c.

5968{
5969 int oldtalktime;
5970 int newtalktime = time(NULL) - starttime;
5971 struct member *mem;
5972 struct call_queue *qtmp;
5973 struct ao2_iterator queue_iter;
5974
5975 /* It is possible for us to be called when a call has already been considered terminated
5976 * and data updated, so to ensure we only act on the call that the agent is currently in
5977 * we check when the call was bridged.
5978 */
5979 if (!starttime || (member->starttime != starttime)) {
5980 return 0;
5981 }
5982
5983 if (shared_lastcall) {
5984 queue_iter = ao2_iterator_init(queues, 0);
5985 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
5986 ao2_lock(qtmp);
5987 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
5988 time(&mem->lastcall);
5989 mem->calls++;
5990 mem->callcompletedinsl = 0;
5991 mem->starttime = 0;
5992 mem->lastqueue = q;
5993 ao2_ref(mem, -1);
5994 }
5995 ao2_unlock(qtmp);
5996 queue_t_unref(qtmp, "Done with iterator");
5997 }
5998 ao2_iterator_destroy(&queue_iter);
5999 } else {
6000 ao2_lock(q);
6001 time(&member->lastcall);
6003 member->calls++;
6004 member->starttime = 0;
6005 member->lastqueue = q;
6006 ao2_unlock(q);
6007 }
6008 /* Member might never experience any direct status change (local
6009 * channel with forwarding in particular). If that's the case,
6010 * this is the last chance to remove it from pending or subsequent
6011 * calls will not occur.
6012 */
6014
6015 ao2_lock(q);
6016 q->callscompleted++;
6017 if (callcompletedinsl) {
6018 q->callscompletedinsl++;
6019 }
6020 if (q->callscompleted == 1) {
6021 q->talktime = newtalktime;
6022 } else {
6023 /* Calculate talktime using the same exponential average as holdtime code */
6024 oldtalktime = q->talktime;
6025 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
6026 }
6027 ao2_unlock(q);
6028 return 0;
6029}

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

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

◆ update_realtime_member_field()

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

Definition at line 3979 of file app_queue.c.

3980{
3981 int ret = -1;
3982
3983 if (ast_strlen_zero(mem->rt_uniqueid)) {
3984 return ret;
3985 }
3986
3987 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) >= 0) {
3988 ret = 0;
3989 }
3990
3991 return ret;
3992}

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

3996{
3997 struct ast_config *member_config = NULL;
3998 struct member *m;
3999 char *category = NULL;
4000 struct ao2_iterator mem_iter;
4001
4002 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
4003 /* This queue doesn't have realtime members. If the queue still has any realtime
4004 * members in memory, they need to be removed.
4005 */
4006 ao2_lock(q);
4007 mem_iter = ao2_iterator_init(q->members, 0);
4008 while ((m = ao2_iterator_next(&mem_iter))) {
4009 if (m->realtime) {
4011 }
4012 ao2_ref(m, -1);
4013 }
4014 ao2_iterator_destroy(&mem_iter);
4015 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
4016 ao2_unlock(q);
4017 return;
4018 }
4019
4020 ao2_lock(q);
4021
4022 /* Temporarily set realtime members dead so we can detect deleted ones.*/
4023 mem_iter = ao2_iterator_init(q->members, 0);
4024 while ((m = ao2_iterator_next(&mem_iter))) {
4025 if (m->realtime) {
4026 m->dead = 1;
4027 }
4028 ao2_ref(m, -1);
4029 }
4030 ao2_iterator_destroy(&mem_iter);
4031
4032 while ((category = ast_category_browse(member_config, category))) {
4033 rt_handle_member_record(q, category, member_config);
4034 }
4035
4036 /* Delete all realtime members that have been deleted in DB. */
4037 mem_iter = ao2_iterator_init(q->members, 0);
4038 while ((m = ao2_iterator_next(&mem_iter))) {
4039 if (m->dead) {
4041 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
4042 } else {
4043 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
4044 }
4046 }
4047 ao2_ref(m, -1);
4048 }
4049 ao2_iterator_destroy(&mem_iter);
4050 ao2_unlock(q);
4051 ast_config_destroy(member_config);
4052}

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

2574{
2575 if (m->status != status) {
2576 /* If this member has transitioned to being available then update their queue
2577 * information. If they are currently in a call then the leg to the agent will be
2578 * considered done and the call finished.
2579 */
2582 }
2583
2584 m->status = status;
2585
2586 /* Remove the member from the pending members pool only when the status changes.
2587 * This is not done unconditionally because we can occasionally see multiple
2588 * device state notifications of not in use after a previous call has ended,
2589 * including after we have initiated a new call. This is more likely to
2590 * happen when there is latency in the connection to the member.
2591 */
2593
2594 queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m));
2595 }
2596}

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

8243{
8244 char *parse;
8246 AST_APP_ARG(queuename);
8247 AST_APP_ARG(interface);
8249 AST_APP_ARG(reason);
8250 );
8251
8252 if (ast_strlen_zero(data)) {
8253 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
8254 return -1;
8255 }
8256
8257 parse = ast_strdupa(data);
8258
8260
8261 if (ast_strlen_zero(args.interface)) {
8262 ast_log(LOG_WARNING, "Missing interface argument to UnpauseQueueMember ([queuename],interface[,options[,reason]])\n");
8263 return -1;
8264 }
8265
8266 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
8267 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
8268 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
8269 return 0;
8270 }
8271
8272 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
8273
8274 return 0;
8275}

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

4168{
4169 int digitlen = strlen(qe->digits);
4170
4171 /* Prevent possible buffer overflow */
4172 if (digitlen < sizeof(qe->digits) - 2) {
4173 qe->digits[digitlen] = digit;
4174 qe->digits[digitlen + 1] = '\0';
4175 } else {
4176 qe->digits[0] = '\0';
4177 return 0;
4178 }
4179
4180 /* If there's no context to goto, short-circuit */
4181 if (ast_strlen_zero(qe->context)) {
4182 return 0;
4183 }
4184
4185 /* If the extension is bad, then reset the digits to blank */
4186 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
4188 qe->digits[0] = '\0';
4189 return 0;
4190 }
4191
4192 /* We have an exact match */
4193 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
4194 qe->valid_digits = 1;
4195 /* Return 1 on a successful goto */
4196 return 1;
4197 }
4198
4199 return 0;
4200}
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8781
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:4190

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

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

◆ wait_a_bit()

static int wait_a_bit ( struct queue_ent qe)
static

Definition at line 7440 of file app_queue.c.

7441{
7442 /* Don't need to hold the lock while we setup the outgoing calls */
7443 int retrywait = qe->parent->retry * 1000;
7444
7445 int res = ast_waitfordigit(qe->chan, retrywait);
7446 if (res > 0 && !valid_exit(qe, res)) {
7447 res = 0;
7448 }
7449
7450 return res;
7451}
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3175

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

5201{
5202 const char *queue = qe->parent->name;
5203 struct callattempt *o, *start = NULL, *prev = NULL;
5204 int status;
5205 int numbusies = prebusies;
5206 int numnochan = 0;
5207 int stillgoing = 0;
5208 int orig = *to;
5209 struct ast_frame *f;
5210 struct callattempt *peer = NULL;
5211 struct ast_channel *winner;
5212 struct ast_channel *in = qe->chan;
5213 char on[80] = "";
5214 char membername[80] = "";
5215 long starttime = 0;
5216 long endtime = 0;
5217 char *inchan_name;
5218 struct timeval start_time_tv = ast_tvnow();
5219 int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */
5220
5222 inchan_name = ast_strdupa(ast_channel_name(qe->chan));
5224
5225 starttime = (long) time(NULL);
5226
5227 while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
5228 int numlines, retry, pos = 1;
5229 struct ast_channel *watchers[AST_MAX_WATCHERS];
5230 watchers[0] = in;
5231 start = NULL;
5232
5233 for (retry = 0; retry < 2; retry++) {
5234 numlines = 0;
5235 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
5236 if (o->stillgoing) { /* Keep track of important channels */
5237 stillgoing = 1;
5238 if (o->chan) {
5239 if (pos < AST_MAX_WATCHERS) {
5240 watchers[pos++] = o->chan;
5241 }
5242 if (!start) {
5243 start = o;
5244 } else {
5245 prev->call_next = o;
5246 }
5247 prev = o;
5248 }
5249 } else if (prev) {
5250 prev->call_next = NULL;
5251 }
5252 numlines++;
5253 }
5254 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
5255 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) {
5256 break;
5257 }
5258 /* On "ringall" strategy we only move to the next penalty level
5259 when *all* ringing phones are done in the current penalty level */
5260 ring_one(qe, outgoing, &numbusies);
5261 /* and retry... */
5262 }
5263 if (pos == 1 /* not found */) {
5264 if (numlines == (numbusies + numnochan)) {
5265 ast_debug(1, "Everyone is busy at this time\n");
5266 } else {
5267 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
5268 }
5269 *to = 0;
5270 return NULL;
5271 }
5272
5273 /* Poll for events from both the incoming channel as well as any outgoing channels */
5274 winner = ast_waitfor_n(watchers, pos, to);
5275
5276 /* Service all of the outgoing channels */
5277 for (o = start; o; o = o->call_next) {
5278 /* We go with a fixed buffer here instead of using ast_strdupa. Using
5279 * ast_strdupa in a loop like this one can cause a stack overflow
5280 */
5281 char ochan_name[AST_CHANNEL_NAME];
5282
5283 if (o->chan) {
5285 ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
5287 }
5288 if (o->stillgoing && (o->chan) && (ast_channel_state(o->chan) == AST_STATE_UP)) {
5289 if (!peer) {
5290 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5291 if (o->orig_chan_name
5292 && strcmp(o->orig_chan_name, ochan_name)) {
5293 /*
5294 * The channel name changed so we must generate COLP update.
5295 * Likely because a call pickup channel masqueraded in.
5296 */
5298 } else if (!o->block_connected_update) {
5299 if (o->pending_connected_update) {
5302 }
5303 } else if (!o->dial_callerid_absent) {
5305 }
5306 }
5307 if (o->aoc_s_rate_list) {
5308 size_t encoded_size;
5309 struct ast_aoc_encoded *encoded;
5310 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5311 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5312 ast_aoc_destroy_encoded(encoded);
5313 }
5314 }
5315 peer = o;
5316 }
5317 } else if (o->chan && (o->chan == winner)) {
5318
5319 ast_copy_string(on, o->member->interface, sizeof(on));
5320 ast_copy_string(membername, o->member->membername, sizeof(membername));
5321
5322 /* Before processing channel, go ahead and check for forwarding */
5323 if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
5324 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
5326 "CANCEL", ast_channel_call_forward(o->chan));
5327 numnochan++;
5328 do_hang(o);
5329 winner = NULL;
5330 continue;
5332 struct ast_channel *original = o->chan;
5333 char forwarder[AST_CHANNEL_NAME];
5334 char tmpchan[256];
5335 char *stuff;
5336 char *tech;
5337 int failed = 0;
5338
5339 ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
5340 ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder));
5341 if ((stuff = strchr(tmpchan, '/'))) {
5342 *stuff++ = '\0';
5343 tech = tmpchan;
5344 } else {
5345 const char *forward_context;
5347 forward_context = pbx_builtin_getvar_helper(o->chan, "FORWARD_CONTEXT");
5348 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), forward_context ? forward_context : ast_channel_context(o->chan));
5350 stuff = tmpchan;
5351 tech = "Local";
5352 }
5353 if (!strcasecmp(tech, "Local")) {
5354 /*
5355 * Drop the connected line update block for local channels since
5356 * this is going to run dialplan and the user can change his
5357 * mind about what connected line information he wants to send.
5358 */
5360 }
5361
5362 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
5363 /* Setup parameters */
5365 if (!o->chan) {
5367 "Forwarding failed to create channel to dial '%s/%s'\n",
5368 tech, stuff);
5369 o->stillgoing = 0;
5370 numnochan++;
5371 } else {
5372 ast_channel_lock_both(o->chan, original);
5374 ast_channel_redirecting(original));
5376 ast_channel_unlock(original);
5377
5381 pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
5383
5384 if (o->pending_connected_update) {
5385 /*
5386 * Re-seed the callattempt's connected line information with
5387 * previously acquired connected line info from the queued
5388 * channel. The previously acquired connected line info could
5389 * have been set through the CONNECTED_LINE dialplan function.
5390 */
5393 }
5394
5397
5399
5402 /*
5403 * The call was not previously redirected so it is
5404 * now redirected from this number.
5405 */
5411 }
5412
5414
5419
5422 && !o->block_connected_update) {
5423 struct ast_party_redirecting redirecting;
5424
5425 /*
5426 * Redirecting updates to the caller make sense only on single
5427 * call at a time strategies.
5428 *
5429 * Need to re-evaluate if calling unlock is still required as we no longer
5430 * use macro.
5431 */
5432 ast_party_redirecting_init(&redirecting);
5435 if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0)) {
5436 ast_channel_update_redirecting(in, &redirecting, NULL);
5437 }
5438 ast_party_redirecting_free(&redirecting);
5439 } else {
5441 }
5442
5443 if (ast_call(o->chan, stuff, 0)) {
5444 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
5445 tech, stuff);
5446 failed = 1;
5447 }
5448 }
5449
5451 "CANCEL", ast_channel_call_forward(original));
5452 if (o->chan) {
5453 ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
5454 }
5455
5456 if (failed) {
5457 do_hang(o);
5458 numnochan++;
5459 }
5460
5461 /* Hangup the original channel now, in case we needed it */
5462 ast_hangup(winner);
5463 continue;
5464 }
5465 f = ast_read(winner);
5466 if (f) {
5467 if (f->frametype == AST_FRAME_CONTROL) {
5468 switch (f->subclass.integer) {
5469 case AST_CONTROL_ANSWER:
5470 /* This is our guy if someone answered. */
5471 if (!peer) {
5472 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5473 ast_channel_publish_dial(qe->chan, o->chan, on, "ANSWER");
5474 publish_dial_end_event(qe->chan, outgoing, o->chan, "CANCEL");
5475 if (o->orig_chan_name
5476 && strcmp(o->orig_chan_name, ochan_name)) {
5477 /*
5478 * The channel name changed so we must generate COLP update.
5479 * Likely because a call pickup channel masqueraded in.
5480 */
5482 } else if (!o->block_connected_update) {
5483 if (o->pending_connected_update) {
5486 }
5487 } else if (!o->dial_callerid_absent) {
5489 }
5490 }
5491 if (o->aoc_s_rate_list) {
5492 size_t encoded_size;
5493 struct ast_aoc_encoded *encoded;
5494 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5495 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5496 ast_aoc_destroy_encoded(encoded);
5497 }
5498 }
5499 peer = o;
5500 }
5501 break;
5502 case AST_CONTROL_BUSY:
5503 ast_verb(3, "%s is busy\n", ochan_name);
5504 ast_channel_publish_dial(qe->chan, o->chan, on, "BUSY");
5505 endtime = (long) time(NULL);
5506 endtime -= starttime;
5507 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopausebusy);
5508 do_hang(o);
5510 if (qe->parent->timeoutrestart) {
5511 start_time_tv = ast_tvnow();
5512 }
5513 /* Have enough time for a queue member to answer? */
5514 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5515 ring_one(qe, outgoing, &numbusies);
5516 starttime = (long) time(NULL);
5517 }
5518 }
5519 numbusies++;
5520 break;
5522 ast_verb(3, "%s is circuit-busy\n", ochan_name);
5523 ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION");
5524 endtime = (long) time(NULL);
5525 endtime -= starttime;
5526 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopauseunavail);
5527 do_hang(o);
5529 if (qe->parent->timeoutrestart) {
5530 start_time_tv = ast_tvnow();
5531 }
5532 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5533 ring_one(qe, outgoing, &numbusies);
5534 starttime = (long) time(NULL);
5535 }
5536 }
5537 numbusies++;
5538 break;
5540 ast_verb(3, "%s is ringing\n", ochan_name);
5541
5542 ast_channel_publish_dial(qe->chan, o->chan, on, "RINGING");
5543
5544 /* Start ring indication when the channel is ringing, if specified */
5545 if (qe->ring_when_ringing) {
5546 ast_moh_stop(qe->chan);
5548 }
5549 break;
5551 /* Ignore going off hook */
5552 break;
5554 if (o->block_connected_update) {
5555 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
5556 break;
5557 }
5560
5561 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
5567 break;
5568 }
5569
5570 /*
5571 * Prevent using the CallerID from the outgoing channel since we
5572 * got a connected line update from it.
5573 */
5574 o->dial_callerid_absent = 1;
5575
5576 if (ast_channel_connected_line_sub(o->chan, in, f, 1)) {
5578 }
5579 break;
5580 case AST_CONTROL_AOC:
5581 {
5582 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
5583 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
5585 o->aoc_s_rate_list = decoded;
5586 } else {
5587 ast_aoc_destroy_decoded(decoded);
5588 }
5589 }
5590 break;
5593 /*
5594 * Redirecting updates to the caller make sense only on single
5595 * call at a time strategies.
5596 */
5597 break;
5598 }
5599 if (o->block_connected_update) {
5600 ast_verb(3, "Redirecting update to %s prevented\n",
5601 inchan_name);
5602 break;
5603 }
5604 ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
5605 ochan_name, inchan_name);
5606 if (ast_channel_redirecting_sub(o->chan, in, f, 1)) {
5608 }
5609 break;
5612 break;
5613 default:
5614 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
5615 break;
5616 }
5617 }
5618 ast_frfree(f);
5619 } else { /* ast_read() returned NULL */
5620 endtime = (long) time(NULL) - starttime;
5621 ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER");
5622 rna(endtime * 1000, qe, o->chan, on, membername, 1);
5623 do_hang(o);
5625 if (qe->parent->timeoutrestart) {
5626 start_time_tv = ast_tvnow();
5627 }
5628 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5629 ring_one(qe, outgoing, &numbusies);
5630 starttime = (long) time(NULL);
5631 }
5632 }
5633 }
5634 }
5635 }
5636
5637 /* If we received an event from the caller, deal with it. */
5638 if (winner == in) {
5639 f = ast_read(in);
5640 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
5641 /* Got hung up */
5642 *to = -1;
5643 if (f) {
5644 if (f->data.uint32) {
5646 }
5647 ast_frfree(f);
5648 }
5649 canceled_by_caller = 1;
5650 } else if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
5651 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
5652 *to = 0;
5653 ast_frfree(f);
5654 canceled_by_caller = 1;
5655 } else if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
5656 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
5657 *to = 0;
5658 *digit = f->subclass.integer;
5659 ast_frfree(f);
5660 canceled_by_caller = 1;
5661 }
5662 /* When caller hung up or pressed * or digit. */
5663 if (canceled_by_caller) {
5665 for (o = start; o; o = o->call_next) {
5666 if (o->chan) {
5667 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));
5668 }
5669 }
5670 return NULL;
5671 }
5672
5673 /* Send the frame from the in channel to all outgoing channels. */
5674 for (o = start; o; o = o->call_next) {
5675 if (!o->stillgoing || !o->chan) {
5676 /* This outgoing channel has died so don't send the frame to it. */
5677 continue;
5678 }
5679 switch (f->frametype) {
5680 case AST_FRAME_CONTROL:
5681 switch (f->subclass.integer) {
5683 if (o->block_connected_update) {
5684 ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
5685 break;
5686 }
5687 if (ast_channel_connected_line_sub(in, o->chan, f, 1)) {
5689 }
5690 break;
5692 if (o->block_connected_update) {
5693 ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
5694 break;
5695 }
5696 if (ast_channel_redirecting_sub(in, o->chan, f, 1)) {
5698 }
5699 break;
5700 default:
5701 /* We are not going to do anything with this frame. */
5702 goto skip_frame;
5703 }
5704 break;
5705 default:
5706 /* We are not going to do anything with this frame. */
5707 goto skip_frame;
5708 }
5709 }
5710skip_frame:;
5711
5712 ast_frfree(f);
5713 }
5714 }
5715
5716 if (!*to) {
5717 for (o = start; o; o = o->call_next) {
5718 if (o->chan) {
5719 rna(orig, qe, o->chan, o->interface, o->member->membername, 1);
5720 }
5721 }
5722
5723 publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER");
5724 }
5725
5726 return peer;
5727}
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:313
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:892
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:449
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:650
@ AST_AOC_S
Definition: aoc.h:64
#define AST_MAX_WATCHERS
Definition: app_queue.c:5186
static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
Definition: app_queue.c:5170
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:5105
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition: channel.c:2122
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition: channel.c:1644
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:3157
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:2054
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:6434
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
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:10383
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:8785
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:4653
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:10284
#define AST_CHANNEL_NAME
Definition: channel.h:171
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition: channel.c:1691
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition: channel.c:2179
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:2045
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
char connected
Definition: eagi_proxy.c:82
void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring, const char *dialstatus, const char *forward)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
#define AST_FRAME_DTMF
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_OFFHOOK
@ AST_CONTROL_BUSY
@ AST_CONTROL_REDIRECTING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_HANGUP
@ AST_CONTROL_CONNECTED_LINE
@ AST_CONTROL_AOC
@ AST_CONTROL_PVT_CAUSE_CODE
const struct ast_channel_tech * tech
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
Definition: channel.h:522
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:527
unsigned int dial_callerid_absent
Definition: app_queue.c:1683
unsigned int block_connected_update
Definition: app_queue.c:1681
struct callattempt * call_next
Definition: app_queue.c:1671
unsigned int pending_connected_update
Definition: app_queue.c:1679
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2281
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

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

Referenced by try_calling().

◆ wait_our_turn()

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

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

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

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

Definition at line 5879 of file app_queue.c.

5880{
5881 int res = 0;
5882
5883 /* This is the holding pen for callers 2 through maxlen */
5884 for (;;) {
5885
5886 /* A request to withdraw this call from the queue arrived */
5887 if (qe->withdraw) {
5888 *reason = QUEUE_WITHDRAW;
5889 res = 1;
5890 break;
5891 }
5892
5893 if (is_our_turn(qe)) {
5894 break;
5895 }
5896
5897 /* If we have timed out, break out */
5898 if (qe->expire && (time(NULL) >= qe->expire)) {
5899 *reason = QUEUE_TIMEOUT;
5900 break;
5901 }
5902
5903 if (qe->parent->leavewhenempty) {
5904 int status = 0;
5905
5907 record_abandoned(qe);
5908 *reason = QUEUE_LEAVEEMPTY;
5909 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));
5910 res = -1;
5911 qe->handled = -1;
5912 break;
5913 }
5914 }
5915
5916 /* Make a position announcement, if enabled */
5917 if (qe->parent->announcefrequency &&
5918 (res = say_position(qe,ringing))) {
5919 break;
5920 }
5921
5922 /* If we have timed out, break out */
5923 if (qe->expire && (time(NULL) >= qe->expire)) {
5924 *reason = QUEUE_TIMEOUT;
5925 break;
5926 }
5927
5928 /* Make a periodic announcement, if enabled */
5931 break;
5932
5933 /* see if we need to move to the next penalty level for this queue */
5934 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
5935 update_qe_rule(qe);
5936 }
5937
5938 /* If we have timed out, break out */
5939 if (qe->expire && (time(NULL) >= qe->expire)) {
5940 *reason = QUEUE_TIMEOUT;
5941 break;
5942 }
5943
5944 /* Wait a second before checking again */
5945 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
5946 if (res > 0 && !valid_exit(qe, res)) {
5947 res = 0;
5948 } else {
5949 break;
5950 }
5951 }
5952
5953 /* If we have timed out, break out */
5954 if (qe->expire && (time(NULL) >= qe->expire)) {
5955 *reason = QUEUE_TIMEOUT;
5956 break;
5957 }
5958 }
5959
5960 return res;
5961}
#define RECHECK
Definition: app_queue.c:1555

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

Referenced by queue_exec().

◆ word_in_list()

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

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

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

Definition at line 10242 of file app_queue.c.

10242 {
10243 int list_len, word_len = strlen(word);
10244 const char *find, *end_find, *end_list;
10245
10246 /* strip whitespace from front */
10247 while(isspace(*list)) {
10248 list++;
10249 }
10250
10251 while((find = strstr(list, word))) {
10252 /* beginning of find starts inside another word? */
10253 if (find != list && *(find - 1) != ' ') {
10254 list = find;
10255 /* strip word from front */
10256 while(!isspace(*list) && *list != '\0') {
10257 list++;
10258 }
10259 /* strip whitespace from front */
10260 while(isspace(*list)) {
10261 list++;
10262 }
10263 continue;
10264 }
10265
10266 /* end of find ends inside another word or at very end of list? */
10267 list_len = strlen(list);
10268 end_find = find + word_len;
10269 end_list = list + list_len;
10270 if (end_find == end_list || *end_find != ' ') {
10271 list = find;
10272 /* strip word from front */
10273 while(!isspace(*list) && *list != '\0') {
10274 list++;
10275 }
10276 /* strip whitespace from front */
10277 while(isspace(*list)) {
10278 list++;
10279 }
10280 continue;
10281 }
10282
10283 /* terminating conditions satisfied, word at beginning or separated by ' ' */
10284 return 1;
10285 }
10286
10287 return 0;
10288}

References call_queue::list.

Referenced by complete_queue().

Variable Documentation

◆ __mod_info

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

Definition at line 11939 of file app_queue.c.

◆ agent_router

struct stasis_message_router* agent_router
static

Definition at line 11673 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app

char* app = "Queue"
static

Definition at line 1572 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_aqm

char* app_aqm = "AddQueueMember"
static

Definition at line 1574 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_pqm

char* app_pqm = "PauseQueueMember"
static

Definition at line 1578 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_ql

char* app_ql = "QueueLog"
static

Definition at line 1582 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_qupd

char* app_qupd = "QueueUpdate"
static

Definition at line 1584 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_rqm

char* app_rqm = "RemoveQueueMember"
static

Definition at line 1576 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_upqm

char* app_upqm = "UnpauseQueueMember"
static

Definition at line 1580 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 11939 of file app_queue.c.

◆ autofill_default

int autofill_default
static

queues.conf [general] option

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

Referenced by load_module(), and unload_module().

◆ device_state_sub

struct stasis_subscription* device_state_sub
static

Subscription to device state change messages.

Definition at line 1608 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 1617 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 1638 of file app_queue.c.

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

◆ log_membername_as_agent

int log_membername_as_agent
static

◆ montype_default

int montype_default
static

queues.conf [general] option

Definition at line 1599 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 1611 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 2511 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 1587 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 1503 of file app_queue.c.

Referenced by queue_exec().

◆ queue_persistent_members

int queue_persistent_members
static

◆ 

const struct { ... } queue_results[]

Referenced by set_queue_result().

◆ queueexists_function

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

Definition at line 9440 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuegetchannel_function

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

Definition at line 9461 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuemembercount_dep

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

Definition at line 9456 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuemembercount_function

struct ast_custom_function queuemembercount_function
static
Initial value:
= {
.name = "QUEUE_MEMBER",
}
static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Get number either busy / free / ready or total members of a specific queue.
Definition: app_queue.c:9002
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:9104

Definition at line 9450 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuememberlist_function

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

Definition at line 9471 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuememberpenalty_function

struct ast_custom_function queuememberpenalty_function
static
Initial value:
= {
.name = "QUEUE_MEMBER_PENALTY",
}
static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.
Definition: app_queue.c:9372
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:9404

Definition at line 9476 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queues

struct ao2_container* queues
static

◆ queuevar_function

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

Definition at line 9445 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ queuewaitingcount_function

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

Definition at line 9466 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ realtime_reason_paused

int realtime_reason_paused
static

does realtime backend support reason_paused

Definition at line 1623 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 1620 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 1605 of file app_queue.c.

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

◆ rule_lists

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

◆ shared_lastcall

int shared_lastcall
static

queues.conf [general] option

Definition at line 1602 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 11674 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 1593 of file app_queue.c.

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