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

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

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

Go to the source code of this file.

Data Structures

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

Macros

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

Enumerations

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

Functions

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

Variables

static 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 int autofill_default
 queues.conf [general] option More...
 
static const struct autopause autopausesmodes []
 
static struct stasis_subscriptiondevice_state_sub
 Subscription to device state change messages. More...
 
static int log_membername_as_agent
 queues.conf [general] option More...
 
static int montype_default
 queues.conf [general] option More...
 
static int negative_penalty_invalid
 queues.conf [general] option More...
 
static struct ao2_containerpending_members
 
static const char *const pm_family = "Queue/PersistentMembers"
 Persistent Members astdb family. More...
 
static const struct ast_app_option queue_exec_options [128] = { [ 'b' ] = { .flag = OPT_PREDIAL_CALLEE , .arg_index = OPT_ARG_PREDIAL_CALLEE + 1 }, [ 'B' ] = { .flag = OPT_PREDIAL_CALLER , .arg_index = OPT_ARG_PREDIAL_CALLER + 1 }, [ 'C' ] = { .flag = OPT_MARK_AS_ANSWERED }, [ 'c' ] = { .flag = OPT_GO_ON }, [ 'd' ] = { .flag = OPT_DATA_QUALITY }, [ 'F' ] = { .flag = OPT_CALLEE_GO_ON , .arg_index = OPT_ARG_CALLEE_GO_ON + 1 }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'i' ] = { .flag = OPT_IGNORE_CALL_FW }, [ 'I' ] = { .flag = OPT_IGNORE_CONNECTEDLINE }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'm' ] = { .flag = OPT_MUSICONHOLD_CLASS , .arg_index = OPT_ARG_MUSICONHOLD_CLASS + 1 }, [ 'n' ] = { .flag = OPT_NO_RETRY }, [ 'r' ] = { .flag = OPT_RINGING }, [ 'R' ] = { .flag = OPT_RING_WHEN_RINGING }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'x' ] = { .flag = OPT_CALLEE_AUTOMIXMON }, [ 'X' ] = { .flag = OPT_CALLER_AUTOMIXMON }, [ 'w' ] = { .flag = OPT_CALLEE_AUTOMON }, [ 'W' ] = { .flag = OPT_CALLER_AUTOMON }, }
 
static int queue_persistent_members
 queues.conf [general] option More...
 
struct {
   enum queue_result   id
 
