Asterisk - The Open Source Telephony Project GIT-master-4c84066
Loading...
Searching...
No Matches
Data Structures | Macros | Enumerations | Functions | Variables
app_queue.c File Reference

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

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

Go to the source code of this file.

Data Structures

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

Macros

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

Enumerations

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

Functions

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

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "True Call Queueing" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, }
 
static struct stasis_message_routeragent_router
 
static char * app = "Queue"
 
static char * app_aqm = "AddQueueMember"
 
static char * app_pqm = "PauseQueueMember"
 
static char * app_ql = "QueueLog"
 
static char * app_qupd = "QueueUpdate"
 
static char * app_rqm = "RemoveQueueMember"
 
static char * app_upqm = "UnpauseQueueMember"
 
static const struct ast_app_option aqm_opts [128] = { [ 'p' ] = { .flag = AQMFLAG_PAUSED }, [ 'r' ] = { .flag = AQMFLAG_REASON , .arg_index = AQM_OPT_ARG_PAUSE_REASON + 1 }, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static int autofill_default
 queues.conf [general] option
 
static const struct autopause autopausesmodes []
 
static struct ast_cli_entry cli_queue []
 
static struct stasis_subscriptiondevice_state_sub
 Subscription to device state change messages.
 
static int force_longest_waiting_caller
 queues.conf [general] option
 
static int log_caller_id_name
 queues.conf [general] option
 
static int log_membername_as_agent
 queues.conf [general] option
 
static int log_unpause_on_reason_change
 queues.conf [general] option
 
static int montype_default
 queues.conf [general] option
 
static int negative_penalty_invalid
 queues.conf [general] option
 
static struct ao2_containerpending_members
 
static const char *const pm_family = "Queue/PersistentMembers"
 Persistent Members astdb family.
 
static const struct ast_app_option queue_exec_options [128] = { [ 'b' ] = { .flag = OPT_PREDIAL_CALLEE , .arg_index = OPT_ARG_PREDIAL_CALLEE + 1 }, [ 'B' ] = { .flag = OPT_PREDIAL_CALLER , .arg_index = OPT_ARG_PREDIAL_CALLER + 1 }, [ 'C' ] = { .flag = OPT_MARK_AS_ANSWERED }, [ 'c' ] = { .flag = OPT_GO_ON }, [ 'd' ] = { .flag = OPT_DATA_QUALITY }, [ 'F' ] = { .flag = OPT_CALLEE_GO_ON , .arg_index = OPT_ARG_CALLEE_GO_ON + 1 }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'i' ] = { .flag = OPT_IGNORE_CALL_FW }, [ 'I' ] = { .flag = OPT_IGNORE_CONNECTEDLINE }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'm' ] = { .flag = OPT_MUSICONHOLD_CLASS , .arg_index = OPT_ARG_MUSICONHOLD_CLASS + 1 }, [ 'n' ] = { .flag = OPT_NO_RETRY }, [ 'r' ] = { .flag = OPT_RINGING }, [ 'R' ] = { .flag = OPT_RING_WHEN_RINGING }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'x' ] = { .flag = OPT_CALLEE_AUTOMIXMON }, [ 'X' ] = { .flag = OPT_CALLER_AUTOMIXMON }, [ 'w' ] = { .flag = OPT_CALLEE_AUTOMON }, [ 'W' ] = { .flag = OPT_CALLER_AUTOMON }, }
 
static int queue_persistent_members
 queues.conf [general] option
 
struct { 
 
   enum queue_result   id 
 
   char *   text 
 
queue_results [] 
 
static struct ast_custom_function queueexists_function
 
static struct ast_custom_function queuegetchannel_function
 
static struct ast_custom_function queuemembercount_function
 
static struct ast_custom_function queuememberlist_function
 
static struct ast_custom_function queuememberpenalty_function
 
static struct ao2_containerqueues
 
static struct ast_custom_function queuevar_function
 
static struct ast_custom_function queuewaitingcount_function
 
static int realtime_reason_paused
 does realtime backend support reason_paused
 
static char * realtime_ringinuse_field
 name of the ringinuse field in the realtime database
 
static int realtime_rules
 queuerules.conf [general] option
 
static struct rule_lists rule_lists = AST_LIST_HEAD_INIT_VALUE
 
static int shared_lastcall
 queues.conf [general] option
 
static const struct strategy strategies []
 
static struct stasis_forwardtopic_forwarder
 
static int use_weight
 Records that one or more queues use weight.
 

Detailed Description

True call queues with optional send URL on answer.

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

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

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

Patch Version 1.07 2003-12-24 01

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

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

Definition in file app_queue.c.

Macro Definition Documentation

◆ ANNOUNCEHOLDTIME_ALWAYS

#define ANNOUNCEHOLDTIME_ALWAYS   1

Definition at line 1924 of file app_queue.c.

◆ ANNOUNCEHOLDTIME_ONCE

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1925 of file app_queue.c.

◆ ANNOUNCEPOSITION_LIMIT

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1943 of file app_queue.c.

◆ ANNOUNCEPOSITION_MORE_THAN

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 1942 of file app_queue.c.

◆ ANNOUNCEPOSITION_NO

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1941 of file app_queue.c.

◆ ANNOUNCEPOSITION_YES

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1940 of file app_queue.c.

◆ AST_MAX_WATCHERS

#define AST_MAX_WATCHERS   256

Definition at line 5379 of file app_queue.c.

◆ DEFAULT_MIN_ANNOUNCE_FREQUENCY

#define DEFAULT_MIN_ANNOUNCE_FREQUENCY   15

The minimum number of seconds between position announcements.

Note
The default value of 15 provides backwards compatibility.

Definition at line 1707 of file app_queue.c.

◆ DEFAULT_RETRY

#define DEFAULT_RETRY   5

Definition at line 1699 of file app_queue.c.

◆ DEFAULT_TIMEOUT

#define DEFAULT_TIMEOUT   15

Definition at line 1700 of file app_queue.c.

◆ FORCELONGESTWAITINGCALLER_NO

#define FORCELONGESTWAITINGCALLER_NO   0

Definition at line 1945 of file app_queue.c.

◆ FORCELONGESTWAITINGCALLER_PRIO

#define FORCELONGESTWAITINGCALLER_PRIO   2

Account for call priorities when forcing longest waiting caller

Definition at line 1947 of file app_queue.c.

◆ FORCELONGESTWAITINGCALLER_YES

#define FORCELONGESTWAITINGCALLER_YES   1

Definition at line 1946 of file app_queue.c.

◆ MAX_CALL_ATTEMPT_BUCKETS

#define MAX_CALL_ATTEMPT_BUCKETS   353

Definition at line 2677 of file app_queue.c.

◆ MAX_PERIODIC_ANNOUNCEMENTS

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 1702 of file app_queue.c.

◆ MAX_QUEUE_BUCKETS

#define MAX_QUEUE_BUCKETS   53

Definition at line 1709 of file app_queue.c.

◆ QUEUE_EVENT_VARIABLES

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1926 of file app_queue.c.

◆ QUEUE_PAUSED_DEVSTATE

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

Definition at line 3714 of file app_queue.c.

◆ queue_ref

#define queue_ref (   q)    ao2_bump(q)

Definition at line 2213 of file app_queue.c.

◆ queue_t_ref

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

Definition at line 2215 of file app_queue.c.

◆ queue_t_unref

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

Definition at line 2216 of file app_queue.c.

◆ QUEUE_UNKNOWN_PAUSED_DEVSTATE

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3716 of file app_queue.c.

◆ QUEUE_UNPAUSED_DEVSTATE

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3715 of file app_queue.c.

◆ queue_unref

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

Definition at line 2214 of file app_queue.c.

◆ queues_t_link

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

Definition at line 2217 of file app_queue.c.

◆ queues_t_unlink

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

Definition at line 2218 of file app_queue.c.

◆ RECHECK

#define RECHECK   1

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

Definition at line 1701 of file app_queue.c.

◆ RES_EXISTS

#define RES_EXISTS   (-1)

Entry already exists

Definition at line 1712 of file app_queue.c.

◆ RES_NOSUCHQUEUE

#define RES_NOSUCHQUEUE   (-3)

No such queue

Definition at line 1714 of file app_queue.c.

◆ RES_NOT_CALLER

#define RES_NOT_CALLER   (-5)

Caller not found

Definition at line 1716 of file app_queue.c.

◆ RES_NOT_DYNAMIC

#define RES_NOT_DYNAMIC   (-4)

Member is not dynamic

Definition at line 1715 of file app_queue.c.

◆ RES_OKAY

#define RES_OKAY   0

Action completed

Definition at line 1711 of file app_queue.c.

◆ RES_OUTOFMEMORY

#define RES_OUTOFMEMORY   (-2)

Out of memory

Definition at line 1713 of file app_queue.c.

Enumeration Type Documentation

◆ anonymous enum

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

Definition at line 1576 of file app_queue.c.

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

◆ anonymous enum

anonymous enum
Enumerator
OPT_ARG_CALLEE_GO_ON 
OPT_ARG_PREDIAL_CALLEE 
OPT_ARG_PREDIAL_CALLER 
OPT_ARG_MUSICONHOLD_CLASS 
OPT_ARG_ARRAY_SIZE 

Definition at line 1601 of file app_queue.c.

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

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_STRATEGY_RINGALL 
QUEUE_STRATEGY_LEASTRECENT 
QUEUE_STRATEGY_FEWESTCALLS 
QUEUE_STRATEGY_RANDOM 
QUEUE_STRATEGY_RRMEMORY 
QUEUE_STRATEGY_LINEAR 
QUEUE_STRATEGY_WRANDOM 
QUEUE_STRATEGY_RRORDERED 

Definition at line 1651 of file app_queue.c.

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

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 1662 of file app_queue.c.

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

◆ agent_complete_reason

Enumerator
CALLER 
AGENT 
TRANSFER 

Definition at line 6329 of file app_queue.c.

6329 {
6330 CALLER,
6331 AGENT,
6332 TRANSFER
6333};
@ AGENT
Definition app_queue.c:6331
@ CALLER
Definition app_queue.c:6330
@ TRANSFER
Definition app_queue.c:6332

◆ aqm_args

enum aqm_args
Enumerator
AQM_OPT_ARG_PAUSE_REASON 
AQM_OPT_ARG_ARRAY_SIZE 

Definition at line 1641 of file app_queue.c.

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

◆ aqm_flags

enum aqm_flags
Enumerator
AQMFLAG_PAUSED 
AQMFLAG_REASON 

Definition at line 1636 of file app_queue.c.

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

◆ empty_conditions

Enumerator
QUEUE_EMPTY_PENALTY 
QUEUE_EMPTY_PAUSED 
QUEUE_EMPTY_INUSE 
QUEUE_EMPTY_RINGING 
QUEUE_EMPTY_UNAVAILABLE 
QUEUE_EMPTY_INVALID 
QUEUE_EMPTY_UNKNOWN 
QUEUE_EMPTY_WRAPUP 

Definition at line 1907 of file app_queue.c.

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

◆ member_properties

Enumerator
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1918 of file app_queue.c.

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

◆ queue_reload_mask

Enumerator
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 1668 of file app_queue.c.

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

◆ queue_result

Enumerator
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 
QUEUE_WITHDRAW 

Definition at line 1777 of file app_queue.c.

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

◆ queue_timeout_priority

Enumerator
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1804 of file app_queue.c.

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

Function Documentation

◆ __queues_show()

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

Show queue(s) status and statistics.

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

Definition at line 10444 of file app_queue.c.

10445{
10446 struct call_queue *q;
10447 struct ast_str *out = ast_str_alloca(512);
10448 struct ao2_container *sorted_queues;
10449
10450 struct ao2_iterator queue_iter;
10451 int found = 0;
10452
10453 if (argc != 2 && argc != 3) {
10454 return CLI_SHOWUSAGE;
10455 }
10456
10457 if (argc == 3) { /* specific queue */
10458 if ((q = find_load_queue_rt_friendly(argv[2]))) {
10459 ao2_lock(q);
10460 print_queue(s, fd, q);
10461 ao2_unlock(q);
10462 queue_unref(q);
10463 } else {
10464 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
10465 do_print(s, fd, ast_str_buffer(out));
10466 }
10467 return CLI_SUCCESS;
10468 }
10469
10470 if (ast_check_realtime("queues")) {
10471 /* This block is to find any queues which are defined in realtime but
10472 * which have not yet been added to the in-core container
10473 */
10474 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10475 if (cfg) {
10476 char *category = NULL;
10477 while ((category = ast_category_browse(cfg, category))) {
10478 const char *queuename = ast_variable_retrieve(cfg, category, "name");
10479 if (ast_strlen_zero(queuename)) {
10480 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
10481 continue;
10482 }
10483 if ((q = find_load_queue_rt_friendly(queuename))) {
10484 queue_t_unref(q, "Done with temporary pointer");
10485 }
10486 }
10487 ast_config_destroy(cfg);
10488 }
10489 }
10490
10491 /*
10492 * Snapping a copy of the container prevents having to lock both the queues container
10493 * and the queue itself at the same time. It also allows us to sort the entries.
10494 */
10495 sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
10496 if (!sorted_queues) {
10497 return CLI_SUCCESS;
10498 }
10499 if (ao2_container_dup(sorted_queues, queues, 0)) {
10500 ao2_ref(sorted_queues, -1);
10501 return CLI_SUCCESS;
10502 }
10503
10504 /*
10505 * No need to lock the container since it's temporary and static.
10506 * We also unlink the entries as we use them so the container is
10507 * empty when the iterator finishes. We can then just unref the container.
10508 */
10509 queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
10510 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10511 struct call_queue *realtime_queue = NULL;
10512 ao2_lock(q);
10513 /* This check is to make sure we don't print information for realtime
10514 * queues which have been deleted from realtime but which have not yet
10515 * been deleted from the in-core container. Only do this if we're not
10516 * looking for a specific queue.
10517 */
10518 if (q->realtime) {
10519 realtime_queue = find_load_queue_rt_friendly(q->name);
10520 if (!realtime_queue) {
10521 ao2_unlock(q);
10522 queue_t_unref(q, "Done with iterator");
10523 continue;
10524 }
10525 queue_t_unref(realtime_queue, "Queue is already in memory");
10526 }
10527
10528 found = 1;
10529 print_queue(s, fd, q);
10530
10531 ao2_unlock(q);
10532 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
10533 }
10534 ao2_iterator_destroy(&queue_iter);
10535 ao2_ref(sorted_queues, -1);
10536 if (!found) {
10537 ast_str_set(&out, 0, "No queues.");
10538 do_print(s, fd, ast_str_buffer(out));
10539 }
10540 return CLI_SUCCESS;
10541}
static void print_queue(struct mansession *s, int fd, struct call_queue *q)
Print a single queue to AMI or the CLI.
static struct ao2_container * queues
Definition app_queue.c:2059
#define queue_t_unref(q, tag)
Definition app_queue.c:2216
#define queue_unref(q)
Definition app_queue.c:2214
static void do_print(struct mansession *s, int fd, const char *str)
direct output to manager or cli with proper terminator
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition app_queue.c:4073
#define ast_log
Definition astobj2.c:42
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
#define ao2_t_iterator_next(iter, tag)
Definition astobj2.h:1909
@ AO2_ITERATOR_UNLINK
Definition astobj2.h:1863
@ AO2_ITERATOR_DONTLOCK
Assume that the ao2_container is already locked.
Definition astobj2.h:1852
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition astobj2.h:1349
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
#define SENTINEL
Definition compiler.h:87
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition extconf.c:3324
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition extconf.c:1287
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
#define LOG_WARNING
#define NULL
Definition resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#define ast_str_alloca(init_len)
Definition strings.h:848
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
Support for dynamic strings.
Definition strings.h:623
unsigned int realtime
Definition app_queue.c:2003
unsigned int found
Definition app_queue.c:2004
const ast_string_field name
Definition app_queue.c:1987
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 12259 of file app_queue.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

7841{
7842 struct call_queue *q;
7843 struct member *new_member, *old_member;
7844 int res = RES_NOSUCHQUEUE;
7845
7846 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7847 * short-circuits if the queue is already in memory. */
7848 if (!(q = find_load_queue_rt_friendly(queuename))) {
7849 return res;
7850 }
7851
7852 ao2_lock(q);
7853 if ((old_member = interface_exists(q, interface)) == NULL) {
7855 new_member->dynamic = 1;
7856 if (reason_paused) {
7857 ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7858 }
7859 member_add_to_queue(q, new_member);
7860 queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7861
7862 if (is_member_available(q, new_member)) {
7864 }
7865
7866 ao2_ref(new_member, -1);
7867 new_member = NULL;
7868
7869 if (dump) {
7871 }
7872
7873 res = RES_OKAY;
7874 } else {
7875 res = RES_OUTOFMEMORY;
7876 }
7877 } else {
7878 ao2_ref(old_member, -1);
7879 res = RES_EXISTS;
7880 }
7881 ao2_unlock(q);
7882 queue_t_unref(q, "Expiring temporary reference");
7883
7884 return res;
7885}
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:3028
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition app_queue.c:7705
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition app_queue.c:7732
static int is_member_available(struct call_queue *q, struct member *mem)
Definition app_queue.c:2769
#define RES_OUTOFMEMORY
Definition app_queue.c:1713
#define RES_NOSUCHQUEUE
Definition app_queue.c:1714
#define RES_OKAY
Definition app_queue.c:1711
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition app_queue.c:3724
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition app_queue.c:2553
#define RES_EXISTS
Definition app_queue.c:1712
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition app_queue.c:2529
@ AST_DEVSTATE_CACHABLE
Definition devicestate.h:70
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
@ AST_DEVICE_NOT_INUSE
Definition devicestate.h:54
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
unsigned int ringinuse
Definition app_queue.c:1991
char interface[AST_CHANNEL_NAME]
Definition app_queue.c:1880
int dynamic
Definition app_queue.c:1888
char membername[80]
Definition app_queue.c:1885
int penalty
Definition app_queue.c:1886
int paused
Definition app_queue.c:1891
int wrapuptime
Definition app_queue.c:1895
char reason_paused[80]
Definition app_queue.c:1892
char state_interface[AST_CHANNEL_NAME]
Definition app_queue.c:1883

References ao2_lock, ao2_ref, ao2_unlock, ast_copy_string(), AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), create_queue_member(), dump_queue_members(), member::dynamic, find_load_queue_rt_friendly(), member::interface, interface_exists(), is_member_available(), member_add_to_queue(), member::membername, call_queue::name, NULL, member::paused, member::penalty, queue_member_blob_create(), queue_publish_member_blob(), queue_t_unref, member::reason_paused, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, call_queue::ringinuse, member::state_interface, and member::wrapuptime.

Referenced by aqm_exec(), handle_queue_add_member(), manager_add_queue_member(), and reload_queue_members().

◆ alloc_queue()

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

Definition at line 3905 of file app_queue.c.

3906{
3907 struct call_queue *q;
3908
3909 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3910 if (ast_string_field_init(q, 64)) {
3911 queue_t_unref(q, "String field allocation failed");
3912 return NULL;
3913 }
3914 ast_string_field_set(q, name, queuename);
3915 }
3916 return q;
3917}
static void destroy_queue(void *obj)
Free queue's member list then its string fields.
Definition app_queue.c:3890
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition astobj2.h:407
static const char name[]
Definition format_mp3.c:68
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.

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

Referenced by find_queue_by_name_rt(), and reload_single_queue().

◆ AO2_STRING_FIELD_SORT_FN()

AO2_STRING_FIELD_SORT_FN ( call_queue  ,
name   
)

◆ aqm_exec()

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

AddQueueMember application.

Definition at line 8606 of file app_queue.c.

8607{
8608 int res=-1;
8609 char *parse, *tmp, *temppos = NULL, *reason = NULL;
8611 AST_APP_ARG(queuename);
8612 AST_APP_ARG(interface);
8613 AST_APP_ARG(penalty);
8615 AST_APP_ARG(membername);
8616 AST_APP_ARG(state_interface);
8617 AST_APP_ARG(wrapuptime);
8618 );
8619 int penalty = 0;
8620 int paused = 0;
8621 int wrapuptime;
8622 struct ast_flags flags = { 0 };
8623
8624 if (ast_strlen_zero(data)) {
8625 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8626 return -1;
8627 }
8628
8629 parse = ast_strdupa(data);
8630
8632
8633 if (args.options) {
8634 char *opts[AQM_OPT_ARG_ARRAY_SIZE] = { NULL, };
8635 ast_app_parse_options(aqm_opts, &flags, opts, args.options);
8637 paused = 1;
8639 reason = ast_strdupa(opts[AQM_OPT_ARG_PAUSE_REASON]);
8640 }
8641 }
8642 }
8643
8644 if (ast_strlen_zero(args.interface)) {
8645 args.interface = ast_strdupa(ast_channel_name(chan));
8646 temppos = strrchr(args.interface, '-');
8647 if (temppos) {
8648 *temppos = '\0';
8649 }
8650 }
8651
8652 if (!ast_strlen_zero(args.penalty)) {
8653 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8654 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8655 penalty = 0;
8656 }
8657 }
8658
8659 if (!ast_strlen_zero(args.wrapuptime)) {
8660 tmp = args.wrapuptime;
8661 ast_strip(tmp);
8662 wrapuptime = atoi(tmp);
8663 if (wrapuptime < 0) {
8664 wrapuptime = 0;
8665 }
8666 } else {
8667 wrapuptime = 0;
8668 }
8669
8670 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, paused, queue_persistent_members, args.state_interface, reason, wrapuptime)) {
8671 case RES_OKAY:
8672 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8673 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8674 } else {
8675 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8676 }
8677 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8678 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8679 res = 0;
8680 break;
8681 case RES_EXISTS:
8682 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8683 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8684 res = 0;
8685 break;
8686 case RES_NOSUCHQUEUE:
8687 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8688 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8689 res = 0;
8690 break;
8691 case RES_OUTOFMEMORY:
8692 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8693 break;
8694 }
8695
8696 return res;
8697}
static int queue_persistent_members
queues.conf [general] option
Definition app_queue.c:1736
static int log_membername_as_agent
queues.conf [general] option
Definition app_queue.c:1760
static const struct ast_app_option aqm_opts[128]
Definition app_queue.c:1649
static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface, const char *reason_paused, int wrapuptime)
Add member to queue.
Definition app_queue.c:7840
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition main/app.c:3067
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition logger.c:957
#define LOG_ERROR
#define LOG_NOTICE
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
static struct @522 args
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
Structure used to handle boolean flags.
Definition utils.h:220
unsigned int flags
Definition utils.h:221
static struct test_options options
#define ast_test_flag(p, flag)
Definition utils.h:64

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

Referenced by load_module().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 12259 of file app_queue.c.

◆ autopause2int()

static int autopause2int ( const char *  autopause)
static

Definition at line 2106 of file app_queue.c.

2107{
2108 int x;
2109 /*This 'double check' that default value is OFF */
2111 return QUEUE_AUTOPAUSE_OFF;
2112 }
2113
2114 /*This 'double check' is to ensure old values works */
2115 if(ast_true(autopause)) {
2116 return QUEUE_AUTOPAUSE_ON;
2117 }
2118
2119 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
2120 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
2121 return autopausesmodes[x].autopause;
2122 }
2123 }
2124
2125 /*This 'double check' that default value is OFF */
2126 return QUEUE_AUTOPAUSE_OFF;
2127}
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:2233
int autopause
Definition app_queue.c:1691
#define ARRAY_LEN(a)
Definition utils.h:706

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

Referenced by queue_set_param().

◆ calc_metric()

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

Calculate the metric of each member in the outgoing callattempts.

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

Return values
-1if penalties are exceeded
0otherwise

Definition at line 6251 of file app_queue.c.

6252{
6253 /* disregarding penalty on too few members? */
6254 int membercount = ao2_container_count(q->members);
6255 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
6256 int penalty = mem->penalty;
6257
6258 if (usepenalty) {
6259 if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty && !(qe->raise_respect_min && qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6260 /* Low penalty is raised up to the current minimum */
6261 penalty = qe->raise_penalty;
6262 }
6263 if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
6264 (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6265 return -1;
6266 }
6267 } else {
6268 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
6269 membercount, q->penaltymemberslimit);
6270 }
6271
6272 switch (q->strategy) {
6274 /* Everyone equal, except for penalty */
6275 tmp->metric = penalty * 1000000 * usepenalty;
6276 break;
6278 if (pos < qe->linpos) {
6279 tmp->metric = 1000 + pos;
6280 } else {
6281 if (pos > qe->linpos) {
6282 /* Indicate there is another priority */
6283 qe->linwrapped = 1;
6284 }
6285 tmp->metric = pos;
6286 }
6287 tmp->metric += penalty * 1000000 * usepenalty;
6288 break;
6291 pos = mem->queuepos;
6292 if (pos < q->rrpos) {
6293 tmp->metric = 1000 + pos;
6294 } else {
6295 if (pos > q->rrpos) {
6296 /* Indicate there is another priority */
6297 q->wrapped = 1;
6298 }
6299 tmp->metric = pos;
6300 }
6301 tmp->metric += penalty * 1000000 * usepenalty;
6302 break;
6304 tmp->metric = ast_random() % 1000;
6305 tmp->metric += penalty * 1000000 * usepenalty;
6306 break;
6308 tmp->metric = ast_random() % ((1 + penalty) * 1000);
6309 break;
6311 tmp->metric = mem->calls;
6312 tmp->metric += penalty * 1000000 * usepenalty;
6313 break;
6315 if (!mem->lastcall) {
6316 tmp->metric = 0;
6317 } else {
6318 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
6319 }
6320 tmp->metric += penalty * 1000000 * usepenalty;
6321 break;
6322 default:
6323 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
6324 break;
6325 }
6326 return 0;
6327}
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:2045
int penaltymemberslimit
Definition app_queue.c:2029
unsigned int wrapped
Definition app_queue.c:1997
int queuepos
Definition app_queue.c:1893
time_t lastcall
Definition app_queue.c:1897
int calls
Definition app_queue.c:1887
int raise_respect_min
Definition app_queue.c:1865
int max_penalty
Definition app_queue.c:1862
int raise_penalty
Definition app_queue.c:1864
int min_penalty
Definition app_queue.c:1863
int linwrapped
Definition app_queue.c:1867
long int ast_random(void)
Definition utils.c:2346

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

Referenced by try_calling().

◆ callattempt_free()

static void callattempt_free ( struct callattempt doomed)
static

Definition at line 4625 of file app_queue.c.

