Asterisk - The Open Source Telephony Project GIT-master-85241bd
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:965
#define LOG_ERROR
#define LOG_NOTICE
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
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:3310

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 re