   char *   text
 
queue_results []
 
static struct ast_custom_function queueexists_function
 
static struct ast_custom_function queuegetchannel_function
 
static struct ast_custom_function queuemembercount_dep
 
static struct ast_custom_function queuemembercount_function
 
static struct ast_custom_function queuememberlist_function
 
static struct ast_custom_function queuememberpenalty_function
 
static struct ao2_containerqueues
 
static struct ast_custom_function queuevar_function
 
static struct ast_custom_function queuewaitingcount_function
 
static char * realtime_ringinuse_field
 name of the ringinuse field in the realtime database More...
 
static int realtime_rules
 queuerules.conf [general] option More...
 
static struct rule_lists rule_lists = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static int shared_lastcall
 queues.conf [general] option More...
 
static const struct strategy strategies []
 
static int use_weight
 Records that one or more queues use weight. More...
 

Detailed Description

True call queues with optional send URL on answer.

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

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

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

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

◆ ANNOUNCEHOLDTIME_ONCE

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1774 of file app_queue.c.

◆ ANNOUNCEPOSITION_LIMIT

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1791 of file app_queue.c.

◆ ANNOUNCEPOSITION_MORE_THAN

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 1790 of file app_queue.c.

◆ ANNOUNCEPOSITION_NO

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1789 of file app_queue.c.

◆ ANNOUNCEPOSITION_YES

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1788 of file app_queue.c.

◆ AST_MAX_WATCHERS

#define AST_MAX_WATCHERS   256

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

◆ DEFAULT_RETRY

#define DEFAULT_RETRY   5

Definition at line 1561 of file app_queue.c.

◆ DEFAULT_TIMEOUT

#define DEFAULT_TIMEOUT   15

Definition at line 1562 of file app_queue.c.

◆ MAX_CALL_ATTEMPT_BUCKETS

#define MAX_CALL_ATTEMPT_BUCKETS   353

Definition at line 2514 of file app_queue.c.

◆ MAX_PERIODIC_ANNOUNCEMENTS

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 1564 of file app_queue.c.

◆ MAX_QUEUE_BUCKETS

#define MAX_QUEUE_BUCKETS   53

Definition at line 1571 of file app_queue.c.

◆ QUEUE_EVENT_VARIABLES

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1775 of file app_queue.c.

◆ QUEUE_PAUSED_DEVSTATE

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

Definition at line 3530 of file app_queue.c.

◆ queue_ref

#define queue_ref (   q)    ao2_bump(q)

Definition at line 2057 of file app_queue.c.

◆ queue_t_ref

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

Definition at line 2059 of file app_queue.c.

◆ queue_t_unref

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

Definition at line 2060 of file app_queue.c.

◆ QUEUE_UNKNOWN_PAUSED_DEVSTATE

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3532 of file app_queue.c.

◆ QUEUE_UNPAUSED_DEVSTATE

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3531 of file app_queue.c.

◆ queue_unref

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

Definition at line 2058 of file app_queue.c.

◆ queues_t_link

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

Definition at line 2061 of file app_queue.c.

◆ queues_t_unlink

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

Definition at line 2062 of file app_queue.c.

◆ RECHECK

#define RECHECK   1

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

Definition at line 1563 of file app_queue.c.

◆ RES_EXISTS

#define RES_EXISTS   (-1)

Entry already exists

Definition at line 1574 of file app_queue.c.

◆ RES_NOSUCHQUEUE

#define RES_NOSUCHQUEUE   (-3)

No such queue

Definition at line 1576 of file app_queue.c.

◆ RES_NOT_CALLER

#define RES_NOT_CALLER   (-5)

Caller not found

Definition at line 1578 of file app_queue.c.

◆ RES_NOT_DYNAMIC

#define RES_NOT_DYNAMIC   (-4)

Member is not dynamic

Definition at line 1577 of file app_queue.c.

◆ RES_OKAY

#define RES_OKAY   0

Action completed

Definition at line 1573 of file app_queue.c.

◆ RES_OUTOFMEMORY

#define RES_OUTOFMEMORY   (-2)

Out of memory

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

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

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

1479  {
1484  /* note: this entry _MUST_ be the last one in the enum */
1486 };
@ OPT_ARG_CALLEE_GO_ON
Definition: app_queue.c:1480
@ OPT_ARG_PREDIAL_CALLEE
Definition: app_queue.c:1481
@ OPT_ARG_MUSICONHOLD_CLASS
Definition: app_queue.c:1483
@ OPT_ARG_PREDIAL_CALLER
Definition: app_queue.c:1482
@ OPT_ARG_ARRAY_SIZE
Definition: app_queue.c:1485

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

1513  {
1522 };
@ QUEUE_STRATEGY_RINGALL
Definition: app_queue.c:1514
@ QUEUE_STRATEGY_RRMEMORY
Definition: app_queue.c:1518
@ QUEUE_STRATEGY_LINEAR
Definition: app_queue.c:1519
@ QUEUE_STRATEGY_LEASTRECENT
Definition: app_queue.c:1515
@ QUEUE_STRATEGY_RANDOM
Definition: app_queue.c:1517
@ QUEUE_STRATEGY_FEWESTCALLS
Definition: app_queue.c:1516
@ QUEUE_STRATEGY_RRORDERED
Definition: app_queue.c:1521
@ QUEUE_STRATEGY_WRANDOM
Definition: app_queue.c:1520

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 1524 of file app_queue.c.

1524  {
1525  QUEUE_AUTOPAUSE_OFF = 0,
1528 };
@ QUEUE_AUTOPAUSE_ON
Definition: app_queue.c:1526
@ QUEUE_AUTOPAUSE_OFF
Definition: app_queue.c:1525
@ QUEUE_AUTOPAUSE_ALL
Definition: app_queue.c:1527

◆ agent_complete_reason

Enumerator
CALLER 
AGENT 
TRANSFER 

Definition at line 6071 of file app_queue.c.

6071  {
6072  CALLER,
6073  AGENT,
6074  TRANSFER
6075 };
@ AGENT
Definition: app_queue.c:6073
@ CALLER
Definition: app_queue.c:6072
@ TRANSFER
Definition: app_queue.c:6074

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

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

◆ member_properties

Enumerator
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1767 of file app_queue.c.

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

◆ queue_reload_mask

Enumerator
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 1530 of file app_queue.c.

1530  {
1531  QUEUE_RELOAD_PARAMETERS = (1 << 0),
1532  QUEUE_RELOAD_MEMBER = (1 << 1),
1533  QUEUE_RELOAD_RULES = (1 << 2),
1534  QUEUE_RESET_STATS = (1 << 3),
1535 };
@ QUEUE_RELOAD_RULES
Definition: app_queue.c:1533
@ QUEUE_RELOAD_MEMBER
Definition: app_queue.c:1532
@ QUEUE_RESET_STATS
Definition: app_queue.c:1534
@ QUEUE_RELOAD_PARAMETERS
Definition: app_queue.c:1531

◆ queue_result

Enumerator
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 
QUEUE_WITHDRAW 

Definition at line 1627 of file app_queue.c.

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

◆ queue_timeout_priority

Enumerator
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1654 of file app_queue.c.

1654  {
1657 };
@ TIMEOUT_PRIORITY_CONF
Definition: app_queue.c:1656
@ TIMEOUT_PRIORITY_APP
Definition: app_queue.c:1655

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

10058 {
10059  struct call_queue *q;
10060  struct ast_str *out = ast_str_alloca(512);
10061  struct ao2_container *sorted_queues;
10062 
10063  struct ao2_iterator queue_iter;
10064  int found = 0;
10065 
10066  if (argc != 2 && argc != 3) {
10067  return CLI_SHOWUSAGE;
10068  }
10069 
10070  if (argc == 3) { /* specific queue */
10071  if ((q = find_load_queue_rt_friendly(argv[2]))) {
10072  ao2_lock(q);
10073  print_queue(s, fd, q);
10074  ao2_unlock(q);
10075  queue_unref(q);
10076  } else {
10077  ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
10078  do_print(s, fd, ast_str_buffer(out));
10079  }
10080  return CLI_SUCCESS;
10081  }
10082 
10083  if (ast_check_realtime("queues")) {
10084  /* This block is to find any queues which are defined in realtime but
10085  * which have not yet been added to the in-core container
10086  */
10087  struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10088  if (cfg) {
10089  char *category = NULL;
10090  while ((category = ast_category_browse(cfg, category))) {
10091  const char *queuename = ast_variable_retrieve(cfg, category, "name");
10092  if (ast_strlen_zero(queuename)) {
10093  ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
10094  continue;
10095  }
10096  if ((q = find_load_queue_rt_friendly(queuename))) {
10097  queue_t_unref(q, "Done with temporary pointer");
10098  }
10099  }
10100  ast_config_destroy(cfg);
10101  }
10102  }
10103 
10104  /*
10105  * Snapping a copy of the container prevents having to lock both the queues container
10106  * and the queue itself at the same time. It also allows us to sort the entries.
10107  */
10108  sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
10109  if (!sorted_queues) {
10110  return CLI_SUCCESS;
10111  }
10112  if (ao2_container_dup(sorted_queues, queues, 0)) {
10113  ao2_ref(sorted_queues, -1);
10114  return CLI_SUCCESS;
10115  }
10116 
10117  /*
10118  * No need to lock the container since it's temporary and static.
10119  * We also unlink the entries as we use them so the container is
10120  * empty when the iterator finishes. We can then just unref the container.
10121  */
10122  queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
10123  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10124  struct call_queue *realtime_queue = NULL;
10125  ao2_lock(q);
10126  /* This check is to make sure we don't print information for realtime
10127  * queues which have been deleted from realtime but which have not yet
10128  * been deleted from the in-core container. Only do this if we're not
10129  * looking for a specific queue.
10130  */
10131  if (q->realtime) {
10132  realtime_queue = find_load_queue_rt_friendly(q->name);
10133  if (!realtime_queue) {
10134  ao2_unlock(q);
10135  queue_t_unref(q, "Done with iterator");
10136  continue;
10137  }
10138  queue_t_unref(realtime_queue, "Queue is already in memory");
10139  }
10140 
10141  found = 1;
10142  print_queue(s, fd, q);
10143 
10144  ao2_unlock(q);
10145  queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
10146  }
10147  ao2_iterator_destroy(&queue_iter);
10148  ao2_ref(sorted_queues, -1);
10149  if (!found) {
10150  ast_str_set(&out, 0, "No queues.");
10151  do_print(s, fd, ast_str_buffer(out));
10152  }
10153  return CLI_SUCCESS;
10154 }
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3882
static void print_queue(struct mansession *s, int fd, struct call_queue *q)
Print a single queue to AMI or the CLI.
Definition: app_queue.c:9949
static struct ao2_container * queues
Definition: app_queue.c:1903
#define queue_t_unref(q, tag)
Definition: app_queue.c:2060
#define queue_unref(q)
Definition: app_queue.c:2058
static void do_print(struct mansession *s, int fd, const char *str)
direct output to manager or cli with proper terminator
Definition: app_queue.c:9939
#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:3327
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3521
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3429
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:768
#define LOG_WARNING
#define NULL
Definition: resample.c:96
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:739
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:826
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:1091
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:604
unsigned int realtime
Definition: app_queue.c:1849
unsigned int found
Definition: app_queue.c:1850
const ast_string_field name
Definition: app_queue.c:1833
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().

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

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

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

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

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

Referenced by find_queue_by_name_rt(), and reload_single_queue().