4626{
4627 if (doomed->member) {
4628 ao2_ref(doomed->member, -1);
4629 }
4631 ast_free(doomed->orig_chan_name);
4632 ast_free(doomed);
4633}
#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:2059
struct ast_party_connected_line connected
Definition app_queue.c:1829
char * orig_chan_name
Definition app_queue.c:1840
struct member * member
Definition app_queue.c:1827

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

Referenced by hangupcalls(), and try_calling().

◆ can_ring_entry()

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

Definition at line 4845 of file app_queue.c.

4846{
4847 struct member *memberp = call->member;
4848 int wrapuptime;
4849
4850 if (memberp->paused) {
4851 ast_debug(1, "%s paused, can't receive call\n", call->interface);
4852 return 0;
4853 }
4854
4855 if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4856 ast_debug(1, "%s not available, can't receive call\n", call->interface);
4857 return 0;
4858 }
4859
4860 if (memberp->lastqueue) {
4861 wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4862 } else {
4863 wrapuptime = get_wrapuptime(qe->parent, memberp);
4864 }
4865 if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4866 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4867 (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4868 call->interface);
4869 return 0;
4870 }
4871
4872 if (use_weight && compare_weight(qe->parent, memberp)) {
4873 ast_debug(1, "Priority queue delaying call to %s:%s\n",
4874 qe->parent->name, call->interface);
4875 return 0;
4876 }
4877
4879 ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
4880 qe->parent->name, call->interface);
4881 return 0;
4882 }
4883
4884 if (!memberp->ringinuse) {
4885 struct member *mem;
4886
4888
4889 mem = ao2_find(pending_members, memberp,
4891 if (mem) {
4892 /*
4893 * If found that means this member is currently being attempted
4894 * from another calling thread, so stop trying from this thread
4895 */
4896 ast_debug(1, "%s has another call trying, can't receive call\n",
4897 call->interface);
4898 ao2_ref(mem, -1);
4900 return 0;
4901 }
4902
4903 /*
4904 * If not found add it to the container so another queue
4905 * won't attempt to call this member at the same time.
4906 */
4907 ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4908 ao2_link(pending_members, memberp);
4910
4911 /*
4912 * The queue member is available. Get current status to be sure
4913 * because the device state and extension state callbacks may
4914 * not have updated the status yet.
4915 */
4917 ast_debug(1, "%s actually not available, can't receive call\n",
4918 call->interface);
4919 pending_members_remove(memberp);
4920 return 0;
4921 }
4922 }
4923
4924 return 1;
4925}
static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
Definition app_queue.c:4754
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition app_queue.c:2149
static int compare_weight(struct call_queue *rq, struct member *member)
Definition app_queue.c:4720
static struct ao2_container * pending_members
Definition app_queue.c:2676
static int force_longest_waiting_caller
queues.conf [general] option
Definition app_queue.c:1763
static void pending_members_remove(struct member *mem)
Definition app_queue.c:2727
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition app_queue.c:3013
static int use_weight
Records that one or more queues use weight.
Definition app_queue.c:1739
static int member_status_available(int status)
Definition app_queue.c:4831
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition astobj2.h:1063
static int call(void *data)
int status
Definition app_queue.c:1890
unsigned int ringinuse
Definition app_queue.c:1904
struct call_queue * lastqueue
Definition app_queue.c:1900
struct call_queue * parent
Definition app_queue.c:1845

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

Referenced by ring_entry().

◆ change_priority_caller_on_queue()

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

Change priority caller into a queue.

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

Definition at line 7893 of file app_queue.c.

7894{
7895 struct call_queue *q;
7896 struct queue_ent *current, *prev = NULL, *caller_qe = NULL;
7897 int res = RES_NOSUCHQUEUE;
7898
7899 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7900 * short-circuits if the queue is already in memory. */
7902 return res;
7903 }
7904
7905 ao2_lock(q);
7907 for (current = q->head; current; current = current->next) {
7908 if (strcmp(ast_channel_name(current->chan), caller) == 0) {
7909 ast_debug(1, "%s Caller new priority %d in queue %s\n",
7910 caller, priority, queuename);
7911 current->prio = priority;
7912 if (immediate) {
7913 /* This caller is being immediately moved in the queue so remove them */
7914 if (prev) {
7915 prev->next = current->next;
7916 } else {
7917 q->head = current->next;
7918 }
7920 /* The position for all callers is not recalculated in here as it will
7921 * be updated when the moved caller is inserted back into the queue
7922 */
7923 }
7924 res = RES_OKAY;
7925 break;
7926 } else if (immediate) {
7927 prev = current;
7928 }
7929 }
7930
7931 if (caller_qe) {
7932 int inserted = 0, pos = 0;
7933
7934 /* If a caller queue entry exists, we are applying their priority immediately
7935 * and have to reinsert them at the correct position.
7936 */
7937 prev = NULL;
7938 current = q->head;
7939 while (current) {
7940 if (!inserted && (caller_qe->prio > current->prio)) {
7941 insert_entry(q, prev, caller_qe, &pos);
7942 inserted = 1;
7943 }
7944
7945 /* We always update the position as it may have changed */
7946 current->pos = ++pos;
7947
7948 /* Move to the next caller in the queue */
7949 prev = current;
7950 current = current->next;
7951 }
7952
7953 if (!inserted) {
7954 insert_entry(q, prev, caller_qe, &pos);
7955 }
7956 }
7957
7958 ao2_unlock(q);
7959 return res;
7960}
#define RES_NOT_CALLER
Definition app_queue.c:1716
static void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
Insert the 'new' entry after the 'prev' entry of queue 'q'.
Definition app_queue.c:2247
static int priority
size_t current
struct queue_ent * head
Definition app_queue.c:2046
time_t start
Definition app_queue.c:1868
struct queue_ent * next
Definition app_queue.c:1876

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

Referenced by handle_queue_change_priority_caller(), and manager_change_priority_caller_on_queue().

◆ clear_queue()

static void clear_queue ( struct call_queue q)
static

Definition at line 3214 of file app_queue.c.

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, member::callcompletedinsl, member::calls, call_queue::callsabandoned, call_queue::callsabandonedinsl, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::holdtime, member::lastcall, call_queue::members, member::starttime, and call_queue::talktime.

Referenced by clear_stats(), and find_queue_by_name_rt().

◆ clear_stats()

static int clear_stats ( const char *  queuename)
static

Facilitates resetting statistics for a queue.

This function actually does not reset any statistics, but rather finds a call_queue struct which corresponds to the passed-in queue name and passes that structure to the clear_queue function. If no queuename is passed in, then all queues will have their statistics reset.

Parameters
queuenameThe name of the queue to reset the statistics for. If this is NULL or zero-length, then this means to reset the statistics for all queues
Return values
0always

Definition at line 10279 of file app_queue.c.

10280{
10281 struct call_queue *q;
10282 struct ao2_iterator queue_iter;
10283
10284 queue_iter = ao2_iterator_init(queues, 0);
10285 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10286 ao2_lock(q);
10287 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
10288 clear_queue(q);
10289 ao2_unlock(q);
10290 queue_t_unref(q, "Done with iterator");
10291 }
10292 ao2_iterator_destroy(&queue_iter);
10293 return 0;
10294}
static void clear_queue(struct call_queue *q)
Definition app_queue.c:3214

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

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

10616{
10617 struct call_queue *q;
10618 char *ret = NULL;
10619 int which = 0;
10620 int wordlen = strlen(word);
10621 struct ao2_iterator queue_iter;
10622 const char *word_list = NULL;
10623
10624 /* for certain commands, already completed items should be left out of
10625 * the list */
10626 if (word_list_offset && strlen(line) >= word_list_offset) {
10627 word_list = line + word_list_offset;
10628 }
10629
10630 queue_iter = ao2_iterator_init(queues, 0);
10631 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10632 if (!strncasecmp(word, q->name, wordlen) && ++which > state
10633 && (!word_list_offset || !word_list || !word_in_list(word_list, q->name))) {
10634 ret = ast_strdup(q->name);
10635 queue_t_unref(q, "Done with iterator");
10636 break;
10637 }
10638 queue_t_unref(q, "Done with iterator");
10639 }
10640 ao2_iterator_destroy(&queue_iter);
10641
10642 /* Pretend "rules" is at the end of the queues list in certain
10643 * circumstances since it is an alternate command that should be
10644 * tab-completable for "queue show" */
10645 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
10646 ret = ast_strdup("rules");
10647 }
10648
10649 return ret;
10650}
static int word_in_list(const char *list, const char *word)
Check if a given word is in a space-delimited list.
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
short word

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_strdup, call_queue::name, NULL, queue_t_unref, queues, and word_in_list().

Referenced by complete_queue_add_member(), complete_queue_pause_member(), complete_queue_remove_member(), complete_queue_set_member_value(), complete_queue_show(), handle_queue_reload(), and handle_queue_reset().

◆ complete_queue_add_member()

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

Definition at line 11122 of file app_queue.c.

11123{
11124 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
11125 switch (pos) {
11126 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11127 return NULL;
11128 case 4: /* only one possible match, "to" */
11129 return state == 0 ? ast_strdup("to") : NULL;
11130 case 5: /* <queue> */
11131 return complete_queue(line, word, pos, state, 0);
11132 case 6: /* only one possible match, "penalty" */
11133 return state == 0 ? ast_strdup("penalty") : NULL;
11134 case 7:
11135 if (0 <= state && state < 100) { /* 0-99 */
11136 char *num;
11137 if ((num = ast_malloc(3))) {
11138 sprintf(num, "%d", state);
11139 }
11140 return num;
11141 } else {
11142 return NULL;
11143 }
11144 case 8: /* only one possible match, "as" */
11145 return state == 0 ? ast_strdup("as") : NULL;
11146 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
11147 return NULL;
11148 default:
11149 return NULL;
11150 }
11151}
static char * complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
Check if a given word is in a space-delimited list.
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191

References ast_malloc, ast_strdup, complete_queue(), and NULL.

Referenced by handle_queue_add_member().

◆ complete_queue_pause_member()

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

Definition at line 11547 of file app_queue.c.

11548{
11549 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
11550 switch (pos) {
11551 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11552 return NULL;
11553 case 4: /* only one possible match, "queue" */
11554 return state == 0 ? ast_strdup("queue") : NULL;
11555 case 5: /* <queue> */
11556 return complete_queue(line, word, pos, state, 0);
11557 case 6: /* "reason" */
11558 return state == 0 ? ast_strdup("reason") : NULL;
11559 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
11560 return NULL;
11561 default:
11562 return NULL;
11563 }
11564}

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

11383{
11384 int which = 0;
11385 struct call_queue *q;
11386 struct member *m;
11387 struct ao2_iterator queue_iter;
11388 struct ao2_iterator mem_iter;
11389 int wordlen = strlen(word);
11390
11391 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
11392 if (pos > 5 || pos < 3) {
11393 return NULL;
11394 }
11395 if (pos == 4) { /* only one possible match, 'from' */
11396 return (state == 0 ? ast_strdup("from") : NULL);
11397 }
11398
11399 if (pos == 5) { /* No need to duplicate code */
11400 return complete_queue(line, word, pos, state, 0);
11401 }
11402
11403 /* here is the case for 3, <member> */
11404 queue_iter = ao2_iterator_init(queues, 0);
11405 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
11406 ao2_lock(q);
11407 mem_iter = ao2_iterator_init(q->members, 0);
11408 while ((m = ao2_iterator_next(&mem_iter))) {
11409 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
11410 char *tmp;
11411 tmp = ast_strdup(m->interface);
11412 ao2_ref(m, -1);
11413 ao2_iterator_destroy(&mem_iter);
11414 ao2_unlock(q);
11415 queue_t_unref(q, "Done with iterator, returning interface name");
11416 ao2_iterator_destroy(&queue_iter);
11417 return tmp;
11418 }
11419 ao2_ref(m, -1);
11420 }
11421 ao2_iterator_destroy(&mem_iter);
11422 ao2_unlock(q);
11423 queue_t_unref(q, "Done with iterator");
11424 }
11425 ao2_iterator_destroy(&queue_iter);
11426
11427 return NULL;
11428}

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

Referenced by handle_queue_remove_member().

◆ complete_queue_rule_show()

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

Definition at line 11742 of file app_queue.c.

11743{
11744 int which = 0;
11745 struct rule_list *rl_iter;
11746 int wordlen = strlen(word);
11747 char *ret = NULL;
11748 if (pos != 3) /* Wha? */ {
11749 return NULL;
11750 }
11751
11753 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11754 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11755 ret = ast_strdup(rl_iter->name);
11756 break;
11757 }
11758 }
11760
11761 return ret;
11762}
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_LOCK(head)
Locks a list.
Definition linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
char name[80]
Definition app_queue.c:2052
struct rule_list::@57 list

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

Referenced by handle_queue_rule_show().

◆ complete_queue_set_member_value()

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

Definition at line 11621 of file app_queue.c.

11622{
11623 /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
11624 switch (pos) {
11625 case 4:
11626 if (state == 0) {
11627 return ast_strdup("on");
11628 } else {
11629 return NULL;
11630 }
11631 case 6:
11632 if (state == 0) {
11633 return ast_strdup("in");
11634 } else {
11635 return NULL;
11636 }
11637 case 7:
11638 return complete_queue(line, word, pos, state, 0);
11639 default:
11640 return NULL;
11641 }
11642}

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

10653{
10654 if (pos == 2) {
10655 return complete_queue(line, word, pos, state, 0);
10656 }
10657 return NULL;
10658}

References complete_queue(), and NULL.

Referenced by queue_show().

◆ compress_char()

static int compress_char ( const char  c)
static

Definition at line 3073 of file app_queue.c.

3074{
3075 if (c < 32) {
3076 return 0;
3077 } else if (c > 96) {
3078 return c - 64;
3079 }
3080 return c - 32;
3081}
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 2940 of file app_queue.c.

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

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

Referenced by context_included(), and extension_state_cb().

◆ copy_rules()

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

Copy rule from global list into specified queue.

Definition at line 8734 of file app_queue.c.

8735{
8736 struct penalty_rule *pr_iter;
8737 struct rule_list *rl_iter;
8738 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8740 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8741 if (!strcasecmp(rl_iter->name, tmp)) {
8742 break;
8743 }
8744 }
8745 if (rl_iter) {
8746 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8747 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8748 if (!new_pr) {
8749 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8750 break;
8751 }
8752 new_pr->time = pr_iter->time;
8753 new_pr->max_value = pr_iter->max_value;
8754 new_pr->min_value = pr_iter->min_value;
8755 new_pr->raise_value = pr_iter->raise_value;
8756 new_pr->max_relative = pr_iter->max_relative;
8757 new_pr->min_relative = pr_iter->min_relative;
8758 new_pr->raise_relative = pr_iter->raise_relative;
8759 new_pr->raise_respect_min = pr_iter->raise_respect_min;
8760 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8761 }
8762 }
8764}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
const ast_string_field defaultrule
Definition app_queue.c:1987
int raise_respect_min
Definition app_queue.c:1936
struct penalty_rule::@53 list
struct queue_ent::@52 qe_rules
struct rule_list::@56 rules

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

Referenced by queue_exec().

◆ create_queue_member()

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

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

Definition at line 3028 of file app_queue.c.

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

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

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

◆ destroy_queue()

static void destroy_queue ( void *  obj)
static

Free queue's member list then its string fields.

Definition at line 3890 of file app_queue.c.

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

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

3019{
3020 struct member *mem = obj;
3021
3022 if (mem->state_id != -1) {
3024 }
3025}
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition pbx.c:3892

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

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

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

Referenced by load_module().

◆ do_hang()

static void do_hang ( struct callattempt o)
static

common hangup actions

Definition at line 4815 of file app_queue.c.

4816{
4817 o->stillgoing = 0;
4818 ast_hangup(o->chan);
4820 o->chan = NULL;
4821}
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2540
struct ast_channel * chan
Definition app_queue.c:1824
unsigned int stillgoing
Definition app_queue.c:1837

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

Referenced by ring_entry(), and wait_for_answer().

◆ do_print()

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

direct output to manager or cli with proper terminator

Definition at line 10326 of file app_queue.c.

10327{
10328 if (s) {
10329 astman_append(s, "%s\r\n", str);
10330 } else {
10331 ast_cli(fd, "%s\n", str);
10332 }
10333}
const char * str
Definition app_jack.c:150
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1921

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

Referenced by __queues_show(), and print_queue().

◆ dump_queue_members()

static void dump_queue_members ( struct call_queue pm_queue)
static

Dump all members in a specific queue to the database.

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

Definition at line 7732 of file app_queue.c.

7733{
7734 struct member *cur_member;
7735 struct ast_str *value;
7736 struct ao2_iterator mem_iter;
7737
7738 if (!pm_queue) {
7739 return;
7740 }
7741
7742 /* 4K is a reasonable default for most applications, but we grow to
7743 * accommodate more if necessary. */
7744 if (!(value = ast_str_create(4096))) {
7745 return;
7746 }
7747
7748 mem_iter = ao2_iterator_init(pm_queue->members, 0);
7749 while ((cur_member = ao2_iterator_next(&mem_iter))) {
7750 if (!cur_member->dynamic) {
7751 ao2_ref(cur_member, -1);
7752 continue;
7753 }
7754
7755 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
7756 ast_str_strlen(value) ? "|" : "",
7757 cur_member->interface,
7758 cur_member->penalty,
7759 cur_member->paused,
7760 cur_member->membername,
7761 cur_member->state_interface,
7762 cur_member->reason_paused,
7763 cur_member->wrapuptime);
7764
7765 ao2_ref(cur_member, -1);
7766 }
7767 ao2_iterator_destroy(&mem_iter);
7768
7769 if (ast_str_strlen(value) && !cur_member) {
7770 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
7771 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
7772 }
7773 } else {
7774 /* Delete the entry if the queue is empty or there is an error */
7775 ast_db_del(pm_family, pm_queue->name);
7776 }
7777
7778 ast_free(value);
7779}
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition db.c:335
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition db.c:472
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
size_t attribute_pure ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition strings.h:730
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
int value
Definition syslog.c:37

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

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

◆ end_bridge_callback()

static void end_bridge_callback ( void *  data)
static

Definition at line 7067 of file app_queue.c.

7068{
7069 struct queue_end_bridge *qeb = data;
7070 struct call_queue *q = qeb->q;
7071 struct ast_channel *chan = qeb->chan;
7072 int64_t answered_time_ms;
7073
7074 if (ao2_ref(qeb, -1) == 1) {
7075 set_queue_variables(q, chan);
7076
7077 /* Match Dial() timing variables */
7078 ast_channel_lock(chan);
7080 answered_time_ms = ast_tvdiff_ms(ast_tvnow(), qeb->start_time);
7081 set_duration_var(chan, "ANSWEREDTIME", answered_time_ms);
7082 set_duration_var(chan, "DIALEDTIME", ast_channel_get_duration_ms(chan));
7084 ast_channel_unlock(chan);
7085
7086 /* This unrefs the reference we made in try_calling when we allocated qeb */
7087 queue_t_unref(q, "Expire bridge_config reference");
7088 }
7089}
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition app_queue.c:2221
static void set_duration_var(struct ast_channel *chan, const char *var_base, int64_t duration)
Definition app_queue.c:7047
#define ast_channel_lock(chan)
Definition channel.h:2983
int64_t ast_channel_get_duration_ms(struct ast_channel *chan)
Obtain how long it's been, in milliseconds, since the channel was created.
Definition channel.c:2820
#define ast_channel_unlock(chan)
Definition channel.h:2984
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
Main Channel structure associated with a channel.
struct call_queue * q
Definition app_queue.c:7038
struct ast_channel * chan
Definition app_queue.c:7039
struct timeval start_time
Definition app_queue.c:7040
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159

References ao2_ref, ast_channel_get_duration_ms(), ast_channel_lock, ast_channel_stage_snapshot(), ast_channel_stage_snapshot_done(), ast_channel_unlock, ast_tvdiff_ms(), ast_tvnow(), queue_end_bridge::chan, queue_end_bridge::q, queue_t_unref, set_duration_var(), set_queue_variables(), and queue_end_bridge::start_time.

Referenced by try_calling().

◆ end_bridge_callback_data_fixup()

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

Definition at line 7060 of file app_queue.c.

7061{
7062 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
7063 ao2_ref(qeb, +1);
7064 qeb->chan = originator;
7065}
void * end_bridge_callback_data
Definition channel.h:1111

References ao2_ref, queue_end_bridge::chan, and ast_bridge_config::end_bridge_callback_data.

Referenced by try_calling().

◆ escape_and_substitute()

static void escape_and_substitute ( struct ast_channel chan,
const char *  input,
char *  output,
size_t  size 
)
static

Definition at line 7118 of file app_queue.c.

7120{
7121 const char *m = input;
7122 char escaped[size];
7123 char *p;
7124
7125 for (p = escaped; p < escaped + size - 1; p++, m++) {
7126 switch (*m) {
7127 case '^':
7128 if (*(m + 1) == '{') {
7129 *p = '$';
7130 }
7131 break;
7132 case ',':
7133 *p++ = '\\';
7134 /* Fall through */
7135 default:
7136 *p = *m;
7137 }
7138 if (*m == '\0')
7139 break;
7140 }
7141
7142 if (p == escaped + size) {
7143 escaped[size - 1] = '\0';
7144 }
7145
7146 pbx_substitute_variables_helper(chan, escaped, output, size - 1);
7147}
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition ael_main.c:211

References pbx_substitute_variables_helper().

Referenced by setup_mixmonitor().

◆ extension_state_cb()

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

Definition at line 2969 of file app_queue.c.

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

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

Referenced by create_queue_member(), and destroy_queue_member_cb().

◆ extensionstate2devicestate()

static int extensionstate2devicestate ( int  state)
static

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

Definition at line 2891 of file app_queue.c.

2892{
2893 switch (state) {
2896 break;
2899 break;
2900 case AST_EXTENSION_BUSY:
2902 break;
2905 break;
2908 break;
2911 break;
2914 break;
2917 break;
2920 default:
2922 break;
2923 }
2924
2925 return state;
2926}
@ AST_DEVICE_RINGINUSE
Definition devicestate.h:60
@ AST_DEVICE_ONHOLD
Definition devicestate.h:61
@ AST_DEVICE_RINGING
Definition devicestate.h:59
@ AST_DEVICE_INVALID
Definition devicestate.h:57
@ AST_DEVICE_BUSY
Definition devicestate.h:56
@ AST_DEVICE_UNAVAILABLE
Definition devicestate.h:58
@ AST_EXTENSION_REMOVED
Definition pbx.h:62
@ AST_EXTENSION_RINGING
Definition pbx.h:68
@ AST_EXTENSION_NOT_INUSE
Definition pbx.h:64
@ AST_EXTENSION_INUSE
Definition pbx.h:65
@ AST_EXTENSION_UNAVAILABLE
Definition pbx.h:67
@ AST_EXTENSION_ONHOLD
Definition pbx.h:69
@ AST_EXTENSION_BUSY
Definition pbx.h:66
@ AST_EXTENSION_DEACTIVATED
Definition pbx.h:63

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

Referenced by extension_state_cb(), and get_queue_member_status().

◆ find_best()

static struct callattempt * find_best ( struct callattempt outgoing)
static

find the entry with the best metric, or NULL

Definition at line 5073 of file app_queue.c.

5074{
5075 struct callattempt *best = NULL, *cur;
5076
5077 for (cur = outgoing; cur; cur = cur->q_next) {
5078 if (cur->stillgoing && /* Not already done */
5079 !cur->chan && /* Isn't already going */
5080 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
5081 best = cur;
5082 }
5083 }
5084
5085 return best;
5086}
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition app_queue.c:1821

References callattempt::metric, and NULL.

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

◆ find_load_queue_rt_friendly()

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

note

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

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

Definition at line 4073 of file app_queue.c.

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

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

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

◆ find_member_by_queuename_and_interface()

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

Find a member by looking up queuename and interface.

Returns
member or NULL if member not found.

Definition at line 12239 of file app_queue.c.

12240{
12241 struct member *mem = NULL;
12242 struct call_queue *q;
12243
12244 if ((q = find_load_queue_rt_friendly(queuename))) {
12245 ao2_lock(q);
12246 mem = ao2_find(q->members, interface, OBJ_KEY);
12247 ao2_unlock(q);
12248 queue_t_unref(q, "Expiring temporary reference.");
12249 }
12250 return mem;
12251}
#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 3929 of file app_queue.c.

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

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

Referenced by find_load_queue_rt_friendly().

◆ free_members()

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

Iterate through queue's member list and delete them.

Definition at line 3874 of file app_queue.c.

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

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

9309{
9310 struct member *m;
9311
9313 ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
9314 return NULL;
9315 }
9316
9318 if (!m) {
9319 ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
9320 interface, q->name);
9321 }
9322 return m;
9323}

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

8322{
8323 int foundqueue = 0, penalty;
8324 struct call_queue *q;
8325 struct member *mem;
8326
8327 if ((q = find_load_queue_rt_friendly(queuename))) {
8328 foundqueue = 1;
8329 ao2_lock(q);
8330 if ((mem = interface_exists(q, interface))) {
8331 penalty = mem->penalty;
8332 ao2_ref(mem, -1);
8333 ao2_unlock(q);
8334 queue_t_unref(q, "Search complete");
8335 return penalty;
8336 }
8337 ao2_unlock(q);
8338 queue_t_unref(q, "Search complete");
8339 }
8340
8341 /* some useful debugging */
8342 if (foundqueue) {
8343 ast_log (LOG_ERROR, "Invalid queuename\n");
8344 } else {
8345 ast_log (LOG_ERROR, "Invalid interface\n");
8346 }
8347
8348 return RESULT_FAILURE;
8349}
#define RESULT_FAILURE
Definition cli.h:42

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

Referenced by queue_function_memberpenalty_read().

◆ get_member_status()

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

Check if members are available.

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

Definition at line 2580 of file app_queue.c.

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

3014{
3015 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
3016}
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:3206

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

2150{
2151 if (member->wrapuptime) {
2152 return member->wrapuptime;
2153 }
2154 return q->wrapuptime;
2155}

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