◆ AO2_STRING_FIELD_SORT_FN()

AO2_STRING_FIELD_SORT_FN ( call_queue  ,
name   
)

◆ aqm_exec()

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

AddQueueMember application.

Definition at line 8283 of file app_queue.c.

8284 {
8285  int res=-1;
8286  char *parse, *tmp, *temppos = NULL;
8288  AST_APP_ARG(queuename);
8289  AST_APP_ARG(interface);
8290  AST_APP_ARG(penalty);
8292  AST_APP_ARG(membername);
8293  AST_APP_ARG(state_interface);
8294  AST_APP_ARG(wrapuptime);
8295  );
8296  int penalty = 0;
8297  int wrapuptime;
8298 
8299  if (ast_strlen_zero(data)) {
8300  ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8301  return -1;
8302  }
8303 
8304  parse = ast_strdupa(data);
8305 
8307 
8308  if (ast_strlen_zero(args.interface)) {
8309  args.interface = ast_strdupa(ast_channel_name(chan));
8310  temppos = strrchr(args.interface, '-');
8311  if (temppos) {
8312  *temppos = '\0';
8313  }
8314  }
8315 
8316  if (!ast_strlen_zero(args.penalty)) {
8317  if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8318  ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8319  penalty = 0;
8320  }
8321  }
8322 
8323  if (!ast_strlen_zero(args.wrapuptime)) {
8324  tmp = args.wrapuptime;
8325  ast_strip(tmp);
8326  wrapuptime = atoi(tmp);
8327  if (wrapuptime < 0) {
8328  wrapuptime = 0;
8329  }
8330  } else {
8331  wrapuptime = 0;
8332  }
8333 
8334  switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface, NULL, wrapuptime)) {
8335  case RES_OKAY:
8336  if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8337  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", "");
8338  } else {
8339  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", "");
8340  }
8341  ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8342  pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8343  res = 0;
8344  break;
8345  case RES_EXISTS:
8346  ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8347  pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8348  res = 0;
8349  break;
8350  case RES_NOSUCHQUEUE:
8351  ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8352  pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8353  res = 0;
8354  break;
8355  case RES_OUTOFMEMORY:
8356  ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8357  break;
8358  }
8359 
8360  return res;
8361 }
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1598
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1622
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:7587
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
static int tmp()
Definition: bt_open.c:389
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1844
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_name(const struct ast_channel *chan)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:952
#define LOG_ERROR
#define LOG_NOTICE
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
const char * args
static struct test_options options

References add_to_queue(), args, AST_APP_ARG, ast_channel_name(), ast_channel_uniqueid(), AST_DECLARE_APP_ARGS, ast_log, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strip(), ast_strlen_zero(), member::interface, LOG_ERROR, log_membername_as_agent, LOG_NOTICE, LOG_WARNING, member::membername, NULL, options, parse(), pbx_builtin_setvar_helper(), member::penalty, queue_persistent_members, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, member::state_interface, tmp(), and member::wrapuptime.

◆ autopause2int()

static int autopause2int ( const char *  autopause)
static

Definition at line 1950 of file app_queue.c.

1951 {
1952  int x;
1953  /*This 'double check' that default value is OFF */
1954  if (ast_strlen_zero(autopause)) {
1955  return QUEUE_AUTOPAUSE_OFF;
1956  }
1957 
1958  /*This 'double check' is to ensure old values works */
1959  if(ast_true(autopause)) {
1960  return QUEUE_AUTOPAUSE_ON;
1961  }
1962 
1963  for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
1964  if (!strcasecmp(autopause, autopausesmodes[x].name)) {
1965  return autopausesmodes[x].autopause;
1966  }
1967  }
1968 
1969  /*This 'double check' that default value is OFF */
1970  return QUEUE_AUTOPAUSE_OFF;
1971 }
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: main/utils.c:2097
int autopause
Definition: app_queue.c:1553
#define ARRAY_LEN(a)
Definition: utils.h:661

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

5994 {
5995  /* disregarding penalty on too few members? */
5996  int membercount = ao2_container_count(q->members);
5997  unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
5998  int penalty = mem->penalty;
5999 
6000  if (usepenalty) {
6001  if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) {
6002  /* Low penalty is raised up to the current minimum */
6003  penalty = qe->raise_penalty;
6004  }
6005  if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
6006  (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6007  return -1;
6008  }
6009  } else {
6010  ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
6011  membercount, q->penaltymemberslimit);
6012  }
6013 
6014  switch (q->strategy) {
6016  /* Everyone equal, except for penalty */
6017  tmp->metric = penalty * 1000000 * usepenalty;
6018  break;
6019  case QUEUE_STRATEGY_LINEAR:
6020  if (pos < qe->linpos) {
6021  tmp->metric = 1000 + pos;
6022  } else {
6023  if (pos > qe->linpos) {
6024  /* Indicate there is another priority */
6025  qe->linwrapped = 1;
6026  }
6027  tmp->metric = pos;
6028  }
6029  tmp->metric += penalty * 1000000 * usepenalty;
6030  break;
6033  pos = mem->queuepos;
6034  if (pos < q->rrpos) {
6035  tmp->metric = 1000 + pos;
6036  } else {
6037  if (pos > q->rrpos) {
6038  /* Indicate there is another priority */
6039  q->wrapped = 1;
6040  }
6041  tmp->metric = pos;
6042  }
6043  tmp->metric += penalty * 1000000 * usepenalty;
6044  break;
6045  case QUEUE_STRATEGY_RANDOM:
6046  tmp->metric = ast_random() % 1000;
6047  tmp->metric += penalty * 1000000 * usepenalty;
6048  break;
6050  tmp->metric = ast_random() % ((1 + penalty) * 1000);
6051  break;
6053  tmp->metric = mem->calls;
6054  tmp->metric += penalty * 1000000 * usepenalty;
6055  break;
6057  if (!mem->lastcall) {
6058  tmp->metric = 0;
6059  } else {
6060  tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
6061  }
6062  tmp->metric += penalty * 1000000 * usepenalty;
6063  break;
6064  default:
6065  ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
6066  break;
6067  }
6068  return 0;
6069 }
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:1889
int penaltymemberslimit
Definition: app_queue.c:1875
unsigned int wrapped
Definition: app_queue.c:1843
int strategy
Definition: app_queue.c:1848
int queuepos
Definition: app_queue.c:1742
time_t lastcall
Definition: app_queue.c:1746
int calls
Definition: app_queue.c:1736
int linpos
Definition: app_queue.c:1715
int max_penalty
Definition: app_queue.c:1712
int raise_penalty
Definition: app_queue.c:1714
int min_penalty
Definition: app_queue.c:1713
int linwrapped
Definition: app_queue.c:1716
long int ast_random(void)
Definition: main/utils.c:2210

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

Referenced by try_calling().

◆ callattempt_free()

static void callattempt_free ( struct callattempt doomed)
static

Definition at line 4434 of file app_queue.c.