6677{
6678 struct queue_stasis_data *queue_data = userdata;
6679 struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6680 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6681 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6682
6683 if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6685 return;
6686 }
6687
6688 ao2_lock(queue_data);
6689
6690 if (queue_data->dying) {
6691 ao2_unlock(queue_data);
6692 return;
6693 }
6694
6695 if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6696 ao2_unlock(queue_data);
6697 return;
6698 }
6699
6700 if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6701 atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6702 (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6704 ao2_unlock(queue_data);
6705 return;
6706 }
6707
6708 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6709 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6710
6711 ao2_unlock(queue_data);
6712
6713 ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6714 log_attended_transfer(queue_data, atxfer_msg);
6715
6716 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6717 queue_data->holdstart, queue_data->starttime, TRANSFER);
6718 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6719 queue_data->starttime);
6720 remove_stasis_subscriptions(queue_data);
6721}
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:6336
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition app_queue.c:6165
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition app_queue.c:6483
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition app_queue.c:6537
#define ao2_cleanup(obj)
Definition astobj2.h:1934
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition bridge.h:1104
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
@ AST_ATTENDED_TRANSFER_DEST_THREEWAY
Message representing attended transfer.
enum ast_attended_transfer_dest_type dest_type
struct ast_bridge_channel_snapshot_pair to_transfer_target
enum ast_transfer_result result
struct ast_bridge_channel_snapshot_pair to_transferee
struct ast_bridge_snapshot * bridge_snapshot
const ast_string_field uniqueid
Definition bridge.h:332
Structure representing a snapshot of channel state.
User data for stasis subscriptions used for queue calls.
Definition app_queue.c:6429
const ast_string_field caller_uniqueid
Definition app_queue.c:6437
const ast_string_field member_uniqueid
Definition app_queue.c:6437
struct call_queue * queue
Definition app_queue.c:6439
const ast_string_field bridge_uniqueid
Definition app_queue.c:6437
struct member * member
Definition app_queue.c:6441
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981

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

Referenced by setup_stasis_subs().

◆ handle_blind_transfer()

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

Handle a blind transfer event.

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

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

Definition at line 6616 of file app_queue.c.

6618{
6619 struct queue_stasis_data *queue_data = userdata;
6620 struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
6621 const char *exten;
6622 const char *context;
6623 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6624 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6625
6626 if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
6627 return;
6628 }
6629
6630 ao2_lock(queue_data);
6631
6632 if (queue_data->dying) {
6633 ao2_unlock(queue_data);
6634 return;
6635 }
6636
6637 if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
6638 strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
6639 ao2_unlock(queue_data);
6640 return;
6641 }
6642
6643 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6644 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6645
6646 ao2_unlock(queue_data);
6647
6648 exten = transfer_msg->exten;
6649 context = transfer_msg->context;
6650
6651 ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
6652 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6653 "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
6654 exten, context,
6655 (long) (queue_data->starttime - queue_data->holdstart),
6656 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6657
6658 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6659 queue_data->holdstart, queue_data->starttime, TRANSFER);
6660 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6661 queue_data->starttime);
6662 remove_stasis_subscriptions(queue_data);
6663}
Message published during a blind transfer.
char exten[AST_MAX_EXTENSION]
struct ast_bridge_snapshot * bridge
enum ast_transfer_result result
char context[AST_MAX_CONTEXT]

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

Referenced by setup_stasis_subs().

◆ handle_bridge_enter()

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

Definition at line 6583 of file app_queue.c.

6585{
6586 struct queue_stasis_data *queue_data = userdata;
6587 struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6588 SCOPED_AO2LOCK(lock, queue_data);
6589
6590 if (queue_data->dying) {
6591 return;
6592 }
6593
6594 if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6595 return;
6596 }
6597
6598 if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6599 ast_string_field_set(queue_data, bridge_uniqueid,
6600 enter_blob->bridge->uniqueid);
6601 ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6602 enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6603 }
6604}
ast_mutex_t lock
Definition app_sla.c:337
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition lock.h:611
Blob of data associated with a bridge.
struct ast_bridge_snapshot * bridge
struct ast_channel_snapshot * channel
const ast_string_field uniqueid
const ast_string_field name
struct ast_channel_snapshot_base * base

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

Referenced by setup_stasis_subs().

◆ handle_hangup()

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

Definition at line 6872 of file app_queue.c.

6874{
6875 struct queue_stasis_data *queue_data = userdata;
6876 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6877 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6878 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6879 RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
6880 enum agent_complete_reason reason;
6881
6882 ao2_lock(queue_data);
6883
6884 if (queue_data->dying) {
6885 ao2_unlock(queue_data);
6886 return;
6887 }
6888
6889 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6890 reason = CALLER;
6891 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6892 reason = AGENT;
6893 } else {
6894 ao2_unlock(queue_data);
6895 return;
6896 }
6897
6898 chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
6899 if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
6900 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
6901 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
6902 /* Channel that is hanging up is doing it as part of a transfer.
6903 * We'll get a transfer event later
6904 */
6905 ao2_unlock(queue_data);
6906 return;
6907 }
6908
6909 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6910 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6911
6912 ao2_unlock(queue_data);
6913
6914 ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
6915 channel_blob->snapshot->base->name);
6916
6917 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6918 reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
6919 (long) (queue_data->starttime - queue_data->holdstart),
6920 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6921
6922 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6923 queue_data->holdstart, queue_data->starttime, reason);
6924 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6925 queue_data->starttime);
6926 remove_stasis_subscriptions(queue_data);
6927}
agent_complete_reason
Definition app_queue.c:6329
#define AST_TRANSFERER_ROLE_NAME
int ast_channel_has_role(struct ast_channel *channel, const char *role_name)
Check if a role exists on a channel.
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition channel.c:1417
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 6749 of file app_queue.c.

6751{
6752 struct queue_stasis_data *queue_data = userdata;
6753 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6754 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6755 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6756 struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6757 struct local_optimization *optimization;
6758 unsigned int id;
6759 SCOPED_AO2LOCK(lock, queue_data);
6760
6761 if (!local_one || !local_two || !source) {
6762 ast_debug(1, "Local optimization begin missing channel snapshots:%s%s%s\n",
6763 !local_one ? " local_one," : "",
6764 !local_two ? " local_two," : "",
6765 !source ? " source," : "");
6766 return;
6767 }
6768
6769 if (queue_data->dying) {
6770 return;
6771 }
6772
6773 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6774 optimization = &queue_data->member_optimize;
6775 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6776 optimization = &queue_data->caller_optimize;
6777 } else {
6778 return;
6779 }
6780
6781 /* We only allow move-swap optimizations, so there had BETTER be a source */
6782 ast_assert(source != NULL);
6783
6784 optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6785 if (!optimization->source_chan_uniqueid) {
6786 ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6787 return;
6788 }
6790
6791 optimization->id = id;
6792 optimization->in_progress = 1;
6793}
enum queue_result id
Definition app_queue.c:1790
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
struct ast_json * ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
Retrieve the JSON blob from a ast_multi_channel_blob. Returned ast_json is still owned by obj.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition json.c:407
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition json.c:332
A multi channel blob data structure for multi_channel_blob stasis messages.
Structure representing relevant data during a local channel optimization.
Definition app_queue.c:6405
const char * source_chan_uniqueid
Definition app_queue.c:6407
unsigned int id
Definition app_queue.c:6411
struct local_optimization member_optimize
Definition app_queue.c:6459
struct local_optimization caller_optimize
Definition app_queue.c:6457
#define ast_assert(a)
Definition utils.h:779

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

Referenced by setup_stasis_subs().

◆ handle_local_optimization_end()

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

Definition at line 6808 of file app_queue.c.

6810{
6811 struct queue_stasis_data *queue_data = userdata;
6812 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6813 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6814 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6815 struct local_optimization *optimization;
6816 int is_caller;
6817 unsigned int id;
6818 SCOPED_AO2LOCK(lock, queue_data);
6819
6820 if (queue_data->dying) {
6821 return;
6822 }
6823
6824 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6825 optimization = &queue_data->member_optimize;
6826 is_caller = 0;
6827 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6828 optimization = &queue_data->caller_optimize;
6829 is_caller = 1;
6830 } else {
6831 return;
6832 }
6833
6835
6836 if (!optimization->in_progress) {
6837 ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
6838 return;
6839 }
6840
6841 if (id != optimization->id) {
6842 ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
6843 id, optimization->id);
6844 return;
6845 }
6846
6847 if (is_caller) {
6848 ast_debug(3, "Local optimization: Changing queue caller uniqueid from %s to %s\n",
6849 queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
6850 ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
6851 } else {
6852 ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
6853 queue_data->member_uniqueid, optimization->source_chan_uniqueid);
6854 ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
6855 }
6856
6857 optimization->in_progress = 0;
6858}

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

6931{
6932 struct queue_stasis_data *queue_data = userdata;
6933 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6934 const char *new_channel_id;
6935
6936 new_channel_id = ast_json_string_get(ast_json_object_get(channel_blob->blob, "newchanneluniqueid"));
6937
6938 ao2_lock(queue_data);
6939
6940 if (queue_data->dying) {
6941 ao2_unlock(queue_data);
6942 return;
6943 }
6944
6945 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6946 ast_debug(1, "Replacing caller channel %s with %s due to masquerade\n", queue_data->caller_uniqueid, new_channel_id);
6947 ast_string_field_set(queue_data, caller_uniqueid, new_channel_id);
6948 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6949 ast_debug(1, "Replacing member channel %s with %s due to masquerade\n", queue_data->member_uniqueid, new_channel_id);
6950 ast_string_field_set(queue_data, member_uniqueid, new_channel_id);
6951 }
6952
6953 ao2_unlock(queue_data);
6954}
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 11297 of file app_queue.c.

11298{
11299 const char *queuename, *interface, *membername = NULL, *state_interface = NULL, *reason = NULL;
11300 int penalty, paused = 0;
11301
11302 switch ( cmd ) {
11303 case CLI_INIT:
11304 e->command = "queue add member";
11305 e->usage =
11306 "Usage: queue add member <dial string> to <queue> [penalty <penalty> [as <membername> [state_interface <interface> [paused <reason>]]]]\n"
11307 " 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";
11308 return NULL;
11309 case CLI_GENERATE:
11310 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
11311 }
11312
11313 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12) && (a->argc != 14)) {
11314 return CLI_SHOWUSAGE;
11315 } else if (strcmp(a->argv[4], "to")) {
11316 return CLI_SHOWUSAGE;
11317 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
11318 return CLI_SHOWUSAGE;
11319 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
11320 return CLI_SHOWUSAGE;
11321 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
11322 return CLI_SHOWUSAGE;
11323 } else if ((a->argc == 14) && strcmp(a->argv[12], "paused")) {
11324 return CLI_SHOWUSAGE;
11325 }
11326
11327 queuename = a->argv[5];
11328 interface = a->argv[3];
11329 if (a->argc >= 8) {
11330 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
11331 if (penalty < 0) {
11332 ast_cli(a->fd, "Penalty must be >= 0\n");
11333 penalty = 0;
11334 }
11335 } else {
11336 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
11337 penalty = 0;
11338 }
11339 } else {
11340 penalty = 0;
11341 }
11342
11343 if (a->argc >= 10) {
11344 membername = a->argv[9];
11345 }
11346
11347 if (a->argc >= 12) {
11348 state_interface = a->argv[11];
11349 }
11350
11351 if (a->argc >= 14) {
11352 paused = 1;
11353 reason = a->argv[13];
11354 }
11355
11356 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, 0)) {
11357 case RES_OKAY:
11358 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
11359 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11360 } else {
11361 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11362 }
11363 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
11364 return CLI_SUCCESS;
11365 case RES_EXISTS:
11366 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
11367 return CLI_FAILURE;
11368 case RES_NOSUCHQUEUE:
11369 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
11370 return CLI_FAILURE;
11371 case RES_OUTOFMEMORY:
11372 ast_cli(a->fd, "Out of memory\n");
11373 return CLI_FAILURE;
11374 case RES_NOT_DYNAMIC:
11375 ast_cli(a->fd, "Member not dynamic\n");
11376 return CLI_FAILURE;
11377 default:
11378 return CLI_FAILURE;
11379 }
11380}
#define RES_NOT_DYNAMIC
Definition app_queue.c:1715
static char * complete_queue_add_member(const char *line, const char *word, int pos, int state)
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
static struct test_val a

References a, add_to_queue(), ast_cli(), ast_queue_log(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_add_member(), log_membername_as_agent, NULL, queue_persistent_members, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, and ast_cli_entry::usage.

◆ handle_queue_change_priority_caller()

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

Definition at line 11493 of file app_queue.c.

11494{
11495 const char *queuename, *caller;
11496 int priority, immediate = 0;
11497 char *res = CLI_FAILURE;
11498
11499 switch (cmd) {
11500 case CLI_INIT:
11501 e->command = "queue priority caller";
11502 e->usage =
11503 "Usage: queue priority caller <channel> on <queue> to <priority> [immediate]\n"
11504 " Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
11505 return NULL;
11506 case CLI_GENERATE:
11507 return NULL;
11508 }
11509
11510 if (a->argc < 8) {
11511 return CLI_SHOWUSAGE;
11512 } else if (strcmp(a->argv[4], "on")) {
11513 return CLI_SHOWUSAGE;
11514 } else if (strcmp(a->argv[6], "to")) {
11515 return CLI_SHOWUSAGE;
11516 } else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
11517 ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
11518 return CLI_SHOWUSAGE;
11519 } else if (a->argc == 9) {
11520 if (strcmp(a->argv[8], "immediate")) {
11521 return CLI_SHOWUSAGE;
11522 }
11523 immediate = 1;
11524 }
11525
11526 caller = a->argv[3];
11527 queuename = a->argv[5];
11528
11529 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11530 case RES_OKAY:
11531 res = CLI_SUCCESS;
11532 break;
11533 case RES_NOSUCHQUEUE:
11534 ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename);
11535 break;
11536 case RES_NOT_CALLER:
11537 ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename);
11538
11539 break;
11540 }
11541
11542 return res;
11543}
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:7893

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

11567{
11568 const char *queuename, *interface, *reason;
11569 int paused;
11570
11571 switch (cmd) {
11572 case CLI_INIT:
11573 e->command = "queue {pause|unpause} member";
11574 e->usage =
11575 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
11576 " Pause or unpause a queue member. Not specifying a particular queue\n"
11577 " will pause or unpause a member across all queues to which the member\n"
11578 " belongs.\n";
11579 return NULL;
11580 case CLI_GENERATE:
11581 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
11582 }
11583
11584 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
11585 return CLI_SHOWUSAGE;
11586 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
11587 return CLI_SHOWUSAGE;
11588 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
11589 return CLI_SHOWUSAGE;
11590 }
11591
11592
11593 interface = a->argv[3];
11594 queuename = a->argc >= 6 ? a->argv[5] : NULL;
11595 reason = a->argc == 8 ? a->argv[7] : NULL;
11596 paused = !strcasecmp(a->argv[1], "pause");
11597
11598 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
11599 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
11600 if (!ast_strlen_zero(queuename)) {
11601 ast_cli(a->fd, " in queue '%s'", queuename);
11602 }
11603 if (!ast_strlen_zero(reason)) {
11604 ast_cli(a->fd, " for reason '%s'", reason);
11605 }
11606 ast_cli(a->fd, "\n");
11607 return CLI_SUCCESS;
11608 } else {
11609 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
11610 if (!ast_strlen_zero(queuename)) {
11611 ast_cli(a->fd, " in queue '%s'", queuename);
11612 }
11613 if (!ast_strlen_zero(reason)) {
11614 ast_cli(a->fd, " for reason '%s'", reason);
11615 }
11616 ast_cli(a->fd, "\n");
11617 return CLI_FAILURE;
11618 }
11619}
static char * complete_queue_pause_member(const char *line, const char *word, int pos, int state)
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition app_queue.c:8104
#define RESULT_SUCCESS
Definition cli.h:40

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

◆ handle_queue_reload()

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

Definition at line 11838 of file app_queue.c.

11839{
11840 struct ast_flags mask = {0,};
11841 int i;
11842
11843 switch (cmd) {
11844 case CLI_INIT:
11845 e->command = "queue reload {parameters|members|rules|all}";
11846 e->usage =
11847 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
11848 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
11849 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
11850 "specified in order to know what information to reload. Below is an explanation\n"
11851 "of each of these qualifiers.\n"
11852 "\n"
11853 "\t'members' - reload queue members from queues.conf\n"
11854 "\t'parameters' - reload all queue options except for queue members\n"
11855 "\t'rules' - reload the queuerules.conf file\n"
11856 "\t'all' - reload queue rules, parameters, and members\n"
11857 "\n"
11858 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
11859 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
11860 "one queue is specified when using this command, reloading queue rules may cause\n"
11861 "other queues to be affected\n";
11862 return NULL;
11863 case CLI_GENERATE:
11864 if (a->pos >= 3) {
11865 /* find the point at which the list of queue names starts */
11866 const char *command_end = a->line + strlen("queue reload ");
11867 command_end = strchr(command_end, ' ');
11868 if (!command_end) {
11869 command_end = a->line + strlen(a->line);
11870 }
11871 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
11872 } else {
11873 return NULL;
11874 }
11875 }
11876
11877 if (a->argc < 3)
11878 return CLI_SHOWUSAGE;
11879
11880 if (!strcasecmp(a->argv[2], "rules")) {
11882 } else if (!strcasecmp(a->argv[2], "members")) {
11884 } else if (!strcasecmp(a->argv[2], "parameters")) {
11886 } else if (!strcasecmp(a->argv[2], "all")) {
11888 }
11889
11890 if (a->argc == 3) {
11891 reload_handler(1, &mask, NULL);
11892 return CLI_SUCCESS;
11893 }
11894
11895 for (i = 3; i < a->argc; ++i) {
11896 reload_handler(1, &mask, a->argv[i]);
11897 }
11898
11899 return CLI_SUCCESS;
11900}
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
#define ast_set_flag(p, flag)
Definition utils.h:71
#define AST_FLAGS_ALL
Definition utils.h:217

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

◆ handle_queue_remove_member()

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

Definition at line 11430 of file app_queue.c.

11431{
11432 const char *queuename, *interface;
11433 struct member *mem = NULL;
11434 char *res = CLI_FAILURE;
11435
11436 switch (cmd) {
11437 case CLI_INIT:
11438 e->command = "queue remove member";
11439 e->usage =
11440 "Usage: queue remove member <channel> from <queue>\n"
11441 " Remove a specific channel from a queue.\n";
11442 return NULL;
11443 case CLI_GENERATE:
11444 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
11445 }
11446
11447 if (a->argc != 6) {
11448 return CLI_SHOWUSAGE;
11449 } else if (strcmp(a->argv[4], "from")) {
11450 return CLI_SHOWUSAGE;
11451 }
11452
11453 queuename = a->argv[5];
11454 interface = a->argv[3];
11455
11457 mem = find_member_by_queuename_and_interface(queuename, interface);
11458 }
11459
11460 switch (remove_from_queue(queuename, interface)) {
11461 case RES_OKAY:
11462 if (!mem || ast_strlen_zero(mem->membername)) {
11463 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
11464 } else {
11465 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
11466 }
11467 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
11468 res = CLI_SUCCESS;
11469 break;
11470 case RES_EXISTS:
11471 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
11472 break;
11473 case RES_NOSUCHQUEUE:
11474 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
11475 break;
11476 case RES_OUTOFMEMORY:
11477 ast_cli(a->fd, "Out of memory\n");
11478 break;
11479 case RES_NOT_DYNAMIC:
11480 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
11481 break;
11482 }
11483
11484 if (mem) {
11485 ao2_ref(mem, -1);
11486 }
11487
11488 return res;
11489}
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition app_queue.c:7787
static struct member * find_member_by_queuename_and_interface(const char *queuename, const char *interface)
Find a member by looking up queuename and interface.
static char * complete_queue_remove_member(const char *line, const char *word, int pos, int state)

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

◆ handle_queue_reset()

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

Definition at line 11799 of file app_queue.c.

11800{
11801 struct ast_flags mask = {QUEUE_RESET_STATS,};
11802 int i;
11803
11804 switch (cmd) {
11805 case CLI_INIT:
11806 e->command = "queue reset stats";
11807 e->usage =
11808 "Usage: queue reset stats [<queuenames>]\n"
11809 "\n"
11810 "Issuing this command will reset statistics for\n"
11811 "<queuenames>, or for all queues if no queue is\n"
11812 "specified.\n";
11813 return NULL;
11814 case CLI_GENERATE:
11815 if (a->pos >= 3) {
11816 return complete_queue(a->line, a->word, a->pos, a->n, 17);
11817 } else {
11818 return NULL;
11819 }
11820 }
11821
11822 if (a->argc < 3) {
11823 return CLI_SHOWUSAGE;
11824 }
11825
11826 if (a->argc == 3) {
11827 reload_handler(1, &mask, NULL);
11828 return CLI_SUCCESS;
11829 }
11830
11831 for (i = 3; i < a->argc; ++i) {
11832 reload_handler(1, &mask, a->argv[i]);
11833 }
11834
11835 return CLI_SUCCESS;
11836}

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

◆ handle_queue_rule_show()

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

Definition at line 11764 of file app_queue.c.

11765{
11766 const char *rule;
11767 struct rule_list *rl_iter;
11768 struct penalty_rule *pr_iter;
11769 switch (cmd) {
11770 case CLI_INIT:
11771 e->command = "queue show rules";
11772 e->usage =
11773 "Usage: queue show rules [rulename]\n"
11774 " Show the list of rules associated with rulename. If no\n"
11775 " rulename is specified, list all rules defined in queuerules.conf\n";
11776 return NULL;
11777 case CLI_GENERATE:
11778 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
11779 }
11780
11781 if (a->argc != 3 && a->argc != 4) {
11782 return CLI_SHOWUSAGE;
11783 }
11784
11785 rule = a->argc == 4 ? a->argv[3] : "";
11787 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11788 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
11789 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
11790 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
11791 ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d, adjust QUEUE_MIN_PENALTY %s %d and adjust QUEUE_RAISE_PENALTY %s %d\n", pr_iter->time, pr_iter->max_relative ? "by" : "to", pr_iter->max_value, pr_iter->min_relative ? "by" : "to", pr_iter->min_value, pr_iter->raise_relative ? "by" : "to", pr_iter->raise_value);
11792 }
11793 }
11794 }
11796 return CLI_SUCCESS;
11797}
static char * complete_queue_rule_show(const char *line, const char *word, int pos, int state)

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

◆ handle_queue_set_member_penalty()

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

Definition at line 11701 of file app_queue.c.

11702{
11703 const char *queuename = NULL, *interface;
11704 int penalty = 0;
11705
11706 switch (cmd) {
11707 case CLI_INIT:
11708 e->command = "queue set penalty";
11709 e->usage =
11710 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
11711 " Set a member's penalty in the queue specified. If no queue is specified\n"
11712 " then that interface's penalty is set in all queues to which that interface is a member\n";
11713 return NULL;
11714 case CLI_GENERATE:
11715 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11716 }
11717
11718 if (a->argc != 6 && a->argc != 8) {
11719 return CLI_SHOWUSAGE;
11720 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11721 return CLI_SHOWUSAGE;
11722 }
11723
11724 if (a->argc == 8) {
11725 queuename = a->argv[7];
11726 }
11727 interface = a->argv[5];
11728 penalty = atoi(a->argv[3]);
11729
11730 switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
11731 case RESULT_SUCCESS:
11732 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11733 return CLI_SUCCESS;
11734 case RESULT_FAILURE:
11735 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11736 return CLI_FAILURE;
11737 default:
11738 return CLI_FAILURE;
11739 }
11740}
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition app_queue.c:8252
static char * complete_queue_set_member_value(const char *line, const char *word, int pos, int state)

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

◆ handle_queue_set_member_ringinuse()

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

Definition at line 11644 of file app_queue.c.

11645{
11646 const char *queuename = NULL, *interface;
11647 int ringinuse;
11648
11649 switch (cmd) {
11650 case CLI_INIT:
11651 e->command = "queue set ringinuse";
11652 e->usage =
11653 "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
11654 " Set a member's ringinuse in the queue specified. If no queue is specified\n"
11655 " then that interface's penalty is set in all queues to which that interface is a member.\n";
11656 break;
11657 return NULL;
11658 case CLI_GENERATE:
11659 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11660 }
11661
11662 /* Sensible argument counts */
11663 if (a->argc != 6 && a->argc != 8) {
11664 return CLI_SHOWUSAGE;
11665 }
11666
11667 /* Uses proper indicational words */
11668 if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11669 return CLI_SHOWUSAGE;
11670 }
11671
11672 /* Set the queue name if applicable */
11673 if (a->argc == 8) {
11674 queuename = a->argv[7];
11675 }
11676
11677 /* Interface being set */
11678 interface = a->argv[5];
11679
11680 /* Check and set the ringinuse value */
11681 if (ast_true(a->argv[3])) {
11682 ringinuse = 1;
11683 } else if (ast_false(a->argv[3])) {
11684 ringinuse = 0;
11685 } else {
11686 return CLI_SHOWUSAGE;
11687 }
11688
11689 switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11690 case RESULT_SUCCESS:
11691 ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11692 return CLI_SUCCESS;
11693 case RESULT_FAILURE:
11694 ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11695 return CLI_FAILURE;
11696 default:
11697 return CLI_FAILURE;
11698 }
11699}
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition utils.c:2250

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

◆ hangupcalls()

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

Hang up a list of outgoing calls.

Definition at line 4647 of file app_queue.c.

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

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

Referenced by try_calling().

◆ init_queue()

static void init_queue ( struct call_queue q)
static

Initialize Queue default values.

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

Definition at line 3112 of file app_queue.c.

3113{
3114 int i;
3115 struct penalty_rule *pr_iter;
3116
3117 q->dead = 0;
3118 q->retry = DEFAULT_RETRY;
3120 q->maxlen = 0;
3121
3122 ast_string_field_set(q, announce, "");
3123 ast_string_field_set(q, context, "");
3124 ast_string_field_set(q, membergosub, "");
3125 ast_string_field_set(q, defaultrule, "");
3126
3127 q->announcefrequency = 0;
3129 q->announceholdtime = 1;
3131 q->announcepositionlimit = 10; /* Default 10 positions */
3132 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
3133 q->roundingseconds = 0; /* Default - don't announce seconds */
3134 q->servicelevel = 0;
3135 q->ringinuse = 1;
3137 q->setinterfacevar = 0;
3138 q->setqueuevar = 0;
3139 q->setqueueentryvar = 0;
3141 q->monfmt[0] = '\0';
3142 q->reportholdtime = 0;
3143 q->wrapuptime = 0;
3144 q->penaltymemberslimit = 0;
3145 q->joinempty = 0;
3146 q->leavewhenempty = 0;
3147 q->memberdelay = 0;
3148 q->weight = 0;
3149 q->timeoutrestart = 0;
3153 q->numperiodicannounce = 0;
3156 q->autopausebusy = 0;
3157 q->autopauseunavail = 0;
3159 q->autopausedelay = 0;
3161 if (!q->members) {
3163 /* linear strategy depends on order, so we have to place all members in a list */
3165 } else {
3168 }
3169 }
3170 q->found = 1;
3171
3172 ast_string_field_set(q, moh, "");
3173 ast_string_field_set(q, sound_next, "queue-youarenext");
3174 ast_string_field_set(q, sound_thereare, "queue-thereare");
3175 ast_string_field_set(q, sound_calls, "queue-callswaiting");
3176 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3177 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3178 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3179 ast_string_field_set(q, sound_minutes, "queue-minutes");
3180 ast_string_field_set(q, sound_minute, "queue-minute");
3181 ast_string_field_set(q, sound_seconds, "queue-seconds");
3182 ast_string_field_set(q, sound_thanks, "queue-thankyou");
3183 ast_string_field_set(q, sound_callerannounce, "");
3184 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3185
3186 if (!q->sound_periodicannounce[0]) {
3188 }
3189
3190 if (q->sound_periodicannounce[0]) {
3191 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3192 }
3193
3194 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3195 if (q->sound_periodicannounce[i]) {
3196 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3197 }
3198 }
3199
3200 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3201 ast_free(pr_iter);
3202 }
3203
3204 /* On restart assume no members are available.
3205 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3206 *
3207 * This seems counter intuitive, but is required to light a BLF
3208 * AST_DEVICE_INUSE indicates no members are available.
3209 * AST_DEVICE_NOT_INUSE indicates a member is available.
3210 */
3212}
#define DEFAULT_RETRY
Definition app_queue.c:1699
static int member_hash_fn(const void *obj, const int flags)
Definition app_queue.c:3083
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition app_queue.c:3099
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition app_queue.c:1707
#define DEFAULT_TIMEOUT
Definition app_queue.c:1700
static int autofill_default
queues.conf [general] option
Definition app_queue.c:1742
#define ANNOUNCEPOSITION_YES
Definition app_queue.c:1940
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition astobj2.h:1327
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition astobj2.h:1303
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
unsigned int autopauseunavail
Definition app_queue.c:2007
unsigned int setinterfacevar
Definition app_queue.c:1993
int announcefrequency
Definition app_queue.c:2011
unsigned int announceholdtime
Definition app_queue.c:1999
unsigned int reportholdtime
Definition app_queue.c:1996
unsigned int setqueueentryvar
Definition app_queue.c:1995
unsigned int timeoutrestart
Definition app_queue.c:1998
int periodicannouncefrequency
Definition app_queue.c:2014
unsigned int announceposition_only_up
Definition app_queue.c:2001
unsigned int setqueuevar
Definition app_queue.c:1994
int announcepositionlimit
Definition app_queue.c:2010
unsigned int announce_to_first_user
Definition app_queue.c:1992
int randomperiodicannounce
Definition app_queue.c:2016
int periodicannouncestartdelay
Definition app_queue.c:2013
int log_restricted_caller_id
Definition app_queue.c:2043
int servicelevel
Definition app_queue.c:2023
int minannouncefrequency
Definition app_queue.c:2012
enum empty_conditions leavewhenempty
Definition app_queue.c:2009
int roundingseconds
Definition app_queue.c:2017
int numperiodicannounce
Definition app_queue.c:2015
unsigned int announceposition
Definition app_queue.c:2000
char monfmt[8]
Definition app_queue.c:2025
enum empty_conditions joinempty
Definition app_queue.c:2008
struct call_queue::@55 rules
int memberdelay
Definition app_queue.c:2040
unsigned int autopausebusy
Definition app_queue.c:2006
int autopausedelay
Definition app_queue.c:2035
int timeoutpriority
Definition app_queue.c:2036
unsigned int relativeperiodicannounce
Definition app_queue.c:2005

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

Referenced by find_queue_by_name_rt(), and reload_single_queue().

◆ insert_entry()

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

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

Definition at line 2247 of file app_queue.c.

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

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

Referenced by change_priority_caller_on_queue(), and join_queue().

◆ insert_penaltychange()

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

Change queue penalty by adding rule.

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

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

Definition at line 3246 of file app_queue.c.

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

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

Referenced by reload_queue_rules().

◆ int2strat()

static const char * int2strat ( int  strategy)
static

Definition at line 2080 of file app_queue.c.

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

References ARRAY_LEN, strategy::name, and strategies.

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

◆ interface_exists()

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

Definition at line 7705 of file app_queue.c.

7706{
7707 struct member *mem;
7708 struct ao2_iterator mem_iter;
7709
7710 if (!q) {
7711 return NULL;
7712 }
7713 mem_iter = ao2_iterator_init(q->members, 0);
7714 while ((mem = ao2_iterator_next(&mem_iter))) {
7715 if (!strcasecmp(interface, mem->interface)) {
7716 ao2_iterator_destroy(&mem_iter);
7717 return mem;
7718 }
7719 ao2_ref(mem, -1);
7720 }
7721 ao2_iterator_destroy(&mem_iter);
7722
7723 return NULL;
7724}

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

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

◆ is_longest_waiting_caller()

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

Definition at line 4754 of file app_queue.c.

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

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

Referenced by can_ring_entry().

◆ is_member_available()

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

Definition at line 2769 of file app_queue.c.

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

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

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

◆ is_our_turn()

static int is_our_turn ( struct queue_ent qe)
static

Check if we should start attempting to call queue members.

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

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

Definition at line 5933 of file app_queue.c.

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

References ao2_lock, ao2_unlock, ast_channel_name(), ast_debug, num_available_members(), queue_ent::start, and update_realtime_members().

Referenced by queue_exec(), and wait_our_turn().

◆ join_queue()

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

Definition at line 4237 of file app_queue.c.

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

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

Referenced by queue_exec().

◆ kill_dead_members()

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

Definition at line 10043 of file app_queue.c.

10044{
10045 struct member *member = obj;
10046
10047 if (!member->delme) {
10049 return 0;
10050 } else {
10051 return CMP_MATCH;
10052 }
10053}
@ CMP_MATCH
Definition astobj2.h:1027
unsigned int delme
Definition app_queue.c:1902

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

Referenced by reload_single_queue().

◆ kill_if_unfound()

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

Definition at line 10198 of file app_queue.c.

10199{
10200 struct call_queue *q = obj;
10201 char *queuename = arg;
10202 if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10203 q->dead = 1;
10204 return CMP_MATCH;
10205 } else {
10206 return 0;
10207 }
10208}

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

Referenced by reload_queues().

◆ leave_queue()

static void leave_queue ( struct queue_ent qe)
static

Caller leaving queue.

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

Definition at line 4550 of file app_queue.c.

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

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

Referenced by queue_exec(), and try_calling().

◆ load_module()

static int load_module ( void  )
static

Load the module.

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

Definition at line 12072 of file app_queue.c.

12073{
12074 int err = 0;
12075 struct ast_flags mask = {AST_FLAGS_ALL, };
12076 struct ast_config *member_config;
12077 struct stasis_topic *queue_topic;
12079
12082 if (!queues) {
12084 }
12085
12088 if (!pending_members) {
12089 unload_module();
12091 }
12092
12093 use_weight = 0;
12094
12095 if (reload_handler(0, &mask, NULL)) {
12096 unload_module();
12098 }
12099
12100 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, "reason_paused", RQ_CHAR, 80, SENTINEL);
12101
12102 /*
12103 * This section is used to determine which name for 'ringinuse' to use in realtime members
12104 * Necessary for supporting older setups.
12105 *
12106 * It also checks if 'reason_paused' exists in the realtime backend
12107 */
12108 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
12109 if (!member_config) {
12110 realtime_ringinuse_field = "ringinuse";
12111 } else {
12112 const char *config_val;
12113
12114 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
12115 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
12116 realtime_ringinuse_field = "ringinuse";
12117 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
12118 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
12119 realtime_ringinuse_field = "ignorebusy";
12120 } else {
12121 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
12122 realtime_ringinuse_field = "ringinuse";
12123 }
12124
12125 if (ast_variable_retrieve(member_config, NULL, "reason_paused")) {
12127 }
12128 }
12129 ast_config_destroy(member_config);
12130
12133 }
12134
12143 err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
12144 err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
12151 err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
12152 err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
12153 err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
12154 err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
12163
12164 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
12166 if (!device_state_sub) {
12167 err = -1;
12168 }
12171
12173 queue_topic = ast_queue_topic_all();
12174 if (!manager_topic || !queue_topic) {
12175 unload_module();
12177 }
12179 if (!topic_forwarder) {
12180 unload_module();
12182 }
12183
12186 unload_module();
12188 }
12190 if (!agent_router) {
12191 unload_module();
12193 }
12197 NULL);
12201 NULL);
12202
12203 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
12204 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
12205 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
12206
12207 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
12208 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
12209 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
12210 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
12211 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
12212 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
12213
12214 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
12215 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
12216 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
12217 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
12218 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
12219
12220 if (err) {
12221 unload_module();
12223 }
12225}
static struct ast_custom_function queuevar_function
Definition app_queue.c:9729
static int manager_queue_reset(struct mansession *s, const struct message *m)
static int pending_members_cmp(void *obj, void *arg, int flags)
Definition app_queue.c:2699
static struct ast_custom_function queuemembercount_function
Definition app_queue.c:9734
static struct ast_custom_function queuewaitingcount_function
Definition app_queue.c:9745
static char * app_pqm
Definition app_queue.c:1724
static struct ast_custom_function queuememberlist_function
Definition app_queue.c:9750
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition app_queue.c:1772
static int manager_add_queue_member(struct mansession *s, const struct message *m)
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition app_queue.c:8606
#define MAX_QUEUE_BUCKETS
Definition app_queue.c:1709
static int upqm_exec(struct ast_channel *chan, const char *data)
UnpauseQueueMember application.
Definition app_queue.c:8499
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6367
static char * app_ql
Definition app_queue.c:1728
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition app_queue.c:8352
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition app_queue.c:8535
#define MAX_CALL_ATTEMPT_BUCKETS
Definition app_queue.c:2677
static char * app_rqm
Definition app_queue.c:1722
static int manager_queue_rule_show(struct mansession *s, const struct message *m)
static int manager_queue_reload(struct mansession *s, const struct message *m)
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition app_queue.c:8463
static int qupd_exec(struct ast_channel *chan, const char *data)
Update Queue with data of an outgoing call.
static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
static char * app_qupd
Definition app_queue.c:1730
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
static char * app_upqm
Definition app_queue.c:1726
static struct ast_custom_function queuememberpenalty_function
Definition app_queue.c:9755
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition app_queue.c:2136
static int manager_request_withdraw_caller_from_queue(struct mansession *s, const struct message *m)
static char * app
Definition app_queue.c:1718
static int queue_hash_cb(const void *obj, const int flags)
Definition app_queue.c:2129
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition app_queue.c:8778
static int pending_members_hash(const void *obj, const int flags)
Definition app_queue.c:2679
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition app_queue.c:8700
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
static struct stasis_message_router * agent_router
static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
set a member's status based on device state of that member's interface
Definition app_queue.c:2804
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition app_queue.c:1754
static int manager_queues_summary(struct mansession *s, const struct message *m)
Summary of queue info via the AMI.
static int unload_module(void)
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
static int realtime_reason_paused
does realtime backend support reason_paused
Definition app_queue.c:1775
static char * app_aqm
Definition app_queue.c:1720
static struct ast_cli_entry cli_queue[]
static struct ast_custom_function queuegetchannel_function
Definition app_queue.c:9740
static struct stasis_forward * topic_forwarder
static struct ast_custom_function queueexists_function
Definition app_queue.c:9724
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition manager.c:450
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition manager.c:182
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
struct stasis_message_type * ast_channel_agent_logoff_type(void)
Message type for agent logoff on a channel.
struct stasis_message_type * ast_channel_agent_login_type(void)
Message type for agent login on a channel.
struct stasis_topic * ast_queue_topic_all(void)
Get the Stasis Message Bus API topic for queue messages.
Definition main/app.c:3345
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:193
#define EVENT_FLAG_AGENT
Definition manager.h:80
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640
#define ast_custom_function_register(acf)
Register a custom function.
Definition pbx.h:1563
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition stasis.h:297
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition stasis.c:1090
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition stasis.c:1144
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1493
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition stasis.c:1645
#define stasis_subscribe(topic, callback, data)
Definition stasis.h:649
#define stasis_message_router_create(topic)
Create a new message router object.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.

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

◆ load_realtime_queues()

static void load_realtime_queues ( const char *  queuename)
static

Definition at line 4134 of file app_queue.c.

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

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

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

◆ load_realtime_rules()

static int load_realtime_rules ( void  )
static

Load queue rules from realtime.

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

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

Definition at line 3355 of file app_queue.c.

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

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

Referenced by reload_queue_rules().

◆ log_attended_transfer()

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

Definition at line 6537 of file app_queue.c.

6539{
6540 RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
6541
6542 if (!transfer_str) {
6543 ast_log(LOG_WARNING, "Unable to log attended transfer to queue log\n");
6544 return;
6545 }
6546
6547 switch (atxfer_msg->dest_type) {
6549 ast_str_set(&transfer_str, 0, "BRIDGE|%s", atxfer_msg->dest.bridge);
6550 break;
6553 ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
6554 break;
6556 ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
6557 atxfer_msg->dest.links[1]->base->name);
6558 break;
6561 /* Threeways are headed off and should not be logged here */
6562 ast_assert(0);
6563 return;
6564 }
6565
6566 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
6567 ast_str_buffer(transfer_str),
6568 (long) (queue_data->starttime - queue_data->holdstart),
6569 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6570}
@ AST_ATTENDED_TRANSFER_DEST_FAIL
@ AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE
@ AST_ATTENDED_TRANSFER_DEST_LOCAL_APP
@ AST_ATTENDED_TRANSFER_DEST_LINK
@ AST_ATTENDED_TRANSFER_DEST_APP
union ast_attended_transfer_message::@301 dest
struct ast_channel_snapshot * links[2]
char bridge[AST_UUID_STR_LEN]

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

Referenced by handle_attended_transfer().

◆ manager_add_queue_member()

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

Definition at line 10917 of file app_queue.c.

10918{
10919 const char *queuename, *interface, *penalty_s, *paused_s, *reason, *membername, *state_interface, *wrapuptime_s;
10920 int paused, penalty, wrapuptime = 0;
10921
10922 queuename = astman_get_header(m, "Queue");
10923 interface = astman_get_header(m, "Interface");
10924 penalty_s = astman_get_header(m, "Penalty");
10925 paused_s = astman_get_header(m, "Paused");
10926 reason = astman_get_header(m, "Reason"); /* Optional */
10927 membername = astman_get_header(m, "MemberName");
10928 state_interface = astman_get_header(m, "StateInterface");
10929 wrapuptime_s = astman_get_header(m, "Wrapuptime");
10930
10931 if (ast_strlen_zero(queuename)) {
10932 astman_send_error(s, m, "'Queue' not specified.");
10933 return 0;
10934 }
10935
10936 if (ast_strlen_zero(interface)) {
10937 astman_send_error(s, m, "'Interface' not specified.");
10938 return 0;
10939 }
10940
10941 if (ast_strlen_zero(penalty_s)) {
10942 penalty = 0;
10943 } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
10944 penalty = 0;
10945 }
10946
10947 if (ast_strlen_zero(wrapuptime_s)) {
10948 wrapuptime = 0;
10949 } else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
10950 wrapuptime = 0;
10951 }
10952
10953 if (ast_strlen_zero(paused_s)) {
10954 paused = 0;
10955 } else {
10956 paused = abs(ast_true(paused_s));
10957 }
10958
10959 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, wrapuptime)) {
10960 case RES_OKAY:
10961 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10962 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10963 } else {
10964 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10965 }
10966 astman_send_ack(s, m, "Added interface to queue");
10967 break;
10968 case RES_EXISTS:
10969 astman_send_error(s, m, "Unable to add interface: Already there");
10970 break;
10971 case RES_NOSUCHQUEUE:
10972 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
10973 break;
10974 case RES_OUTOFMEMORY:
10975 astman_send_error(s, m, "Out of memory");
10976 break;
10977 }
10978
10979 return 0;
10980}
#define abs(x)
Definition f2c.h:195
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:2000
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition manager.c:2032
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1661

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

Referenced by load_module().

◆ manager_change_priority_caller_on_queue()

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

Definition at line 11213 of file app_queue.c.

11214{
11215 const char *queuename, *caller, *priority_s, *immediate_s;
11216 int priority = 0, immediate = 0;
11217
11218 queuename = astman_get_header(m, "Queue");
11219 caller = astman_get_header(m, "Caller");
11220 priority_s = astman_get_header(m, "Priority");
11221 immediate_s = astman_get_header(m, "Immediate");
11222
11223 if (ast_strlen_zero(queuename)) {
11224 astman_send_error(s, m, "'Queue' not specified.");
11225 return 0;
11226 }
11227
11228 if (ast_strlen_zero(caller)) {
11229 astman_send_error(s, m, "'Caller' not specified.");
11230 return 0;
11231 }
11232
11233 if (ast_strlen_zero(priority_s)) {
11234 astman_send_error(s, m, "'Priority' not specified.");
11235 return 0;
11236 } else if (sscanf(priority_s, "%30d", &priority) != 1) {
11237 astman_send_error(s, m, "'Priority' need integer.");
11238 return 0;
11239 }
11240
11241 if (!ast_strlen_zero(immediate_s)) {
11242 immediate = ast_true(immediate_s);
11243 }
11244
11245 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11246 case RES_OKAY:
11247 astman_send_ack(s, m, "Priority change for caller on queue");
11248 break;
11249 case RES_NOSUCHQUEUE:
11250 astman_send_error(s, m, "Unable to change priority caller on queue: No such queue");
11251 break;
11252 case RES_NOT_CALLER:
11253 astman_send_error(s, m, "Unable to change priority caller on queue: No such caller");
11254 break;
11255 }
11256
11257 return 0;
11258}

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

Referenced by load_module().

◆ manager_pause_queue_member()

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

Definition at line 11029 of file app_queue.c.

11030{
11031 const char *queuename, *interface, *paused_s, *reason;
11032 int paused;
11033
11034 interface = astman_get_header(m, "Interface");
11035 paused_s = astman_get_header(m, "Paused");
11036 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
11037 reason = astman_get_header(m, "Reason"); /* Optional */
11038
11039 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
11040 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
11041 return 0;
11042 }
11043
11044 paused = abs(ast_true(paused_s));
11045
11046 if (set_member_paused(queuename, interface, reason, paused)) {
11047 astman_send_error(s, m, "Interface not found");
11048 } else {
11049 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
11050 }
11051 return 0;
11052}

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

Referenced by load_module().

◆ manager_queue_log_custom()

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

Definition at line 11054 of file app_queue.c.

11055{
11056 const char *queuename, *event, *message, *interface, *uniqueid;
11057
11058 queuename = astman_get_header(m, "Queue");
11059 uniqueid = astman_get_header(m, "UniqueId");
11060 interface = astman_get_header(m, "Interface");
11061 event = astman_get_header(m, "Event");
11062 message = astman_get_header(m, "Message");
11063
11064 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
11065 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
11066 return 0;
11067 }
11068
11069 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
11070 astman_send_ack(s, m, "Event added successfully");
11071
11072 return 0;
11073}

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

Referenced by load_module().

◆ manager_queue_member_penalty()

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

Definition at line 11187 of file app_queue.c.

11188{
11189 const char *queuename, *interface, *penalty_s;
11190 int penalty;
11191
11192 interface = astman_get_header(m, "Interface");
11193 penalty_s = astman_get_header(m, "Penalty");
11194 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
11195 queuename = astman_get_header(m, "Queue");
11196
11197 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
11198 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
11199 return 0;
11200 }
11201
11202 penalty = atoi(penalty_s);
11203
11204 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
11205 astman_send_error(s, m, "Invalid interface, queuename or penalty");
11206 } else {
11207 astman_send_ack(s, m, "Interface penalty set successfully");
11208 }
11209
11210 return 0;
11211}

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

Referenced by load_module().

◆ manager_queue_member_ringinuse()

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

Definition at line 11153 of file app_queue.c.

11154{
11155 const char *queuename, *interface, *ringinuse_s;
11156 int ringinuse;
11157
11158 interface = astman_get_header(m, "Interface");
11159 ringinuse_s = astman_get_header(m, "RingInUse");
11160
11161 /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
11162 queuename = astman_get_header(m, "Queue");
11163
11164 if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
11165 astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
11166 return 0;
11167 }
11168
11169 if (ast_true(ringinuse_s)) {
11170 ringinuse = 1;
11171 } else if (ast_false(ringinuse_s)) {
11172 ringinuse = 0;
11173 } else {
11174 astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
11175 return 0;
11176 }
11177
11178 if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11179 astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
11180 } else {
11181 astman_send_ack(s, m, "Interface ringinuse set successfully");
11182 }
11183
11184 return 0;
11185}

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

Referenced by load_module().

◆ manager_queue_reload()

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

Definition at line 11075 of file app_queue.c.

11076{
11077 struct ast_flags mask = {0,};
11078 const char *queuename = NULL;
11079 int header_found = 0;
11080
11081 queuename = astman_get_header(m, "Queue");
11082 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
11084 header_found = 1;
11085 }
11086 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
11088 header_found = 1;
11089 }
11090 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
11092 header_found = 1;
11093 }
11094
11095 if (!header_found) {
11097 }
11098
11099 if (!reload_handler(1, &mask, queuename)) {
11100 astman_send_ack(s, m, "Queue reloaded successfully");
11101 } else {
11102 astman_send_error(s, m, "Error encountered while reloading queue");
11103 }
11104 return 0;
11105}

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

Referenced by load_module().

◆ manager_queue_reset()

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

Definition at line 11107 of file app_queue.c.

11108{
11109 const char *queuename = NULL;
11110 struct ast_flags mask = {QUEUE_RESET_STATS,};
11111
11112 queuename = astman_get_header(m, "Queue");
11113
11114 if (!reload_handler(1, &mask, queuename)) {
11115 astman_send_ack(s, m, "Queue stats reset successfully");
11116 } else {
11117 astman_send_error(s, m, "Error encountered while resetting queue stats");
11118 }
11119 return 0;
11120}

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

Referenced by load_module().

◆ manager_queue_rule_show()

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

Definition at line 10676 of file app_queue.c.

10677{
10678 const char *rule = astman_get_header(m, "Rule");
10679 const char *id = astman_get_header(m, "ActionID");
10680 struct rule_list *rl_iter;
10681 struct penalty_rule *pr_iter;
10682
10683 astman_append(s, "Response: Success\r\n");
10684 if (!ast_strlen_zero(id)) {
10685 astman_append(s, "ActionID: %s\r\n", id);
10686 }
10687
10689 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10690 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
10691 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
10692 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10693 astman_append(s, "Rule: %d,%s%d,%s%d\r\n", pr_iter->time, pr_iter->max_relative && pr_iter->max_value >= 0 ? "+" : "", pr_iter->max_value, pr_iter->min_relative && pr_iter->min_value >= 0 ? "+" : "", pr_iter->min_value );
10694 }
10695 if (!ast_strlen_zero(rule)) {
10696 break;
10697 }
10698 }
10699 }
10701
10702 /*
10703 * Two blank lines instead of one because the Response and
10704 * ActionID headers used to not be present.
10705 */
10706 astman_append(s, "\r\n\r\n");
10707
10708 return RESULT_SUCCESS;
10709}

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

Referenced by load_module().

◆ manager_queues_status()

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

Queue status info via AMI.

Definition at line 10794 of file app_queue.c.

10795{
10796 time_t now;
10797 int pos;
10798 int q_items = 0;
10799 const char *id = astman_get_header(m,"ActionID");
10800 const char *queuefilter = astman_get_header(m,"Queue");
10801 const char *memberfilter = astman_get_header(m,"Member");
10802 char idText[256];
10803 struct call_queue *q;
10804 struct queue_ent *qe;
10805 float sl = 0;
10806 float sl2 = 0;
10807 struct member *mem;
10808 struct ao2_iterator queue_iter;
10809 struct ao2_iterator mem_iter;
10810
10811 if (ast_check_realtime("queues")) {
10812 load_realtime_queues(queuefilter);
10813 }
10814
10815 astman_send_listack(s, m, "Queue status will follow", "start");
10816 time(&now);
10817 idText[0] = '\0';
10818 if (!ast_strlen_zero(id)) {
10819 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10820 }
10821
10822 queue_iter = ao2_iterator_init(queues, 0);
10823 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10824 ao2_lock(q);
10825
10826 /* List queue properties */
10827 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10828 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
10829 sl2 = (((q->callscompleted + q->callsabandoned) > 0) ? 100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)) : 0);
10830
10831 astman_append(s, "Event: QueueParams\r\n"
10832 "Queue: %s\r\n"
10833 "Max: %d\r\n"
10834 "Strategy: %s\r\n"
10835 "Calls: %d\r\n"
10836 "Holdtime: %d\r\n"
10837 "TalkTime: %d\r\n"
10838 "Completed: %d\r\n"
10839 "Abandoned: %d\r\n"
10840 "ServiceLevel: %d\r\n"
10841 "ServicelevelPerf: %2.1f\r\n"
10842 "ServicelevelPerf2: %2.1f\r\n"
10843 "Weight: %d\r\n"
10844 "%s"
10845 "\r\n",
10846 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
10847 q->callsabandoned, q->servicelevel, sl, sl2, q->weight, idText);
10848 ++q_items;
10849
10850 /* List Queue Members */
10851 mem_iter = ao2_iterator_init(q->members, 0);
10852 while ((mem = ao2_iterator_next(&mem_iter))) {
10853 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
10854 astman_append(s, "Event: QueueMember\r\n"
10855 "Queue: %s\r\n"
10856 "Name: %s\r\n"
10857 "Location: %s\r\n"
10858 "StateInterface: %s\r\n"
10859 "Membership: %s\r\n"
10860 "Penalty: %d\r\n"
10861 "CallsTaken: %d\r\n"
10862 "LastCall: %d\r\n"
10863 "LastPause: %d\r\n"
10864 "LoginTime: %d\r\n"
10865 "InCall: %d\r\n"
10866 "Status: %d\r\n"
10867 "Paused: %d\r\n"
10868 "PausedReason: %s\r\n"
10869 "Wrapuptime: %d\r\n"
10870 "%s"
10871 "\r\n",
10872 q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
10873 mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, (int)mem->logintime, mem->starttime ? 1 : 0, mem->status,
10874 mem->paused, mem->reason_paused, mem->wrapuptime, idText);
10875 ++q_items;
10876 }
10877 ao2_ref(mem, -1);
10878 }
10879 ao2_iterator_destroy(&mem_iter);
10880
10881 /* List Queue Entries */
10882 pos = 1;
10883 for (qe = q->head; qe; qe = qe->next) {
10884 astman_append(s, "Event: QueueEntry\r\n"
10885 "Queue: %s\r\n"
10886 "Position: %d\r\n"
10887 "Channel: %s\r\n"
10888 "Uniqueid: %s\r\n"
10889 "CallerIDNum: %s\r\n"
10890 "CallerIDName: %s\r\n"
10891 "ConnectedLineNum: %s\r\n"
10892 "ConnectedLineName: %s\r\n"
10893 "Wait: %ld\r\n"
10894 "Priority: %d\r\n"
10895 "%s"
10896 "\r\n",
10897 q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
10902 (long) (now - qe->start), qe->prio, idText);
10903 ++q_items;
10904 }
10905 }
10906 ao2_unlock(q);
10907 queue_t_unref(q, "Done with iterator");
10908 }
10909 ao2_iterator_destroy(&queue_iter);
10910
10911 astman_send_list_complete_start(s, m, "QueueStatusComplete", q_items);
10913
10914 return RESULT_SUCCESS;
10915}
static void load_realtime_queues(const char *queuename)
Definition app_queue.c:4134
static const char * int2strat(int strategy)
Definition app_queue.c:2080
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition manager.c:2042
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition manager.c:2078
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2086
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
struct ast_party_id id
Caller party ID.
Definition channel.h:422
struct ast_party_id id
Connected party ID.
Definition channel.h:460
struct ast_party_name name
Subscriber name.
Definition channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition channel.h:281
char * str
Subscriber name (Malloced)
Definition channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition channel.h:299
char * str
Subscriber phone number (Malloced)
Definition channel.h:293

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