4435 {
4436  if (doomed->member) {
4437  ao2_ref(doomed->member, -1);
4438  }
4440  ast_free(doomed->orig_chan_name);
4441  ast_free(doomed);
4442 }
#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:2066
struct ast_party_connected_line connected
Definition: app_queue.c:1679
char * orig_chan_name
Definition: app_queue.c:1690
struct member * member
Definition: app_queue.c:1677

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

4595 {
4596  struct member *memberp = call->member;
4597  int wrapuptime;
4598 
4599  if (memberp->paused) {
4600  ast_debug(1, "%s paused, can't receive call\n", call->interface);
4601  return 0;
4602  }
4603 
4604  if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4605  ast_debug(1, "%s not available, can't receive call\n", call->interface);
4606  return 0;
4607  }
4608 
4609  if (memberp->lastqueue) {
4610  wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4611  } else {
4612  wrapuptime = get_wrapuptime(qe->parent, memberp);
4613  }
4614  if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4615  ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4616  (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4617  call->interface);
4618  return 0;
4619  }
4620 
4621  if (use_weight && compare_weight(qe->parent, memberp)) {
4622  ast_debug(1, "Priority queue delaying call to %s:%s\n",
4623  qe->parent->name, call->interface);
4624  return 0;
4625  }
4626 
4627  if (!memberp->ringinuse) {
4628  struct member *mem;
4629 
4631 
4632  mem = ao2_find(pending_members, memberp,
4634  if (mem) {
4635  /*
4636  * If found that means this member is currently being attempted
4637  * from another calling thread, so stop trying from this thread
4638  */
4639  ast_debug(1, "%s has another call trying, can't receive call\n",
4640  call->interface);
4641  ao2_ref(mem, -1);
4643  return 0;
4644  }
4645 
4646  /*
4647  * If not found add it to the container so another queue
4648  * won't attempt to call this member at the same time.
4649  */
4650  ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4651  ao2_link(pending_members, memberp);
4653 
4654  /*
4655  * The queue member is available. Get current status to be sure
4656  * because the device state and extension state callbacks may
4657  * not have updated the status yet.
4658  */
4660  ast_debug(1, "%s actually not available, can't receive call\n",
4661  call->interface);
4662  pending_members_remove(memberp);
4663  return 0;
4664  }
4665  }
4666 
4667  return 1;
4668 }
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:1993
static int compare_weight(struct call_queue *rq, struct member *member)
Definition: app_queue.c:4529
static struct ao2_container * pending_members
Definition: app_queue.c:2513
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2564
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:2850
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1601
static int member_status_available(int status)
Definition: app_queue.c:4580
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
static int call(void *data)
Definition: chan_pjsip.c:2379
int status
Definition: app_queue.c:1739
unsigned int ringinuse
Definition: app_queue.c:1753
struct call_queue * lastqueue
Definition: app_queue.c:1749
struct call_queue * parent
Definition: app_queue.c:1695

References ao2_find, ao2_link, ao2_lock, ao2_ref, ao2_unlock, ast_debug, call(), compare_weight(), get_queue_member_status(), get_wrapuptime(), 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 
)
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 7640 of file app_queue.c.

7641 {
7642  struct call_queue *q;
7643  struct queue_ent *qe;
7644  int res = RES_NOSUCHQUEUE;
7645 
7646  /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7647  * short-circuits if the queue is already in memory. */
7648  if (!(q = find_load_queue_rt_friendly(queuename))) {
7649  return res;
7650  }
7651 
7652  ao2_lock(q);
7653  res = RES_NOT_CALLER;
7654  for (qe = q->head; qe; qe = qe->next) {
7655  if (strcmp(ast_channel_name(qe->chan), caller) == 0) {
7656  ast_debug(1, "%s Caller new priority %d in queue %s\n",
7657  caller, priority, queuename);
7658  qe->prio = priority;
7659  res = RES_OKAY;
7660  }
7661  }
7662  ao2_unlock(q);
7663  return res;
7664 }
#define RES_NOT_CALLER
Definition: app_queue.c:1578
static int priority
struct queue_ent * head
Definition: app_queue.c:1890
struct ast_channel * chan
Definition: app_queue.c:1722
struct queue_ent * next
Definition: app_queue.c:1725

References ao2_lock, ao2_unlock, ast_channel_name(), ast_debug, queue_ent::chan, find_load_queue_rt_friendly(), call_queue::head, queue_ent::next, queue_ent::prio, priority, RES_NOSUCHQUEUE, RES_NOT_CALLER, and RES_OKAY.

Referenced by manager_change_priority_caller_on_queue().

◆ clear_queue()

static void clear_queue ( struct call_queue q)
static

Definition at line 3043 of file app_queue.c.

3044 {
3045  q->holdtime = 0;
3046  q->callscompleted = 0;
3047  q->callsabandoned = 0;
3048  q->callscompletedinsl = 0;
3049  q->callsabandonedinsl = 0;
3050  q->talktime = 0;
3051 
3052  if (q->members) {
3053  struct member *mem;
3054  struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3055  while ((mem = ao2_iterator_next(&mem_iter))) {
3056  mem->calls = 0;
3057  mem->callcompletedinsl = 0;
3058  mem->lastcall = 0;
3059  mem->starttime = 0;
3060  ao2_ref(mem, -1);
3061  }
3062  ao2_iterator_destroy(&mem_iter);
3063  }
3064 }
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
int talktime
Definition: app_queue.c:1864
int callsabandoned
Definition: app_queue.c:1866
int callscompleted
Definition: app_queue.c:1865
int callsabandonedinsl
Definition: app_queue.c:1867
int callscompletedinsl
Definition: app_queue.c:1869
int holdtime
Definition: app_queue.c:1863
time_t starttime
Definition: app_queue.c:1745
int callcompletedinsl
Definition: app_queue.c:1743

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

9893 {
9894  struct call_queue *q;
9895  struct ao2_iterator queue_iter;
9896 
9897  queue_iter = ao2_iterator_init(queues, 0);
9898  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
9899  ao2_lock(q);
9900  if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
9901  clear_queue(q);
9902  ao2_unlock(q);
9903  queue_t_unref(q, "Done with iterator");
9904  }
9905  ao2_iterator_destroy(&queue_iter);
9906  return 0;
9907 }
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:3043

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

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

10229 {
10230  struct call_queue *q;
10231  char *ret = NULL;
10232  int which = 0;
10233  int wordlen = strlen(word);
10234  struct ao2_iterator queue_iter;
10235  const char *word_list = NULL;
10236 
10237  /* for certain commands, already completed items should be left out of
10238  * the list */
10239  if (word_list_offset && strlen(line) >= word_list_offset) {
10240  word_list = line + word_list_offset;
10241  }
10242 
10243  queue_iter = ao2_iterator_init(queues, 0);
10244  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10245  if (!strncasecmp(word, q->name, wordlen) && ++which > state
10246  && (!word_list_offset || !word_in_list(word_list, q->name))) {
10247  ret = ast_strdup(q->name);
10248  queue_t_unref(q, "Done with iterator");
10249  break;
10250  }
10251  queue_t_unref(q, "Done with iterator");
10252  }
10253  ao2_iterator_destroy(&queue_iter);
10254 
10255  /* Pretend "rules" is at the end of the queues list in certain
10256  * circumstances since it is an alternate command that should be
10257  * tab-completable for "queue show" */
10258  if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
10259  ret = ast_strdup("rules");
10260  }
10261 
10262  return ret;
10263 }
static int word_in_list(const char *list, const char *word)
Check if a given word is in a space-delimited list.
Definition: app_queue.c:10169
#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(), and complete_queue_show().