Referenced by load_module().

◆ manager_queues_summary()

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

Summary of queue info via the AMI.

Definition at line 10712 of file app_queue.c.

10713{
10714 time_t now;
10715 int qmemcount = 0;
10716 int qmemavail = 0;
10717 int qchancount = 0;
10718 int qlongestholdtime = 0;
10719 int qsummaries = 0;
10720 const char *id = astman_get_header(m, "ActionID");
10721 const char *queuefilter = astman_get_header(m, "Queue");
10722 char idText[256];
10723 struct call_queue *q;
10724 struct queue_ent *qe;
10725 struct member *mem;
10726 struct ao2_iterator queue_iter;
10727 struct ao2_iterator mem_iter;
10728
10729 if (ast_check_realtime("queues")) {
10730 load_realtime_queues(queuefilter);
10731 }
10732
10733 astman_send_listack(s, m, "Queue summary will follow", "start");
10734 time(&now);
10735 idText[0] = '\0';
10736 if (!ast_strlen_zero(id)) {
10737 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10738 }
10739 queue_iter = ao2_iterator_init(queues, 0);
10740 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10741 ao2_lock(q);
10742
10743 /* List queue properties */
10744 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10745 /* Reset the necessary local variables if no queuefilter is set*/
10746 qmemcount = 0;
10747 qmemavail = 0;
10748 qchancount = 0;
10749 qlongestholdtime = 0;
10750
10751 /* List Queue Members */
10752 mem_iter = ao2_iterator_init(q->members, 0);
10753 while ((mem = ao2_iterator_next(&mem_iter))) {
10754 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
10755 ++qmemcount;
10756 if (member_status_available(mem->status) && !mem->paused) {
10757 ++qmemavail;
10758 }
10759 }
10760 ao2_ref(mem, -1);
10761 }
10762 ao2_iterator_destroy(&mem_iter);
10763 for (qe = q->head; qe; qe = qe->next) {
10764 if ((now - qe->start) > qlongestholdtime) {
10765 qlongestholdtime = now - qe->start;
10766 }
10767 ++qchancount;
10768 }
10769 astman_append(s, "Event: QueueSummary\r\n"
10770 "Queue: %s\r\n"
10771 "LoggedIn: %d\r\n"
10772 "Available: %d\r\n"
10773 "Callers: %d\r\n"
10774 "HoldTime: %d\r\n"
10775 "TalkTime: %d\r\n"
10776 "LongestHoldTime: %d\r\n"
10777 "%s"
10778 "\r\n",
10779 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
10780 ++qsummaries;
10781 }
10782 ao2_unlock(q);
10783 queue_t_unref(q, "Done with iterator");
10784 }
10785 ao2_iterator_destroy(&queue_iter);
10786
10787 astman_send_list_complete_start(s, m, "QueueSummaryComplete", qsummaries);
10789
10790 return RESULT_SUCCESS;
10791}

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

Referenced by load_module().

◆ manager_remove_queue_member()

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

Definition at line 10982 of file app_queue.c.

10983{
10984 const char *queuename, *interface;
10985 struct member *mem = NULL;
10986
10987 queuename = astman_get_header(m, "Queue");
10988 interface = astman_get_header(m, "Interface");
10989
10990 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
10991 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
10992 return 0;
10993 }
10994
10996 mem = find_member_by_queuename_and_interface(queuename, interface);
10997 }
10998
10999 switch (remove_from_queue(queuename, interface)) {
11000 case RES_OKAY:
11001 if (!mem || ast_strlen_zero(mem->membername)) {
11002 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
11003 } else {
11004 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
11005 }
11006 astman_send_ack(s, m, "Removed interface from queue");
11007 break;
11008 case RES_EXISTS:
11009 astman_send_error(s, m, "Unable to remove interface: Not there");
11010 break;
11011 case RES_NOSUCHQUEUE:
11012 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
11013 break;
11014 case RES_OUTOFMEMORY:
11015 astman_send_error(s, m, "Out of memory");
11016 break;
11017 case RES_NOT_DYNAMIC:
11018 astman_send_error(s, m, "Member not dynamic");
11019 break;
11020 }
11021
11022 if (mem) {
11023 ao2_ref(mem, -1);
11024 }
11025
11026 return 0;
11027}

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

Referenced by load_module().

◆ manager_request_withdraw_caller_from_queue()

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

Definition at line 11260 of file app_queue.c.

11261{
11262 const char *queuename, *caller, *withdraw_info;
11263
11264 queuename = astman_get_header(m, "Queue");
11265 caller = astman_get_header(m, "Caller");
11266 withdraw_info = astman_get_header(m, "WithdrawInfo");
11267
11268 if (ast_strlen_zero(queuename)) {
11269 astman_send_error(s, m, "'Queue' not specified.");
11270 return 0;
11271 }
11272
11273 if (ast_strlen_zero(caller)) {
11274 astman_send_error(s, m, "'Caller' not specified.");
11275 return 0;
11276 }
11277
11278 switch (request_withdraw_caller_from_queue(queuename, caller, withdraw_info)) {
11279 case RES_OKAY:
11280 astman_send_ack(s, m, "Withdraw requested successfully");
11281 break;
11282 case RES_NOSUCHQUEUE:
11283 astman_send_error(s, m, "Unable to request withdraw from queue: No such queue");
11284 break;
11285 case RES_NOT_CALLER:
11286 astman_send_error(s, m, "Unable to request withdraw from queue: No such caller");
11287 break;
11288 case RES_EXISTS:
11289 astman_send_error(s, m, "Unable to request withdraw from queue: Already requested");
11290 break;
11291 }
11292
11293 return 0;
11294}
static int request_withdraw_caller_from_queue(const char *queuename, const char *caller, const char *withdraw_info)
Request to withdraw a caller from a queue.
Definition app_queue.c:7969

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

Referenced by load_module().

◆ mark_member_dead()

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

Definition at line 10034 of file app_queue.c.

10035{
10036 struct member *member = obj;
10037 if (!member->dynamic && !member->realtime) {
10038 member->delme = 1;
10039 }
10040 return 0;
10041}

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

Referenced by reload_single_queue().

◆ mark_unfound()

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

Definition at line 10188 of file app_queue.c.

10189{
10190 struct call_queue *q = obj;
10191 char *queuename = arg;
10192 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10193 q->found = 0;
10194 }
10195 return 0;
10196}

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

Referenced by reload_queues().

◆ member_add_to_queue()

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

◆ member_cmp_fn()

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

Definition at line 3099 of file app_queue.c.

3100{
3101 struct member *mem1 = obj1;
3102 struct member *mem2 = obj2;
3103 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
3104
3105 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
3106}
@ CMP_STOP
Definition astobj2.h:1028

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

Referenced by init_queue().

◆ member_hash_fn()

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

Definition at line 3083 of file app_queue.c.

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

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

Referenced by init_queue().

◆ member_remove_from_queue()

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

Definition at line 3740 of file app_queue.c.

3741{
3743 ao2_lock(queue->members);
3746 ao2_unlink(queue->members, mem);
3747 ao2_unlock(queue->members);
3748}
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition app_queue.c:2200
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition app_queue.c:3716
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition astobj2.h:1578

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

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

◆ member_status_available()

static int member_status_available ( int  status)
static

Definition at line 4831 of file app_queue.c.

4832{
4834}

References AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, and status.

Referenced by can_ring_entry(), and manager_queues_summary().

◆ num_available_members()

static int num_available_members ( struct call_queue q)
static

Get the number of members available to accept a call.

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

Definition at line 4687 of file app_queue.c.

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

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

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

◆ parse_empty_options()

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

Definition at line 3467 of file app_queue.c.

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

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

Referenced by queue_set_param().

◆ pending_members_cmp()

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

Definition at line 2699 of file app_queue.c.

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

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

Referenced by load_module().

◆ pending_members_hash()

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

Definition at line 2679 of file app_queue.c.

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

References ast_assert, ast_str_case_hash(), member::interface, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, and OBJ_SEARCH_OBJECT.

Referenced by load_module().

◆ pending_members_remove()

static void pending_members_remove ( struct member mem)
static

Definition at line 2727 of file app_queue.c.

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

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

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

◆ play_file()

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

Definition at line 4321 of file app_queue.c.

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

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

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

◆ pqm_exec()

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

PauseQueueMember application.

Definition at line 8463 of file app_queue.c.

8464{
8465 char *parse;
8467 AST_APP_ARG(queuename);
8468 AST_APP_ARG(interface);
8470 AST_APP_ARG(reason);
8471 );
8472
8473 if (ast_strlen_zero(data)) {
8474 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
8475 return -1;
8476 }
8477
8478 parse = ast_strdupa(data);
8479
8481
8482 if (ast_strlen_zero(args.interface)) {
8483 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
8484 return -1;
8485 }
8486
8487 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
8488 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
8489 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
8490 return 0;
8491 }
8492
8493 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
8494
8495 return 0;
8496}

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

Referenced by load_module().

◆ print_queue()

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

Print a single queue to AMI or the CLI.

Definition at line 10336 of file app_queue.c.

10337{
10338 float sl;
10339 float sl2;
10340 struct ao2_iterator mem_iter;
10341 struct ast_str *out = ast_str_alloca(512);
10342 time_t now = time(NULL);
10343
10344 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
10345 if (q->maxlen) {
10346 ast_str_append(&out, 0, "%d", q->maxlen);
10347 } else {
10348 ast_str_append(&out, 0, "unlimited");
10349 }
10350 sl = 0;
10351 sl2 = 0;
10352 if (q->callscompleted > 0) {
10353 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
10354 }
10355 if (q->callscompleted + q->callsabandoned > 0) {
10356 sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted));
10357 }
10358
10359 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%%, SL2:%2.1f%% within %ds",
10361 do_print(s, fd, ast_str_buffer(out));
10362 if (!ao2_container_count(q->members)) {
10363 do_print(s, fd, " No Members");
10364 } else {
10365 struct member *mem;
10366
10367 do_print(s, fd, " Members: ");
10368 mem_iter = ao2_iterator_init(q->members, 0);
10369 while ((mem = ao2_iterator_next(&mem_iter))) {
10370 ast_str_set(&out, 0, " %s", mem->membername);
10371 if (strcasecmp(mem->membername, mem->interface)) {
10372 ast_str_append(&out, 0, " (%s", mem->interface);
10374 && strcmp(mem->state_interface, mem->interface)) {
10375 ast_str_append(&out, 0, " from %s", mem->state_interface);
10376 }
10377 ast_str_append(&out, 0, ")");
10378 }
10379 if (mem->penalty) {
10380 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
10381 }
10382
10383 ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
10384
10385 ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s",
10386 mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
10387 mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
10388 mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
10389
10390 if (mem->paused) {
10391 ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
10393 ast_strlen_zero(mem->reason_paused) ? "" : ":",
10395 (long) (now - mem->lastpause),
10396 ast_term_reset());
10397 }
10398
10399 ast_str_append(&out, 0, " (%s%s%s)",
10404 if (mem->calls) {
10405 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
10406 mem->calls, (long) (now - mem->lastcall));
10407 } else {
10408 ast_str_append(&out, 0, " has taken no calls yet");
10409 }
10410 ast_str_append(&out, 0, " %s(login was %ld secs ago)%s",
10412 (long) (now - mem->logintime),
10413 ast_term_reset());
10414 do_print(s, fd, ast_str_buffer(out));
10415 ao2_ref(mem, -1);
10416 }
10417 ao2_iterator_destroy(&mem_iter);
10418 }
10419 if (!q->head) {
10420 do_print(s, fd, " No Callers");
10421 } else {
10422 struct queue_ent *qe;
10423 int pos = 1;
10424
10425 do_print(s, fd, " Callers: ");
10426 for (qe = q->head; qe; qe = qe->next) {
10427 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
10428 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
10429 (long) (now - qe->start) % 60, qe->prio);
10430 do_print(s, fd, ast_str_buffer(out));
10431 }
10432 }
10433 do_print(s, fd, ""); /* blank line between entries */
10434}
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition term.c:357
#define COLOR_CYAN
Definition term.h:62
#define COLOR_MAGENTA
Definition term.h:60
#define COLOR_BROWN
Definition term.h:56
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition term.c:341
#define COLOR_BLACK
Definition term.h:50
#define COLOR_RED
Definition term.h:52
#define COLOR_GREEN
Definition term.h:54

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

Referenced by __queues_show().

◆ publish_dial_end_event()

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

Definition at line 4635 of file app_queue.c.

4636{
4637 struct callattempt *cur;
4638
4639 for (cur = outgoing; cur; cur = cur->q_next) {
4640 if (cur->chan && cur->chan != exception) {
4642 }
4643 }
4644}
struct callattempt * q_next
Definition app_queue.c:1822
FILE * in
Definition utils/frame.c:33

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

Referenced by ring_entry(), and wait_for_answer().

◆ publish_queue_member_pause()

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

Definition at line 8008 of file app_queue.c.

8009{
8010 struct ast_json *json_blob = queue_member_blob_create(q, member);
8011
8012 if (!json_blob) {
8013 return -1;
8014 }
8015
8016 queue_publish_member_blob(queue_member_pause_type(), json_blob);
8017
8018 return 0;
8019}

References queue_member_blob_create(), and queue_publish_member_blob().

Referenced by set_queue_member_pause().

◆ ql_exec()

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

QueueLog application.

Definition at line 8700 of file app_queue.c.

8701{
8702 char *parse;
8703
8705 AST_APP_ARG(queuename);
8706 AST_APP_ARG(uniqueid);
8707 AST_APP_ARG(membername);
8709 AST_APP_ARG(params);
8710 );
8711
8712 if (ast_strlen_zero(data)) {
8713 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
8714 return -1;
8715 }
8716
8717 parse = ast_strdupa(data);
8718
8720
8721 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
8722 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
8723 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
8724 return -1;
8725 }
8726
8727 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
8728 "%s", args.params ? args.params : "");
8729
8730 return 0;
8731}

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

Referenced by load_module().

◆ queue_agent_called_to_ami()

static struct ast_manager_event_blob * queue_agent_called_to_ami ( struct stasis_message message)
static

Definition at line 2422 of file app_queue.c.

2423{
2424 return queue_multi_channel_to_ami("AgentCalled", message);
2425}
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition app_queue.c:2381

References queue_multi_channel_to_ami().

◆ queue_agent_cb()

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

Definition at line 6367 of file app_queue.c.

6369{
6370 struct ast_channel_blob *agent_blob;
6371
6372 agent_blob = stasis_message_data(msg);
6373
6375 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6376 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6377 "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
6379 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6380 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6381 "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
6382 (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
6383 }
6384}

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

Referenced by load_module().

◆ queue_agent_complete_to_ami()

static struct ast_manager_event_blob * queue_agent_complete_to_ami ( struct stasis_message message)
static

Definition at line 2432 of file app_queue.c.

2433{
2434 return queue_multi_channel_to_ami("AgentComplete", message);
2435}

References queue_multi_channel_to_ami().

◆ queue_agent_connect_to_ami()

static struct ast_manager_event_blob * queue_agent_connect_to_ami ( struct stasis_message message)
static

Definition at line 2427 of file app_queue.c.

2428{
2429 return queue_multi_channel_to_ami("AgentConnect", message);
2430}

References queue_multi_channel_to_ami().

◆ queue_agent_dump_to_ami()

static struct ast_manager_event_blob * queue_agent_dump_to_ami ( struct stasis_message message)
static

Definition at line 2437 of file app_queue.c.

2438{
2439 return queue_multi_channel_to_ami("AgentDump", message);
2440}

References queue_multi_channel_to_ami().

◆ queue_agent_ringnoanswer_to_ami()

static struct ast_manager_event_blob * queue_agent_ringnoanswer_to_ami ( struct stasis_message message)
static

Definition at line 2442 of file app_queue.c.

2443{
2444 return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2445}

References queue_multi_channel_to_ami().

◆ queue_bridge_cb()

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

Definition at line 6730 of file app_queue.c.

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

References ao2_cleanup, stasis_subscription_final_message(), and sub.

Referenced by setup_stasis_subs().

◆ queue_caller_abandon_to_ami()

static struct ast_manager_event_blob * queue_caller_abandon_to_ami ( struct stasis_message message)
static

Definition at line 2302 of file app_queue.c.

2303{
2304 return queue_channel_to_ami("QueueCallerAbandon", message);
2305}
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition app_queue.c:2273

References queue_channel_to_ami().

◆ queue_caller_join_to_ami()

static struct ast_manager_event_blob * queue_caller_join_to_ami ( struct stasis_message message)
static

Definition at line 2292 of file app_queue.c.

2293{
2294 return queue_channel_to_ami("QueueCallerJoin", message);
2295}

References queue_channel_to_ami().

◆ queue_caller_leave_to_ami()

static struct ast_manager_event_blob * queue_caller_leave_to_ami ( struct stasis_message message)
static

Definition at line 2297 of file app_queue.c.

2298{
2299 return queue_channel_to_ami("QueueCallerLeave", message);
2300}

References queue_channel_to_ami().

◆ queue_channel_cb()

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

Definition at line 6963 of file app_queue.c.

6965{
6967 ao2_cleanup(userdata);
6968 }
6969}

References ao2_cleanup, stasis_subscription_final_message(), and sub.

Referenced by setup_stasis_subs().

◆ queue_channel_to_ami()

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

Definition at line 2273 of file app_queue.c.

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

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

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

◆ queue_cmp_cb()

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

Definition at line 2136 of file app_queue.c.

2137{
2138 struct call_queue *q = obj, *q2 = arg;
2139 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
2140}

References CMP_MATCH, CMP_STOP, and call_queue::name.

Referenced by load_module().

◆ queue_delme_members_decrement_followers()

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

Definition at line 2182 of file app_queue.c.

2183{
2184 struct member *mem = obj;
2185 struct call_queue *queue = arg;
2186 int rrpos = mem->queuepos;
2187
2188 if (mem->delme) {
2190 }
2191
2192 return 0;
2193}
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition app_queue.c:2163
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
@ OBJ_MULTIPLE
Definition astobj2.h:1049

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

Referenced by reload_single_queue().

◆ queue_exec()

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

The starting point for all queue calls.

The process involved here is to

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

Definition at line 8778 of file app_queue.c.

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

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

Referenced by load_module().

◆ queue_function_exists()

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

Check if a given queue exists.

Definition at line 9289 of file app_queue.c.

9290{
9291 struct call_queue *q;
9292
9293 buf[0] = '\0';
9294
9295 if (ast_strlen_zero(data)) {
9296 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9297 return -1;
9298 }
9300 snprintf(buf, len, "%d", q != NULL? 1 : 0);
9301 if (q) {
9302 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
9303 }
9304
9305 return 0;
9306}
char buf[BUFSIZE]
Definition eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)

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

◆ queue_function_mem_read()

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

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

Get or set member properties penalty / paused / ringinuse

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

Definition at line 9331 of file app_queue.c.

9332{
9333 int count = 0;
9334 struct member *m;
9335 struct ao2_iterator mem_iter;
9336 struct call_queue *q;
9337
9339 AST_APP_ARG(queuename);
9340 AST_APP_ARG(option);
9341 AST_APP_ARG(interface);
9342 );
9343 /* Make sure the returned value on error is zero length string. */
9344 buf[0] = '\0';
9345
9346 if (ast_strlen_zero(data)) {
9348 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9349 cmd);
9350 return -1;
9351 }
9352
9354
9355 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) {
9357 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9358 cmd);
9359 return -1;
9360 }
9361
9362 if ((q = find_load_queue_rt_friendly(args.queuename))) {
9363 ao2_lock(q);
9364 if (!strcasecmp(args.option, "logged")) {
9365 mem_iter = ao2_iterator_init(q->members, 0);
9366 while ((m = ao2_iterator_next(&mem_iter))) {
9367 /* Count the agents who are logged in and presently answering calls */
9368 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9369 count++;
9370 }
9371 ao2_ref(m, -1);
9372 }
9373 ao2_iterator_destroy(&mem_iter);
9374 } else if (!strcasecmp(args.option, "free")) {
9375 mem_iter = ao2_iterator_init(q->members, 0);
9376 while ((m = ao2_iterator_next(&mem_iter))) {
9377 /* Count the agents who are logged in and presently answering calls */
9378 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
9379 count++;
9380 }
9381 ao2_ref(m, -1);
9382 }
9383 ao2_iterator_destroy(&mem_iter);
9384 } else if (!strcasecmp(args.option, "ready")) {
9385 time_t now;
9386 time(&now);
9387 mem_iter = ao2_iterator_init(q->members, 0);
9388 while ((m = ao2_iterator_next(&mem_iter))) {
9389 /* Count the agents who are logged in, not paused and not wrapping up */
9390 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
9391 !(m->lastcall && get_wrapuptime(q, m) && ((now - get_wrapuptime(q, m)) < m->lastcall))) {
9392 count++;
9393 }
9394 ao2_ref(m, -1);
9395 }
9396 ao2_iterator_destroy(&mem_iter);
9397 } else if (!strcasecmp(args.option, "count")) {
9399 } else if (!strcasecmp(args.option, "penalty")) {
9400 m = get_interface_helper(q, args.interface);
9401 if (m) {
9402 count = m->penalty;
9403 ao2_ref(m, -1);
9404 }
9405 } else if (!strcasecmp(args.option, "paused")) {
9406 m = get_interface_helper(q, args.interface);
9407 if (m) {
9408 count = m->paused;
9409 ao2_ref(m, -1);
9410 }
9411 } else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9412 || !strcasecmp(args.option, "ringinuse"))) {
9413 m = get_interface_helper(q, args.interface);
9414 if (m) {
9415 count = m->ringinuse;
9416 ao2_ref(m, -1);
9417 }
9418 } else {
9419 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9420 }
9421 ao2_unlock(q);
9422 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
9423 } else {
9424 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9425 }
9426
9427 snprintf(buf, len, "%d", count);
9428
9429 return 0;
9430}
static struct member * get_interface_helper(struct call_queue *q, const char *interface)
Definition app_queue.c:9308

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

◆ queue_function_mem_write()

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

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

Definition at line 9433 of file app_queue.c.

9434{
9435 int memvalue;
9436
9438 AST_APP_ARG(queuename);
9439 AST_APP_ARG(option);
9440 AST_APP_ARG(interface);
9441 );
9442
9443 if (ast_strlen_zero(data)) {
9445 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9446 cmd);
9447 return -1;
9448 }
9449
9451
9452 if (ast_strlen_zero(args.option)
9453 || ast_strlen_zero(args.interface)) {
9455 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9456 cmd);
9457 return -1;
9458 }
9459
9460 /*
9461 * If queuename is empty then the option will be
9462 * set for the interface in all queues.
9463 */
9464
9465 memvalue = atoi(value);
9466 if (!strcasecmp(args.option, "penalty")) {
9467 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
9468 ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
9469 return -1;
9470 }
9471 } else if (!strcasecmp(args.option, "paused")) {
9472 memvalue = (memvalue <= 0) ? 0 : 1;
9473 if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
9474 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9475 return -1;
9476 }
9477 } else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9478 || !strcasecmp(args.option, "ringinuse")) {
9479 memvalue = (memvalue <= 0) ? 0 : 1;
9480 if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
9481 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9482 return -1;
9483 }
9484 } else {
9485 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9486 return -1;
9487 }
9488 return 0;
9489}

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

◆ queue_function_memberpenalty_read()

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

Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.

Definition at line 9656 of file app_queue.c.

9657{
9658 int penalty;
9660 AST_APP_ARG(queuename);
9661 AST_APP_ARG(interface);
9662 );
9663 /* Make sure the returned value on error is NULL. */
9664 buf[0] = '\0';
9665
9666 if (ast_strlen_zero(data)) {
9667 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9668 return -1;
9669 }
9670
9672
9673 if (args.argc < 2) {
9674 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9675 return -1;
9676 }
9677
9678 penalty = get_member_penalty (args.queuename, args.interface);
9679
9680 if (penalty >= 0) { /* remember that buf is already '\0' */
9681 snprintf (buf, len, "%d", penalty);
9682 }
9683
9684 return 0;
9685}
static int get_member_penalty(char *queuename, char *interface)
Gets members penalty.
Definition app_queue.c:8321

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

◆ queue_function_memberpenalty_write()

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

Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.

Definition at line 9688 of file app_queue.c.

9689{
9690 int penalty;
9692 AST_APP_ARG(queuename);
9693 AST_APP_ARG(interface);
9694 );
9695
9696 if (ast_strlen_zero(data)) {
9697 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9698 return -1;
9699 }
9700
9702
9703 if (args.argc < 2) {
9704 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9705 return -1;
9706 }
9707
9708 penalty = atoi(value);
9709
9710 if (ast_strlen_zero(args.interface)) {
9711 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9712 return -1;
9713 }
9714
9715 /* if queuename = NULL then penalty will be set for interface in all the queues. */
9716 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9717 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9718 return -1;
9719 }
9720
9721 return 0;
9722}

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

◆ queue_function_queuegetchannel()

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

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

Definition at line 9492 of file app_queue.c.

9493{
9494 int position;
9495 char *parse;
9496 struct call_queue *q;
9497 struct ast_variable *var;
9498
9500 AST_APP_ARG(queuename);
9501 AST_APP_ARG(position);
9502 );
9503
9504 buf[0] = '\0';
9505
9506 if (ast_strlen_zero(data)) {
9507 ast_log(LOG_ERROR, "Missing argument. QUEUE_GET_CHANNEL(<queuename>,<position>)\n");
9508 return -1;
9509 }
9510
9511 parse = ast_strdupa(data);
9513
9514 if (ast_strlen_zero(args.queuename)) {
9515 ast_log (LOG_ERROR, "The <queuename> parameter is required.\n");
9516 return -1;
9517 }
9518
9519 if (ast_strlen_zero(args.position)) {
9520 position = 1;
9521 } else {
9522 if (sscanf(args.position, "%30d", &position) != 1) {
9523 ast_log (LOG_ERROR, "<position> parameter must be an integer.\n");
9524 return -1;
9525 }
9526 if (position < 1) {
9527 ast_log (LOG_ERROR, "<position> parameter must be an integer greater than zero.\n");
9528 return -1;
9529 }
9530 }
9531
9532 {
9533 struct call_queue tmpq = {
9534 .name = args.queuename,
9535 };
9536
9537 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_GET_CHANNEL()");
9538 }
9539 if (q) {
9540 ao2_lock(q);
9541 if (q->count >= position) {
9542 struct queue_ent *qe;
9543
9544 for (qe = q->head; qe; qe = qe->next) {
9545 if (qe->pos == position) {
9547 break;
9548 }
9549 }
9550 }
9551 ao2_unlock(q);
9552 queue_t_unref(q, "Done with reference in QUEUE_GET_CHANNEL()");
9553 return 0;
9554 }
9555
9556 var = ast_load_realtime("queues", "name", args.queuename, SENTINEL);
9557 if (var) {
9558 /* if the queue is realtime but was not found in memory, this
9559 * means that the queue had been deleted from memory since it was
9560 * "dead."
9561 */
9563 return 0;
9564 }
9565
9566 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9567 return 0;
9568}

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

◆ queue_function_queuememberlist()

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

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

Definition at line 9608 of file app_queue.c.

9609{
9610 struct call_queue *q;
9611 struct member *m;
9612
9613 /* Ensure an otherwise empty list doesn't return garbage */
9614 buf[0] = '\0';
9615
9616 if (ast_strlen_zero(data)) {
9617 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
9618 return -1;
9619 }
9620
9621 if ((q = find_load_queue_rt_friendly(data))) {
9622 int buflen = 0, count = 0;
9623 struct ao2_iterator mem_iter;
9624
9625 ao2_lock(q);
9626 mem_iter = ao2_iterator_init(q->members, 0);
9627 while ((m = ao2_iterator_next(&mem_iter))) {
9628 /* strcat() is always faster than printf() */
9629 if (count++) {
9630 strncat(buf + buflen, ",", len - buflen - 1);
9631 buflen++;
9632 }
9633 strncat(buf + buflen, m->interface, len - buflen - 1);
9634 buflen += strlen(m->interface);
9635 /* Safeguard against overflow (negative length) */
9636 if (buflen >= len - 2) {
9637 ao2_ref(m, -1);
9638 ast_log(LOG_WARNING, "Truncating list\n");
9639 break;
9640 }
9641 ao2_ref(m, -1);
9642 }
9643 ao2_iterator_destroy(&mem_iter);
9644 ao2_unlock(q);
9645 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
9646 } else
9647 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9648
9649 /* We should already be terminated, but let's make sure. */
9650 buf[len - 1] = '\0';
9651
9652 return 0;
9653}

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

◆ queue_function_queuewaitingcount()

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

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

Definition at line 9571 of file app_queue.c.

9572{
9573 int count = 0;
9574 struct call_queue *q, tmpq = {
9575 .name = data,
9576 };
9577 struct ast_variable *var = NULL;
9578
9579 buf[0] = '\0';
9580
9581 if (ast_strlen_zero(data)) {
9582 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
9583 return -1;
9584 }
9585
9586 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
9587 ao2_lock(q);
9588 count = q->count;
9589 ao2_unlock(q);
9590 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
9591 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
9592 /* if the queue is realtime but was not found in memory, this
9593 * means that the queue had been deleted from memory since it was
9594 * "dead." This means it has a 0 waiting count
9595 */
9596 count = 0;
9598 } else {
9599 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9600 }
9601
9602 snprintf(buf, len, "%d", count);
9603
9604 return 0;
9605}

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

◆ queue_function_var()

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

create interface var with all queue details.

Return values
0on success
-1on error

Definition at line 9245 of file app_queue.c.

9246{
9247 int res = -1;
9248 struct call_queue *q;
9249 char interfacevar[256] = "";
9250 float sl = 0;
9251
9252 if (ast_strlen_zero(data)) {
9253 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9254 return -1;
9255 }
9256
9257 if ((q = find_load_queue_rt_friendly(data))) {
9258 ao2_lock(q);
9259 if (q->setqueuevar) {
9260 sl = 0;
9261 res = 0;
9262
9263 if (q->callscompleted > 0) {
9264 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
9265 }
9266
9267 snprintf(interfacevar, sizeof(interfacevar),
9268 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
9270
9271 pbx_builtin_setvar_multiple(chan, interfacevar);
9272 }
9273
9274 ao2_unlock(q);
9275 queue_t_unref(q, "Done with QUEUE() function");
9276 } else {
9277 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9278 }
9279
9280 snprintf(buf, len, "%d", res);
9281
9282 return 0;
9283}
int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *data)
Parse and set multiple channel variables, where the pairs are separated by the ',' character,...

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

◆ queue_hash_cb()

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

Definition at line 2129 of file app_queue.c.

2130{
2131 const struct call_queue *q = obj;
2132
2133 return ast_str_case_hash(q->name);
2134}

References ast_str_case_hash(), and call_queue::name.

Referenced by load_module().

◆ queue_member_added_to_ami()

static struct ast_manager_event_blob * queue_member_added_to_ami ( struct stasis_message message)
static

Definition at line 2337 of file app_queue.c.

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

References queue_member_to_ami().

◆ queue_member_blob_create()

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

Definition at line 2553 of file app_queue.c.

2554{
2555 return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: s, s: i, s: i}",
2556 "Queue", q->name,
2557 "MemberName", mem->membername,
2558 "Interface", mem->interface,
2559 "StateInterface", mem->state_interface,
2560 "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
2561 "Penalty", mem->penalty,
2562 "CallsTaken", mem->calls,
2563 "LastCall", (int)mem->lastcall,
2564 "LastPause", (int)mem->lastpause,
2565 "LoginTime", (int)mem->logintime,
2566 "InCall", mem->starttime ? 1 : 0,
2567 "Status", mem->status,
2568 "Paused", mem->paused,
2569 "PausedReason", mem->reason_paused,
2570 "Ringinuse", mem->ringinuse,
2571 "Wrapuptime", mem->wrapuptime);
2572}

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

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

◆ queue_member_decrement_followers()

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

Definition at line 2163 of file app_queue.c.

2164{
2165 struct member *mem = obj;
2166 int *decrement_followers_after = arg;
2167
2168 if (mem->queuepos > *decrement_followers_after) {
2169 mem->queuepos--;
2170 }
2171
2172 return 0;
2173}

References member::queuepos.

Referenced by queue_delme_members_decrement_followers(), and queue_member_follower_removal().

◆ queue_member_follower_removal()

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

Definition at line 2200 of file app_queue.c.

2201{
2202 int pos = mem->queuepos;
2203
2204 /* If the position being removed is less than the current place in the queue, reduce the queue position by one so that we don't skip the member
2205 * who would have been next otherwise. */
2206 if (pos < queue->rrpos) {
2207 queue->rrpos--;
2208 }
2209
2211}

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

Referenced by member_remove_from_queue().

◆ queue_member_pause_to_ami()

static struct ast_manager_event_blob * queue_member_pause_to_ami ( struct stasis_message message)
static

Definition at line 2347 of file app_queue.c.

2348{
2349 return queue_member_to_ami("QueueMemberPause", message);
2350}

References queue_member_to_ami().

◆ queue_member_penalty_to_ami()

static struct ast_manager_event_blob * queue_member_penalty_to_ami ( struct stasis_message message)
static

Definition at line 2352 of file app_queue.c.

2353{
2354 return queue_member_to_ami("QueueMemberPenalty", message);
2355}

References queue_member_to_ami().

◆ queue_member_removed_to_ami()

static struct ast_manager_event_blob * queue_member_removed_to_ami ( struct stasis_message message)
static

Definition at line 2342 of file app_queue.c.

2343{
2344 return queue_member_to_ami("QueueMemberRemoved", message);
2345}

References queue_member_to_ami().

◆ queue_member_ringinuse_to_ami()

static struct ast_manager_event_blob * queue_member_ringinuse_to_ami ( struct stasis_message message)
static

Definition at line 2357 of file app_queue.c.

2358{
2359 return queue_member_to_ami("QueueMemberRinginuse", message);
2360}

References queue_member_to_ami().

◆ queue_member_status_to_ami()

static struct ast_manager_event_blob * queue_member_status_to_ami ( struct stasis_message message)
static

Definition at line 2332 of file app_queue.c.

2333{
2334 return queue_member_to_ami("QueueMemberStatus", message);
2335}

References queue_member_to_ami().

◆ queue_member_to_ami()

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

◆ queue_multi_channel_to_ami()

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

Definition at line 2381 of file app_queue.c.

2382{
2385 struct ast_channel_snapshot *agent;
2386 RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2387 RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2388 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2389
2391 if (caller) {
2392 caller_event_string = ast_manager_build_channel_state_string(caller);
2393 if (!caller_event_string) {
2394 ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2395 return NULL;
2396 }
2397 }
2398
2399 agent = ast_multi_channel_blob_get_channel(obj, "agent");
2400 if (agent) {
2401 agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2402 if (!agent_event_string) {
2403 ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2404 return NULL;
2405 }
2406 }
2407
2409 if (!event_string) {
2410 return NULL;
2411 }
2412
2414 "%s"
2415 "%s"
2416 "%s",
2417 caller_event_string ? ast_str_buffer(caller_event_string) : "",
2418 agent_event_string ? ast_str_buffer(agent_event_string) : "",
2419 ast_str_buffer(event_string));
2420}
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
struct ast_channel_snapshot_caller * caller

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

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

◆ queue_publish_member_blob()

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

Definition at line 2529 of file app_queue.c.

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

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

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

◆ queue_publish_multi_channel_blob()

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

Definition at line 2498 of file app_queue.c.

2500{
2501 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2502 RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2503
2504 ast_channel_lock(caller);
2505 caller_snapshot = ast_channel_snapshot_create(caller);
2506 ast_channel_unlock(caller);
2507 ast_channel_lock(agent);
2508 agent_snapshot = ast_channel_snapshot_create(agent);
2509 ast_channel_unlock(agent);
2510
2511 if (!caller_snapshot || !agent_snapshot) {
2512 return;
2513 }
2514
2516 agent_snapshot, type, blob);
2517}
static void queue_publish_multi_channel_snapshot_blob(struct stasis_topic *topic, struct ast_channel_snapshot *caller_snapshot, struct ast_channel_snapshot *agent_snapshot, struct stasis_message_type *type, struct ast_json *blob)
Definition app_queue.c:2463
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate.

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

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

◆ queue_publish_multi_channel_snapshot_blob()

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

Definition at line 2463 of file app_queue.c.

2467{
2468 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
2469 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2470
2471 if (!type) {
2472 return;
2473 }
2474
2475 payload = ast_multi_channel_blob_create(blob);
2476 if (!payload) {
2477 return;
2478 }
2479
2480 if (caller_snapshot) {
2481 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
2482 } else {
2483 ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
2484 }
2485
2486 if (agent_snapshot) {
2487 ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
2488 }
2489
2490 msg = stasis_message_create(type, payload);
2491 if (!msg) {
2492 return;
2493 }
2494
2495 stasis_publish(topic, msg);
2496}
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.

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

Referenced by queue_publish_multi_channel_blob(), and send_agent_complete().

◆ queue_reset_global_params()

static void queue_reset_global_params ( void  )
static

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

Definition at line 9841 of file app_queue.c.

9842{
9844 autofill_default = 0;
9845 montype_default = 0;
9846 shared_lastcall = 0;
9851}
static int montype_default
queues.conf [general] option
Definition app_queue.c:1745
static int negative_penalty_invalid
queues.conf [general] option
Definition app_queue.c:1757
static int shared_lastcall
queues.conf [general] option
Definition app_queue.c:1748
static int log_unpause_on_reason_change
queues.conf [general] option
Definition app_queue.c:1769

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

Referenced by reload_queues().

◆ queue_rules_reset_global_params()

static void queue_rules_reset_global_params ( void  )
static

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

Definition at line 9762 of file app_queue.c.

9763{
9764 realtime_rules = 0;
9765}
static int realtime_rules
queuerules.conf [general] option
Definition app_queue.c:1751

References realtime_rules.

Referenced by reload_queue_rules().

◆ queue_rules_set_global_params()

static void queue_rules_set_global_params ( struct ast_config cfg)
static

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

Definition at line 9768 of file app_queue.c.

9769{
9770 const char *general_val = NULL;
9771 if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9772 realtime_rules = ast_true(general_val);
9773 }
9774}

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

Referenced by reload_queue_rules().

◆ queue_set_global_params()

static void queue_set_global_params ( struct ast_config cfg)
static

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

Definition at line 9854 of file app_queue.c.

9855{
9856 const char *general_val = NULL;
9857 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
9858 queue_persistent_members = ast_true(general_val);
9859 }
9860 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
9861 autofill_default = ast_true(general_val);
9862 }
9863 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
9864 if (!strcasecmp(general_val, "mixmonitor"))
9865 montype_default = 1;
9866 }
9867 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
9868 shared_lastcall = ast_true(general_val);
9869 }
9870 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
9871 negative_penalty_invalid = ast_true(general_val);
9872 }
9873 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
9874 log_membername_as_agent = ast_true(general_val);
9875 }
9876 if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
9877 if (!strcasecmp(general_val, "prio")) {
9879 } else if (ast_true(general_val)) {
9881 } else {
9883 }
9884 }
9885 if ((general_val = ast_variable_retrieve(cfg, "general", "log_unpause_on_reason_change"))) {
9887 }
9888 /* Apply log-caller-id-name in the same place as other global settings */
9889 if ((general_val = ast_variable_retrieve(cfg, "general", "log-caller-id-name"))) {
9890 log_caller_id_name = ast_true(general_val);
9891 }
9892}
#define FORCELONGESTWAITINGCALLER_YES
Definition app_queue.c:1946
#define FORCELONGESTWAITINGCALLER_NO
Definition app_queue.c:1945

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

Referenced by reload_queues().

◆ queue_set_param()

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

Configure a queue parameter.

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

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

Definition at line 3510 of file app_queue.c.

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

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

Referenced by find_queue_by_name_rt(), and reload_single_queue().

◆ queue_show()

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

Definition at line 10660 of file app_queue.c.

10661{
10662 switch ( cmd ) {
10663 case CLI_INIT:
10664 e->command = "queue show";
10665 e->usage =
10666 "Usage: queue show\n"
10667 " Provides summary information on a specified queue.\n";
10668 return NULL;
10669 case CLI_GENERATE:
10670 return complete_queue_show(a->line, a->word, a->pos, a->n);
10671 }
10672
10673 return __queues_show(NULL, a->fd, a->argc, a->argv);
10674}
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
static char * __queues_show(struct mansession *s, int fd, int argc, const char *const *argv)
Show queue(s) status and statistics.

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

◆ queue_stasis_data_alloc()

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

Definition at line 6498 of file app_queue.c.

6501{
6502 struct queue_stasis_data *queue_data;
6503
6504 queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
6505 if (!queue_data) {
6506 return NULL;
6507 }
6508
6509 if (ast_string_field_init(queue_data, 64)) {
6510 ao2_cleanup(queue_data);
6511 return NULL;
6512 }
6513
6516 queue_data->queue = queue_ref(qe->parent);
6517 queue_data->starttime = starttime;
6518 queue_data->holdstart = holdstart;
6520 queue_data->caller_pos = qe->opos;
6521 ao2_ref(mem, +1);
6522 queue_data->member = mem;
6523
6524 return queue_data;
6525}
static void queue_stasis_data_destructor(void *obj)
Definition app_queue.c:6466

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

Referenced by setup_stasis_subs().

◆ queue_stasis_data_destructor()

static void queue_stasis_data_destructor ( void *  obj)
static

Definition at line 6466 of file app_queue.c.

6467{
6468 struct queue_stasis_data *queue_data = obj;
6469
6470 /* This can only happen if refcounts for this object have got severely messed up */
6471 ast_assert(queue_data->bridge_router == NULL);
6472 ast_assert(queue_data->channel_router == NULL);
6473
6474 ao2_cleanup(queue_data->member);
6475 queue_unref(queue_data->queue);
6476 ast_string_field_free_memory(queue_data);
6477}
struct stasis_message_router * channel_router
Definition app_queue.c:6455
struct stasis_message_router * bridge_router
Definition app_queue.c:6453

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

Referenced by queue_stasis_data_alloc().

◆ qupd_exec()

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

Update Queue with data of an outgoing call.

Definition at line 11905 of file app_queue.c.

11906{
11907 int oldtalktime;
11908 char *parse;
11909 struct call_queue *q;
11910 struct member *mem;
11911 int newtalktime = 0;
11912
11914 AST_APP_ARG(queuename);
11915 AST_APP_ARG(uniqueid);
11916 AST_APP_ARG(agent);
11918 AST_APP_ARG(talktime);
11919 AST_APP_ARG(params););
11920
11921 if (ast_strlen_zero(data)) {
11922 ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n");
11923 return -1;
11924 }
11925
11926 parse = ast_strdupa(data);
11927
11929
11930 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) {
11931 ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n");
11932 return -1;
11933 }
11934
11935 if (!ast_strlen_zero(args.talktime)) {
11936 newtalktime = atoi(args.talktime);
11937 }
11938
11939 q = find_load_queue_rt_friendly(args.queuename);
11940 if (!q) {
11941 ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename);
11942 return 0;
11943 }
11944
11945 ao2_lock(q);
11946 if (q->members) {
11947 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
11948 while ((mem = ao2_iterator_next(&mem_iter))) {
11949 if (!strcasecmp(mem->membername, args.agent)) {
11950 if (!strcasecmp(args.status, "ANSWER")) {
11951 oldtalktime = q->talktime;
11952 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
11953 time(&mem->lastcall);
11954 mem->calls++;
11955 mem->lastqueue = q;
11956 q->callscompleted++;
11957
11958 if (newtalktime <= q->servicelevel) {
11959 q->callscompletedinsl++;
11960 }
11961 } else {
11962
11963 time(&mem->lastcall);
11964 q->callsabandoned++;
11965 }
11966
11967 ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params);
11968 }
11969
11970 ao2_ref(mem, -1);
11971 }
11972
11973 ao2_iterator_destroy(&mem_iter);
11974 }
11975
11976 ao2_unlock(q);
11977 queue_t_unref(q, "Done with temporary pointer");
11978
11979 return 0;
11980}

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

Referenced by load_module().

◆ recalc_holdtime()

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

Definition at line 4527 of file app_queue.c.

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

References ao2_lock, ao2_unlock, and queue_ent::start.

Referenced by try_calling().

◆ record_abandoned()

static void record_abandoned ( struct queue_ent qe)
static

Record that a caller gave up on waiting in queue.

Definition at line 5267 of file app_queue.c.

5268{
5269 int callabandonedinsl = 0;
5270 time_t now;
5271
5272 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5273
5274 pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE");
5275
5277 ao2_lock(qe->parent);
5278 blob = ast_json_pack("{s: s, s: i, s: i, s: i}",
5279 "Queue", qe->parent->name,
5280 "Position", qe->pos,
5281 "OriginalPosition", qe->opos,
5282 "HoldTime", (int)(time(NULL) - qe->start));
5283
5284
5285 time(&now);
5286 callabandonedinsl = ((now - qe->start) <= qe->parent->servicelevel);
5287 if (callabandonedinsl) {
5289 }
5290
5291 qe->parent->callsabandoned++;
5292 ao2_unlock(qe->parent);
5293
5294 ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
5295}

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

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

◆ reload()

static int reload ( void  )
static

Definition at line 12227 of file app_queue.c.

12228{
12229 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
12230 ast_unload_realtime("queue_members");
12231 reload_handler(1, &mask, NULL);
12232 return 0;
12233}
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.

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

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

◆ reload_handler()

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

The command center for all reload operations.

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

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

Definition at line 10309 of file app_queue.c.

10310{
10311 int res = 0;
10312
10313 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
10314 res |= reload_queue_rules(reload);
10315 }
10316 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
10317 res |= clear_stats(queuename);
10318 }
10320 res |= reload_queues(reload, mask, queuename);
10321 }
10322 return res;
10323}
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition app_queue.c:9782
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
static int reload(void)

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

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

◆ reload_queue_members()

static void reload_queue_members ( void  )
static

Reload dynamic queue members persisted into the astdb.

Definition at line 8352 of file app_queue.c.

8353{
8354 char *cur_ptr;
8355 const char *queue_name;
8356 char *member;
8357 char *interface;
8358 char *membername = NULL;
8359 char *state_interface;
8360 char *penalty_tok;
8361 int penalty = 0;
8362 char *paused_tok;
8363 int paused = 0;
8364 char *wrapuptime_tok;
8365 int wrapuptime = 0;
8366 char *reason_paused;
8367 struct ast_db_entry *db_tree;
8368 struct ast_db_entry *entry;
8369 struct call_queue *cur_queue;
8370 char *queue_data;
8371
8372 /* Each key in 'pm_family' is the name of a queue */
8373 db_tree = ast_db_gettree(pm_family, NULL);
8374 for (entry = db_tree; entry; entry = entry->next) {
8375
8376 queue_name = entry->key + strlen(pm_family) + 2;
8377
8378 {
8379 struct call_queue tmpq = {
8380 .name = queue_name,
8381 };
8382 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
8383 }
8384
8385 if (!cur_queue) {
8386 cur_queue = find_load_queue_rt_friendly(queue_name);
8387 }
8388
8389 if (!cur_queue) {
8390 /* If the queue no longer exists, remove it from the
8391 * database */
8392 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
8393 ast_db_del(pm_family, queue_name);
8394 continue;
8395 }
8396
8397 if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
8398 queue_t_unref(cur_queue, "Expire reload reference");
8399 continue;
8400 }
8401
8402 cur_ptr = queue_data;
8403 while ((member = strsep(&cur_ptr, ",|"))) {
8404 if (ast_strlen_zero(member)) {
8405 continue;
8406 }
8407
8408 interface = strsep(&member, ";");
8409 penalty_tok = strsep(&member, ";");
8410 paused_tok = strsep(&member, ";");
8411 membername = strsep(&member, ";");
8412 state_interface = strsep(&member, ";");
8413 reason_paused = strsep(&member, ";");
8414 wrapuptime_tok = strsep(&member, ";");
8415
8416 if (!penalty_tok) {
8417 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
8418 break;
8419 }
8420 penalty = strtol(penalty_tok, NULL, 10);
8421 if (errno == ERANGE) {
8422 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
8423 break;
8424 }
8425
8426 if (!paused_tok) {
8427 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
8428 break;
8429 }
8430 paused = strtol(paused_tok, NULL, 10);
8431 if ((errno == ERANGE) || paused < 0 || paused > 1) {
8432 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
8433 break;
8434 }
8435
8436 if (!ast_strlen_zero(wrapuptime_tok)) {
8437 wrapuptime = strtol(wrapuptime_tok, NULL, 10);
8438 if (errno == ERANGE) {
8439 ast_log(LOG_WARNING, "Error converting wrapuptime: %s: Out of range.\n", wrapuptime_tok);
8440 break;
8441 }
8442 }
8443
8444 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s Wrapuptime: %d\n",
8445 queue_name, interface, membername, penalty, paused, reason_paused, wrapuptime);
8446
8447 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused, wrapuptime) == RES_OUTOFMEMORY) {
8448 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
8449 break;
8450 }
8451 }
8452 queue_t_unref(cur_queue, "Expire reload reference");
8453 ast_free(queue_data);
8454 }
8455
8456 if (db_tree) {
8457 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
8458 ast_db_freetree(db_tree);
8459 }
8460}
int ast_db_get_allocated(const char *family, const char *key, char **out)
Get key value specified by family/key as a heap allocated string.
Definition db.c:431
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
Definition db.c:635
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition db.c:695
int errno
Definition astdb.h:31
struct ast_db_entry * next
Definition astdb.h:32
char * key
Definition astdb.h:33

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

Referenced by load_module().

◆ reload_queue_rules()

static int reload_queue_rules ( int  reload)
static

Reload the rules defined in queuerules.conf.

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

Definition at line 9782 of file app_queue.c.

9783{
9784 struct ast_config *cfg;
9785 struct rule_list *rl_iter, *new_rl;
9786 struct penalty_rule *pr_iter;
9787 char *rulecat = NULL;
9788 struct ast_variable *rulevar = NULL;
9789 struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9790
9791 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
9792 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
9794 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9795 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
9797 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9798 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
9800 }
9801
9803 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
9804 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
9805 ast_free(pr_iter);
9806 ast_free(rl_iter);
9807 }
9809 while ((rulecat = ast_category_browse(cfg, rulecat))) {
9810 if (!strcasecmp(rulecat, "general")) {
9812 continue;
9813 }
9814 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
9816 ast_config_destroy(cfg);
9818 } else {
9819 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
9820 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
9821 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
9822 if(!strcasecmp(rulevar->name, "penaltychange"))
9823 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
9824 else
9825 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
9826 }
9827 }
9828
9829 ast_config_destroy(cfg);
9830
9834 }
9835
9838}
static int load_realtime_rules(void)
Load queue rules from realtime.
Definition app_queue.c:3355
static void queue_rules_reset_global_params(void)
Definition app_queue.c:9762
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition app_queue.c:3246
static void queue_rules_set_global_params(struct ast_config *cfg)
Definition app_queue.c:9768
#define ast_config_load(filename, flags)
Load a config file.
#define CONFIG_STATUS_FILEUNCHANGED
@ CONFIG_FLAG_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition extconf.c:1213

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

Referenced by reload_handler().

◆ reload_queues()

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

reload the queues.conf file

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

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

Definition at line 10222 of file app_queue.c.