◆ complete_queue_add_member()

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

Definition at line 10734 of file app_queue.c.

10735 {
10736  /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
10737  switch (pos) {
10738  case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
10739  return NULL;
10740  case 4: /* only one possible match, "to" */
10741  return state == 0 ? ast_strdup("to") : NULL;
10742  case 5: /* <queue> */
10743  return complete_queue(line, word, pos, state, 0);
10744  case 6: /* only one possible match, "penalty" */
10745  return state == 0 ? ast_strdup("penalty") : NULL;
10746  case 7:
10747  if (0 <= state && state < 100) { /* 0-99 */
10748  char *num;
10749  if ((num = ast_malloc(3))) {
10750  sprintf(num, "%d", state);
10751  }
10752  return num;
10753  } else {
10754  return NULL;
10755  }
10756  case 8: /* only one possible match, "as" */
10757  return state == 0 ? ast_strdup("as") : NULL;
10758  case 9: /* Don't attempt to complete name of member (infinite possibilities) */
10759  return NULL;
10760  default:
10761  return NULL;
10762  }
10763 }
static char * complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
Check if a given word is in a space-delimited list.
Definition: app_queue.c:10228
#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_show()

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

Definition at line 10265 of file app_queue.c.

10266 {
10267  if (pos == 2) {
10268  return complete_queue(line, word, pos, state, 0);
10269  }
10270  return NULL;
10271 }

References complete_queue(), and NULL.

Referenced by queue_show().

◆ compress_char()

static int compress_char ( const char  c)
static

Definition at line 2910 of file app_queue.c.

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

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

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

Referenced by 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 8398 of file app_queue.c.

8399 {
8400  struct penalty_rule *pr_iter;
8401  struct rule_list *rl_iter;
8402  const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8404  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8405  if (!strcasecmp(rl_iter->name, tmp)) {
8406  break;
8407  }
8408  }
8409  if (rl_iter) {
8410  AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8411  struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8412  if (!new_pr) {
8413  ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8414  break;
8415  }
8416  new_pr->time = pr_iter->time;
8417  new_pr->max_value = pr_iter->max_value;
8418  new_pr->min_value = pr_iter->min_value;
8419  new_pr->raise_value = pr_iter->raise_value;
8420  new_pr->max_relative = pr_iter->max_relative;
8421  new_pr->min_relative = pr_iter->min_relative;
8422  new_pr->raise_relative = pr_iter->raise_relative;
8423  AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8424  }
8425  }
8427 }
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
const ast_string_field defaultrule
Definition: app_queue.c:1833
struct penalty_rule::@65 list
int raise_relative
Definition: app_queue.c:1784
int min_relative
Definition: app_queue.c:1783
int max_relative
Definition: app_queue.c:1782
struct queue_ent::@64 qe_rules
struct rule_list::@69 list
struct rule_list::@68 rules
char name[80]
Definition: app_queue.c:1896

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

Referenced by queue_exec().

◆ create_queue_member()

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

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

Definition at line 2865 of file app_queue.c.

2866 {
2867  struct member *cur;
2868 
2869  if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
2870  cur->ringinuse = ringinuse;
2871  cur->penalty = penalty;
2872  cur->paused = paused;
2873  cur->wrapuptime = wrapuptime;
2874  if (paused) {
2875  time(&cur->lastpause); /* Update time of last pause */
2876  }
2877  time(&cur->logintime);
2878  ast_copy_string(cur->interface, interface, sizeof(cur->interface));
2881  } else {
2883  }
2884  if (!ast_strlen_zero(membername)) {
2885  ast_copy_string(cur->membername, membername, sizeof(cur->membername));
2886  } else {
2887  ast_copy_string(cur->membername, interface, sizeof(cur->membername));
2888  }
2889  if (!strchr(cur->interface, '/')) {
2890  ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
2891  }
2892  if (!strncmp(cur->state_interface, "hint:", 5)) {
2893  char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
2894  char *exten = strsep(&context, "@") + 5;
2895 
2896  ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
2897  ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
2898 
2900  } else {
2901  cur->state_id = -1;
2902  }
2903  cur->status = get_queue_member_status(cur);
2904  }
2905 
2906  return cur;
2907 }
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: app_queue.c:2806
static void destroy_queue_member_cb(void *obj)
Definition: app_queue.c:2855
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:122
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
char * strsep(char **str, const char *delims)
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
Definition: pbx.c:3830
#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:1748
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1730
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1731
int state_id
Definition: app_queue.c:1733
time_t lastpause
Definition: app_queue.c:1747

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

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

◆ destroy_queue()

static void destroy_queue ( void *  obj)
static

Free queue's member list then its string fields.

Definition at line 3699 of file app_queue.c.

3700 {
3701  struct call_queue *q = obj;
3702  int i;
3703 
3704  free_members(q, 1);
3706  for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3707  if (q->sound_periodicannounce[i]) {
3709  }
3710  }
3711  ao2_ref(q->members, -1);
3712 }
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1564
static void free_members(struct call_queue *q, int all)
Iterate through queue's member list and delete them.
Definition: app_queue.c:3683
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
struct ast_str * sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]
Definition: app_queue.c:1835

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

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

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

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

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

◆ do_hang()

static void do_hang ( struct callattempt o)
static

common hangup actions

Definition at line 4564 of file app_queue.c.

4565 {
4566  o->stillgoing = 0;
4567  ast_hangup(o->chan);
4569  o->chan = NULL;
4570 }
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2542
struct ast_channel * chan
Definition: app_queue.c:1674
unsigned int stillgoing
Definition: app_queue.c:1687

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

Referenced by ring_entry(), and wait_for_answer().

◆ do_print()

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

direct output to manager or cli with proper terminator

Definition at line 9939 of file app_queue.c.

9940 {
9941  if (s) {
9942  astman_append(s, "%s\r\n", str);
9943  } else {
9944  ast_cli(fd, "%s\n", str);
9945  }
9946 }
const char * str
Definition: app_jack.c:147
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3087

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

Definition at line 7479 of file app_queue.c.

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

6784 {
6785  struct queue_end_bridge *qeb = data;
6786  struct call_queue *q = qeb->q;
6787  struct ast_channel *chan = qeb->chan;
6788 
6789  if (ao2_ref(qeb, -1) == 1) {
6790  set_queue_variables(q, chan);
6791  /* This unrefs the reference we made in try_calling when we allocated qeb */
6792  queue_t_unref(q, "Expire bridge_config reference");
6793  }
6794 }
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:2065
Main Channel structure associated with a channel.
struct call_queue * q
Definition: app_queue.c:6772
struct ast_channel * chan
Definition: app_queue.c:6773

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