10223{
10224 struct ast_config *cfg;
10225 char *cat;
10226 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
10227 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
10228
10229 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
10230 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
10231 return -1;
10232 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
10233 return 0;
10234 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
10235 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
10236 return -1;
10237 }
10238
10239 /* We've made it here, so it looks like we're doing operations on all queues. */
10241
10242 /* Mark non-realtime queues not found at the beginning. */
10243 ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
10244
10245 /* Chug through config file. */
10246 cat = NULL;
10248 while ((cat = ast_category_browse(cfg, cat)) ) {
10249 if (!strcasecmp(cat, "general") && queue_reload) {
10251 continue;
10252 }
10253 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
10254 reload_single_queue(cfg, mask, cat);
10255 }
10256
10257 ast_config_destroy(cfg);
10258 if (queue_reload) {
10259 /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
10261 }
10263 return 0;
10264}
static void queue_reset_global_params(void)
Definition app_queue.c:9841
static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
Reload information pertaining to a particular queue.
static void queue_set_global_params(struct ast_config *cfg)
Definition app_queue.c:9854
static int mark_unfound(void *obj, void *arg, int flags)
static int kill_if_unfound(void *obj, void *arg, int flags)

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

Referenced by reload_handler().

◆ reload_single_member()

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

reload information pertaining to a single member

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

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

Definition at line 9902 of file app_queue.c.

9903{
9904 char *membername, *interface, *state_interface, *tmp;
9905 char *parse;
9906 struct member *cur, *newm;
9907 struct member tmpmem;
9908 int penalty;
9909 int ringinuse;
9910 int wrapuptime;
9911 int paused;
9920 );
9921
9922 if (ast_strlen_zero(memberdata)) {
9923 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
9924 return;
9925 }
9926
9927 /* Add a new member */
9928 parse = ast_strdupa(memberdata);
9929
9931
9932 interface = args.interface;
9933 if (!ast_strlen_zero(args.penalty)) {
9934 tmp = args.penalty;
9935 ast_strip(tmp);
9936 penalty = atoi(tmp);
9937 if (penalty < 0) {
9938 penalty = 0;
9939 }
9940 } else {
9941 penalty = 0;
9942 }
9943
9944 if (!ast_strlen_zero(args.membername)) {
9945 membername = args.membername;
9946 ast_strip(membername);
9947 } else {
9948 membername = interface;
9949 }
9950
9951 if (!ast_strlen_zero(args.state_interface)) {
9952 state_interface = args.state_interface;
9953 ast_strip(state_interface);
9954 } else {
9955 state_interface = interface;
9956 }
9957
9958 if (!ast_strlen_zero(args.ringinuse)) {
9959 tmp = args.ringinuse;
9960 ast_strip(tmp);
9961 if (ast_true(tmp)) {
9962 ringinuse = 1;
9963 } else if (ast_false(tmp)) {
9964 ringinuse = 0;
9965 } else {
9966 ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n",
9967 membername, q->name);
9968 ringinuse = q->ringinuse;
9969 }
9970 } else {
9971 ringinuse = q->ringinuse;
9972 }
9973
9974 if (!ast_strlen_zero(args.wrapuptime)) {
9975 tmp = args.wrapuptime;
9976 ast_strip(tmp);
9977 wrapuptime = atoi(tmp);
9978 if (wrapuptime < 0) {
9979 wrapuptime = 0;
9980 }
9981 } else {
9982 wrapuptime = 0;
9983 }
9984
9985 if (!ast_strlen_zero(args.paused)) {
9986 tmp = args.paused;
9987 ast_strip(tmp);
9988 if (ast_true(tmp)) {
9989 paused = 1;
9990 } else if (ast_false(tmp)) {
9991 paused = 0;
9992 } else {
9993 ast_log(LOG_ERROR, "Member %s has an invalid paused value.\n", membername);
9994 paused = 0;
9995 }
9996 } else {
9997 paused = 0;
9998 }
9999
10000 /* Find the old position in the list */
10001 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
10002 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
10003
10004 if (cur) {
10005 paused = cur->paused;
10006 }
10007
10008 if ((newm = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
10009 newm->wrapuptime = wrapuptime;
10010 if (cur) {
10011 ao2_lock(q->members);
10012 /* Round Robin Queue Position must be copied if this is replacing an existing member */
10013 newm->queuepos = cur->queuepos;
10014 /* Don't reset agent stats either */
10015 newm->calls = cur->calls;
10016 newm->lastcall = cur->lastcall;
10017
10018 ao2_link(q->members, newm);
10019 ao2_unlink(q->members, cur);
10020 ao2_unlock(q->members);
10021 } else {
10022 /* Otherwise we need to add using the function that will apply a round robin queue position manually. */
10023 member_add_to_queue(q, newm);
10024 }
10025 ao2_ref(newm, -1);
10026 }
10027 newm = NULL;
10028
10029 if (cur) {
10030 ao2_ref(cur, -1);
10031 }
10032}

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

Referenced by reload_single_queue().

◆ reload_single_queue()

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

Reload information pertaining to a particular queue.

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

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

Definition at line 10065 of file app_queue.c.

10066{
10067 int new;
10068 struct call_queue *q = NULL;
10069 struct member *member;
10070 /*We're defining a queue*/
10071 struct call_queue tmpq = {
10072 .name = queuename,
10073 };
10074 const char *tmpvar;
10075 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
10076 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
10077 int prev_weight = 0;
10078 struct ast_variable *var;
10079 struct ao2_iterator mem_iter;
10080
10081 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
10082 if (queue_reload) {
10083 /* Make one then */
10084 if (!(q = alloc_queue(queuename))) {
10085 return;
10086 }
10087 } else {
10088 /* Since we're not reloading queues, this means that we found a queue
10089 * in the configuration file which we don't know about yet. Just return.
10090 */
10091 return;
10092 }
10093 new = 1;
10094 } else {
10095 new = 0;
10096 }
10097
10098 if (!new) {
10099 ao2_lock(q);
10100 prev_weight = q->weight ? 1 : 0;
10101 }
10102 /* Check if we already found a queue with this name in the config file */
10103 if (q->found) {
10104 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
10105 if (!new) {
10106 /* It should be impossible to *not* hit this case*/
10107 ao2_unlock(q);
10108 }
10109 queue_t_unref(q, "We exist! Expiring temporary pointer");
10110 return;
10111 }
10112 /* Due to the fact that the "linear" strategy will have a different allocation
10113 * scheme for queue members, we must devise the queue's strategy before other initializations.
10114 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
10115 * container used will have only a single bucket instead of the typical number.
10116 */
10117 if (queue_reload) {
10118 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
10119 q->strategy = strat2int(tmpvar);
10120 if (q->strategy < 0) {
10121 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
10122 tmpvar, q->name);
10124 }
10125 } else {
10127 }
10128 init_queue(q);
10129 }
10130 if (member_reload) {
10132 q->found = 1;
10133 }
10134
10135 /* On the first pass we just read the parameters of the queue */
10136 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
10137 if (queue_reload && strcasecmp(var->name, "member")) {
10138 queue_set_param(q, var->name, var->value, var->lineno, 1);
10139 }
10140 }
10141
10142 /* On the second pass, we read members */
10143 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
10144 if (member_reload && !strcasecmp(var->name, "member")) {
10145 reload_single_member(var->value, q);
10146 }
10147 }
10148
10149 /* Update ringinuse for dynamic members */
10150 if (member_reload) {
10151 ao2_lock(q->members);
10153 while ((member = ao2_iterator_next(&mem_iter))) {
10154 if (member->dynamic) {
10156 }
10157 ao2_ref(member, -1);
10158 }
10159 ao2_iterator_destroy(&mem_iter);
10160 ao2_unlock(q->members);
10161 }
10162
10163 /* At this point, we've determined if the queue has a weight, so update use_weight
10164 * as appropriate
10165 */
10166 if (!q->weight && prev_weight) {
10168 } else if (q->weight && !prev_weight) {
10170 }
10171
10172 /* Free remaining members marked as delme */
10173 if (member_reload) {
10174 ao2_lock(q->members);
10177 ao2_unlock(q->members);
10178 }
10179
10180 if (new) {
10181 queues_t_link(queues, q, "Add queue to container");
10182 } else {
10183 ao2_unlock(q);
10184 }
10185 queue_t_unref(q, "Expiring creation reference");
10186}
static int mark_member_dead(void *obj, void *arg, int flags)
static void reload_single_member(const char *memberdata, struct call_queue *q)
reload information pertaining to a single member
Definition app_queue.c:9902
static int kill_dead_members(void *obj, void *arg, int flags)
static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
Definition app_queue.c:2182

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

Referenced by reload_queues().

◆ remove_from_queue()

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

Remove member from queue.

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

Definition at line 7787 of file app_queue.c.

7788{
7789 struct call_queue *q, tmpq = {
7790 .name = queuename,
7791 };
7792 struct member *mem, tmpmem;
7793 int res = RES_NOSUCHQUEUE;
7794
7795 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7796 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
7797 ao2_lock(q);
7798 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
7799 /* XXX future changes should beware of this assumption!! */
7800 /*Change Penalty on realtime users*/
7802 update_realtime_member_field(mem, q->name, "penalty", "-1");
7803 } else if (!mem->dynamic) {
7804 ao2_ref(mem, -1);
7805 ao2_unlock(q);
7806 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
7807 return RES_NOT_DYNAMIC;
7808 }
7809 queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
7810
7812 ao2_ref(mem, -1);
7813
7816 }
7817
7818 if (!num_available_members(q)) {
7820 }
7821
7822 res = RES_OKAY;
7823 } else {
7824 res = RES_EXISTS;
7825 }
7826 ao2_unlock(q);
7827 queue_t_unref(q, "Expiring temporary reference");
7828 }
7829
7830 return res;
7831}
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition app_queue.c:4162
char rt_uniqueid[80]
Definition app_queue.c:1903

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

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

◆ remove_stasis_subscriptions()

static void remove_stasis_subscriptions ( struct queue_stasis_data queue_data)
static

Definition at line 6483 of file app_queue.c.

6484{
6485 SCOPED_AO2LOCK(lock, queue_data);
6486
6487 queue_data->dying = 1;
6489 queue_data->bridge_router = NULL;
6491 queue_data->channel_router = NULL;
6492}
void stasis_message_router_unsubscribe(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic.

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

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

◆ request_withdraw_caller_from_queue()

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

Request to withdraw a caller from a queue.

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

Definition at line 7969 of file app_queue.c.

7970{
7971 struct call_queue *q;
7972 struct queue_ent *qe;
7973 int res = RES_NOSUCHQUEUE;
7974
7975 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7976 * short-circuits if the queue is already in memory. */
7978 return res;
7979 }
7980
7981 ao2_lock(q);
7983 for (qe = q->head; qe; qe = qe->next) {
7984 if (!strcmp(ast_channel_name(qe->chan), caller)) {
7985 if (qe->withdraw) {
7986 ast_debug(1, "Ignoring duplicate withdraw request of caller %s from queue %s\n", caller, queuename);
7987 res = RES_EXISTS;
7988 } else {
7989 ast_debug(1, "Requested withdraw of caller %s from queue %s\n", caller, queuename);
7990 /* It is not possible to change the withdraw info by further withdraw requests for this caller (channel)
7991 in this queue, so we do not need to worry about a memory leak here. */
7992 if (withdraw_info) {
7993 qe->withdraw_info = ast_strdup(withdraw_info);
7994 }
7995 qe->withdraw = 1;
7996 res = RES_OKAY;
7997 }
7998 break;
7999 }
8000 }
8001 ao2_unlock(q);
8002 queue_unref(q);
8003
8004 return res;
8005}

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

Referenced by manager_request_withdraw_caller_from_queue().

◆ ring_entry()

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

Part 2 of ring_one.

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

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

Definition at line 4941 of file app_queue.c.

4942{
4943 int res;
4944 int status;
4945 char tech[256];
4946 char *location;
4947 struct ast_format_cap *nativeformats;
4948 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4949
4950 /* on entry here, we know that tmp->chan == NULL */
4951 if (!can_ring_entry(qe, tmp)) {
4952 tmp->stillgoing = 0;
4953 ++*busies;
4954 return 0;
4955 }
4956
4957 ast_copy_string(tech, tmp->interface, sizeof(tech));
4958 if ((location = strchr(tech, '/'))) {
4959 *location++ = '\0';
4960 } else {
4961 location = "";
4962 }
4963
4965 nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
4967
4968 /* Request the peer */
4969 tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
4970 ao2_cleanup(nativeformats);
4971 if (!tmp->chan) { /* If we can't, just go on to the next call */
4972 ao2_lock(qe->parent);
4973 qe->parent->rrpos++;
4974 qe->linpos++;
4975 ao2_unlock(qe->parent);
4976
4978
4979 publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
4980 tmp->stillgoing = 0;
4981 ++*busies;
4982 return 0;
4983 }
4984
4985 ast_channel_lock_both(tmp->chan, qe->chan);
4986
4989 if (qe->cancel_answered_elsewhere) {
4991 }
4992 ast_channel_appl_set(tmp->chan, "AppQueue");
4993 ast_channel_data_set(tmp->chan, "(Outgoing Line)");
4994 memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
4995
4996 /* If the new channel has no callerid, try to guess what it should be */
4997 if (!ast_channel_caller(tmp->chan)->id.number.valid) {
4999 struct ast_party_caller caller;
5000
5002 caller.id = ast_channel_connected(qe->chan)->id;
5003 caller.ani = ast_channel_connected(qe->chan)->ani;
5004 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
5005 } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
5007 } else if (!ast_strlen_zero(ast_channel_exten(qe->chan))) {
5009 }
5010 tmp->dial_callerid_absent = 1;
5011 }
5012
5014
5016
5018
5019 /* Inherit specially named variables from parent channel */
5023
5024 /* Presense of ADSI CPE on outgoing channel follows ours */
5026
5027 /* Inherit context and extension */
5028 ast_channel_dialcontext_set(tmp->chan, ast_channel_context(qe->chan));
5030
5031 /* Save the original channel name to detect call pickup masquerading in. */
5033
5036
5037 /* location is tmp->interface where tech/ has been stripped, so it follow the same syntax as DIALEDPEERNUMBER in app_dial.c */
5038 pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", strlen(location) ? location : tmp->interface);
5039
5040 /* PREDIAL: Run gosub on the callee's channel */
5041 if (qe->predial_callee) {
5042 ast_pre_call(tmp->chan, qe->predial_callee);
5043 }
5044
5045 /* Place the call, but don't wait on the answer */
5046 if ((res = ast_call(tmp->chan, location, 0))) {
5047 /* Again, keep going even if there's an error */
5048 ast_verb(3, "Couldn't call %s\n", tmp->interface);
5049 do_hang(tmp);
5050 ++*busies;
5051 return 0;
5052 }
5053
5054 ast_channel_lock_both(tmp->chan, qe->chan);
5055
5056 blob = ast_json_pack("{s: s, s: s, s: s}",
5057 "Queue", qe->parent->name,
5058 "Interface", tmp->interface,
5059 "MemberName", tmp->member->membername);
5060 queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
5061
5063
5066
5067 ast_verb(3, "Called %s\n", tmp->interface);
5068
5069 return 1;
5070}
static void do_hang(struct callattempt *o)
common hangup actions
Definition app_queue.c:4815
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition app_queue.c:4845
static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
Definition app_queue.c:2498
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition app_queue.c:4635
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
void ast_channel_appl_set(struct ast_channel *chan, const char *value)
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition channel.c:6480
@ AST_CHANNEL_REQUESTOR_BRIDGE_PEER
Definition channel.h:1525
void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update)
Set the caller id information in the Asterisk channel and generate an AMI event if the caller id name...
Definition channel.c:7408
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
void ast_channel_data_set(struct ast_channel *chan, const char *value)
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition channel.h:2990
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition channel.c:2359
const char * ast_channel_context(const struct ast_channel *chan)
ast_channel_adsicpe
Definition channel.h:888
void ast_party_caller_set_init(struct ast_party_caller *init, const struct ast_party_caller *guide)
Initialize the given caller structure using the given guide for a set update operation.
Definition channel.c:1986
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition channel.c:7370
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
Definition channel.c:6795
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition channel.c:8361
void ast_channel_req_accountcodes_precious(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition channel.c:6458
int ast_pre_call(struct ast_channel *chan, const char *sub_args)
Execute a Gosub call on the channel before a call is placed.
Definition channel.c:6463
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition channel.c:6373
const char * ast_channel_exten(const struct ast_channel *chan)
void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
Copy the source redirecting information to the destination redirecting.
Definition channel.c:2122
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
Caller Party information.
Definition channel.h:420
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition channel.h:467
char * str
Subscriber phone number (Malloced)
Definition channel.h:388
struct ast_party_dialed::@217 number
Dialed/Called number.
int transit_network_select
Transit Network Select.
Definition channel.h:399
unsigned int dial_callerid_absent
Definition app_queue.c:1835
char interface[256]
Definition app_queue.c:1825
int cancel_answered_elsewhere
Definition app_queue.c:1870

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

Referenced by ring_one().

◆ ring_one()

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

Place a call to a queue member.

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

Return values
1if a member was called successfully
0otherwise

Definition at line 5098 of file app_queue.c.

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

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

Referenced by try_calling(), and wait_for_answer().

◆ rna()

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

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

Definition at line 5298 of file app_queue.c.

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

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

Referenced by wait_for_answer().

◆ rqm_exec()

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

RemoveQueueMember application.

Definition at line 8535 of file app_queue.c.

8536{
8537 int res=-1;
8538 char *parse, *temppos = NULL;
8539 struct member *mem = NULL;
8540
8542 AST_APP_ARG(queuename);
8544 );
8545
8546
8547 if (ast_strlen_zero(data)) {
8548 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
8549 return -1;
8550 }
8551
8552 parse = ast_strdupa(data);
8553
8555
8556 if (ast_strlen_zero(args.interface)) {
8557 args.interface = ast_strdupa(ast_channel_name(chan));
8558 temppos = strrchr(args.interface, '-');
8559 if (temppos) {
8560 *temppos = '\0';
8561 }
8562 }
8563
8564 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
8565
8567 mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
8568 }
8569
8570 switch (remove_from_queue(args.queuename, args.interface)) {
8571 case RES_OKAY:
8572 if (!mem || ast_strlen_zero(mem->membername)) {
8573 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
8574 } else {
8575 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
8576 }
8577 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
8578 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
8579 res = 0;
8580 break;
8581 case RES_EXISTS:
8582 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
8583 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
8584 res = 0;
8585 break;
8586 case RES_NOSUCHQUEUE:
8587 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
8588 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
8589 res = 0;
8590 break;
8591 case RES_NOT_DYNAMIC:
8592 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
8593 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
8594 res = 0;
8595 break;
8596 }
8597
8598 if (mem) {
8599 ao2_ref(mem, -1);
8600 }
8601
8602 return res;
8603}

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

Referenced by load_module().

◆ rt_handle_member_record()

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

Find rt member record to update otherwise create one.

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

Definition at line 3756 of file app_queue.c.

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

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

Referenced by find_queue_by_name_rt(), and update_realtime_members().

◆ say_periodic_announcement()

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

Playback announcement to queued members if period has elapsed.

Definition at line 5206 of file app_queue.c.

5207{
5208 int res = 0;
5209 time_t now;
5210
5211 /* Get the current time */
5212 time(&now);
5213
5214 /* Check to see if it is time to announce */
5216 return 0;
5217 }
5218
5219 /* Stop the music on hold so we can play our own file */
5220 if (ringing) {
5221 ast_indicate(qe->chan,-1);
5222 } else {
5223 ast_moh_stop(qe->chan);
5224 }
5225
5226 ast_verb(3, "Playing periodic announcement\n");
5227
5229 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
5233 }
5234
5235 /* play the announcement */
5237
5238 if (res > 0 && !valid_exit(qe, res)) {
5239 res = 0;
5240 }
5241
5242 /* Resume Music on Hold if the caller is going to stay in the queue */
5243 if (!res) {
5244 if (ringing) {
5246 } else {
5247 ast_moh_start(qe->chan, qe->moh, NULL);
5248 }
5249 }
5250
5251 /* update last_periodic_announce_time */
5253 time(&qe->last_periodic_announce_time);
5254 } else {
5256 }
5257
5258 /* Update the current periodic announcement to the next announcement */
5259 if (!qe->parent->randomperiodicannounce) {
5261 }
5262
5263 return res;
5264}
static int play_file(struct ast_channel *chan, const char *filename)
Definition app_queue.c:4321
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition app_queue.c:4350

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

Referenced by queue_exec(), and wait_our_turn().

◆ say_position()

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

Definition at line 4385 of file app_queue.c.

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

References ANNOUNCEHOLDTIME_ONCE, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_YES, ast_channel_language(), ast_channel_name(), AST_CONTROL_RINGING, AST_DIGIT_ANY, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_say_number(), ast_verb, NULL, play_file(), ringing(), queue_ent::start, and valid_exit().

Referenced by queue_exec(), and wait_our_turn().

◆ send_agent_complete()

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

Send out AMI message with member call completion status information.

Definition at line 6336 of file app_queue.c.

6339{
6340 const char *reason = NULL; /* silence dumb compilers */
6341 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
6342
6343 switch (rsn) {
6344 case CALLER:
6345 reason = "caller";
6346 break;
6347 case AGENT:
6348 reason = "agent";
6349 break;
6350 case TRANSFER:
6351 reason = "transfer";
6352 break;
6353 }
6354
6355 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
6356 "Queue", queuename,
6357 "Interface", member->interface,
6358 "MemberName", member->membername,
6359 "HoldTime", (ast_json_int_t)(callstart - holdstart),
6360 "TalkTime", (ast_json_int_t)(time(NULL) - callstart),
6361 "Reason", reason ?: "");
6362
6364 queue_agent_complete_type(), blob);
6365}
struct stasis_topic * ast_queue_topic(const char *queuename)
Get the Stasis Message Bus API topic for queue messages for a particular queue name.
Definition main/app.c:3350
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition json.h:87

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

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

◆ set_duration_var()

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

Definition at line 7047 of file app_queue.c.

7048{
7049 char buf[32];
7050 char full_var_name[128];
7051
7052 snprintf(buf, sizeof(buf), "%" PRId64, duration / 1000);
7053 pbx_builtin_setvar_helper(chan, var_base, buf);
7054
7055 snprintf(full_var_name, sizeof(full_var_name), "%s_MS", var_base);
7056 snprintf(buf, sizeof(buf), "%" PRId64, duration);
7057 pbx_builtin_setvar_helper(chan, full_var_name, buf);
7058}

References buf, and pbx_builtin_setvar_helper().

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

◆ set_member_paused()

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

Definition at line 8104 of file app_queue.c.

8105{
8106 int found = 0;
8107 struct call_queue *q;
8108 struct ao2_iterator queue_iter;
8109
8110 if (ast_check_realtime("queues")) {
8111 load_realtime_queues(queuename);
8112 }
8113
8114 queue_iter = ao2_iterator_init(queues, 0);
8115 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
8116 ao2_lock(q);
8117 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
8118 struct member *mem;
8119
8120 if ((mem = interface_exists(q, interface))) {
8121 /*
8122 * Before we do the PAUSE/UNPAUSE, log if this was a
8123 * PAUSEALL/UNPAUSEALL but only on the first found entry.
8124 */
8125 ++found;
8126 if (found == 1
8127 && ast_strlen_zero(queuename)) {
8128 /*
8129 * XXX In all other cases, we use the queue name,
8130 * but since this affects all queues, we cannot.
8131 */
8132 ast_queue_log("NONE", "NONE", mem->membername,
8133 (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", S_OR(reason, ""));
8134 }
8135
8136 set_queue_member_pause(q, mem, reason, paused);
8137 ao2_ref(mem, -1);
8138 }
8139
8140 if (!ast_strlen_zero(queuename)) {
8141 ao2_unlock(q);
8142 queue_t_unref(q, "Done with iterator");
8143 break;
8144 }
8145 }
8146
8147 ao2_unlock(q);
8148 queue_t_unref(q, "Done with iterator");
8149 }
8150 ao2_iterator_destroy(&queue_iter);
8151
8152 return found ? RESULT_SUCCESS : RESULT_FAILURE;
8153}
static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
Definition app_queue.c:8032

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

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

◆ set_member_penalty_help_members()

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

Definition at line 8164 of file app_queue.c.

8165{
8166 struct member *mem;
8167 int foundinterface = 0;
8168
8169 ao2_lock(q);
8170 if ((mem = interface_exists(q, interface))) {
8171 foundinterface++;
8172 if (mem->realtime) {
8173 char rtpenalty[80];
8174
8175 sprintf(rtpenalty, "%i", penalty);
8176 update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
8177 }
8178
8179 mem->penalty = penalty;
8180
8181 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
8182 queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem));
8183 ao2_ref(mem, -1);
8184 }
8185 ao2_unlock(q);
8186
8187 return foundinterface;
8188}

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

Referenced by set_member_value_help_members().

◆ set_member_ringinuse_help_members()

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

Definition at line 8213 of file app_queue.c.

8214{
8215 struct member *mem;
8216 int foundinterface = 0;
8217
8218 ao2_lock(q);
8219 if ((mem = interface_exists(q, interface))) {
8220 foundinterface++;
8222 ao2_ref(mem, -1);
8223 }
8224 ao2_unlock(q);
8225
8226 return foundinterface;
8227}
static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
Definition app_queue.c:8200

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

Referenced by set_member_value_help_members().

◆ set_member_value()

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

Definition at line 8252 of file app_queue.c.

8253{
8254 int foundinterface = 0, foundqueue = 0;
8255 struct call_queue *q;
8256 struct ast_config *queue_config = NULL;
8257 struct ao2_iterator queue_iter;
8258
8259 /* property dependent restrictions on values should be checked in this switch */
8260 switch (property) {
8261 case MEMBER_PENALTY:
8262 if (value < 0 && !negative_penalty_invalid) {
8263 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value);
8264 return RESULT_FAILURE;
8265 }
8266 }
8267
8268 if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */
8269 if (ast_check_realtime("queues")) {
8270 queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
8271 if (queue_config) {
8272 char *category = NULL;
8273 while ((category = ast_category_browse(queue_config, category))) {
8274 const char *name = ast_variable_retrieve(queue_config, category, "name");
8275 if (ast_strlen_zero(name)) {
8276 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
8277 continue;
8278 }
8279 if ((q = find_load_queue_rt_friendly(name))) {
8280 foundqueue++;
8281 foundinterface += set_member_value_help_members(q, interface, property, value);
8282 queue_unref(q);
8283 }
8284 }
8285
8286 ast_config_destroy(queue_config);
8287 }
8288 }
8289
8290 /* After hitting realtime queues, go back and get the regular ones. */
8291 queue_iter = ao2_iterator_init(queues, 0);
8292 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8293 foundqueue++;
8294 foundinterface += set_member_value_help_members(q, interface, property, value);
8295 queue_unref(q);
8296 }
8297 ao2_iterator_destroy(&queue_iter);
8298 } else { /* We actually have a queuename, so we can just act on the single queue. */
8299 if ((q = find_load_queue_rt_friendly(queuename))) {
8300 foundqueue++;
8301 foundinterface += set_member_value_help_members(q, interface, property, value);
8302 queue_unref(q);
8303 }
8304 }
8305
8306 if (foundinterface) {
8307 return RESULT_SUCCESS;
8308 } else if (!foundqueue) {
8309 ast_log (LOG_ERROR, "Invalid queuename\n");
8310 } else {
8311 ast_log (LOG_ERROR, "Invalid interface\n");
8312 }
8313
8314 return RESULT_FAILURE;
8315}
static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
Definition app_queue.c:8229

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

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