Referenced by try_calling().

◆ end_bridge_callback_data_fixup()

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

Definition at line 6776 of file app_queue.c.

6777 {
6778  struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
6779  ao2_ref(qeb, +1);
6780  qeb->chan = originator;
6781 }
void * end_bridge_callback_data
Definition: channel.h:1091

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

Referenced by try_calling().

◆ escape_and_substitute()

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

Definition at line 6823 of file app_queue.c.

6825 {
6826  const char *m = input;
6827  char escaped[size];
6828  char *p;
6829 
6830  for (p = escaped; p < escaped + size - 1; p++, m++) {
6831  switch (*m) {
6832  case '^':
6833  if (*(m + 1) == '{') {
6834  *p = '$';
6835  }
6836  break;
6837  case ',':
6838  *p++ = '\\';
6839  /* Fall through */
6840  default:
6841  *p = *m;
6842  }
6843  if (*m == '\0')
6844  break;
6845  }
6846 
6847  if (p == escaped + size) {
6848  escaped[size - 1] = '\0';
6849  }
6850 
6851  pbx_substitute_variables_helper(chan, escaped, output, size - 1);
6852 }
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1584
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211

References input(), and pbx_substitute_variables_helper().

Referenced by setup_mixmonitor().

◆ extension_state_cb()

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

Definition at line 2806 of file app_queue.c.

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

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

Referenced by create_queue_member(), and destroy_queue_member_cb().

◆ extensionstate2devicestate()

static int extensionstate2devicestate ( int  state)
static

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

Definition at line 2728 of file app_queue.c.

2729 {
2730  switch (state) {
2733  break;
2734  case AST_EXTENSION_INUSE:
2736  break;
2737  case AST_EXTENSION_BUSY:
2739  break;
2740  case AST_EXTENSION_RINGING:
2742  break;
2745  break;
2746  case AST_EXTENSION_ONHOLD:
2748  break;
2751  break;
2754  break;
2755  case AST_EXTENSION_REMOVED:
2757  default:
2759  break;
2760  }
2761 
2762  return state;
2763 }
enum sip_cc_notify_state state
Definition: chan_sip.c:966
@ AST_DEVICE_RINGINUSE
Definition: devicestate.h:60
@ AST_DEVICE_ONHOLD
Definition: devicestate.h:61
@ AST_DEVICE_RINGING
Definition: devicestate.h:59
@ AST_DEVICE_INVALID
Definition: devicestate.h:57
@ AST_DEVICE_BUSY
Definition: devicestate.h:56
@ AST_DEVICE_UNAVAILABLE
Definition: devicestate.h:58
@ AST_EXTENSION_REMOVED
Definition: pbx.h:62
@ AST_EXTENSION_RINGING
Definition: pbx.h:68
@ AST_EXTENSION_NOT_INUSE
Definition: pbx.h:64
@ AST_EXTENSION_INUSE
Definition: pbx.h:65
@ AST_EXTENSION_UNAVAILABLE
Definition: pbx.h:67
@ AST_EXTENSION_ONHOLD
Definition: pbx.h:69
@ AST_EXTENSION_BUSY
Definition: pbx.h:66
@ AST_EXTENSION_DEACTIVATED
Definition: pbx.h:63

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

Referenced by extension_state_cb(), and get_queue_member_status().

◆ find_best()

static struct callattempt* find_best ( struct callattempt outgoing)
static

find the entry with the best metric, or NULL

Definition at line 4823 of file app_queue.c.

4824 {
4825  struct callattempt *best = NULL, *cur;
4826 
4827  for (cur = outgoing; cur; cur = cur->q_next) {
4828  if (cur->stillgoing && /* Not already done */
4829  !cur->chan && /* Isn't already going */
4830  (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
4831  best = cur;
4832  }
4833  }
4834 
4835  return best;
4836 }
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1671

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

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

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

Referenced by __queues_show(), add_to_queue(), change_priority_caller_on_queue(), get_member_penalty(), join_queue(), load_realtime_queues(), queue_function_exists(), queue_function_mem_read(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_var(), 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_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 3738 of file app_queue.c.

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

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

Referenced by find_load_queue_rt_friendly().

◆ free_members()

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

Iterate through queue's member list and delete them.

Definition at line 3683 of file app_queue.c.

3684 {
3685  /* Free non-dynamic members */
3686  struct member *cur;
3687  struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3688 
3689  while ((cur = ao2_iterator_next(&mem_iter))) {
3690  if (all || !cur->dynamic) {
3691  member_remove_from_queue(q, cur);
3692  }
3693  ao2_ref(cur, -1);
3694  }
3695  ao2_iterator_destroy(&mem_iter);
3696 }

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

8911 {
8912  struct member *m;
8913 
8914  if (ast_strlen_zero(interface)) {
8915  ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
8916  return NULL;
8917  }
8918 
8919  m = interface_exists(q, interface);
8920  if (!m) {
8921  ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
8922  interface, q->name);
8923  }
8924  return m;
8925 }

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

7999 {
8000  int foundqueue = 0, penalty;
8001  struct call_queue *q;
8002  struct member *mem;
8003 
8004  if ((q = find_load_queue_rt_friendly(queuename))) {
8005  foundqueue = 1;
8006  ao2_lock(q);
8007  if ((mem = interface_exists(q, interface))) {
8008  penalty = mem->penalty;
8009  ao2_ref(mem, -1);
8010  ao2_unlock(q);
8011  queue_t_unref(q, "Search complete");
8012  return penalty;
8013  }
8014  ao2_unlock(q);
8015  queue_t_unref(q, "Search complete");
8016  }
8017 
8018  /* some useful debugging */
8019  if (foundqueue) {
8020  ast_log (LOG_ERROR, "Invalid queuename\n");
8021  } else {
8022  ast_log (LOG_ERROR, "Invalid interface\n");
8023  }
8024 
8025  return RESULT_FAILURE;
8026 }
#define RESULT_FAILURE
Definition: cli.h:42

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

Referenced by queue_function_memberpenalty_read().

◆ get_member_status()

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

Check if members are available.

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

Definition at line 2422 of file app_queue.c.

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

2851 {
2852  return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
2853 }
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:3177

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

1994 {
1995  if (member->wrapuptime) {
1996  return member->wrapuptime;
1997  }
1998  return q->wrapuptime;
1999 }
int wrapuptime
Definition: app_queue.c:1874

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

6419 {
6420  struct queue_stasis_data *queue_data = userdata;
6421  struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6422  RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6423  RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6424 
6425  if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6427  return;
6428  }
6429 
6430  ao2_lock(queue_data);
6431 
6432  if (queue_data->dying) {
6433  ao2_unlock(queue_data);
6434  return;
6435  }
6436 
6437  if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6438  ao2_unlock(queue_data);
6439  return;
6440  }
6441 
6442  if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6443  atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6444  (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6445  atxfer_msg->to_transfer_target.bridge_snapshot->uniqueid))) {
6446  ao2_unlock(queue_data);
6447  return;
6448  }
6449 
6450  caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6451  member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6452 
6453  ao2_unlock(queue_data);
6454 
6455  ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6456  log_attended_transfer(queue_data, atxfer_msg);
6457 
6458  send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6459  queue_data->holdstart, queue_data->starttime, TRANSFER);
6460  update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6461  queue_data->starttime);
6462  remove_stasis_subscriptions(queue_data);
6463 }
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:6078
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:5921
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6225
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition: app_queue.c:6279
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition: bridge.h:1100
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
@ AST_ATTENDED_TRANSFER_DEST_THREEWAY
Message representing attended transfer.
enum ast_attended_transfer_dest_type dest_type
struct ast_bridge_channel_snapshot_pair to_transfer_target
enum ast_transfer_result result
struct ast_bridge_channel_snapshot_pair to_transferee
struct ast_bridge_snapshot * bridge_snapshot
const ast_string_field uniqueid
Definition: bridge.h:328
Structure representing a snapshot of channel state.
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:6171
const ast_string_field caller_uniqueid
Definition: app_queue.c:6179
const ast_string_field member_uniqueid
Definition: app_queue.c:6179
struct call_queue * queue
Definition: app_queue.c:6181
const ast_string_field bridge_uniqueid
Definition: app_queue.c:6179
struct member * member
Definition: app_queue.c:6183
#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:936

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

6360 {
6361  struct queue_stasis_data *queue_data = userdata;
6362  struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
6363  const char *exten;
6364  const char *context;
6365  RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6366  RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6367 
6368  if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
6369  return;
6370  }
6371 
6372  ao2_lock(queue_data);
6373 
6374  if (queue_data->dying) {
6375  ao2_unlock(queue_data);
6376  return;
6377  }
6378 
6379  if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
6380  strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
6381  ao2_unlock(queue_data);
6382  return;
6383  }
6384 
6385  caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6386  member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6387 
6388  ao2_unlock(queue_data);
6389 
6390  exten = transfer_msg->exten;
6391  context = transfer_msg->context;
6392 
6393  ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
6394  ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6395  "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
6396  exten, context,
6397  (long) (queue_data->starttime - queue_data->holdstart),
6398  (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6399 
6400  send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6401  queue_data->holdstart, queue_data->starttime, TRANSFER);
6402  update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6403  queue_data->starttime);
6404  remove_stasis_subscriptions(queue_data);
6405 }
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, context, ast_blind_transfer_message::context, queue_stasis_data::dying, exten, 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 6325 of file app_queue.c.

6327 {
6328  struct queue_stasis_data *queue_data = userdata;
6329  struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6330  SCOPED_AO2LOCK(lock, queue_data);
6331 
6332  if (queue_data->dying) {
6333  return;
6334  }
6335 
6336  if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6337  return;
6338  }
6339 
6340  if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6341  ast_string_field_set(queue_data, bridge_uniqueid,
6342  enter_blob->bridge->uniqueid);
6343  ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6344  enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6345  }
6346 }
ast_mutex_t lock
Definition: app_meetme.c:1093
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:602
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 6606 of file app_queue.c.

6608 {
6609  struct queue_stasis_data *queue_data = userdata;
6610  struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6611  RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6612  RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6613  RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
6614  enum agent_complete_reason reason;
6615 
6616  ao2_lock(queue_data);
6617 
6618  if (queue_data->dying) {
6619  ao2_unlock(queue_data);
6620  return;
6621  }
6622 
6623  if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6624  reason = CALLER;
6625  } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6626  reason = AGENT;
6627  } else {
6628  ao2_unlock(queue_data);
6629  return;
6630  }
6631 
6632  chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
6633  if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
6634  !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
6635  !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
6636  /* Channel that is hanging up is doing it as part of a transfer.
6637  * We'll get a transfer event later
6638  */
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  ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
6649  channel_blob->snapshot->base->name);
6650 
6651  ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6652  reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
6653  (long) (queue_data->starttime - queue_data->holdstart),
6654  (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6655 
6656  send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6657  queue_data->holdstart, queue_data->starttime, reason);
6658  update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6659  queue_data->starttime);
6660  remove_stasis_subscriptions(queue_data);
6661 }
agent_complete_reason
Definition: app_queue.c:6071
#define AST_TRANSFERER_ROLE_NAME
Definition: bridge_basic.h:36
int ast_channel_has_role(struct ast_channel *channel, const char *role_name)
Check if a role exists on a channel.
Definition: bridge_roles.c:394
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1448
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 6491 of file app_queue.c.

6493 {
6494  struct queue_stasis_data *queue_data = userdata;
6495  struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6496  struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6497  struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6498  struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6499  struct local_optimization *optimization;
6500  unsigned int id;
6501  SCOPED_AO2LOCK(lock, queue_data);
6502 
6503  if (queue_data->dying) {
6504  return;
6505  }
6506 
6507  if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6508  optimization = &queue_data->member_optimize;
6509  } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6510  optimization = &queue_data->caller_optimize;
6511  } else {
6512  return;
6513  }
6514 
6515  /* We only allow move-swap optimizations, so there had BETTER be a source */
6516  ast_assert(source != NULL);
6517 
6518  optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6519  if (!optimization->source_chan_uniqueid) {
6520  ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6521  return;
6522  }
6524 
6525  optimization->id = id;
6526  optimization->in_progress = 1;
6527 }
enum queue_result id
Definition: app_queue.c:1640
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_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_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:397
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:322
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:6147
const char * source_chan_uniqueid
Definition: app_queue.c:6149
unsigned int id
Definition: app_queue.c:6153
struct local_optimization member_optimize
Definition: app_queue.c:6201
struct local_optimization caller_optimize
Definition: app_queue.c:6199
#define ast_assert(a)
Definition: utils.h:734

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

Referenced by setup_stasis_subs().

◆ handle_local_optimization_end()

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

Definition at line 6542 of file app_queue.c.

6544 {
6545  struct queue_stasis_data *queue_data = userdata;
6546  struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6547  struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6548  struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6549  struct local_optimization *optimization;
6550  int is_caller;
6551  unsigned int id;
6552  SCOPED_AO2LOCK(lock, queue_data);
6553 
6554  if (queue_data->dying) {
6555  return;
6556  }
6557 
6558  if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6559  optimization = &queue_data->member_optimize;
6560  is_caller = 0;
6561  } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6562  optimization = &queue_data->caller_optimize;
6563  is_caller = 1;
6564  } else {
6565  return;
6566  }
6567 
6569 
6570  if (!optimization->in_progress) {
6571  ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
6572  return;
6573  }
6574 
6575  if (id != optimization->id) {
6576  ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
6577  id, optimization->id);
6578  return;
6579  }
6580 
6581  if (is_caller) {
6582  ast_debug(3, "Local optimization: Changing queue caller uniqueid from %s to %s\n",
6583  queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
6584  ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
6585  } else {
6586  ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
6587  queue_data->member_uniqueid, optimization->source_chan_uniqueid);
6588  ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
6589  }
6590 
6591  optimization->in_progress = 0;
6592 }

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