◆ set_member_value_help_members()

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

Definition at line 8229 of file app_queue.c.

8230{
8231 switch(property) {
8232 case MEMBER_PENALTY:
8233 return set_member_penalty_help_members(q, interface, value);
8234
8235 case MEMBER_RINGINUSE:
8236 return set_member_ringinuse_help_members(q, interface, value);
8237
8238 default:
8239 ast_log(LOG_ERROR, "Attempted to set invalid property\n");
8240 return 0;
8241 }
8242}
static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
Definition app_queue.c:8213
static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
Definition app_queue.c:8164

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

Referenced by set_member_value().

◆ set_queue_member_pause()

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

Definition at line 8032 of file app_queue.c.

8033{
8034 if (mem->paused == paused) {
8035 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
8036 (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
8037 if (log_unpause_on_reason_change && paused) {
8038 if (!ast_strings_equal(mem->reason_paused, reason)) {
8039 ast_queue_log(q->name, "NONE", mem->membername, "UNPAUSE", "%s", "Auto-Unpause");
8040 }
8041 }
8042 }
8043
8044 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid)) {
8046 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "reason_paused", S_OR(reason, ""), "paused", paused ? "1" : "0", SENTINEL) < 0) {
8047 ast_log(LOG_WARNING, "Failed update of realtime queue member %s:%s %spause and reason '%s'\n",
8048 q->name, mem->interface, (paused ? "" : "un"), S_OR(reason, ""));
8049 }
8050 } else {
8051 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "paused", paused ? "1" : "0", SENTINEL) < 0) {
8052 ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
8053 (paused ? "" : "un"), q->name, mem->interface);
8054 }
8055 }
8056 }
8057
8058 mem->paused = paused;
8059 if (paused) {
8060 time(&mem->lastpause); /* update last pause field */
8061 }
8062 if (paused && !ast_strlen_zero(reason)) {
8063 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
8064 } else {
8065 /* We end up filling this in again later (temporarily) but we need it
8066 * empty for now so that the intervening code - specifically
8067 * dump_queue_members() - has the correct view of things. */
8068 mem->reason_paused[0] = '\0';
8069 }
8070
8072 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
8073
8076 }
8077
8078 if (is_member_available(q, mem)) {
8080 "Queue:%s_avail", q->name);
8081 } else if (!num_available_members(q)) {
8083 "Queue:%s_avail", q->name);
8084 }
8085
8086 if (!paused && !ast_strlen_zero(reason)) {
8087 /* Because we've been unpaused with a 'reason' we need to ensure that
8088 * that reason is emitted when the subsequent PauseQueueMember event
8089 * is raised. So temporarily set it on the member and clear it out
8090 * again right after. */
8091 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
8092 }
8093
8094 ast_queue_log(q->name, "NONE", mem->membername, paused ? "PAUSE" : "UNPAUSE",
8095 "%s", mem->reason_paused);
8096
8098
8099 if (!paused) {
8100 mem->reason_paused[0] = '\0';
8101 }
8102}
static int publish_queue_member_pause(struct call_queue *q, struct member *member)
Definition app_queue.c:8008
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition strings.c:238

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

Referenced by set_member_paused().

◆ set_queue_member_ringinuse()

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

Definition at line 8200 of file app_queue.c.

8201{
8202 if (mem->realtime) {
8204 ringinuse ? "1" : "0");
8205 }
8206
8207 mem->ringinuse = ringinuse;
8208
8209 ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
8210 queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
8211}

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

Referenced by set_member_ringinuse_help_members().

◆ set_queue_result()

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

sets the QUEUESTATUS channel variable

Definition at line 2068 of file app_queue.c.

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

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

Referenced by queue_exec().

◆ set_queue_variables()

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

Set variables of queue.

Definition at line 2221 of file app_queue.c.

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

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

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

◆ setup_mixmonitor()

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

Definition at line 7149 of file app_queue.c.

7150{
7151 char escaped_filename[256];
7152 char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
7153 char mixmonargs[1512];
7154 char escaped_monitor_exec[1024];
7155 const char *monitor_options;
7156 const char *monitor_exec;
7157
7158 escaped_monitor_exec[0] = '\0';
7159
7160 if (filename) {
7161 escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
7162 } else {
7163 ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
7164 }
7165
7167 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
7168 monitor_exec = ast_strdupa(monitor_exec);
7169 }
7170 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
7171 monitor_options = ast_strdupa(monitor_options);
7172 } else {
7173 monitor_options = "";
7174 }
7176
7177 if (monitor_exec) {
7178 escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
7179 }
7180
7181 snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
7182
7183 if (!ast_strlen_zero(escaped_monitor_exec)) {
7184 snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
7185 } else {
7186 snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
7187 }
7188
7189 ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
7190
7191 if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
7192 ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
7193 }
7194}
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition app_queue.c:7118
int ast_start_mixmonitor(struct ast_channel *chan, const char *filename, const char *options)
Start a mixmonitor on a channel with the given parameters.
Definition mixmonitor.c:74

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

Referenced by try_calling().

◆ setup_peer_after_bridge_goto()

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

Definition at line 7101 of file app_queue.c.

7102{
7103 const char *context;
7104 const char *extension;
7105 int priority;
7106
7107 if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
7108 ast_channel_lock(chan);
7112 ast_channel_unlock(chan);
7114 opt_args[OPT_ARG_CALLEE_GO_ON]);
7115 }
7116}
void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
Set channel to go on in the dialplan after the bridge.
int ast_channel_priority(const struct ast_channel *chan)
structure to hold extensions

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

Referenced by try_calling().

◆ setup_stasis_subs()

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

Definition at line 6988 of file app_queue.c.

6990{
6991 struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6992
6993 if (!queue_data) {
6994 return -1;
6995 }
6996
6998 if (!queue_data->bridge_router) {
6999 ao2_ref(queue_data, -1);
7000 return -1;
7001 }
7002
7004 handle_bridge_enter, queue_data);
7006 handle_blind_transfer, queue_data);
7008 handle_attended_transfer, queue_data);
7010 queue_bridge_cb, queue_data);
7011
7013 if (!queue_data->channel_router) {
7014 /* Unsubscribing from the bridge router will remove the only ref of queue_data,
7015 * thus beginning the destruction process
7016 */
7018 queue_data->bridge_router = NULL;
7019 return -1;
7020 }
7021
7022 ao2_ref(queue_data, +1);
7026 handle_local_optimization_end, queue_data);
7028 handle_hangup, queue_data);
7030 handle_masquerade, queue_data);
7032 queue_channel_cb, queue_data);
7033
7034 return 0;
7035}
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6583
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6730
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition app_queue.c:6675
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6929
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6749
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6808
static struct queue_stasis_data * queue_stasis_data_alloc(struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
Definition app_queue.c:6498
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6963
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition app_queue.c:6872
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition app_queue.c:6616
struct stasis_message_type * ast_local_optimization_end_type(void)
Message type for when a local channel optimization completes.
struct stasis_message_type * ast_local_optimization_begin_type(void)
Message type for when a local channel optimization begins.
struct stasis_message_type * ast_channel_masquerade_type(void)
Message type for when a channel is being masqueraded.
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
struct stasis_message_type * ast_channel_hangup_request_type(void)
Message type for when a hangup is requested on a channel.
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for ast_channel enter bridge blob messages.
struct stasis_message_type * ast_blind_transfer_type(void)
Message type for ast_blind_transfer_message.
struct stasis_message_type * ast_attended_transfer_type(void)
Message type for ast_attended_transfer_message.
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
#define stasis_message_router_create_pool(topic)
Create a new message router object.

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

Referenced by try_calling().

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [1/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_called_type  ,
to_ami = queue_agent_called_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [2/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_complete_type  ,
to_ami = queue_agent_complete_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [3/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_connect_type  ,
to_ami = queue_agent_connect_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [4/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_dump_type  ,
to_ami = queue_agent_dump_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [5/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_ringnoanswer_type  ,
to_ami = queue_agent_ringnoanswer_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [6/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_abandon_type  ,
to_ami = queue_caller_abandon_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [7/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_join_type  ,
to_ami = queue_caller_join_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [8/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_leave_type  ,
to_ami = queue_caller_leave_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [9/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_added_type  ,
to_ami = queue_member_added_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [10/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_pause_type  ,
to_ami = queue_member_pause_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [11/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_penalty_type  ,
to_ami = queue_member_penalty_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [12/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_removed_type  ,
to_ami = queue_member_removed_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [13/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_ringinuse_type  ,
to_ami = queue_member_ringinuse_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [14/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_status_type  ,
to_ami = queue_member_status_to_ami 
)

◆ store_next_lin()

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

Search for best metric and add to Linear queue.

Definition at line 5182 of file app_queue.c.

5183{
5184 struct callattempt *best = find_best(outgoing);
5185
5186 if (best) {
5187 /* Ring just the best channel */
5188 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
5189 qe->linpos = best->metric % 1000;
5190 } else {
5191 /* Just increment rrpos */
5192 if (qe->linwrapped) {
5193 /* No more channels, start over */
5194 qe->linpos = 0;
5195 } else {
5196 /* Prioritize next entry */
5197 qe->linpos++;
5198 }
5199 }
5200 qe->linwrapped = 0;
5201
5202 return 0;
5203}

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

Referenced by try_calling().

◆ store_next_rr()

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

Search for best metric and add to Round Robbin queue.

Definition at line 5158 of file app_queue.c.

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

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

Referenced by try_calling().

◆ strat2int()

static int strat2int ( const char *  strategy)
static

Definition at line 2093 of file app_queue.c.

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

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

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

◆ try_calling()

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

Definition at line 7222 of file app_queue.c.

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

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

Referenced by queue_exec().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 11998 of file app_queue.c.

11999{
12002
12004
12005 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
12006 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
12007 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
12008
12009 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
12010 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
12011 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
12012 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
12013 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
12014 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
12015
12016 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
12017 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
12018 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
12019 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
12020 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
12021
12023 ast_manager_unregister("QueueStatus");
12024 ast_manager_unregister("QueueRule");
12025 ast_manager_unregister("QueueSummary");
12026 ast_manager_unregister("QueueAdd");
12027 ast_manager_unregister("QueueRemove");
12028 ast_manager_unregister("QueuePause");
12029 ast_manager_unregister("QueueLog");
12030 ast_manager_unregister("QueueUpdate");
12031 ast_manager_unregister("QueuePenalty");
12032 ast_manager_unregister("QueueReload");
12033 ast_manager_unregister("QueueReset");
12034 ast_manager_unregister("QueueMemberRingInUse");
12035 ast_manager_unregister("QueueChangePriorityCaller");
12036 ast_manager_unregister("QueueWithdrawCaller");
12051
12053
12054 ast_unload_realtime("queue_members");
12057
12058 queues = NULL;
12059 return 0;
12060}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7716
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:404
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition stasis.h:1515
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition stasis.c:1615
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition stasis.c:1201
void stasis_message_router_unsubscribe_and_join(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic, blocking until the final message has been processed.

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

Referenced by load_module().

◆ update_connected_line_from_peer()

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

Definition at line 5363 of file app_queue.c.

5364{
5365 struct ast_party_connected_line connected_caller;
5366
5367 ast_party_connected_line_init(&connected_caller);
5368
5369 ast_channel_lock(peer);
5371 ast_channel_unlock(peer);
5372 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
5373 if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
5374 ast_channel_update_connected_line(chan, &connected_caller, NULL);
5375 }
5376 ast_party_connected_line_free(&connected_caller);
5377}
@ AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER
Definition callerid.h:554
int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int frame)
Run a connected line interception subroutine and update a channel's connected line information.
Definition channel.c:10406
void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Indicate that the connected line information has changed.
Definition channel.c:9161
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition channel.c:2009
Connected Line/Party information.
Definition channel.h:458

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

Referenced by wait_for_answer().

◆ update_qe_rule()

static void update_qe_rule ( struct queue_ent qe)
static

update rules for queues

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

Definition at line 5982 of file app_queue.c.

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

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

Referenced by queue_exec(), and wait_our_turn().

◆ update_queue()

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

update the queue status

Return values
0always

Definition at line 6165 of file app_queue.c.

6167{
6168 int oldtalktime;
6169 int newtalktime;
6170 struct member *mem;
6171 struct call_queue *qtmp;
6172 struct ao2_iterator queue_iter;
6173 int did_increment_any = 0;
6174
6175 if (!starttime) {
6176 return 0;
6177 }
6178
6179 newtalktime = (int)(time(NULL) - starttime);
6180
6181 /* It is possible for us to be called when a call has already been considered terminated
6182 * and data updated, so to ensure we only act on the call that the agent is currently in
6183 * we check when the call was bridged.
6184 */
6185 ao2_lock(q);
6186 if (member->starttime != starttime) {
6187 ao2_unlock(q);
6188 return 0;
6189 }
6190 member->starttime = 0;
6191 ao2_unlock(q);
6192
6193 if (shared_lastcall) {
6194 queue_iter = ao2_iterator_init(queues, 0);
6195 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate queues"))) {
6196 ao2_lock(qtmp);
6197 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
6198 time(&mem->lastcall);
6199 mem->calls++;
6200 mem->callcompletedinsl = 0;
6201 mem->lastqueue = q;
6202 did_increment_any = 1;
6203 ao2_ref(mem, -1);
6204 }
6205 ao2_unlock(qtmp);
6206 queue_t_unref(qtmp, "queue iteration done");
6207 }
6208 ao2_iterator_destroy(&queue_iter);
6209 } else {
6210 ao2_lock(q);
6211 time(&member->lastcall);
6213 member->calls++;
6214 member->lastqueue = q;
6215 did_increment_any = 1;
6216 ao2_unlock(q);
6217 }
6218 /* Member might never experience any direct status change (local
6219 * channel with forwarding in particular). If that's the case,
6220 * this is the last chance to remove it from pending or subsequent
6221 * calls will not occur.
6222 */
6224
6225 if (did_increment_any) {
6226 ao2_lock(q);
6227 q->callscompleted++;
6228 if (callcompletedinsl) {
6229 q->callscompletedinsl++;
6230 }
6231 if (q->callscompleted == 1) {
6232 q->talktime = newtalktime;
6233 } else {
6234 /* Calculate talktime using the same exponential average as holdtime code */
6235 oldtalktime = q->talktime;
6236 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
6237 }
6238 ao2_unlock(q);
6239 }
6240
6241 return 0;
6242}

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

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

◆ update_realtime_member_field()

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

Definition at line 4162 of file app_queue.c.

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

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

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

◆ update_realtime_members()

static void update_realtime_members ( struct call_queue q)
static

Definition at line 4178 of file app_queue.c.

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

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

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

◆ update_status()

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

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

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

Definition at line 2738 of file app_queue.c.

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

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

Referenced by device_state_cb(), and extension_state_cb().

◆ upqm_exec()

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

UnpauseQueueMember application.

Definition at line 8499 of file app_queue.c.

8500{
8501 char *parse;
8503 AST_APP_ARG(queuename);
8504 AST_APP_ARG(interface);
8506 AST_APP_ARG(reason);
8507 );
8508
8509 if (ast_strlen_zero(data)) {
8510 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
8511 return -1;
8512 }
8513
8514 parse = ast_strdupa(data);
8515
8517
8518 if (ast_strlen_zero(args.interface)) {
8519 ast_log(LOG_WARNING, "Missing interface argument to UnpauseQueueMember ([queuename],interface[,options[,reason]])\n");
8520 return -1;
8521 }
8522
8523 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
8524 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
8525 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
8526 return 0;
8527 }
8528
8529 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
8530
8531 return 0;
8532}

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

Referenced by load_module().

◆ valid_exit()

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

Check for valid exit from queue via goto.

Return values
0if failure
1if successful

Definition at line 4350 of file app_queue.c.

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

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

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

◆ wait_a_bit()

static int wait_a_bit ( struct queue_ent qe)
static

Definition at line 7692 of file app_queue.c.

7693{
7694 /* Don't need to hold the lock while we setup the outgoing calls */
7695 int retrywait = qe->parent->retry * 1000;
7696
7697 int res = ast_waitfordigit(qe->chan, retrywait);
7698 if (res > 0 && !valid_exit(qe, res)) {
7699 res = 0;
7700 }
7701
7702 return res;
7703}
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition channel.c:3179

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

Referenced by queue_exec().

◆ wait_for_answer()

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

Wait for a member to answer the call.

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

Definition at line 5393 of file app_queue.c.

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

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

Referenced by try_calling().

◆ wait_our_turn()

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

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

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

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

Definition at line 6077 of file app_queue.c.

6078{
6079 int res = 0;
6080
6081 /* This is the holding pen for callers 2 through maxlen */
6082 for (;;) {
6083
6084 /* A request to withdraw this call from the queue arrived */
6085 if (qe->withdraw) {
6086 *reason = QUEUE_WITHDRAW;
6087 res = 1;
6088 break;
6089 }
6090
6091 if (is_our_turn(qe)) {
6092 break;
6093 }
6094
6095 /* If we have timed out, break out */
6096 if (qe->expire && (time(NULL) >= qe->expire)) {
6097 *reason = QUEUE_TIMEOUT;
6098 break;
6099 }
6100
6101 if (qe->parent->leavewhenempty) {
6102 int status = 0;
6103
6105 record_abandoned(qe);
6106 *reason = QUEUE_LEAVEEMPTY;
6107 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
6108 res = -1;
6109 qe->handled = -1;
6110 break;
6111 }
6112 }
6113
6114 /* Make a position announcement, if enabled */
6115 if (qe->parent->announcefrequency &&
6116 (res = say_position(qe,ringing))) {
6117 break;
6118 }
6119
6120 /* If we have timed out, break out */
6121 if (qe->expire && (time(NULL) >= qe->expire)) {
6122 *reason = QUEUE_TIMEOUT;
6123 break;
6124 }
6125
6126 /* Make a periodic announcement, if enabled */
6129 break;
6130
6131 /* see if we need to move to the next penalty level for this queue */
6132 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
6133 update_qe_rule(qe);
6134 }
6135
6136 /* If we have timed out, break out */
6137 if (qe->expire && (time(NULL) >= qe->expire)) {
6138 *reason = QUEUE_TIMEOUT;
6139 break;
6140 }
6141
6142 /* Wait a second before checking again */
6143 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
6144 if (res > 0 && !valid_exit(qe, res)) {
6145 res = 0;
6146 } else {
6147 break;
6148 }
6149 }
6150
6151 /* If we have timed out, break out */
6152 if (qe->expire && (time(NULL) >= qe->expire)) {
6153 *reason = QUEUE_TIMEOUT;
6154 break;
6155 }
6156 }
6157
6158 return res;
6159}
#define RECHECK
Definition app_queue.c:1701

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

Referenced by queue_exec().

◆ word_in_list()

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

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

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

Definition at line 10556 of file app_queue.c.

10556 {
10557 int list_len, word_len = strlen(word);
10558 const char *find, *end_find, *end_list;
10559
10560 /* strip whitespace from front */
10561 while(isspace(*list)) {
10562 list++;
10563 }
10564
10565 while((find = strstr(list, word))) {
10566 /* beginning of find starts inside another word? */
10567 if (find != list && *(find - 1) != ' ') {
10568 list = find;
10569 /* strip word from front */
10570 while(!isspace(*list) && *list != '\0') {
10571 list++;
10572 }
10573 /* strip whitespace from front */
10574 while(isspace(*list)) {
10575 list++;
10576 }
10577 continue;
10578 }
10579
10580 /* end of find ends inside another word or at very end of list? */
10581 list_len = strlen(list);
10582 end_find = find + word_len;
10583 end_list = list + list_len;
10584 if (end_find == end_list || *end_find != ' ') {
10585 list = find;
10586 /* strip word from front */
10587 while(!isspace(*list) && *list != '\0') {
10588 list++;
10589 }
10590 /* strip whitespace from front */
10591 while(isspace(*list)) {
10592 list++;
10593 }
10594 continue;
10595 }
10596
10597 /* terminating conditions satisfied, word at beginning or separated by ' ' */
10598 return 1;
10599 }
10600
10601 return 0;
10602}

References call_queue::list.

Referenced by complete_queue().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "True Call Queueing" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, }
static

Definition at line 12259 of file app_queue.c.

◆ agent_router

struct stasis_message_router* agent_router
static

Definition at line 11995 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app

char* app = "Queue"
static

Definition at line 1718 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_aqm

char* app_aqm = "AddQueueMember"
static

Definition at line 1720 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_pqm

char* app_pqm = "PauseQueueMember"
static

Definition at line 1724 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_ql

char* app_ql = "QueueLog"
static

Definition at line 1728 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_qupd

char* app_qupd = "QueueUpdate"
static

Definition at line 1730 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_rqm

char* app_rqm = "RemoveQueueMember"
static

Definition at line 1722 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ app_upqm

char* app_upqm = "UnpauseQueueMember"
static

Definition at line 1726 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ aqm_opts

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

Definition at line 1649 of file app_queue.c.

Referenced by aqm_exec().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 12259 of file app_queue.c.

◆ autofill_default

int autofill_default
static

queues.conf [general] option

Definition at line 1742 of file app_queue.c.

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

◆ autopausesmodes

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

Referenced by autopause2int().

◆ cli_queue

struct ast_cli_entry cli_queue[]
static

Definition at line 11982 of file app_queue.c.

11982 {
11983 AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
11984 AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
11985 AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
11986 AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
11987 AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
11988 AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
11989 AST_CLI_DEFINE(handle_queue_set_member_ringinuse, "Set ringinuse for a channel of a specified queue"),
11990 AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
11991 AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
11992 AST_CLI_DEFINE(handle_queue_change_priority_caller, "Change priority caller on queue"),
11993};
static char * queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_set_member_ringinuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_change_priority_caller(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197

Referenced by load_module(), and unload_module().

◆ device_state_sub

struct stasis_subscription* device_state_sub
static

Subscription to device state change messages.

Definition at line 1754 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ force_longest_waiting_caller

int force_longest_waiting_caller
static

queues.conf [general] option

Definition at line 1763 of file app_queue.c.

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

◆ id

enum queue_result id

Definition at line 1790 of file app_queue.c.

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

◆ log_caller_id_name

int log_caller_id_name
static

queues.conf [general] option

Definition at line 1766 of file app_queue.c.

Referenced by queue_exec(), and queue_set_global_params().

◆ log_membername_as_agent

int log_membername_as_agent
static

◆ log_unpause_on_reason_change

int log_unpause_on_reason_change
static

queues.conf [general] option

Definition at line 1769 of file app_queue.c.

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

◆ montype_default

int montype_default
static

queues.conf [general] option

Definition at line 1745 of file app_queue.c.

Referenced by queue_reset_global_params(), and queue_set_global_params().

◆ negative_penalty_invalid

int negative_penalty_invalid
static

queues.conf [general] option

Definition at line 1757 of file app_queue.c.

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

◆ pending_members

struct ao2_container* pending_members
static

Definition at line 2676 of file app_queue.c.

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

◆ pm_family

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

Persistent Members astdb family.

Definition at line 1733 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

◆ queue_exec_options

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

Definition at line 1633 of file app_queue.c.

Referenced by queue_exec().

◆ queue_persistent_members

int queue_persistent_members
static

◆ [struct]

const struct { ... } queue_results[]

Referenced by set_queue_result().

◆ queueexists_function

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

Definition at line 9724 of file app_queue.c.

9724 {
9725 .name = "QUEUE_EXISTS",
9726 .read = queue_function_exists,
9727};

Referenced by load_module(), and unload_module().

◆ queuegetchannel_function

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

Definition at line 9740 of file app_queue.c.

9740 {
9741 .name = "QUEUE_GET_CHANNEL",
9743};

Referenced by load_module(), and unload_module().

◆ queuemembercount_function

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

Definition at line 9734 of file app_queue.c.

9734 {
9735 .name = "QUEUE_MEMBER",
9737 .write = queue_function_mem_write,
9738};

Referenced by load_module(), and unload_module().

◆ queuememberlist_function

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

Definition at line 9750 of file app_queue.c.

9750 {
9751 .name = "QUEUE_MEMBER_LIST",
9753};

Referenced by load_module(), and unload_module().

◆ queuememberpenalty_function

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

Definition at line 9755 of file app_queue.c.

9755 {
9756 .name = "QUEUE_MEMBER_PENALTY",
9759};

Referenced by load_module(), and unload_module().

◆ queues

struct ao2_container* queues
static

◆ queuevar_function

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

Definition at line 9729 of file app_queue.c.

9729 {
9730 .name = "QUEUE_VARIABLES",
9731 .read = queue_function_var,
9732};

Referenced by load_module(), and unload_module().

◆ queuewaitingcount_function

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

Definition at line 9745 of file app_queue.c.

9745 {
9746 .name = "QUEUE_WAITING_COUNT",
9748};

Referenced by load_module(), and unload_module().

◆ realtime_reason_paused

int realtime_reason_paused
static

does realtime backend support reason_paused

Definition at line 1775 of file app_queue.c.

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

◆ realtime_ringinuse_field

char* realtime_ringinuse_field
static

name of the ringinuse field in the realtime database

Definition at line 1772 of file app_queue.c.

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

◆ realtime_rules

int realtime_rules
static

queuerules.conf [general] option

Definition at line 1751 of file app_queue.c.

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

◆ rule_lists

◆ shared_lastcall

int shared_lastcall
static

queues.conf [general] option

Definition at line 1748 of file app_queue.c.

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

◆ strategies

const struct strategy strategies[]
static

Referenced by int2strat(), and strat2int().

◆ text

char* text

◆ topic_forwarder

struct stasis_forward* topic_forwarder
static

Definition at line 11996 of file app_queue.c.

Referenced by load_module(), and unload_module().

◆ use_weight

int use_weight
static

Records that one or more queues use weight.

Definition at line 1739 of file app_queue.c.

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