6665 {
6666  struct queue_stasis_data *queue_data = userdata;
6667  struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6668  const char *new_channel_id;
6669 
6670  new_channel_id = ast_json_string_get(ast_json_object_get(channel_blob->blob, "newchanneluniqueid"));
6671 
6672  ao2_lock(queue_data);
6673 
6674  if (queue_data->dying) {
6675  ao2_unlock(queue_data);
6676  return;
6677  }
6678 
6679  if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6680  ast_debug(1, "Replacing caller channel %s with %s due to masquerade\n", queue_data->caller_uniqueid, new_channel_id);
6681  ast_string_field_set(queue_data, caller_uniqueid, new_channel_id);
6682  } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6683  ast_debug(1, "Replacing member channel %s with %s due to masquerade\n", queue_data->member_uniqueid, new_channel_id);
6684  ast_string_field_set(queue_data, member_uniqueid, new_channel_id);
6685  }
6686 
6687  ao2_unlock(queue_data);
6688 }
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
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

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

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

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

2950 {
2951  int i;
2952  struct penalty_rule *pr_iter;
2953 
2954  q->dead = 0;
2955  q->retry = DEFAULT_RETRY;
2956  q->timeout = DEFAULT_TIMEOUT;
2957  q->maxlen = 0;
2958 
2959  ast_string_field_set(q, context, "");
2960 
2961  q->announcefrequency = 0;
2963  q->announceholdtime = 1;
2964  q->announceposition_only_up = 0;
2965  q->announcepositionlimit = 10; /* Default 10 positions */
2966  q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
2967  q->roundingseconds = 0; /* Default - don't announce seconds */
2968  q->servicelevel = 0;
2969  q->ringinuse = 1;
2970  q->announce_to_first_user = 0;
2971  q->setinterfacevar = 0;
2972  q->setqueuevar = 0;
2973  q->setqueueentryvar = 0;
2975  q->montype = montype_default;
2976  q->monfmt[0] = '\0';
2977  q->reportholdtime = 0;
2978  q->wrapuptime = 0;
2979  q->penaltymemberslimit = 0;
2980  q->joinempty = 0;
2981  q->leavewhenempty = 0;
2982  q->memberdelay = 0;
2983  q->weight = 0;
2984  q->timeoutrestart = 0;
2986  q->randomperiodicannounce = 0;
2987  q->numperiodicannounce = 0;
2990  q->autopausedelay = 0;
2991  if (!q->members) {
2993  /* linear strategy depends on order, so we have to place all members in a list */
2995  } else {
2998  }
2999  }
3000  q->found = 1;
3001 
3002  ast_string_field_set(q, moh, "");
3003  ast_string_field_set(q, sound_next, "queue-youarenext");
3004  ast_string_field_set(q, sound_thereare, "queue-thereare");
3005  ast_string_field_set(q, sound_calls, "queue-callswaiting");
3006  ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3007  ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3008  ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3009  ast_string_field_set(q, sound_minutes, "queue-minutes");
3010  ast_string_field_set(q, sound_minute, "queue-minute");
3011  ast_string_field_set(q, sound_seconds, "queue-seconds");
3012  ast_string_field_set(q, sound_thanks, "queue-thankyou");
3013  ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3014 
3015  if (!q->sound_periodicannounce[0]) {
3017  }
3018 
3019  if (q->sound_periodicannounce[0]) {
3020  ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3021  }
3022 
3023  for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3024  if (q->sound_periodicannounce[i]) {
3025  ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3026  }
3027  }
3028 
3029  while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3030  ast_free(pr_iter);
3031  }
3032 
3033  /* On restart assume no members are available.
3034  * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3035  *
3036  * This seems counter intuitive, but is required to light a BLF
3037  * AST_DEVICE_INUSE indicates no members are available.
3038  * AST_DEVICE_NOT_INUSE indicates a member is available.
3039  */
3041 }
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1607
#define DEFAULT_RETRY
Definition: app_queue.c:1561
static int member_hash_fn(const void *obj, const int flags)
Definition: app_queue.c:2920
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition: app_queue.c:2936
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition: app_queue.c:1569
#define DEFAULT_TIMEOUT
Definition: app_queue.c:1562
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1604
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1788
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
unsigned int setinterfacevar
Definition: app_queue.c:1839
int announcefrequency
Definition: app_queue.c:1857
unsigned int announceholdtime
Definition: app_queue.c:1845
unsigned int reportholdtime
Definition: app_queue.c:1842
unsigned int setqueueentryvar
Definition: app_queue.c:1841
unsigned int timeoutrestart
Definition: app_queue.c:1844
int periodicannouncefrequency
Definition: app_queue.c:1859
unsigned int announceposition_only_up
Definition: app_queue.c:1847
unsigned int setqueuevar
Definition: app_queue.c:1840
int announcepositionlimit
Definition: app_queue.c:1856
unsigned int announce_to_first_user
Definition: app_queue.c:1838
int randomperiodicannounce
Definition: app_queue.c:1861
int autopause
Definition: app_queue.c:1880
int servicelevel
Definition: app_queue.c:1868
int autofill
Definition: app_queue.c:1887
int minannouncefrequency
Definition: app_queue.c:1858
enum empty_conditions leavewhenempty
Definition: app_queue.c:1855
int roundingseconds
Definition: app_queue.c:1862
int numperiodicannounce
Definition: app_queue.c:1860
unsigned int announceposition
Definition: app_queue.c:1846
char monfmt[8]
Definition: app_queue.c:1870
enum empty_conditions joinempty
Definition: app_queue.c:1854
int memberdelay
Definition: app_queue.c:1886
struct call_queue::@67 rules
int autopausedelay
Definition: app_queue.c:1881
int timeoutpriority
Definition: app_queue.c:1882

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::autopausedelay, context, call_queue::dead, DEFAULT_MIN_ANNOUNCE_FREQUENCY, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, penalty_rule::list, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, member_cmp_fn(), member_hash_fn(), call_queue::memberdelay, call_queue::members, call_queue::minannouncefrequency, call_queue::monfmt, call_queue::montype, montype_default, call_queue::name, NULL, call_queue::numperiodicannounce, call_queue::penaltymemberslimit, call_queue::periodicannouncefrequency, QUEUE_AUTOPAUSE_OFF, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRORDERED, call_queue::randomperiodicannounce, 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 2091 of file app_queue.c.

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

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

Referenced by 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 3075 of file app_queue.c.

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

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

Referenced by reload_queue_rules().

◆ int2strat()

static const char* int2strat ( int  strategy)
static

Definition at line 1924 of file app_queue.c.

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

References ARRAY_LEN, strategy::name, and strategies.

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