Asterisk - The Open Source Telephony Project  18.5.0
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)
}
 
enum  { OPT_ARG_CALLEE_GO_ON = 0, OPT_ARG_PREDIAL_CALLEE, OPT_ARG_PREDIAL_CALLER, 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
}
 
enum  queue_timeout_priority { TIMEOUT_PRIORITY_APP, TIMEOUT_PRIORITY_CONF }
 

Functions

static char * __queues_show (struct mansession *s, int fd, int argc, const char *const *argv)
 Show queue(s) status and statistics. More...
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
static int add_to_queue (const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface, const char *reason_paused, int wrapuptime)
 Add member to queue. More...
 
static struct call_queuealloc_queue (const char *queuename)
 
 AO2_STRING_FIELD_SORT_FN (call_queue, name)
 
static int aqm_exec (struct ast_channel *chan, const char *data)
 AddQueueMember application. More...
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int autopause2int (const char *autopause)
 
static int calc_metric (struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
 Calculate the metric of each member in the outgoing callattempts. More...
 
static void callattempt_free (struct callattempt *doomed)
 
static int can_ring_entry (struct queue_ent *qe, struct callattempt *call)
 
static int change_priority_caller_on_queue (const char *queuename, const char *caller, int priority)
 Change priority caller into a queue. More...
 
static void clear_queue (struct call_queue *q)
 
static int clear_stats (const char *queuename)
 Facilitates resetting statistics for a queue. More...
 
static int compare_weight (struct call_queue *rq, struct member *member)
 
static char * complete_queue (const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
 Check if a given word is in a space-delimited list. More...
 
static char * complete_queue_add_member (const char *line, const char *word, int pos, int state)
 
static char * complete_queue_pause_member (const char *line, const char *word, int pos, int state)
 
static char * complete_queue_remove_member (const char *line, const char *word, int pos, int state)
 
static char * complete_queue_rule_show (const char *line, const char *word, int pos, int state)
 
static char * complete_queue_set_member_value (const char *line, const char *word, int pos, int state)
 
static char * complete_queue_show (const char *line, const char *word, int pos, int state)
 
static int compress_char (const char c)
 
static 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 ouput 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)
 
static int get_member_status (struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate)
 Check if members are available. More...
 
static int get_queue_member_status (struct member *cur)
 Return the current state of a member. More...
 
static int get_wrapuptime (struct call_queue *q, struct member *member)
 Return wrapuptime. More...
 
static void handle_attended_transfer (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 Handle an attended transfer event. More...
 
static void handle_blind_transfer (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 Handle a blind transfer event. More...
 
static void handle_bridge_enter (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void handle_hangup (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void handle_local_optimization_begin (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void handle_local_optimization_end (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static void handle_masquerade (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static char * handle_queue_add_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_change_priority_caller (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_pause_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_remove_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_reset (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_rule_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_set_member_penalty (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_queue_set_member_ringinuse (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void hangupcalls (struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
 Hang up a list of outgoing calls. More...
 
static void init_queue (struct call_queue *q)
 Initialize Queue default values. More...
 
static void insert_entry (struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
 Insert the 'new' entry after the 'prev' entry of queue 'q'. More...
 
static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
 Change queue penalty by adding rule. More...
 
static const char * int2strat (int strategy)
 
static struct memberinterface_exists (struct call_queue *q, const char *interface)
 
static int is_member_available (struct call_queue *q, struct member *mem)
 
static int is_our_turn (struct queue_ent *qe)
 Check if we should start attempting to call queue members. More...
 
static int join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
 
static int kill_dead_members (void *obj, void *arg, int flags)
 
static int kill_if_unfound (void *obj, void *arg, int flags)
 
static void leave_queue (struct queue_ent *qe)
 Caller leaving queue. More...
 
static int load_module (void)
 Load the module. More...
 
static 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 mark_member_dead (void *obj, void *arg, int flags)
 
static int mark_unfound (void *obj, void *arg, int flags)
 
static void member_add_to_queue (struct call_queue *queue, struct member *mem)
 
static int member_cmp_fn (void *obj1, void *obj2, int flags)
 
static int member_hash_fn (const void *obj, const int flags)
 
static void member_remove_from_queue (struct call_queue *queue, struct member *mem)
 
static int member_status_available (int status)
 
static int num_available_members (struct call_queue *q)
 Get the number of members available to accept a call. More...
 
static void parse_empty_options (const char *value, enum empty_conditions *empty, int joinempty)
 
static int pending_members_cmp (void *obj, void *arg, int flags)
 
static int pending_members_hash (const void *obj, const int flags)
 
static void pending_members_remove (struct member *mem)
 
static int play_file (struct ast_channel *chan, const char *filename)
 
static int pqm_exec (struct ast_channel *chan, const char *data)
 PauseQueueMember application. More...
 
static void print_queue (struct mansession *s, int fd, struct call_queue *q)
 Print a single queue to AMI or the CLI. More...
 
static void publish_dial_end_event (struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
 
static int publish_queue_member_pause (struct call_queue *q, struct member *member)
 
static int ql_exec (struct ast_channel *chan, const char *data)
 QueueLog application. More...
 
static struct ast_manager_event_blobqueue_agent_called_to_ami (struct stasis_message *message)
 
static void queue_agent_cb (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static struct ast_manager_event_blobqueue_agent_complete_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_agent_connect_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_agent_dump_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_agent_ringnoanswer_to_ami (struct stasis_message *message)
 
static void queue_bridge_cb (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static struct ast_manager_event_blobqueue_caller_abandon_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_caller_join_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_caller_leave_to_ami (struct stasis_message *message)
 
static void queue_channel_cb (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 
static struct ast_manager_event_blobqueue_channel_to_ami (const char *type, struct stasis_message *message)
 
static int queue_cmp_cb (void *obj, void *arg, int flags)
 
static int queue_delme_members_decrement_followers (void *obj, void *arg, int flag)
 
static int queue_exec (struct ast_channel *chan, const char *data)
 The starting point for all queue calls. More...
 
static int queue_function_exists (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Check if a given queue exists. More...
 
static int queue_function_mem_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Get number either busy / free / ready or total members of a specific queue. More...
 
static int queue_function_mem_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse. More...
 
static int queue_function_memberpenalty_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. More...
 
static int queue_function_memberpenalty_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. More...
 
static int queue_function_qac_dep (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Get the total number of members in a specific queue (Deprecated) More...
 
static int queue_function_queuegetchannel (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue. More...
 
static int queue_function_queuememberlist (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue. More...
 
static int queue_function_queuewaitingcount (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue. More...
 
static int queue_function_var (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 create interface var with all queue details. More...
 
static int queue_hash_cb (const void *obj, const int flags)
 
static struct ast_manager_event_blobqueue_member_added_to_ami (struct stasis_message *message)
 
static struct ast_jsonqueue_member_blob_create (struct call_queue *q, struct member *mem)
 
static int queue_member_decrement_followers (void *obj, void *arg, int flag)
 
static void queue_member_follower_removal (struct call_queue *queue, struct member *mem)
 
static struct ast_manager_event_blobqueue_member_pause_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_penalty_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_removed_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_ringinuse_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_status_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_member_to_ami (const char *type, struct stasis_message *message)
 
static struct ast_manager_event_blobqueue_multi_channel_to_ami (const char *type, struct stasis_message *message)
 
static void queue_publish_member_blob (struct stasis_message_type *type, struct ast_json *blob)
 
static void queue_publish_multi_channel_blob (struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
 
static void queue_publish_multi_channel_snapshot_blob (struct stasis_topic *topic, struct ast_channel_snapshot *caller_snapshot, struct ast_channel_snapshot *agent_snapshot, struct stasis_message_type *type, struct ast_json *blob)
 
static void queue_reset_global_params (void)
 
static void queue_rules_reset_global_params (void)
 
static void queue_rules_set_global_params (struct ast_config *cfg)
 
static void queue_set_global_params (struct ast_config *cfg)
 
static void queue_set_param (struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
 Configure a queue parameter. More...
 
static char * queue_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static struct queue_stasis_dataqueue_stasis_data_alloc (struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
 
static void queue_stasis_data_destructor (void *obj)
 
static int qupd_exec (struct ast_channel *chan, const char *data)
 Update Queue with data of an outgoing call. More...
 
static void recalc_holdtime (struct queue_ent *qe, int newholdtime)
 
static void record_abandoned (struct queue_ent *qe)
 Record that a caller gave up on waiting in queue. More...
 
static int reload (void)
 
static int reload_handler (int reload, struct ast_flags *mask, const char *queuename)
 The command center for all reload operations. More...
 
static void reload_queue_members (void)
 Reload dynamic queue members persisted into the astdb. More...
 
static int reload_queue_rules (int reload)
 Reload the rules defined in queuerules.conf. More...
 
static int reload_queues (int reload, struct ast_flags *mask, const char *queuename)
 reload the queues.conf file More...
 
static void reload_single_member (const char *memberdata, struct call_queue *q)
 reload information pertaining to a single member More...
 
static void reload_single_queue (struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
 Reload information pertaining to a particular queue. More...
 
static int remove_from_queue (const char *queuename, const char *interface)
 Remove member from queue. More...
 
static void remove_stasis_subscriptions (struct queue_stasis_data *queue_data)
 
static int 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_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_caller_abandon_type,.to_ami=queue_caller_abandon_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_status_type,.to_ami=queue_member_status_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_removed_type,.to_ami=queue_member_removed_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_ringinuse_type,.to_ami=queue_member_ringinuse_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_called_type,.to_ami=queue_agent_called_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_complete_type,.to_ami=queue_agent_complete_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,)
 
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 int unload_module (void)
 
static void update_connected_line_from_peer (struct ast_channel *chan, struct ast_channel *peer, int is_caller)
 
static void update_qe_rule (struct queue_ent *qe)
 update rules for queues More...
 
static int update_queue (struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
 update the queue status More...
 
static int update_realtime_member_field (struct member *mem, const char *queue_name, const char *field, const char *value)
 
static void update_realtime_members (struct call_queue *q)
 
static void update_status (struct call_queue *q, struct member *m, const int status)
 set a member's status based on device state of that member's state_interface. More...
 
static int upqm_exec (struct ast_channel *chan, const char *data)
 UnPauseQueueMember application. More...
 
static int valid_exit (struct queue_ent *qe, char digit)
 Check for valid exit from queue via goto. More...
 
static int wait_a_bit (struct queue_ent *qe)
 
static struct callattemptwait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
 Wait for a member to answer the call. More...
 
static int wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason)
 The waiting areas for callers who are not actively calling members. More...
 
static int word_in_list (const char *list, const char *word)
 Check if a given word is in a space-delimited list. More...
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, .optional_modules = "res_monitor", }
 
static struct stasis_message_routeragent_router
 
static char * app = "Queue"
 
static char * app_aqm = "AddQueueMember"
 
static char * app_pqm = "PauseQueueMember"
 
static char * app_ql = "QueueLog"
 
static char * app_qupd = "QueueUpdate"
 
static char * app_rqm = "RemoveQueueMember"
 
static char * app_upqm = "UnpauseQueueMember"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static int autofill_default
 queues.conf [general] option More...
 
static const struct autopause autopausesmodes []
 
static struct ast_cli_entry cli_queue []
 
static struct stasis_subscriptiondevice_state_sub
 Subscription to device state change messages. More...
 
static int 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 }, [ '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
 queuesrules.conf [general] option More...
 
static struct rule_lists rule_lists = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static int shared_lastcall
 queues.conf [general] option More...
 
static const struct strategy strategies []
 
static struct stasis_forwardtopic_forwarder
 
static int use_weight
 Records that one or more queues use weight. More...
 

Detailed Description

True call queues with optional send URL on answer.

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

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

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

Referenced by queue_set_param().

◆ ANNOUNCEHOLDTIME_ONCE

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1637 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

◆ ANNOUNCEPOSITION_LIMIT

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1654 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

◆ ANNOUNCEPOSITION_MORE_THAN

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 1653 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

◆ ANNOUNCEPOSITION_NO

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1652 of file app_queue.c.

Referenced by queue_set_param().

◆ ANNOUNCEPOSITION_YES

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1651 of file app_queue.c.

Referenced by init_queue(), queue_set_param(), and say_position().

◆ AST_MAX_WATCHERS

#define AST_MAX_WATCHERS   256

Definition at line 4923 of file app_queue.c.

Referenced by wait_for_answer().

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

Referenced by init_queue().

◆ DEFAULT_RETRY

#define DEFAULT_RETRY   5

Definition at line 1429 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

◆ DEFAULT_TIMEOUT

#define DEFAULT_TIMEOUT   15

Definition at line 1430 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

◆ MAX_CALL_ATTEMPT_BUCKETS

#define MAX_CALL_ATTEMPT_BUCKETS   353

Definition at line 2376 of file app_queue.c.

Referenced by load_module().

◆ MAX_PERIODIC_ANNOUNCEMENTS

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 1432 of file app_queue.c.

Referenced by destroy_queue(), init_queue(), and queue_set_param().

◆ MAX_QUEUE_BUCKETS

#define MAX_QUEUE_BUCKETS   53

Definition at line 1439 of file app_queue.c.

Referenced by load_module().

◆ QUEUE_EVENT_VARIABLES

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1638 of file app_queue.c.

◆ QUEUE_PAUSED_DEVSTATE

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

◆ queue_ref

#define queue_ref (   q)    ao2_bump(q)

Definition at line 1918 of file app_queue.c.

Referenced by insert_entry(), and queue_stasis_data_alloc().

◆ queue_t_ref

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

Definition at line 1920 of file app_queue.c.

Referenced by leave_queue(), and try_calling().

◆ queue_t_unref

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

◆ QUEUE_UNKNOWN_PAUSED_DEVSTATE

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3352 of file app_queue.c.

Referenced by member_remove_from_queue().

◆ QUEUE_UNPAUSED_DEVSTATE

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

◆ queue_unref

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

◆ queues_t_link

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

Definition at line 1922 of file app_queue.c.

Referenced by find_queue_by_name_rt(), and reload_single_queue().

◆ queues_t_unlink

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

Definition at line 1923 of file app_queue.c.

Referenced by find_queue_by_name_rt(), and leave_queue().

◆ RECHECK

#define RECHECK   1

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

Definition at line 1431 of file app_queue.c.

Referenced by wait_our_turn().

◆ RES_EXISTS

#define RES_EXISTS   (-1)

◆ RES_NOSUCHQUEUE

#define RES_NOSUCHQUEUE   (-3)

◆ RES_NOT_CALLER

#define RES_NOT_CALLER   (-5)

◆ RES_NOT_DYNAMIC

#define RES_NOT_DYNAMIC   (-4)

◆ RES_OKAY

#define RES_OKAY   0

◆ RES_OUTOFMEMORY

#define RES_OUTOFMEMORY   (-2)

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 

Definition at line 1325 of file app_queue.c.

1325  {
1326  OPT_MARK_AS_ANSWERED = (1 << 0),
1327  OPT_GO_ON = (1 << 1),
1328  OPT_DATA_QUALITY = (1 << 2),
1329  OPT_CALLEE_GO_ON = (1 << 3),
1330  OPT_CALLEE_HANGUP = (1 << 4),
1331  OPT_CALLER_HANGUP = (1 << 5),
1332  OPT_IGNORE_CALL_FW = (1 << 6),
1333  OPT_IGNORE_CONNECTEDLINE = (1 << 7),
1334  OPT_CALLEE_PARK = (1 << 8),
1335  OPT_CALLER_PARK = (1 << 9),
1336  OPT_NO_RETRY = (1 << 10),
1337  OPT_RINGING = (1 << 11),
1338  OPT_RING_WHEN_RINGING = (1 << 12),
1339  OPT_CALLEE_TRANSFER = (1 << 13),
1340  OPT_CALLER_TRANSFER = (1 << 14),
1341  OPT_CALLEE_AUTOMIXMON = (1 << 15),
1342  OPT_CALLER_AUTOMIXMON = (1 << 16),
1343  OPT_CALLEE_AUTOMON = (1 << 17),
1344  OPT_CALLER_AUTOMON = (1 << 18),
1345  OPT_PREDIAL_CALLEE = (1 << 19),
1346  OPT_PREDIAL_CALLER = (1 << 20),
1347 };

◆ anonymous enum

anonymous enum
Enumerator
OPT_ARG_CALLEE_GO_ON 
OPT_ARG_PREDIAL_CALLEE 
OPT_ARG_PREDIAL_CALLER 
OPT_ARG_ARRAY_SIZE 

Definition at line 1349 of file app_queue.c.

1349  {
1353  /* note: this entry _MUST_ be the last one in the enum */
1355 };

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

◆ anonymous enum

anonymous enum
Enumerator
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 1392 of file app_queue.c.

◆ agent_complete_reason

Enumerator
CALLER 
AGENT 
TRANSFER 

Definition at line 5857 of file app_queue.c.

5857  {
5858  CALLER,
5859  AGENT,
5860  TRANSFER
5861 };

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

◆ member_properties

Enumerator
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1630 of file app_queue.c.

1630  {
1631  MEMBER_PENALTY = 0,
1632  MEMBER_RINGINUSE = 1,
1633 };

◆ queue_reload_mask

Enumerator
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 1398 of file app_queue.c.

1398  {
1399  QUEUE_RELOAD_PARAMETERS = (1 << 0),
1400  QUEUE_RELOAD_MEMBER = (1 << 1),
1401  QUEUE_RELOAD_RULES = (1 << 2),
1402  QUEUE_RESET_STATS = (1 << 3),
1403 };

◆ queue_result

Enumerator
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 

Definition at line 1495 of file app_queue.c.

◆ queue_timeout_priority

Enumerator
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1520 of file app_queue.c.

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

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(), LOG_WARNING, call_queue::name, NULL, out, print_queue(), queue_t_unref, queue_unref, call_queue::realtime, and SENTINEL.

Referenced by queue_show().

9759 {
9760  struct call_queue *q;
9761  struct ast_str *out = ast_str_alloca(512);
9762  struct ao2_container *sorted_queues;
9763 
9764  struct ao2_iterator queue_iter;
9765  int found = 0;
9766 
9767  if (argc != 2 && argc != 3) {
9768  return CLI_SHOWUSAGE;
9769  }
9770 
9771  if (argc == 3) { /* specific queue */
9772  if ((q = find_load_queue_rt_friendly(argv[2]))) {
9773  ao2_lock(q);
9774  print_queue(s, fd, q);
9775  ao2_unlock(q);
9776  queue_unref(q);
9777  } else {
9778  ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
9779  do_print(s, fd, ast_str_buffer(out));
9780  }
9781  return CLI_SUCCESS;
9782  }
9783 
9784  if (ast_check_realtime("queues")) {
9785  /* This block is to find any queues which are defined in realtime but
9786  * which have not yet been added to the in-core container
9787  */
9788  struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
9789  if (cfg) {
9790  char *category = NULL;
9791  while ((category = ast_category_browse(cfg, category))) {
9792  const char *queuename = ast_variable_retrieve(cfg, category, "name");
9793  if (ast_strlen_zero(queuename)) {
9794  ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
9795  continue;
9796  }
9797  if ((q = find_load_queue_rt_friendly(queuename))) {
9798  queue_t_unref(q, "Done with temporary pointer");
9799  }
9800  }
9801  ast_config_destroy(cfg);
9802  }
9803  }
9804 
9805  /*
9806  * Snapping a copy of the container prevents having to lock both the queues container
9807  * and the queue itself at the same time. It also allows us to sort the entries.
9808  */
9809  sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
9810  if (!sorted_queues) {
9811  return CLI_SUCCESS;
9812  }
9813  if (ao2_container_dup(sorted_queues, queues, 0)) {
9814  ao2_ref(sorted_queues, -1);
9815  return CLI_SUCCESS;
9816  }
9817 
9818  /*
9819  * No need to lock the container since it's temporary and static.
9820  * We also unlink the entries as we use them so the container is
9821  * empty when the iterator finishes. We can then just unref the container.
9822  */
9823  queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
9824  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
9825  struct call_queue *realtime_queue = NULL;
9826  ao2_lock(q);
9827  /* This check is to make sure we don't print information for realtime
9828  * queues which have been deleted from realtime but which have not yet
9829  * been deleted from the in-core container. Only do this if we're not
9830  * looking for a specific queue.
9831  */
9832  if (q->realtime) {
9833  realtime_queue = find_load_queue_rt_friendly(q->name);
9834  if (!realtime_queue) {
9835  ao2_unlock(q);
9836  queue_t_unref(q, "Done with iterator");
9837  continue;
9838  }
9839  queue_t_unref(realtime_queue, "Queue is already in memory");
9840  }
9841 
9842  found = 1;
9843  print_queue(s, fd, q);
9844 
9845  ao2_unlock(q);
9846  queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
9847  }
9848  ao2_iterator_destroy(&queue_iter);
9849  ao2_ref(sorted_queues, -1);
9850  if (!found) {
9851  ast_str_set(&out, 0, "No queues.");
9852  do_print(s, fd, ast_str_buffer(out));
9853  }
9854  return CLI_SUCCESS;
9855 }
static void do_print(struct mansession *s, int fd, const char *str)
direct ouput to manager or cli with proper terminator
Definition: app_queue.c:9644
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
#define LOG_WARNING
Definition: logger.h:274
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3363
#define queue_unref(q)
Definition: app_queue.c:1919
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ast_str_alloca(init_len)
Definition: strings.h:800
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
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:1065
#define ast_log
Definition: astobj2.c:42
#define SENTINEL
Definition: compiler.h:87
static struct ao2_container * queues
Definition: app_queue.c:1766
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define ao2_lock(a)
Definition: astobj2.h:718
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3452
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
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.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
const ast_string_field name
Definition: app_queue.c:1696
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
#define CLI_SUCCESS
Definition: cli.h:44
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
Assume that the ao2_container is already locked.
Definition: astobj2.h:1872
FILE * out
Definition: utils/frame.c:33
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
unsigned int realtime
Definition: app_queue.c:1712
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:9654
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1358
Generic container type.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 11505 of file app_queue.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 11505 of file app_queue.c.

◆ add_to_queue()

static int add_to_queue ( const char *  queuename,
const char *  interface,
const char *  membername,
int  penalty,
int  paused,
int  dump,
const char *  state_interface,
const char *  reason_paused,
int  wrapuptime 
)
static

Add member to queue.

Return values
RES_NOT_DYNAMICwhen they aren't a RT member
RES_NOSUCHQUEUEqueue does not exist
RES_OKAYadded member from queue
RES_EXISTSqueue exists but no members
RES_OUT_OF_MEMORYqueue exists but not enough memory to create member
Note
Ensure the appropriate realtime queue is loaded. Note that this short-circuits if the queue is already in memory.

Definition at line 7377 of file app_queue.c.

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(), interface_exists(), is_member_available(), member_add_to_queue(), call_queue::name, NULL, queue_member_blob_create(), queue_publish_member_blob(), queue_t_unref, member::reason_paused, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and call_queue::ringinuse.

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

7378 {
7379  struct call_queue *q;
7380  struct member *new_member, *old_member;
7381  int res = RES_NOSUCHQUEUE;
7382 
7383  /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7384  * short-circuits if the queue is already in memory. */
7385  if (!(q = find_load_queue_rt_friendly(queuename))) {
7386  return res;
7387  }
7388 
7389  ao2_lock(q);
7390  if ((old_member = interface_exists(q, interface)) == NULL) {
7392  new_member->dynamic = 1;
7393  if (reason_paused) {
7394  ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7395  }
7396  member_add_to_queue(q, new_member);
7397  queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7398 
7399  if (is_member_available(q, new_member)) {
7401  }
7402 
7403  ao2_ref(new_member, -1);
7404  new_member = NULL;
7405 
7406  if (dump) {
7407  dump_queue_members(q);
7408  }
7409 
7410  res = RES_OKAY;
7411  } else {
7412  res = RES_OUTOFMEMORY;
7413  }
7414  } else {
7415  ao2_ref(old_member, -1);
7416  res = RES_EXISTS;
7417  }
7418  ao2_unlock(q);
7419  queue_t_unref(q, "Expiring temporary reference");
7420 
7421  return res;
7422 }
int dynamic
Definition: app_queue.c:1601
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:2686
int paused
Definition: app_queue.c:1604
#define RES_OKAY
Definition: app_queue.c:1441
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1596
int wrapuptime
Definition: app_queue.c:1608
unsigned int ringinuse
Definition: app_queue.c:1700
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define RES_OUTOFMEMORY
Definition: app_queue.c:1443
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3360
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
int penalty
Definition: app_queue.c:1599
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7242
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2258
const ast_string_field name
Definition: app_queue.c:1696
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:7269
char reason_paused[80]
Definition: app_queue.c:1605
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1444
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define RES_EXISTS
Definition: app_queue.c:1442
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2234
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2468

◆ alloc_queue()

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

Definition at line 3534 of file app_queue.c.

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

Referenced by find_queue_by_name_rt(), and reload_single_queue().

3535 {
3536  struct call_queue *q;
3537 
3538  if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3539  if (ast_string_field_init(q, 64)) {
3540  queue_t_unref(q, "String field allocation failed");
3541  return NULL;
3542  }
3543  ast_string_field_set(q, name, queuename);
3544  }
3545  return q;
3546 }
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:409
#define NULL
Definition: resample.c:96
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
static void destroy_queue(void *obj)
Free queue&#39;s member list then its string fields.
Definition: app_queue.c:3519
static const char name[]
Definition: cdr_mysql.c:74
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514

◆ AO2_STRING_FIELD_SORT_FN()

AO2_STRING_FIELD_SORT_FN ( call_queue  ,
name   
)

Referenced by print_queue().

◆ aqm_exec()

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

AddQueueMember application.

Definition at line 8025 of file app_queue.c.

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_NOTICE, LOG_WARNING, member::membername, NULL, options, parse(), pbx_builtin_setvar_helper(), member::penalty, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, member::state_interface, tmp(), and member::wrapuptime.

Referenced by load_module().

8026 {
8027  int res=-1;
8028  char *parse, *tmp, *temppos = NULL;
8030  AST_APP_ARG(queuename);
8031  AST_APP_ARG(interface);
8032  AST_APP_ARG(penalty);
8034  AST_APP_ARG(membername);
8035  AST_APP_ARG(state_interface);
8037  );
8038  int penalty = 0;
8039  int wrapuptime;
8040 
8041  if (ast_strlen_zero(data)) {
8042  ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8043  return -1;
8044  }
8045 
8046  parse = ast_strdupa(data);
8047 
8048  AST_STANDARD_APP_ARGS(args, parse);
8049 
8050  if (ast_strlen_zero(args.interface)) {
8051  args.interface = ast_strdupa(ast_channel_name(chan));
8052  temppos = strrchr(args.interface, '-');
8053  if (temppos) {
8054  *temppos = '\0';
8055  }
8056  }
8057 
8058  if (!ast_strlen_zero(args.penalty)) {
8059  if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8060  ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8061  penalty = 0;
8062  }
8063  }
8064 
8065  if (!ast_strlen_zero(args.wrapuptime)) {
8066  tmp = args.wrapuptime;
8067  ast_strip(tmp);
8068  wrapuptime = atoi(tmp);
8069  if (wrapuptime < 0) {
8070  wrapuptime = 0;
8071  }
8072  } else {
8073  wrapuptime = 0;
8074  }
8075 
8076  switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface, NULL, wrapuptime)) {
8077  case RES_OKAY:
8078  if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8079  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", "");
8080  } else {
8081  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", "");
8082  }
8083  ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8084  pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8085  res = 0;
8086  break;
8087  case RES_EXISTS:
8088  ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8089  pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8090  res = 0;
8091  break;
8092  case RES_NOSUCHQUEUE:
8093  ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8094  pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8095  res = 0;
8096  break;
8097  case RES_OUTOFMEMORY:
8098  ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8099  break;
8100  }
8101 
8102  return res;
8103 }
#define RES_OKAY
Definition: app_queue.c:1441
int wrapuptime
Definition: app_queue.c:1737
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
static int tmp()
Definition: bt_open.c:389
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1490
const char * args
#define NULL
Definition: resample.c:96
#define RES_OUTOFMEMORY
Definition: app_queue.c:1443
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define LOG_ERROR
Definition: logger.h:285
#define LOG_NOTICE
Definition: logger.h:263
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
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...
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1444
const char * ast_channel_name(const struct ast_channel *chan)
#define RES_EXISTS
Definition: app_queue.c:1442
static struct test_options options
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
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:7377
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1466
#define AST_APP_ARG(name)
Define an application argument.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 11505 of file app_queue.c.

◆ autopause2int()

static int autopause2int ( const char *  autopause)
static

Definition at line 1813 of file app_queue.c.

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

Referenced by queue_set_param().

1814 {
1815  int x;
1816  /*This 'double check' that default value is OFF */
1817  if (ast_strlen_zero(autopause)) {
1818  return QUEUE_AUTOPAUSE_OFF;
1819  }
1820 
1821  /*This 'double check' is to ensure old values works */
1822  if(ast_true(autopause)) {
1823  return QUEUE_AUTOPAUSE_ON;
1824  }
1825 
1826  for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
1827  if (!strcasecmp(autopause, autopausesmodes[x].name)) {
1828  return autopausesmodes[x].autopause;
1829  }
1830  }
1831 
1832  /*This 'double check' that default value is OFF */
1833  return QUEUE_AUTOPAUSE_OFF;
1834 }
int autopause
Definition: app_queue.c:1421
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define ast_strlen_zero(foo)
Definition: strings.h:52
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
static const char name[]
Definition: cdr_mysql.c:74
static const struct autopause autopausesmodes[]

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

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

Referenced by try_calling().

5780 {
5781  /* disregarding penalty on too few members? */
5782  int membercount = ao2_container_count(q->members);
5783  unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
5784  int penalty = mem->penalty;
5785 
5786  if (usepenalty) {
5787  if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) {
5788  /* Low penalty is raised up to the current minimum */
5789  penalty = qe->raise_penalty;
5790  }
5791  if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
5792  (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
5793  return -1;
5794  }
5795  } else {
5796  ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
5797  membercount, q->penaltymemberslimit);
5798  }
5799 
5800  switch (q->strategy) {
5802  /* Everyone equal, except for penalty */
5803  tmp->metric = penalty * 1000000 * usepenalty;
5804  break;
5805  case QUEUE_STRATEGY_LINEAR:
5806  if (pos < qe->linpos) {
5807  tmp->metric = 1000 + pos;
5808  } else {
5809  if (pos > qe->linpos) {
5810  /* Indicate there is another priority */
5811  qe->linwrapped = 1;
5812  }
5813  tmp->metric = pos;
5814  }
5815  tmp->metric += penalty * 1000000 * usepenalty;
5816  break;
5819  pos = mem->queuepos;
5820  if (pos < q->rrpos) {
5821  tmp->metric = 1000 + pos;
5822  } else {
5823  if (pos > q->rrpos) {
5824  /* Indicate there is another priority */
5825  q->wrapped = 1;
5826  }
5827  tmp->metric = pos;
5828  }
5829  tmp->metric += penalty * 1000000 * usepenalty;
5830  break;
5831  case QUEUE_STRATEGY_RANDOM:
5832  tmp->metric = ast_random() % 1000;
5833  tmp->metric += penalty * 1000000 * usepenalty;
5834  break;
5836  tmp->metric = ast_random() % ((1 + penalty) * 1000);
5837  break;
5839  tmp->metric = mem->calls;
5840  tmp->metric += penalty * 1000000 * usepenalty;
5841  break;
5843  if (!mem->lastcall) {
5844  tmp->metric = 0;
5845  } else {
5846  tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
5847  }
5848  tmp->metric += penalty * 1000000 * usepenalty;
5849  break;
5850  default:
5851  ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
5852  break;
5853  }
5854  return 0;
5855 }
int queuepos
Definition: app_queue.c:1606
int raise_penalty
Definition: app_queue.c:1580
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
int min_penalty
Definition: app_queue.c:1579
int max_penalty
Definition: app_queue.c:1578
int penaltymemberslimit
Definition: app_queue.c:1738
#define LOG_WARNING
Definition: logger.h:274
int linwrapped
Definition: app_queue.c:1582
#define NULL
Definition: resample.c:96
struct ao2_container * members
Definition: app_queue.c:1752
unsigned int wrapped
Definition: app_queue.c:1706
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
int penalty
Definition: app_queue.c:1599
long int ast_random(void)
Definition: main/utils.c:2064
int strategy
Definition: app_queue.c:1711
int linpos
Definition: app_queue.c:1581
int calls
Definition: app_queue.c:1600
time_t lastcall
Definition: app_queue.c:1610

◆ callattempt_free()

static void callattempt_free ( struct callattempt doomed)
static

Definition at line 4228 of file app_queue.c.

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().

4229 {
4230  if (doomed->member) {
4231  ao2_ref(doomed->member, -1);
4232  }
4234  ast_free(doomed->orig_chan_name);
4235  ast_free(doomed);
4236 }
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2072
struct ast_party_connected_line connected
Definition: app_queue.c:1545
#define ao2_ref(o, delta)
Definition: astobj2.h:464
struct member * member
Definition: app_queue.c:1543
char * orig_chan_name
Definition: app_queue.c:1556
#define ast_free(a)
Definition: astmm.h:182

◆ can_ring_entry()

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

Definition at line 4388 of file app_queue.c.

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

Referenced by ring_entry().

4389 {
4390  struct member *memberp = call->member;
4391  int wrapuptime;
4392 
4393  if (memberp->paused) {
4394  ast_debug(1, "%s paused, can't receive call\n", call->interface);
4395  return 0;
4396  }
4397 
4398  if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4399  ast_debug(1, "%s not available, can't receive call\n", call->interface);
4400  return 0;
4401  }
4402 
4403  if (memberp->lastqueue) {
4404  wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4405  } else {
4406  wrapuptime = get_wrapuptime(qe->parent, memberp);
4407  }
4408  if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4409  ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4410  (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4411  call->interface);
4412  return 0;
4413  }
4414 
4415  if (use_weight && compare_weight(qe->parent, memberp)) {
4416  ast_debug(1, "Priority queue delaying call to %s:%s\n",
4417  qe->parent->name, call->interface);
4418  return 0;
4419  }
4420 
4421  if (!memberp->ringinuse) {
4422  struct member *mem;
4423 
4425 
4426  mem = ao2_find(pending_members, memberp,
4428  if (mem) {
4429  /*
4430  * If found that means this member is currently being attempted
4431  * from another calling thread, so stop trying from this thread
4432  */
4433  ast_debug(1, "%s has another call trying, can't receive call\n",
4434  call->interface);
4435  ao2_ref(mem, -1);
4437  return 0;
4438  }
4439 
4440  /*
4441  * If not found add it to the container so another queue
4442  * won't attempt to call this member at the same time.
4443  */
4444  ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4445  ao2_link(pending_members, memberp);
4447 
4448  /*
4449  * The queue member is available. Get current status to be sure
4450  * because the device state and extension state callbacks may
4451  * not have updated the status yet.
4452  */
4454  ast_debug(1, "%s actually not available, can't receive call\n",
4455  call->interface);
4456  pending_members_remove(memberp);
4457  return 0;
4458  }
4459  }
4460 
4461  return 1;
4462 }
struct call_queue * parent
Definition: app_queue.c:1561
int paused
Definition: app_queue.c:1604
static struct ao2_container * pending_members
Definition: app_queue.c:2375
int wrapuptime
Definition: app_queue.c:1608
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
char interface[256]
Definition: app_queue.c:1541
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2426
char membername[80]
Definition: app_queue.c:1598
static int member_status_available(int status)
Definition: app_queue.c:4374
static int compare_weight(struct call_queue *rq, struct member *member)
Definition: app_queue.c:4323
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
struct member * member
Definition: app_queue.c:1543
struct call_queue * lastqueue
Definition: app_queue.c:1612
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:1856
const ast_string_field name
Definition: app_queue.c:1696
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
int status
Definition: app_queue.c:1603
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1469
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:2671
unsigned int ringinuse
Definition: app_queue.c:1616
time_t lastcall
Definition: app_queue.c:1610
#define ao2_link(container, obj)
Definition: astobj2.h:1549

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

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 handle_queue_change_priority_caller(), and manager_change_priority_caller_on_queue().

7431 {
7432  struct call_queue *q;
7433  struct queue_ent *qe;
7434  int res = RES_NOSUCHQUEUE;
7435 
7436  /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7437  * short-circuits if the queue is already in memory. */
7438  if (!(q = find_load_queue_rt_friendly(queuename))) {
7439  return res;
7440  }
7441 
7442  ao2_lock(q);
7443  res = RES_NOT_CALLER;
7444  for (qe = q->head; qe; qe = qe->next) {
7445  if (strcmp(ast_channel_name(qe->chan), caller) == 0) {
7446  ast_debug(1, "%s Caller new prioriry %d in queue %s\n",
7447  caller, priority, queuename);
7448  qe->prio = priority;
7449  res = RES_OKAY;
7450  }
7451  }
7452  ao2_unlock(q);
7453  return res;
7454 }
#define RES_OKAY
Definition: app_queue.c:1441
struct ast_channel * chan
Definition: app_queue.c:1586
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
#define ao2_unlock(a)
Definition: astobj2.h:730
static int priority
struct queue_ent * head
Definition: app_queue.c:1753
#define RES_NOT_CALLER
Definition: app_queue.c:1446
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ao2_lock(a)
Definition: astobj2.h:718
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1444
const char * ast_channel_name(const struct ast_channel *chan)
struct queue_ent * next
Definition: app_queue.c:1589

◆ clear_queue()

static void clear_queue ( struct call_queue q)
static

Definition at line 2863 of file app_queue.c.

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().

2864 {
2865  q->holdtime = 0;
2866  q->callscompleted = 0;
2867  q->callsabandoned = 0;
2868  q->callscompletedinsl = 0;
2869  q->callsabandonedinsl = 0;
2870  q->talktime = 0;
2871 
2872  if (q->members) {
2873  struct member *mem;
2874  struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
2875  while ((mem = ao2_iterator_next(&mem_iter))) {
2876  mem->calls = 0;
2877  mem->callcompletedinsl = 0;
2878  mem->lastcall = 0;
2879  mem->starttime = 0;
2880  ao2_ref(mem, -1);
2881  }
2882  ao2_iterator_destroy(&mem_iter);
2883  }
2884 }
int callsabandonedinsl
Definition: app_queue.c:1730
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
struct ao2_container * members
Definition: app_queue.c:1752
int callscompletedinsl
Definition: app_queue.c:1732
int holdtime
Definition: app_queue.c:1726
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int talktime
Definition: app_queue.c:1727
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
time_t starttime
Definition: app_queue.c:1609
int calls
Definition: app_queue.c:1600
int callsabandoned
Definition: app_queue.c:1729
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
int callcompletedinsl
Definition: app_queue.c:1607
int callscompleted
Definition: app_queue.c:1728
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
time_t lastcall
Definition: app_queue.c:1610

◆ 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
void

Definition at line 9597 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_t_iterator_next, ao2_unlock, ast_strlen_zero, clear_queue(), call_queue::name, and queue_t_unref.

Referenced by reload_handler().

9598 {
9599  struct call_queue *q;
9600  struct ao2_iterator queue_iter;
9601 
9602  queue_iter = ao2_iterator_init(queues, 0);
9603  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
9604  ao2_lock(q);
9605  if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
9606  clear_queue(q);
9607  ao2_unlock(q);
9608  queue_t_unref(q, "Done with iterator");
9609  }
9610  ao2_iterator_destroy(&queue_iter);
9611  return 0;
9612 }
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:2863
#define ast_strlen_zero(foo)
Definition: strings.h:52
static struct ao2_container * queues
Definition: app_queue.c:1766
#define ao2_lock(a)
Definition: astobj2.h:718
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
const ast_string_field name
Definition: app_queue.c:1696
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ compare_weight()

static int compare_weight ( struct call_queue rq,
struct member member 
)
static

Definition at line 4323 of file app_queue.c.

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, and call_queue::weight.

Referenced by can_ring_entry().

4324 {
4325  struct call_queue *q;
4326  struct member *mem;
4327  int found = 0;
4328  struct ao2_iterator queue_iter;
4329 
4330  queue_iter = ao2_iterator_init(queues, 0);
4331  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4332  if (q == rq) { /* don't check myself, could deadlock */
4333  queue_t_unref(q, "Done with iterator");
4334  continue;
4335  }
4336  ao2_lock(q);
4337  if (q->count && q->members) {
4338  if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4339  ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4340  if (q->weight > rq->weight && q->count >= num_available_members(q)) {
4341  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);
4342  found = 1;
4343  }
4344  ao2_ref(mem, -1);
4345  }
4346  }
4347  ao2_unlock(q);
4348  queue_t_unref(q, "Done with iterator");
4349  if (found) {
4350  break;
4351  }
4352  }
4353  ao2_iterator_destroy(&queue_iter);
4354  return found;
4355 }
#define OBJ_POINTER
Definition: astobj2.h:1154
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
struct ao2_container * members
Definition: app_queue.c:1752
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static struct ao2_container * queues
Definition: app_queue.c:1766
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:4290
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
const ast_string_field name
Definition: app_queue.c:1696
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

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

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

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

9930 {
9931  struct call_queue *q;
9932  char *ret = NULL;
9933  int which = 0;
9934  int wordlen = strlen(word);
9935  struct ao2_iterator queue_iter;
9936  const char *word_list = NULL;
9937 
9938  /* for certain commands, already completed items should be left out of
9939  * the list */
9940  if (word_list_offset && strlen(line) >= word_list_offset) {
9941  word_list = line + word_list_offset;
9942  }
9943 
9944  queue_iter = ao2_iterator_init(queues, 0);
9945  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
9946  if (!strncasecmp(word, q->name, wordlen) && ++which > state
9947  && (!word_list_offset || !word_in_list(word_list, q->name))) {
9948  ret = ast_strdup(q->name);
9949  queue_t_unref(q, "Done with iterator");
9950  break;
9951  }
9952  queue_t_unref(q, "Done with iterator");
9953  }
9954  ao2_iterator_destroy(&queue_iter);
9955 
9956  /* Pretend "rules" is at the end of the queues list in certain
9957  * circumstances since it is an alternate command that should be
9958  * tab-completable for "queue show" */
9959  if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
9960  ret = ast_strdup("rules");
9961  }
9962 
9963  return ret;
9964 }
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
static struct ao2_container * queues
Definition: app_queue.c:1766
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:9870
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
const ast_string_field name
Definition: app_queue.c:1696
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
short word

◆ complete_queue_add_member()

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

Definition at line 10426 of file app_queue.c.

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

Referenced by handle_queue_add_member().

10427 {
10428  /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
10429  switch (pos) {
10430  case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
10431  return NULL;
10432  case 4: /* only one possible match, "to" */
10433  return state == 0 ? ast_strdup("to") : NULL;
10434  case 5: /* <queue> */
10435  return complete_queue(line, word, pos, state, 0);
10436  case 6: /* only one possible match, "penalty" */
10437  return state == 0 ? ast_strdup("penalty") : NULL;
10438  case 7:
10439  if (0 <= state && state < 100) { /* 0-99 */
10440  char *num;
10441  if ((num = ast_malloc(3))) {
10442  sprintf(num, "%d", state);
10443  }
10444  return num;
10445  } else {
10446  return NULL;
10447  }
10448  case 8: /* only one possible match, "as" */
10449  return state == 0 ? ast_strdup("as") : NULL;
10450  case 9: /* Don't attempt to complete name of member (infinite possibilities) */
10451  return NULL;
10452  default:
10453  return NULL;
10454  }
10455 }
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
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:9929
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
short word

◆ complete_queue_pause_member()

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

Definition at line 10799 of file app_queue.c.

References ast_strdup, complete_queue(), and NULL.

Referenced by handle_queue_pause_member().

10800 {
10801  /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
10802  switch (pos) {
10803  case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
10804  return NULL;
10805  case 4: /* only one possible match, "queue" */
10806  return state == 0 ? ast_strdup("queue") : NULL;
10807  case 5: /* <queue> */
10808  return complete_queue(line, word, pos, state, 0);
10809  case 6: /* "reason" */
10810  return state == 0 ? ast_strdup("reason") : NULL;
10811  case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
10812  return NULL;
10813  default:
10814  return NULL;
10815  }
10816 }
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
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:9929
short word

◆ complete_queue_remove_member()

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

Definition at line 10639 of file app_queue.c.

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

Referenced by handle_queue_remove_member().

10640 {
10641  int which = 0;
10642  struct call_queue *q;
10643  struct member *m;
10644  struct ao2_iterator queue_iter;
10645  struct ao2_iterator mem_iter;
10646  int wordlen = strlen(word);
10647 
10648  /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
10649  if (pos > 5 || pos < 3) {
10650  return NULL;
10651  }
10652  if (pos == 4) { /* only one possible match, 'from' */
10653  return (state == 0 ? ast_strdup("from") : NULL);
10654  }
10655 
10656  if (pos == 5) { /* No need to duplicate code */
10657  return complete_queue(line, word, pos, state, 0);
10658  }
10659 
10660  /* here is the case for 3, <member> */
10661  queue_iter = ao2_iterator_init(queues, 0);
10662  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10663  ao2_lock(q);
10664  mem_iter = ao2_iterator_init(q->members, 0);
10665  while ((m = ao2_iterator_next(&mem_iter))) {
10666  if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
10667  char *tmp;
10668  tmp = ast_strdup(m->interface);
10669  ao2_ref(m, -1);
10670  ao2_iterator_destroy(&mem_iter);
10671  ao2_unlock(q);
10672  queue_t_unref(q, "Done with iterator, returning interface name");
10673  ao2_iterator_destroy(&queue_iter);
10674  return tmp;
10675  }
10676  ao2_ref(m, -1);
10677  }
10678  ao2_iterator_destroy(&mem_iter);
10679  ao2_unlock(q);
10680  queue_t_unref(q, "Done with iterator");
10681  }
10682  ao2_iterator_destroy(&queue_iter);
10683 
10684  return NULL;
10685 }
static int tmp()
Definition: bt_open.c:389
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
struct ao2_container * members
Definition: app_queue.c:1752
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
static struct ao2_container * queues
Definition: app_queue.c:1766
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:9929
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
short word

◆ complete_queue_rule_show()

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

Definition at line 10994 of file app_queue.c.

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

Referenced by handle_queue_rule_show().

10995 {
10996  int which = 0;
10997  struct rule_list *rl_iter;
10998  int wordlen = strlen(word);
10999  char *ret = NULL;
11000  if (pos != 3) /* Wha? */ {
11001  return NULL;
11002  }
11003 
11005  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11006  if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11007  ret = ast_strdup(rl_iter->name);
11008  break;
11009  }
11010  }
11012 
11013  return ret;
11014 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
char name[80]
Definition: app_queue.c:1759
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct rule_list::@72 list
short word

◆ complete_queue_set_member_value()

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

Definition at line 10873 of file app_queue.c.

References ast_strdup, complete_queue(), and NULL.

Referenced by handle_queue_set_member_penalty(), and handle_queue_set_member_ringinuse().

10874 {
10875  /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
10876  switch (pos) {
10877  case 4:
10878  if (state == 0) {
10879  return ast_strdup("on");
10880  } else {
10881  return NULL;
10882  }
10883  case 6:
10884  if (state == 0) {
10885  return ast_strdup("in");
10886  } else {
10887  return NULL;
10888  }
10889  case 7:
10890  return complete_queue(line, word, pos, state, 0);
10891  default:
10892  return NULL;
10893  }
10894 }
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
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:9929
short word

◆ complete_queue_show()

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

Definition at line 9966 of file app_queue.c.

References complete_queue(), and NULL.

Referenced by queue_show().

9967 {
9968  if (pos == 2) {
9969  return complete_queue(line, word, pos, state, 0);
9970  }
9971  return NULL;
9972 }
#define NULL
Definition: resample.c:96
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:9929
short word

◆ compress_char()

static int compress_char ( const char  c)
static

Definition at line 2730 of file app_queue.c.

Referenced by member_hash_fn().

2731 {
2732  if (c < 32) {
2733  return 0;
2734  } else if (c > 96) {
2735  return c - 64;
2736  }
2737  return c - 32;
2738 }
static struct test_val c

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

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().

8141 {
8142  struct penalty_rule *pr_iter;
8143  struct rule_list *rl_iter;
8144  const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8146  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8147  if (!strcasecmp(rl_iter->name, tmp)) {
8148  break;
8149  }
8150  }
8151  if (rl_iter) {
8152  AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8153  struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8154  if (!new_pr) {
8155  ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8156  break;
8157  }
8158  new_pr->time = pr_iter->time;
8159  new_pr->max_value = pr_iter->max_value;
8160  new_pr->min_value = pr_iter->min_value;
8161  new_pr->raise_value = pr_iter->raise_value;
8162  new_pr->max_relative = pr_iter->max_relative;
8163  new_pr->min_relative = pr_iter->min_relative;
8164  new_pr->raise_relative = pr_iter->raise_relative;
8165  AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8166  }
8167  }
8169 }
struct call_queue * parent
Definition: app_queue.c:1561
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
int max_relative
Definition: app_queue.c:1645
char name[80]
Definition: app_queue.c:1759
int min_relative
Definition: app_queue.c:1646
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
static int tmp()
Definition: bt_open.c:389
struct rule_list::@71 rules
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
int raise_relative
Definition: app_queue.c:1647
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
struct penalty_rule::@68 list
struct rule_list::@72 list
const ast_string_field defaultrule
Definition: app_queue.c:1696
struct queue_ent::@67 qe_rules

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

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::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().

2687 {
2688  struct member *cur;
2689 
2690  if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
2691  cur->ringinuse = ringinuse;
2692  cur->penalty = penalty;
2693  cur->paused = paused;
2694  cur->wrapuptime = wrapuptime;
2695  if (paused) {
2696  time(&cur->lastpause); /* Update time of last pause */
2697  }
2698  ast_copy_string(cur->interface, interface, sizeof(cur->interface));
2701  } else {
2703  }
2704  if (!ast_strlen_zero(membername)) {
2705  ast_copy_string(cur->membername, membername, sizeof(cur->membername));
2706  } else {
2707  ast_copy_string(cur->membername, interface, sizeof(cur->membername));
2708  }
2709  if (!strchr(cur->interface, '/')) {
2710  ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
2711  }
2712  if (!strncmp(cur->state_interface, "hint:", 5)) {
2713  char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
2714  char *exten = strsep(&context, "@") + 5;
2715 
2716  ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
2717  ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
2718 
2720  } else {
2721  cur->state_id = -1;
2722  }
2723  cur->status = get_queue_member_status(cur);
2724  }
2725 
2726  return cur;
2727 }
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
int paused
Definition: app_queue.c:1604
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1596
int wrapuptime
Definition: app_queue.c:1608
#define LOG_WARNING
Definition: logger.h:274
static int tmp()
Definition: bt_open.c:389
#define NULL
Definition: resample.c:96
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: app_queue.c:2627
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
time_t lastpause
Definition: app_queue.c:1611
int penalty
Definition: app_queue.c:1599
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static void destroy_queue_member_cb(void *obj)
Definition: app_queue.c:2676
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
int state_id
Definition: app_queue.c:1597
int status
Definition: app_queue.c:1603
char * strsep(char **str, const char *delims)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1595
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:2671
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
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:3825
unsigned int ringinuse
Definition: app_queue.c:1616
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1594

◆ destroy_queue()

static void destroy_queue ( void *  obj)
static

Free queue's member list then its string fields.

Definition at line 3519 of file app_queue.c.

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().

3520 {
3521  struct call_queue *q = obj;
3522  int i;
3523 
3524  free_members(q, 1);
3526  for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3527  if (q->sound_periodicannounce[i]) {
3529  }
3530  }
3531  ao2_ref(q->members, -1);
3532 }
struct ast_str * sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]
Definition: app_queue.c:1698
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1432
struct ao2_container * members
Definition: app_queue.c:1752
static void free_members(struct call_queue *q, int all)
Iterate through queue&#39;s member list and delete them.
Definition: app_queue.c:3503
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_free(a)
Definition: astmm.h:182
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368

◆ destroy_queue_member_cb()

static void destroy_queue_member_cb ( void *  obj)
static

Definition at line 2676 of file app_queue.c.

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

Referenced by create_queue_member().

2677 {
2678  struct member *mem = obj;
2679 
2680  if (mem->state_id != -1) {
2682  }
2683 }
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition: pbx.c:3858
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: app_queue.c:2627
int state_id
Definition: app_queue.c:1597

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

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, stasis_message_data(), stasis_message_type(), ast_device_state_message::state, member::state_interface, and update_status().

Referenced by load_module().

2504 {
2505  struct ao2_iterator miter, qiter;
2506  struct ast_device_state_message *dev_state;
2507  struct member *m;
2508  struct call_queue *q;
2509  char interface[80], *slash_pos;
2510  int found = 0; /* Found this member in any queue */
2511  int found_member; /* Found this member in this queue */
2512  int avail = 0; /* Found an available member in this queue */
2513 
2515  return;
2516  }
2517 
2518  dev_state = stasis_message_data(msg);
2519  if (dev_state->eid) {
2520  /* ignore non-aggregate states */
2521  return;
2522  }
2523 
2524  qiter = ao2_iterator_init(queues, 0);
2525  while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
2526  ao2_lock(q);
2527 
2528  avail = 0;
2529  found_member = 0;
2530  miter = ao2_iterator_init(q->members, 0);
2531  for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2532  if (!found_member) {
2533  ast_copy_string(interface, m->state_interface, sizeof(interface));
2534 
2535  if ((slash_pos = strchr(interface, '/'))) {
2536  if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
2537  *slash_pos = '\0';
2538  }
2539  }
2540 
2541  if (!strcasecmp(interface, dev_state->device)) {
2542  found_member = 1;
2543  update_status(q, m, dev_state->state);
2544  }
2545  }
2546 
2547  /* check every member until we find one NOT_INUSE */
2548  if (!avail) {
2549  avail = is_member_available(q, m);
2550  }
2551  if (avail && found_member) {
2552  /* early exit as we've found an available member and the member of interest */
2553  ao2_ref(m, -1);
2554  break;
2555  }
2556  }
2557 
2558  if (found_member) {
2559  found = 1;
2560  if (avail) {
2562  } else {
2564  }
2565  }
2566 
2567  ao2_iterator_destroy(&miter);
2568 
2569  ao2_unlock(q);
2570  queue_t_unref(q, "Done with iterator");
2571  }
2572  ao2_iterator_destroy(&qiter);
2573 
2574  if (found) {
2575  ast_debug(1, "Device '%s' changed to state '%u' (%s)\n",
2576  dev_state->device,
2577  dev_state->state,
2578  ast_devstate2str(dev_state->state));
2579  } else {
2580  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",
2581  dev_state->device,
2582  dev_state->state,
2583  ast_devstate2str(dev_state->state));
2584  }
2585 
2586  return;
2587 }
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Definition: devicestate.c:237
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1596
enum ast_device_state state
Definition: devicestate.h:250
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
struct ao2_container * members
Definition: app_queue.c:1752
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
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
static struct ao2_container * queues
Definition: app_queue.c:1766
const struct ast_eid * eid
The EID of the server where this message originated.
Definition: devicestate.h:248
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
const ast_string_field name
Definition: app_queue.c:1696
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
static void update_status(struct call_queue *q, struct member *m, const int status)
set a member&#39;s status based on device state of that member&#39;s state_interface.
Definition: app_queue.c:2437
unsigned int found
Definition: app_queue.c:1713
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
The structure that contains device state.
Definition: devicestate.h:240
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2468

◆ do_hang()

static void do_hang ( struct callattempt o)
static

common hangup actions

Definition at line 4358 of file app_queue.c.

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

Referenced by ring_entry(), and wait_for_answer().

4359 {
4360  o->stillgoing = 0;
4361  ast_hangup(o->chan);
4363  o->chan = NULL;
4364 }
#define NULL
Definition: resample.c:96
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2426
struct member * member
Definition: app_queue.c:1543
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
struct ast_channel * chan
Definition: app_queue.c:1540
unsigned int stillgoing
Definition: app_queue.c:1553

◆ do_print()

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

direct ouput to manager or cli with proper terminator

Definition at line 9644 of file app_queue.c.

References ast_cli(), and astman_append().

Referenced by __queues_show(), and print_queue().

9645 {
9646  if (s) {
9647  astman_append(s, "%s\r\n", str);
9648  } else {
9649  ast_cli(fd, "%s\n", str);
9650  }
9651 }
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
const char * str
Definition: app_jack.c:147
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6

◆ 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>[|...]

Definition at line 7269 of file app_queue.c.

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, member::reason_paused, member::state_interface, value, and member::wrapuptime.

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

7270 {
7271  struct member *cur_member;
7272  struct ast_str *value;
7273  struct ao2_iterator mem_iter;
7274 
7275  if (!pm_queue) {
7276  return;
7277  }
7278 
7279  /* 4K is a reasonable default for most applications, but we grow to
7280  * accommodate more if necessary. */
7281  if (!(value = ast_str_create(4096))) {
7282  return;
7283  }
7284 
7285  mem_iter = ao2_iterator_init(pm_queue->members, 0);
7286  while ((cur_member = ao2_iterator_next(&mem_iter))) {
7287  if (!cur_member->dynamic) {
7288  ao2_ref(cur_member, -1);
7289  continue;
7290  }
7291 
7292  ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
7293  ast_str_strlen(value) ? "|" : "",
7294  cur_member->interface,
7295  cur_member->penalty,
7296  cur_member->paused,
7297  cur_member->membername,
7298  cur_member->state_interface,
7299  cur_member->reason_paused,
7300  cur_member->wrapuptime);
7301 
7302  ao2_ref(cur_member, -1);
7303  }
7304  ao2_iterator_destroy(&mem_iter);
7305 
7306  if (ast_str_strlen(value) && !cur_member) {
7307  if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
7308  ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
7309  }
7310  } else {
7311  /* Delete the entry if the queue is empty or there is an error */
7312  ast_db_del(pm_family, pm_queue->name);
7313  }
7314 
7315  ast_free(value);
7316 }
int dynamic
Definition: app_queue.c:1601
int paused
Definition: app_queue.c:1604
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1596
int wrapuptime
Definition: app_queue.c:1608
#define LOG_WARNING
Definition: logger.h:274
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
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:1091
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int value
Definition: syslog.c:37
struct ao2_container * members
Definition: app_queue.c:1752
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_log
Definition: astobj2.c:42
int penalty
Definition: app_queue.c:1599
#define ao2_ref(o, delta)
Definition: astobj2.h:464
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
const ast_string_field name
Definition: app_queue.c:1696
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
char reason_paused[80]
Definition: app_queue.c:1605
#define ast_free(a)
Definition: astmm.h:182
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: main/db.c:429
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: main/db.c:327
static const char *const pm_family
Persistent Members astdb family.
Definition: app_queue.c:1463
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ end_bridge_callback()

static void end_bridge_callback ( void *  data)
static

Definition at line 6575 of file app_queue.c.

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

Referenced by try_calling().

6576 {
6577  struct queue_end_bridge *qeb = data;
6578  struct call_queue *q = qeb->q;
6579  struct ast_channel *chan = qeb->chan;
6580 
6581  if (ao2_ref(qeb, -1) == 1) {
6582  set_queue_variables(q, chan);
6583  /* This unrefs the reference we made in try_calling when we allocated qeb */
6584  queue_t_unref(q, "Expire bridge_config reference");
6585  }
6586 }
Main Channel structure associated with a channel.
struct call_queue * q
Definition: app_queue.c:6564
#define ao2_ref(o, delta)
Definition: astobj2.h:464
struct ast_channel * chan
Definition: app_queue.c:6565
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:1926

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

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

Referenced by try_calling().

6569 {
6570  struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
6571  ao2_ref(qeb, +1);
6572  qeb->chan = originator;
6573 }
void * end_bridge_callback_data
Definition: channel.h:1092
#define ao2_ref(o, delta)
Definition: astobj2.h:464
struct ast_channel * chan
Definition: app_queue.c:6565

◆ escape_and_substitute()

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

Definition at line 6617 of file app_queue.c.

References input(), and pbx_substitute_variables_helper().

Referenced by setup_mixmonitor().

6619 {
6620  const char *m = input;
6621  char escaped[size];
6622  char *p;
6623 
6624  for (p = escaped; p < escaped + size - 1; p++, m++) {
6625  switch (*m) {
6626  case '^':
6627  if (*(m + 1) == '{') {
6628  *p = '$';
6629  }
6630  break;
6631  case ',':
6632  *p++ = '\\';
6633  /* Fall through */
6634  default:
6635  *p = *m;
6636  }
6637  if (*m == '\0')
6638  break;
6639  }
6640 
6641  if (p == escaped + size) {
6642  escaped[size - 1] = '\0';
6643  }
6644 
6645  pbx_substitute_variables_helper(chan, escaped, output, size - 1);
6646 }
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

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

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, ast_state_cb_info::exten_state, extensionstate2devicestate(), call_queue::found, call_queue::members, queue_t_unref, ast_state_cb_info::reason, member::state_context, member::state_exten, and update_status().

Referenced by create_queue_member(), and destroy_queue_member_cb().

2628 {
2629  struct ao2_iterator miter, qiter;
2630  struct member *m;
2631  struct call_queue *q;
2632  int state = info->exten_state;
2633  int found = 0, device_state = extensionstate2devicestate(state);
2634 
2635  /* only interested in extension state updates involving device states */
2636  if (info->reason != AST_HINT_UPDATE_DEVICE) {
2637  return 0;
2638  }
2639 
2640  qiter = ao2_iterator_init(queues, 0);
2641  while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
2642  ao2_lock(q);
2643 
2644  miter = ao2_iterator_init(q->members, 0);
2645  for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2646  if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
2647  update_status(q, m, device_state);
2648  ao2_ref(m, -1);
2649  found = 1;
2650  break;
2651  }
2652  }
2653  ao2_iterator_destroy(&miter);
2654 
2655  ao2_unlock(q);
2656  queue_t_unref(q, "Done with iterator");
2657  }
2658  ao2_iterator_destroy(&qiter);
2659 
2660  if (found) {
2661  ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
2662  } else {
2663  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",
2664  exten, context, device_state, ast_devstate2str(device_state));
2665  }
2666 
2667  return 0;
2668 }
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Definition: devicestate.c:237
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
enum ast_state_cb_update_reason reason
Definition: pbx.h:103
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
struct ao2_container * members
Definition: app_queue.c:1752
enum ast_extension_states exten_state
Definition: pbx.h:104
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static struct ao2_container * queues
Definition: app_queue.c:1766
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
static int extensionstate2devicestate(int state)
Helper function which converts from extension state to device state values.
Definition: app_queue.c:2590
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
static void update_status(struct call_queue *q, struct member *m, const int status)
set a member&#39;s status based on device state of that member&#39;s state_interface.
Definition: app_queue.c:2437
unsigned int found
Definition: app_queue.c:1713
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1595
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1594

◆ extensionstate2devicestate()

static int extensionstate2devicestate ( int  state)
static

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

Definition at line 2590 of file app_queue.c.

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().

2591 {
2592  switch (state) {
2595  break;
2596  case AST_EXTENSION_INUSE:
2598  break;
2599  case AST_EXTENSION_BUSY:
2601  break;
2602  case AST_EXTENSION_RINGING:
2604  break;
2607  break;
2608  case AST_EXTENSION_ONHOLD:
2610  break;
2613  break;
2616  break;
2617  case AST_EXTENSION_REMOVED:
2619  default:
2621  break;
2622  }
2623 
2624  return state;
2625 }
enum sip_cc_notify_state state
Definition: chan_sip.c:959

◆ find_best()

static struct callattempt* find_best ( struct callattempt outgoing)
static

find the entry with the best metric, or NULL

Definition at line 4614 of file app_queue.c.

References callattempt::metric, NULL, and callattempt::q_next.

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

4615 {
4616  struct callattempt *best = NULL, *cur;
4617 
4618  for (cur = outgoing; cur; cur = cur->q_next) {
4619  if (cur->stillgoing && /* Not already done */
4620  !cur->chan && /* Isn't already going */
4621  (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
4622  best = cur;
4623  }
4624  }
4625 
4626  return best;
4627 }
struct callattempt * q_next
Definition: app_queue.c:1538
#define NULL
Definition: resample.c:96
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1537

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

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, call_queue::realtime, SENTINEL, update_realtime_members(), and call_queue::weight.

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

3703 {
3704  struct ast_variable *queue_vars;
3705  struct ast_config *member_config = NULL;
3706  struct call_queue *q = NULL, tmpq = {
3707  .name = queuename,
3708  };
3709  int prev_weight = 0;
3710 
3711  /* Find the queue in the in-core list first. */
3712  q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
3713 
3714  if (!q || q->realtime) {
3715  /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
3716  queue operations while waiting for the DB.
3717 
3718  This will be two separate database transactions, so we might
3719  see queue parameters as they were before another process
3720  changed the queue and member list as it was after the change.
3721  Thus we might see an empty member list when a queue is
3722  deleted. In practise, this is unlikely to cause a problem. */
3723 
3724  queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
3725  if (queue_vars) {
3726  member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
3727  if (!member_config) {
3728  ast_debug(1, "No queue_members defined in config extconfig.conf\n");
3729  member_config = ast_config_new();
3730  }
3731  }
3732  if (q) {
3733  prev_weight = q->weight ? 1 : 0;
3734  queue_t_unref(q, "Need to find realtime queue");
3735  }
3736 
3737  q = find_queue_by_name_rt(queuename, queue_vars, member_config);
3738  ast_config_destroy(member_config);
3739  ast_variables_destroy(queue_vars);
3740 
3741  /* update the use_weight value if the queue's has gained or lost a weight */
3742  if (q) {
3743  if (!q->weight && prev_weight) {
3745  }
3746  if (q->weight && !prev_weight) {
3748  }
3749  }
3750  /* Other cases will end up with the proper value for use_weight */
3751  } else {
3753  }
3754  return q;
3755 }
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3339
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
static void update_realtime_members(struct call_queue *q)
Definition: app_queue.c:3773
#define OBJ_POINTER
Definition: astobj2.h:1154
Structure for variables, used for configurations and for channel variables.
#define NULL
Definition: resample.c:96
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
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define SENTINEL
Definition: compiler.h:87
static struct ao2_container * queues
Definition: app_queue.c:1766
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: extconf.c:3276
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3452
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
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:3558
unsigned int realtime
Definition: app_queue.c:1712
#define ao2_t_find(container, arg, flags, tag)
Definition: astobj2.h:1754
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1469

◆ find_member_by_queuename_and_interface()

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

Definition at line 11484 of file app_queue.c.

References ao2_find, ao2_lock, ao2_unlock, AST_MODFLAG_LOAD_ORDER, AST_MODPRI_DEVSTATE_CONSUMER, AST_MODULE_INFO(), AST_MODULE_SUPPORT_CORE, ASTERISK_GPL_KEY, find_load_queue_rt_friendly(), load_module(), call_queue::members, NULL, OBJ_KEY, queue_t_unref, reload(), and unload_module().

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

11485 {
11486  struct member *mem = NULL;
11487  struct call_queue *q;
11488 
11489  if ((q = find_load_queue_rt_friendly(queuename))) {
11490  ao2_lock(q);
11491  mem = ao2_find(q->members, interface, OBJ_KEY);
11492  ao2_unlock(q);
11493  queue_t_unref(q, "Expiring temporary reference.");
11494  }
11495  return mem;
11496 }
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
#define OBJ_KEY
Definition: astobj2.h:1155
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
struct ao2_container * members
Definition: app_queue.c:1752
#define ao2_lock(a)
Definition: astobj2.h:718
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921

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

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_WARNING, member_remove_from_queue(), member::membername, call_queue::members, ast_variable::name, call_queue::name, ast_variable::next, NULL, OBJ_POINTER, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_t_unref, 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().

3559 {
3560  struct ast_variable *v;
3561  struct call_queue *q, tmpq = {
3562  .name = queuename,
3563  };
3564  struct member *m;
3565  struct ao2_iterator mem_iter;
3566  char *category = NULL;
3567  const char *tmp_name;
3568  char *tmp;
3569  char tmpbuf[64]; /* Must be longer than the longest queue param name. */
3570 
3571  /* Static queues override realtime. */
3572  if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
3573  ao2_lock(q);
3574  if (!q->realtime) {
3575  if (q->dead) {
3576  ao2_unlock(q);
3577  queue_t_unref(q, "Queue is dead; can't return it");
3578  return NULL;
3579  }
3580  ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
3581  ao2_unlock(q);
3582  return q;
3583  }
3584  } else if (!member_config) {
3585  /* Not found in the list, and it's not realtime ... */
3586  return NULL;
3587  }
3588  /* Check if queue is defined in realtime. */
3589  if (!queue_vars) {
3590  /* Delete queue from in-core list if it has been deleted in realtime. */
3591  if (q) {
3592  /*! \note Hmm, can't seem to distinguish a DB failure from a not
3593  found condition... So we might delete an in-core queue
3594  in case of DB failure. */
3595  ast_debug(1, "Queue %s not found in realtime.\n", queuename);
3596 
3597  q->dead = 1;
3598  /* Delete if unused (else will be deleted when last caller leaves). */
3599  queues_t_unlink(queues, q, "Unused; removing from container");
3600  ao2_unlock(q);
3601  queue_t_unref(q, "Queue is dead; can't return it");
3602  }
3603  return NULL;
3604  }
3605 
3606  /* Create a new queue if an in-core entry does not exist yet. */
3607  if (!q) {
3608  struct ast_variable *tmpvar = NULL;
3609  if (!(q = alloc_queue(queuename))) {
3610  return NULL;
3611  }
3612  ao2_lock(q);
3613  clear_queue(q);
3614  q->realtime = 1;
3615  /*Before we initialize the queue, we need to set the strategy, so that linear strategy
3616  * will allocate the members properly
3617  */
3618  for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
3619  if (!strcasecmp(tmpvar->name, "strategy")) {
3620  q->strategy = strat2int(tmpvar->value);
3621  if (q->strategy < 0) {
3622  ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3623  tmpvar->value, q->name);
3625  }
3626  break;
3627  }
3628  }
3629  /* We traversed all variables and didn't find a strategy */
3630  if (!tmpvar) {
3632  }
3633  queues_t_link(queues, q, "Add queue to container");
3634  }
3635  init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
3636 
3637  memset(tmpbuf, 0, sizeof(tmpbuf));
3638  for (v = queue_vars; v; v = v->next) {
3639  /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
3640  if (strchr(v->name, '_')) {
3641  ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
3642  tmp_name = tmpbuf;
3643  tmp = tmpbuf;
3644  while ((tmp = strchr(tmp, '_'))) {
3645  *tmp++ = '-';
3646  }
3647  } else {
3648  tmp_name = v->name;
3649  }
3650 
3651  /* NULL values don't get returned from realtime; blank values should
3652  * still get set. If someone doesn't want a value to be set, they
3653  * should set the realtime column to NULL, not blank. */
3654  queue_set_param(q, tmp_name, v->value, -1, 0);
3655  }
3656 
3657  /* Temporarily set realtime members dead so we can detect deleted ones. */
3658  mem_iter = ao2_iterator_init(q->members, 0);
3659  while ((m = ao2_iterator_next(&mem_iter))) {
3660  if (m->realtime) {
3661  m->dead = 1;
3662  }
3663  ao2_ref(m, -1);
3664  }
3665  ao2_iterator_destroy(&mem_iter);
3666 
3667  while ((category = ast_category_browse(member_config, category))) {
3668  rt_handle_member_record(q, category, member_config);
3669  }
3670 
3671  /* Delete all realtime members that have been deleted in DB. */
3672  mem_iter = ao2_iterator_init(q->members, 0);
3673  while ((m = ao2_iterator_next(&mem_iter))) {
3674  if (m->dead) {
3676  ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
3677  } else {
3678  ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
3679  }
3681  }
3682  ao2_ref(m, -1);
3683  }
3684  ao2_iterator_destroy(&mem_iter);
3685 
3686  ao2_unlock(q);
3687 
3688  return q;
3689 }
struct ast_variable * next
#define OBJ_POINTER
Definition: astobj2.h:1154
#define LOG_WARNING
Definition: logger.h:274
static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3376
static int tmp()
Definition: bt_open.c:389
Structure for variables, used for configurations and for channel variables.
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1490
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int realtime
Definition: app_queue.c:1602
#define ao2_unlock(a)
Definition: astobj2.h:730
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
unsigned int dead
Definition: app_queue.c:1613
#define NULL
Definition: resample.c:96
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:2863
struct ao2_container * members
Definition: app_queue.c:1752
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:3392
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
static int strat2int(const char *strategy)
Definition: app_queue.c:1800
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
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:3144
static struct ao2_container * queues
Definition: app_queue.c:1766
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
int strategy
Definition: app_queue.c:1711
unsigned int dead
Definition: app_queue.c:1699
const ast_string_field name
Definition: app_queue.c:1696
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
static struct call_queue * alloc_queue(const char *queuename)
Definition: app_queue.c:3534
#define queues_t_link(c, q, tag)
Definition: app_queue.c:1922
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
unsigned int realtime
Definition: app_queue.c:1712
#define ao2_t_find(container, arg, flags, tag)
Definition: astobj2.h:1754
static void init_queue(struct call_queue *q)
Initialize Queue default values.
Definition: app_queue.c:2769
#define queues_t_unlink(c, q, tag)
Definition: app_queue.c:1923
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

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

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().

3504 {
3505  /* Free non-dynamic members */
3506  struct member *cur;
3507  struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3508 
3509  while ((cur = ao2_iterator_next(&mem_iter))) {
3510  if (all || !cur->dynamic) {
3511  member_remove_from_queue(q, cur);
3512  }
3513  ao2_ref(cur, -1);
3514  }
3515  ao2_iterator_destroy(&mem_iter);
3516 }
int dynamic
Definition: app_queue.c:1601
static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3376
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
struct ao2_container * members
Definition: app_queue.c:1752
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ get_interface_helper()

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

Definition at line 8618 of file app_queue.c.

References ast_log, ast_strlen_zero, interface_exists(), LOG_ERROR, call_queue::name, and NULL.

Referenced by queue_function_mem_read().

8619 {
8620  struct member *m;
8621 
8622  if (ast_strlen_zero(interface)) {
8623  ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
8624  return NULL;
8625  }
8626 
8627  m = interface_exists(q, interface);
8628  if (!m) {
8629  ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
8630  interface, q->name);
8631  }
8632  return m;
8633 }
#define NULL
Definition: resample.c:96
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7242
#define LOG_ERROR
Definition: logger.h:285
const ast_string_field name
Definition: app_queue.c:1696

◆ get_member_penalty()

static int get_member_penalty ( char *  queuename,
char *  interface 
)
static

Definition at line 7740 of file app_queue.c.

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

Referenced by queue_function_memberpenalty_read().

7741 {
7742  int foundqueue = 0, penalty;
7743  struct call_queue *q;
7744  struct member *mem;
7745 
7746  if ((q = find_load_queue_rt_friendly(queuename))) {
7747  foundqueue = 1;
7748  ao2_lock(q);
7749  if ((mem = interface_exists(q, interface))) {
7750  penalty = mem->penalty;
7751  ao2_ref(mem, -1);
7752  ao2_unlock(q);
7753  queue_t_unref(q, "Search complete");
7754  return penalty;
7755  }
7756  ao2_unlock(q);
7757  queue_t_unref(q, "Search complete");
7758  }
7759 
7760  /* some useful debuging */
7761  if (foundqueue) {
7762  ast_log (LOG_ERROR, "Invalid queuename\n");
7763  } else {
7764  ast_log (LOG_ERROR, "Invalid interface\n");
7765  }
7766 
7767  return RESULT_FAILURE;
7768 }
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
#define ao2_unlock(a)
Definition: astobj2.h:730
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_log
Definition: astobj2.c:42
int penalty
Definition: app_queue.c:1599
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7242
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
#define LOG_ERROR
Definition: logger.h:285
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
#define RESULT_FAILURE
Definition: cli.h:42

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

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().

2285 {
2286  struct member *member;
2287  struct ao2_iterator mem_iter;
2288 
2289  ao2_lock(q);
2290  mem_iter = ao2_iterator_init(q->members, 0);
2291  for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
2292  int penalty = member->penalty;
2293  if (raise_penalty != INT_MAX && penalty < raise_penalty) {
2294  ast_debug(4, "%s is having his penalty raised up from %d to %d\n", member->membername, penalty, raise_penalty);
2295  penalty = raise_penalty;
2296  }
2297  if ((max_penalty != INT_MAX && penalty > max_penalty) || (min_penalty != INT_MAX && penalty < min_penalty)) {
2298  if (conditions & QUEUE_EMPTY_PENALTY) {
2299  ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
2300  continue;
2301  }
2302  }
2303 
2304  switch (devstate ? ast_device_state(member->state_interface) : member->status) {
2305  case AST_DEVICE_INVALID:
2306  if (conditions & QUEUE_EMPTY_INVALID) {
2307  ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
2308  break;
2309  }
2310  goto default_case;
2312  if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
2313  ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
2314  break;
2315  }
2316  goto default_case;
2317  case AST_DEVICE_INUSE:
2318  if (conditions & QUEUE_EMPTY_INUSE) {
2319  ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
2320  break;
2321  }
2322  goto default_case;
2323  case AST_DEVICE_RINGING:
2324  if (conditions & QUEUE_EMPTY_RINGING) {
2325  ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
2326  break;
2327  }
2328  goto default_case;
2329  case AST_DEVICE_UNKNOWN:
2330  if (conditions & QUEUE_EMPTY_UNKNOWN) {
2331  ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
2332  break;
2333  }
2334  /* Fall-through */
2335  default:
2336  default_case:
2337  if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
2338  ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
2339  break;
2340  } else if ((conditions & QUEUE_EMPTY_WRAPUP)
2341  && member->lastcall
2342  && get_wrapuptime(q, member)
2343  && (time(NULL) - get_wrapuptime(q, member) < member->lastcall)) {
2344  ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n",
2345  member->membername, (int) (time(NULL) - member->lastcall), get_wrapuptime(q, member));
2346  break;
2347  } else {
2348  ao2_ref(member, -1);
2349  ao2_iterator_destroy(&mem_iter);
2350  ao2_unlock(q);
2351  ast_debug(4, "%s is available.\n", member->membername);
2352  return 0;
2353  }
2354  break;
2355  }
2356  }
2357  ao2_iterator_destroy(&mem_iter);
2358  ao2_unlock(q);
2359 
2360  if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
2361  /* member state still may be RINGING due to lag in event message - check again with device state */
2362  return get_member_status(q, max_penalty, min_penalty, raise_penalty, conditions, 1);
2363  }
2364  return -1;
2365 }
ast_device_state
Device States.
Definition: devicestate.h:52
int paused
Definition: app_queue.c:1604
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1596
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
struct ao2_container * members
Definition: app_queue.c:1752
char membername[80]
Definition: app_queue.c:1598
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
int penalty
Definition: app_queue.c:1599
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:1856
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
int status
Definition: app_queue.c:1603
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
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:2284
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
time_t lastcall
Definition: app_queue.c:1610

◆ get_queue_member_status()

static int get_queue_member_status ( struct member cur)
static

Return the current state of a member.

Definition at line 2671 of file app_queue.c.

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().

2672 {
2673  return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
2674 }
ast_device_state
Device States.
Definition: devicestate.h:52
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1596
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
static int extensionstate2devicestate(int state)
Helper function which converts from extension state to device state values.
Definition: app_queue.c:2590
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
Uses hint and devicestate callback to get the state of an extension.
Definition: pbx.c:3170
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1594

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

References member::wrapuptime, and call_queue::wrapuptime.

Referenced by can_ring_entry(), get_member_status(), is_member_available(), and queue_function_mem_read().

1857 {
1858  if (member->wrapuptime) {
1859  return member->wrapuptime;
1860  }
1861  return q->wrapuptime;
1862 }
int wrapuptime
Definition: app_queue.c:1737
int wrapuptime
Definition: app_queue.c:1608

◆ 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.
topicThe topic for this event.
msgThe stasis message for the attended transfer event.

Definition at line 6206 of file app_queue.c.

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().

6208 {
6209  struct queue_stasis_data *queue_data = userdata;
6210  struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6211  RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6212  RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6213 
6214  if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6216  return;
6217  }
6218 
6219  ao2_lock(queue_data);
6220 
6221  if (queue_data->dying) {
6222  ao2_unlock(queue_data);
6223  return;
6224  }
6225 
6226  if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6227  ao2_unlock(queue_data);
6228  return;
6229  }
6230 
6231  if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6232  atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6233  (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6234  atxfer_msg->to_transfer_target.bridge_snapshot->uniqueid))) {
6235  ao2_unlock(queue_data);
6236  return;
6237  }
6238 
6239  caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6240  member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6241 
6242  ao2_unlock(queue_data);
6243 
6244  ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6245  log_attended_transfer(queue_data, atxfer_msg);
6246 
6247  send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6248  queue_data->holdstart, queue_data->starttime, TRANSFER);
6249  update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6250  queue_data->starttime);
6251  remove_stasis_subscriptions(queue_data);
6252 }
Message representing attended transfer.
Structure representing a snapshot of channel state.
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
struct ast_bridge_channel_snapshot_pair to_transferee
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_bridge_channel_snapshot_pair to_transfer_target
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
enum ast_transfer_result result
struct call_queue * queue
Definition: app_queue.c:5967
#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:911
struct member * member
Definition: app_queue.c:5969
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:5707
#define ao2_lock(a)
Definition: astobj2.h:718
const ast_string_field member_uniqueid
Definition: app_queue.c:5965
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition: app_queue.c:6065
enum ast_attended_transfer_dest_type dest_type
const ast_string_field bridge_uniqueid
Definition: app_queue.c:5965
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
const ast_string_field name
Definition: app_queue.c:1696
const ast_string_field caller_uniqueid
Definition: app_queue.c:5965
struct ast_bridge_snapshot * bridge_snapshot
const ast_string_field uniqueid
Definition: bridge.h:336
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:5864
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...
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:5957
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6011

◆ 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.
topicThe topic for this event.
msgThe stasis message for the blind transfer event

Definition at line 6146 of file app_queue.c.

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().

6148 {
6149  struct queue_stasis_data *queue_data = userdata;
6150  struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
6151  const char *exten;
6152  const char *context;
6153  RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6154  RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6155 
6156  if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
6157  return;
6158  }
6159 
6160  ao2_lock(queue_data);
6161 
6162  if (queue_data->dying) {
6163  ao2_unlock(queue_data);
6164  return;
6165  }
6166 
6167  if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
6168  strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
6169  ao2_unlock(queue_data);
6170  return;
6171  }
6172 
6173  caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6174  member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6175 
6176  ao2_unlock(queue_data);
6177 
6178  exten = transfer_msg->exten;
6179  context = transfer_msg->context;
6180 
6181  ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
6182  ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6183  "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
6184  exten, context,
6185  (long) (queue_data->starttime - queue_data->holdstart),
6186  (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6187 
6188  send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6189  queue_data->holdstart, queue_data->starttime, TRANSFER);
6190  update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6191  queue_data->starttime);
6192  remove_stasis_subscriptions(queue_data);
6193 }
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
char exten[AST_MAX_EXTENSION]
Message published during a blind transfer.
Structure representing a snapshot of channel state.
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
char membername[80]
Definition: app_queue.c:1598
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct call_queue * queue
Definition: app_queue.c:5967
#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:911
struct member * member
Definition: app_queue.c:5969
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:5707
#define ao2_lock(a)
Definition: astobj2.h:718
struct ast_bridge_snapshot * bridge
const ast_string_field member_uniqueid
Definition: app_queue.c:5965
const ast_string_field bridge_uniqueid
Definition: app_queue.c:5965
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
const ast_string_field name
Definition: app_queue.c:1696
const ast_string_field caller_uniqueid
Definition: app_queue.c:5965
char context[AST_MAX_CONTEXT]
const ast_string_field uniqueid
Definition: bridge.h:336
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:5864
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...
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:5957
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6011
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
enum ast_transfer_result result

◆ handle_bridge_enter()

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

Definition at line 6112 of file app_queue.c.

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_channel_snapshot_base::uniqueid, and ast_bridge_snapshot::uniqueid.

Referenced by setup_stasis_subs().

6114 {
6115  struct queue_stasis_data *queue_data = userdata;
6116  struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6117  SCOPED_AO2LOCK(lock, queue_data);
6118 
6119  if (queue_data->dying) {
6120  return;
6121  }
6122 
6123  if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6124  return;
6125  }
6126 
6127  if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6128  ast_string_field_set(queue_data, bridge_uniqueid,
6129  enter_blob->bridge->uniqueid);
6130  ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6131  enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6132  }
6133 }
struct ast_channel_snapshot_base * base
struct ast_channel_snapshot * channel
const ast_string_field uniqueid
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_bridge_snapshot * bridge
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
ast_mutex_t lock
Definition: app_meetme.c:1091
Blob of data associated with a bridge.
const ast_string_field bridge_uniqueid
Definition: app_queue.c:5965
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
const ast_string_field caller_uniqueid
Definition: app_queue.c:5965
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:602
const ast_string_field uniqueid
Definition: bridge.h:336
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:5957
const ast_string_field name
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514

◆ handle_hangup()

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

Definition at line 6398 of file app_queue.c.

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, ast_channel_snapshot_base::name, call_queue::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().

6400 {
6401  struct queue_stasis_data *queue_data = userdata;
6402  struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6403  RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6404  RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6405  RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
6406  enum agent_complete_reason reason;
6407 
6408  ao2_lock(queue_data);
6409 
6410  if (queue_data->dying) {
6411  ao2_unlock(queue_data);
6412  return;
6413  }
6414 
6415  if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6416  reason = CALLER;
6417  } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6418  reason = AGENT;
6419  } else {
6420  ao2_unlock(queue_data);
6421  return;
6422  }
6423 
6424  chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
6425  if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
6426  !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
6427  !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
6428  /* Channel that is hanging up is doing it as part of a transfer.
6429  * We'll get a transfer event later
6430  */
6431  ao2_unlock(queue_data);
6432  return;
6433  }
6434 
6435  caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6436  member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6437 
6438  ao2_unlock(queue_data);
6439 
6440  ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
6441  channel_blob->snapshot->base->name);
6442 
6443  ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6444  reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
6445  (long) (queue_data->starttime - queue_data->holdstart),
6446  (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6447 
6448  send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6449  queue_data->holdstart, queue_data->starttime, reason);
6450  update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6451  queue_data->starttime);
6452  remove_stasis_subscriptions(queue_data);
6453 }
Main Channel structure associated with a channel.
struct ast_channel_snapshot_base * base
struct ast_channel_snapshot * snapshot
Structure representing a snapshot of channel state.
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
const ast_string_field uniqueid
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
char membername[80]
Definition: app_queue.c:1598
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.
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
agent_complete_reason
Definition: app_queue.c:5857
struct call_queue * queue
Definition: app_queue.c:5967
#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:911
struct member * member
Definition: app_queue.c:5969
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:5707
#define ao2_lock(a)
Definition: astobj2.h:718
const ast_string_field member_uniqueid
Definition: app_queue.c:5965
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:398
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
const ast_string_field name
Definition: app_queue.c:1696
const ast_string_field caller_uniqueid
Definition: app_queue.c:5965
#define AST_TRANSFERER_ROLE_NAME
Definition: bridge_basic.h:36
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:5864
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...
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:5957
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6011
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
const ast_string_field name

◆ handle_local_optimization_begin()

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

Definition at line 6281 of file app_queue.c.

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().

6283 {
6284  struct queue_stasis_data *queue_data = userdata;
6285  struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6286  struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6287  struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6288  struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6289  struct local_optimization *optimization;
6290  unsigned int id;
6291  SCOPED_AO2LOCK(lock, queue_data);
6292 
6293  if (queue_data->dying) {
6294  return;
6295  }
6296 
6297  if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6298  optimization = &queue_data->member_optimize;
6299  } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6300  optimization = &queue_data->caller_optimize;
6301  } else {
6302  return;
6303  }
6304 
6305  /* We only allow move-swap optimizations, so there had BETTER be a source */
6306  ast_assert(source != NULL);
6307 
6308  optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6309  if (!optimization->source_chan_uniqueid) {
6310  ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6311  return;
6312  }
6314 
6315  optimization->id = id;
6316  optimization->in_progress = 1;
6317 }
struct ast_channel_snapshot_base * base
Structure representing a snapshot of channel state.
const ast_string_field uniqueid
#define ast_assert(a)
Definition: utils.h:695
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
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...
const char * source_chan_uniqueid
Definition: app_queue.c:5935
#define ast_log
Definition: astobj2.c:42
ast_mutex_t lock
Definition: app_meetme.c:1091
Structure representing relevant data during a local channel optimization.
Definition: app_queue.c:5933
unsigned int id
Definition: app_queue.c:5939
const ast_string_field member_uniqueid
Definition: app_queue.c:5965
#define LOG_ERROR
Definition: logger.h:285
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
const ast_string_field caller_uniqueid
Definition: app_queue.c:5965
struct local_optimization caller_optimize
Definition: app_queue.c:5985
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:602
struct local_optimization member_optimize
Definition: app_queue.c:5987
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
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.
A multi channel blob data structure for multi_channel_blob stasis messages.
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:5957
enum queue_result id
Definition: app_queue.c:1507
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:322
const ast_string_field name

◆ handle_local_optimization_end()

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

Definition at line 6333 of file app_queue.c.

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().

6335 {
6336  struct queue_stasis_data *queue_data = userdata;
6337  struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6338  struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6339  struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6340  struct local_optimization *optimization;
6341  int is_caller;
6342  unsigned int id;
6343  SCOPED_AO2LOCK(lock, queue_data);
6344 
6345  if (queue_data->dying) {
6346  return;
6347  }
6348 
6349  if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6350  optimization = &queue_data->member_optimize;
6351  is_caller = 0;
6352  } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6353  optimization = &queue_data->caller_optimize;
6354  is_caller = 1;
6355  } else {
6356  return;
6357  }
6358 
6360 
6361  if (!optimization->in_progress) {
6362  ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
6363  return;
6364  }
6365 
6366  if (id != optimization->id) {
6367  ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
6368  id, optimization->id);
6369  return;
6370  }
6371 
6372  if (is_caller) {
6373  ast_debug(3, "Local optimization: Changing queue caller uniqueid from %s to %s\n",
6374  queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
6375  ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
6376  } else {
6377  ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
6378  queue_data->member_uniqueid, optimization->source_chan_uniqueid);
6379  ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
6380  }
6381 
6382  optimization->in_progress = 0;
6383 }
struct ast_channel_snapshot_base * base
#define LOG_WARNING
Definition: logger.h:274
Structure representing a snapshot of channel state.
const ast_string_field uniqueid
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...
const char * source_chan_uniqueid
Definition: app_queue.c:5935
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
ast_mutex_t lock
Definition: app_meetme.c:1091
Structure representing relevant data during a local channel optimization.
Definition: app_queue.c:5933
unsigned int id
Definition: app_queue.c:5939
const ast_string_field member_uniqueid
Definition: app_queue.c:5965
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
const ast_string_field caller_uniqueid
Definition: app_queue.c:5965
struct local_optimization caller_optimize
Definition: app_queue.c:5985
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:602
struct local_optimization member_optimize
Definition: app_queue.c:5987
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
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.
A multi channel blob data structure for multi_channel_blob stasis messages.
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:5957
enum queue_result id
Definition: app_queue.c:1507
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:322
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514

◆ handle_masquerade()

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

Definition at line 6455 of file app_queue.c.

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().

6457 {
6458  struct queue_stasis_data *queue_data = userdata;
6459  struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6460  const char *new_channel_id;
6461 
6462  new_channel_id = ast_json_string_get(ast_json_object_get(channel_blob->blob, "newchanneluniqueid"));
6463 
6464  ao2_lock(queue_data);
6465 
6466  if (queue_data->dying) {
6467  ao2_unlock(queue_data);
6468  return;
6469  }
6470 
6471  if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6472  ast_debug(1, "Replacing caller channel %s with %s due to masquerade\n", queue_data->caller_uniqueid, new_channel_id);
6473  ast_string_field_set(queue_data, caller_uniqueid, new_channel_id);
6474  } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6475  ast_debug(1, "Replacing member channel %s with %s due to masquerade\n", queue_data->member_uniqueid, new_channel_id);
6476  ast_string_field_set(queue_data, member_uniqueid, new_channel_id);
6477  }
6478 
6479  ao2_unlock(queue_data);
6480 }
struct ast_channel_snapshot_base * base
struct ast_json * blob
struct ast_channel_snapshot * snapshot
const ast_string_field uniqueid
#define ao2_unlock(a)
Definition: astobj2.h:730
Blob of data associated with a channel.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ao2_lock(a)
Definition: astobj2.h:718
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
const ast_string_field member_uniqueid
Definition: app_queue.c:5965
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
const ast_string_field caller_uniqueid
Definition: app_queue.c:5965
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
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:5957
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514

◆ handle_queue_add_member()

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

Definition at line 10561 of file app_queue.c.

References add_to_queue(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), ast_strlen_zero, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_add_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, NULL, ast_cli_args::pos, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, ast_cli_entry::usage, and ast_cli_args::word.

10562 {
10563  const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
10564  int penalty;
10565 
10566  switch ( cmd ) {
10567  case CLI_INIT:
10568  e->command = "queue add member";
10569  e->usage =
10570  "Usage: queue add member <dial string> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"
10571  " Add a dial string (Such as a channel,e.g. SIP/6001) to a queue with optionally: a penalty, membername and a state_interface\n";
10572  return NULL;
10573  case CLI_GENERATE:
10574  return complete_queue_add_member(a->line, a->word, a->pos, a->n);
10575  }
10576 
10577  if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
10578  return CLI_SHOWUSAGE;
10579  } else if (strcmp(a->argv[4], "to")) {
10580  return CLI_SHOWUSAGE;
10581  } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
10582  return CLI_SHOWUSAGE;
10583  } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
10584  return CLI_SHOWUSAGE;
10585  } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
10586  return CLI_SHOWUSAGE;
10587  }
10588 
10589  queuename = a->argv[5];
10590  interface = a->argv[3];
10591  if (a->argc >= 8) {
10592  if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
10593  if (penalty < 0) {
10594  ast_cli(a->fd, "Penalty must be >= 0\n");
10595  penalty = 0;
10596  }
10597  } else {
10598  ast_cli(a->fd, "Penalty must be an integer >= 0\n");
10599  penalty = 0;
10600  }
10601  } else {
10602  penalty = 0;
10603  }
10604 
10605  if (a->argc >= 10) {
10606  membername = a->argv[9];
10607  }
10608 
10609  if (a->argc >= 12) {
10610  state_interface = a->argv[11];
10611  }
10612 
10613  switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface, NULL, 0)) {
10614  case RES_OKAY:
10615  if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10616  ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
10617  } else {
10618  ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", "");
10619  }
10620  ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
10621  return CLI_SUCCESS;
10622  case RES_EXISTS:
10623  ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
10624  return CLI_FAILURE;
10625  case RES_NOSUCHQUEUE:
10626  ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
10627  return CLI_FAILURE;
10628  case RES_OUTOFMEMORY:
10629  ast_cli(a->fd, "Out of memory\n");
10630  return CLI_FAILURE;
10631  case RES_NOT_DYNAMIC:
10632  ast_cli(a->fd, "Member not dynamic\n");
10633  return CLI_FAILURE;
10634  default:
10635  return CLI_FAILURE;
10636  }
10637 }
#define RES_OKAY
Definition: app_queue.c:1441
const int argc
Definition: cli.h:160
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1445
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1490
Definition: cli.h:152
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
const char * line
Definition: cli.h:162
#define RES_OUTOFMEMORY
Definition: app_queue.c:1443
#define ast_strlen_zero(foo)
Definition: strings.h:52
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
const char *const * argv
Definition: cli.h:161
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
static char * complete_queue_add_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10426
const char * usage
Definition: cli.h:177
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1444
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164
#define RES_EXISTS
Definition: app_queue.c:1442
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:7377
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1466

◆ handle_queue_change_priority_caller()

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

Definition at line 10750 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_log, change_priority_caller_on_queue(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, LOG_ERROR, NULL, priority, RES_NOSUCHQUEUE, RES_NOT_CALLER, RES_OKAY, and ast_cli_entry::usage.

10751 {
10752  const char *queuename, *caller;
10753  int priority;
10754  char *res = CLI_FAILURE;
10755 
10756  switch (cmd) {
10757  case CLI_INIT:
10758  e->command = "queue priority caller";
10759  e->usage =
10760  "Usage: queue priority caller <channel> on <queue> to <priority>\n"
10761  " Change the priority of a channel on a queue.\n";
10762  return NULL;
10763  case CLI_GENERATE:
10764  return NULL;
10765  }
10766 
10767  if (a->argc != 8) {
10768  return CLI_SHOWUSAGE;
10769  } else if (strcmp(a->argv[4], "on")) {
10770  return CLI_SHOWUSAGE;
10771  } else if (strcmp(a->argv[6], "to")) {
10772  return CLI_SHOWUSAGE;
10773  } else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
10774  ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
10775  return CLI_SHOWUSAGE;
10776  }
10777 
10778  caller = a->argv[3];
10779  queuename = a->argv[5];
10780 
10781  switch (change_priority_caller_on_queue(queuename, caller, priority)) {
10782  case RES_OKAY:
10783  res = CLI_SUCCESS;
10784  break;
10785  case RES_NOSUCHQUEUE:
10786  ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename);
10787  break;
10788  case RES_NOT_CALLER:
10789  ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename);
10790 
10791  break;
10792  }
10793 
10794  return res;
10795 }
static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority)
Change priority caller into a queue.
Definition: app_queue.c:7430
#define RES_OKAY
Definition: app_queue.c:1441
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static int priority
#define RES_NOT_CALLER
Definition: app_queue.c:1446
#define ast_log
Definition: astobj2.c:42
const int fd
Definition: cli.h:159
const char *const * argv
Definition: cli.h:161
#define LOG_ERROR
Definition: logger.h:285
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1444
#define CLI_SUCCESS
Definition: cli.h:44

◆ handle_queue_pause_member()

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

Definition at line 10818 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_strlen_zero, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_pause_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, NULL, ast_cli_args::pos, RESULT_SUCCESS, set_member_paused(), and ast_cli_entry::usage.

10819 {
10820  const char *queuename, *interface, *reason;
10821  int paused;
10822 
10823  switch (cmd) {
10824  case CLI_INIT:
10825  e->command = "queue {pause|unpause} member";
10826  e->usage =
10827  "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
10828  " Pause or unpause a queue member. Not specifying a particular queue\n"
10829  " will pause or unpause a member across all queues to which the member\n"
10830  " belongs.\n";
10831  return NULL;
10832  case CLI_GENERATE:
10833  return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
10834  }
10835 
10836  if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
10837  return CLI_SHOWUSAGE;
10838  } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
10839  return CLI_SHOWUSAGE;
10840  } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
10841  return CLI_SHOWUSAGE;
10842  }
10843 
10844 
10845  interface = a->argv[3];
10846  queuename = a->argc >= 6 ? a->argv[5] : NULL;
10847  reason = a->argc == 8 ? a->argv[7] : NULL;
10848  paused = !strcasecmp(a->argv[1], "pause");
10849 
10850  if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
10851  ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
10852  if (!ast_strlen_zero(queuename)) {
10853  ast_cli(a->fd, " in queue '%s'", queuename);
10854  }
10855  if (!ast_strlen_zero(reason)) {
10856  ast_cli(a->fd, " for reason '%s'", reason);
10857  }
10858  ast_cli(a->fd, "\n");
10859  return CLI_SUCCESS;
10860  } else {
10861  ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
10862  if (!ast_strlen_zero(queuename)) {
10863  ast_cli(a->fd, " in queue '%s'", queuename);
10864  }
10865  if (!ast_strlen_zero(reason)) {
10866  ast_cli(a->fd, " for reason '%s'", reason);
10867  }
10868  ast_cli(a->fd, "\n");
10869  return CLI_FAILURE;
10870  }
10871 }
static char * complete_queue_pause_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10799
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
const char * line
Definition: cli.h:162
#define ast_strlen_zero(foo)
Definition: strings.h:52
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
const char *const * argv
Definition: cli.h:161
#define CLI_SHOWUSAGE
Definition: cli.h:45
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:7528
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164
#define RESULT_SUCCESS
Definition: cli.h:40
short word

◆ handle_queue_reload()

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

Definition at line 11090 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, AST_FLAGS_ALL, ast_set_flag, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue(), ast_cli_args::line, ast_cli_args::n, NULL, ast_cli_args::pos, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, reload_handler(), ast_cli_entry::usage, and ast_cli_args::word.

11091 {
11092  struct ast_flags mask = {0,};
11093  int i;
11094 
11095  switch (cmd) {
11096  case CLI_INIT:
11097  e->command = "queue reload {parameters|members|rules|all}";
11098  e->usage =
11099  "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
11100  "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
11101  "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
11102  "specified in order to know what information to reload. Below is an explanation\n"
11103  "of each of these qualifiers.\n"
11104  "\n"
11105  "\t'members' - reload queue members from queues.conf\n"
11106  "\t'parameters' - reload all queue options except for queue members\n"
11107  "\t'rules' - reload the queuerules.conf file\n"
11108  "\t'all' - reload queue rules, parameters, and members\n"
11109  "\n"
11110  "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
11111  "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
11112  "one queue is specified when using this command, reloading queue rules may cause\n"
11113  "other queues to be affected\n";
11114  return NULL;
11115  case CLI_GENERATE:
11116  if (a->pos >= 3) {
11117  /* find the point at which the list of queue names starts */
11118  const char *command_end = a->line + strlen("queue reload ");
11119  command_end = strchr(command_end, ' ');
11120  if (!command_end) {
11121  command_end = a->line + strlen(a->line);
11122  }
11123  return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
11124  } else {
11125  return NULL;
11126  }
11127  }
11128 
11129  if (a->argc < 3)
11130  return CLI_SHOWUSAGE;
11131 
11132  if (!strcasecmp(a->argv[2], "rules")) {
11134  } else if (!strcasecmp(a->argv[2], "members")) {
11136  } else if (!strcasecmp(a->argv[2], "parameters")) {
11138  } else if (!strcasecmp(a->argv[2], "all")) {
11139  ast_set_flag(&mask, AST_FLAGS_ALL);
11140  }
11141 
11142  if (a->argc == 3) {
11143  reload_handler(1, &mask, NULL);
11144  return CLI_SUCCESS;
11145  }
11146 
11147  for (i = 3; i < a->argc; ++i) {
11148  reload_handler(1, &mask, a->argv[i]);
11149  }
11150 
11151  return CLI_SUCCESS;
11152 }
#define ast_set_flag(p, flag)
Definition: utils.h:70
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define NULL
Definition: resample.c:96
const char * line
Definition: cli.h:162
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:9929
const int n
Definition: cli.h:165
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:9627
const char *const * argv
Definition: cli.h:161
#define CLI_SHOWUSAGE
Definition: cli.h:45
char * command
Definition: cli.h:186
#define AST_FLAGS_ALL
Definition: utils.h:196
const char * word
Definition: cli.h:163
Structure used to handle boolean flags.
Definition: utils.h:199
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164

◆ handle_queue_remove_member()

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

Definition at line 10687 of file app_queue.c.

References ao2_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), ast_strlen_zero, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_remove_member(), ast_cli_args::fd, find_member_by_queuename_and_interface(), ast_cli_args::line, member::membername, ast_cli_args::n, NULL, ast_cli_args::pos, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, ast_cli_entry::usage, and ast_cli_args::word.

10688 {
10689  const char *queuename, *interface;
10690  struct member *mem = NULL;
10691  char *res = CLI_FAILURE;
10692 
10693  switch (cmd) {
10694  case CLI_INIT:
10695  e->command = "queue remove member";
10696  e->usage =
10697  "Usage: queue remove member <channel> from <queue>\n"
10698  " Remove a specific channel from a queue.\n";
10699  return NULL;
10700  case CLI_GENERATE:
10701  return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
10702  }
10703 
10704  if (a->argc != 6) {
10705  return CLI_SHOWUSAGE;
10706  } else if (strcmp(a->argv[4], "from")) {
10707  return CLI_SHOWUSAGE;
10708  }
10709 
10710  queuename = a->argv[5];
10711  interface = a->argv[3];
10712 
10714  mem = find_member_by_queuename_and_interface(queuename, interface);
10715  }
10716 
10717  switch (remove_from_queue(queuename, interface)) {
10718  case RES_OKAY:
10719  if (!mem || ast_strlen_zero(mem->membername)) {
10720  ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
10721  } else {
10722  ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
10723  }
10724  ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
10725  res = CLI_SUCCESS;
10726  break;
10727  case RES_EXISTS:
10728  ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
10729  break;
10730  case RES_NOSUCHQUEUE:
10731  ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
10732  break;
10733  case RES_OUTOFMEMORY:
10734  ast_cli(a->fd, "Out of memory\n");
10735  break;
10736  case RES_NOT_DYNAMIC:
10737  ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
10738  break;
10739  }
10740 
10741  if (mem) {
10742  ao2_ref(mem, -1);
10743  }
10744 
10745  return res;
10746 }
#define RES_OKAY
Definition: app_queue.c:1441
const int argc
Definition: cli.h:160
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1445
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1490
Definition: cli.h:152
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
const char * line
Definition: cli.h:162
char membername[80]
Definition: app_queue.c:1598
#define RES_OUTOFMEMORY
Definition: app_queue.c:1443
#define ast_strlen_zero(foo)
Definition: strings.h:52
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
static struct member * find_member_by_queuename_and_interface(const char *queuename, const char *interface)
Definition: app_queue.c:11484
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char *const * argv
Definition: cli.h:161
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
static char * complete_queue_remove_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10639
const char * word
Definition: cli.h:163
const char * usage
Definition: cli.h:177
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1444
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164
#define RES_EXISTS
Definition: app_queue.c:1442
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:7324

◆ handle_queue_reset()

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

Definition at line 11051 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue(), ast_cli_args::line, ast_cli_args::n, NULL, ast_cli_args::pos, QUEUE_RESET_STATS, reload_handler(), ast_cli_entry::usage, and ast_cli_args::word.

11052 {
11053  struct ast_flags mask = {QUEUE_RESET_STATS,};
11054  int i;
11055 
11056  switch (cmd) {
11057  case CLI_INIT:
11058  e->command = "queue reset stats";
11059  e->usage =
11060  "Usage: queue reset stats [<queuenames>]\n"
11061  "\n"
11062  "Issuing this command will reset statistics for\n"
11063  "<queuenames>, or for all queues if no queue is\n"
11064  "specified.\n";
11065  return NULL;
11066  case CLI_GENERATE:
11067  if (a->pos >= 3) {
11068  return complete_queue(a->line, a->word, a->pos, a->n, 17);
11069  } else {
11070  return NULL;
11071  }
11072  }
11073 
11074  if (a->argc < 3) {
11075  return CLI_SHOWUSAGE;
11076  }
11077 
11078  if (a->argc == 3) {
11079  reload_handler(1, &mask, NULL);
11080  return CLI_SUCCESS;
11081  }
11082 
11083  for (i = 3; i < a->argc; ++i) {
11084  reload_handler(1, &mask, a->argv[i]);
11085  }
11086 
11087  return CLI_SUCCESS;
11088 }
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define NULL
Definition: resample.c:96
const char * line
Definition: cli.h:162
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:9929
const int n
Definition: cli.h:165
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:9627
const char *const * argv
Definition: cli.h:161
#define CLI_SHOWUSAGE
Definition: cli.h:45
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
Structure used to handle boolean flags.
Definition: utils.h:199
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164

◆ handle_queue_rule_show()

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

Definition at line 11016 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_rule_show(), ast_cli_args::fd, ast_cli_args::line, penalty_rule::list, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, ast_cli_args::n, rule_list::name, NULL, ast_cli_args::pos, penalty_rule::raise_relative, penalty_rule::raise_value, rule_list::rules, penalty_rule::time, ast_cli_entry::usage, and ast_cli_args::word.

11017 {
11018  const char *rule;
11019  struct rule_list *rl_iter;
11020  struct penalty_rule *pr_iter;
11021  switch (cmd) {
11022  case CLI_INIT:
11023  e->command = "queue show rules";
11024  e->usage =
11025  "Usage: queue show rules [rulename]\n"
11026  " Show the list of rules associated with rulename. If no\n"
11027  " rulename is specified, list all rules defined in queuerules.conf\n";
11028  return NULL;
11029  case CLI_GENERATE:
11030  return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
11031  }
11032 
11033  if (a->argc != 3 && a->argc != 4) {
11034  return CLI_SHOWUSAGE;
11035  }
11036 
11037  rule = a->argc == 4 ? a->argv[3] : "";
11039  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11040  if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
11041  ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
11042  AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
11043  ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d, adjust QUEUE_MIN_PENALTY %s %d and adjust QUEUE_RAISE_PENALTY %s %d\n", pr_iter->time, pr_iter->max_relative ? "by" : "to", pr_iter->max_value, pr_iter->min_relative ? "by" : "to", pr_iter->min_value, pr_iter->raise_relative ? "by" : "to", pr_iter->raise_value);
11044  }
11045  }
11046  }
11048  return CLI_SUCCESS;
11049 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
int max_relative
Definition: app_queue.c:1645
char name[80]
Definition: app_queue.c:1759
int min_relative
Definition: app_queue.c:1646
const int argc
Definition: cli.h:160
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
Definition: cli.h:152
struct rule_list::@71 rules
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
const char * line
Definition: cli.h:162
#define ast_strlen_zero(foo)
Definition: strings.h:52
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
const char *const * argv
Definition: cli.h:161
static char * complete_queue_rule_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10994
int raise_relative
Definition: app_queue.c:1647
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
char * command
Definition: cli.h:186
struct penalty_rule::@68 list
const char * word
Definition: cli.h:163
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164

◆ handle_queue_set_member_penalty()

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

Definition at line 10953 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_set_member_value(), ast_cli_args::fd, ast_cli_args::line, MEMBER_PENALTY, ast_cli_args::n, NULL, ast_cli_args::pos, RESULT_FAILURE, RESULT_SUCCESS, set_member_value(), ast_cli_entry::usage, and ast_cli_args::word.

10954 {
10955  const char *queuename = NULL, *interface;
10956  int penalty = 0;
10957 
10958  switch (cmd) {
10959  case CLI_INIT:
10960  e->command = "queue set penalty";
10961  e->usage =
10962  "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
10963  " Set a member's penalty in the queue specified. If no queue is specified\n"
10964  " then that interface's penalty is set in all queues to which that interface is a member\n";
10965  return NULL;
10966  case CLI_GENERATE:
10967  return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
10968  }
10969 
10970  if (a->argc != 6 && a->argc != 8) {
10971  return CLI_SHOWUSAGE;
10972  } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
10973  return CLI_SHOWUSAGE;
10974  }
10975 
10976  if (a->argc == 8) {
10977  queuename = a->argv[7];
10978  }
10979  interface = a->argv[5];
10980  penalty = atoi(a->argv[3]);
10981 
10982  switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
10983  case RESULT_SUCCESS:
10984  ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
10985  return CLI_SUCCESS;
10986  case RESULT_FAILURE:
10987  ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
10988  return CLI_FAILURE;
10989  default:
10990  return CLI_FAILURE;
10991  }
10992 }
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
const char * line
Definition: cli.h:162
static char * complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10873
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
const char *const * argv
Definition: cli.h:161
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
const int pos
Definition: cli.h:164
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:7674
#define RESULT_SUCCESS
Definition: cli.h:40
#define RESULT_FAILURE
Definition: cli.h:42

◆ handle_queue_set_member_ringinuse()

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

Definition at line 10896 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_false(), ast_true(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_set_member_value(), ast_cli_args::fd, ast_cli_args::line, MEMBER_RINGINUSE, ast_cli_args::n, NULL, ast_cli_args::pos, RESULT_FAILURE, RESULT_SUCCESS, set_member_value(), ast_cli_entry::usage, and ast_cli_args::word.

10897 {
10898  const char *queuename = NULL, *interface;
10899  int ringinuse;
10900 
10901  switch (cmd) {
10902  case CLI_INIT:
10903  e->command = "queue set ringinuse";
10904  e->usage =
10905  "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
10906  " Set a member's ringinuse in the queue specified. If no queue is specified\n"
10907  " then that interface's penalty is set in all queues to which that interface is a member.\n";
10908  break;
10909  return NULL;
10910  case CLI_GENERATE:
10911  return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
10912  }
10913 
10914  /* Sensible argument counts */
10915  if (a->argc != 6 && a->argc != 8) {
10916  return CLI_SHOWUSAGE;
10917  }
10918 
10919  /* Uses proper indicational words */
10920  if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
10921  return CLI_SHOWUSAGE;
10922  }
10923 
10924  /* Set the queue name if applicale */
10925  if (a->argc == 8) {
10926  queuename = a->argv[7];
10927  }
10928 
10929  /* Interface being set */
10930  interface = a->argv[5];
10931 
10932  /* Check and set the ringinuse value */
10933  if (ast_true(a->argv[3])) {
10934  ringinuse = 1;
10935  } else if (ast_false(a->argv[3])) {
10936  ringinuse = 0;
10937  } else {
10938  return CLI_SHOWUSAGE;
10939  }
10940 
10941  switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
10942  case RESULT_SUCCESS:
10943  ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
10944  return CLI_SUCCESS;
10945  case RESULT_FAILURE:
10946  ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
10947  return CLI_FAILURE;
10948  default:
10949  return CLI_FAILURE;
10950  }
10951 }
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
const char * line
Definition: cli.h:162
static char * complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10873
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
const char *const * argv
Definition: cli.h:161
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
const int pos
Definition: cli.h:164
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:7674
#define RESULT_SUCCESS
Definition: cli.h:40
#define RESULT_FAILURE
Definition: cli.h:42

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

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(), callattempt::chan, queue_ent::chan, callattempt::interface, callattempt::member, pending_members_remove(), callattempt::q_next, and member::status.

Referenced by try_calling().

4251 {
4252  struct callattempt *oo;
4253 
4254  while (outgoing) {
4255  /* If someone else answered the call we should indicate this in the CANCEL */
4256  /* Hangup any existing lines we have open */
4257  if (outgoing->chan && (outgoing->chan != exception)) {
4258  if (exception || cancel_answered_elsewhere) {
4260  }
4261  ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
4262 
4263  /* When dialing channels it is possible that they may not ever
4264  * leave the not in use state (Local channels in particular) by
4265  * the time we cancel them. If this occurs but we know they were
4266  * dialed we explicitly remove them from the pending members
4267  * container so that subsequent call attempts occur.
4268  */
4269  if (outgoing->member->status == AST_DEVICE_NOT_INUSE) {
4270  pending_members_remove(outgoing->member);
4271  }
4272 
4273  ast_hangup(outgoing->chan);
4274  }
4275  oo = outgoing;
4276  outgoing = outgoing->q_next;
4278  callattempt_free(oo);
4279  }
4280 }
struct callattempt * q_next
Definition: app_queue.c:1538
struct ast_channel * chan
Definition: app_queue.c:1586
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...
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:307
char interface[256]
Definition: app_queue.c:1541
struct ast_aoc_decoded * aoc_s_rate_list
Definition: app_queue.c:1554
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2426
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition: causes.h:113
struct member * member
Definition: app_queue.c:1543
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1537
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
int status
Definition: app_queue.c:1603
static void callattempt_free(struct callattempt *doomed)
Definition: app_queue.c:4228
struct ast_channel * chan
Definition: app_queue.c:1540

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

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().

2770 {
2771  int i;
2772  struct penalty_rule *pr_iter;
2773 
2774  q->dead = 0;
2775  q->retry = DEFAULT_RETRY;
2776  q->timeout = DEFAULT_TIMEOUT;
2777  q->maxlen = 0;
2778 
2779  ast_string_field_set(q, context, "");
2780 
2781  q->announcefrequency = 0;
2783  q->announceholdtime = 1;
2784  q->announceposition_only_up = 0;
2785  q->announcepositionlimit = 10; /* Default 10 positions */
2786  q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
2787  q->roundingseconds = 0; /* Default - don't announce seconds */
2788  q->servicelevel = 0;
2789  q->ringinuse = 1;
2790  q->announce_to_first_user = 0;
2791  q->setinterfacevar = 0;
2792  q->setqueuevar = 0;
2793  q->setqueueentryvar = 0;
2795  q->montype = montype_default;
2796  q->monfmt[0] = '\0';
2797  q->reportholdtime = 0;
2798  q->wrapuptime = 0;
2799  q->penaltymemberslimit = 0;
2800  q->joinempty = 0;
2801  q->leavewhenempty = 0;
2802  q->memberdelay = 0;
2803  q->weight = 0;
2804  q->timeoutrestart = 0;
2806  q->randomperiodicannounce = 0;
2807  q->numperiodicannounce = 0;
2810  q->autopausedelay = 0;
2811  if (!q->members) {
2813  /* linear strategy depends on order, so we have to place all members in a list */
2815  } else {
2818  }
2819  }
2820  q->found = 1;
2821 
2822  ast_string_field_set(q, moh, "");
2823  ast_string_field_set(q, sound_next, "queue-youarenext");
2824  ast_string_field_set(q, sound_thereare, "queue-thereare");
2825  ast_string_field_set(q, sound_calls, "queue-callswaiting");
2826  ast_string_field_set(q, queue_quantity1, "queue-quantity1");
2827  ast_string_field_set(q, queue_quantity2, "queue-quantity2");
2828  ast_string_field_set(q, sound_holdtime, "queue-holdtime");
2829  ast_string_field_set(q, sound_minutes, "queue-minutes");
2830  ast_string_field_set(q, sound_minute, "queue-minute");
2831  ast_string_field_set(q, sound_seconds, "queue-seconds");
2832  ast_string_field_set(q, sound_thanks, "queue-thankyou");
2833  ast_string_field_set(q, sound_reporthold, "queue-reporthold");
2834 
2835  if (!q->sound_periodicannounce[0]) {
2837  }
2838 
2839  if (q->sound_periodicannounce[0]) {
2840  ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
2841  }
2842 
2843  for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
2844  if (q->sound_periodicannounce[i]) {
2845  ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
2846  }
2847  }
2848 
2849  while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
2850  ast_free(pr_iter);
2851  }
2852 
2853  /* On restart assume no members are available.
2854  * The queue_avail hint is a boolean state to indicate whether a member is available or not.
2855  *
2856  * This seems counter intuitive, but is required to light a BLF
2857  * AST_DEVICE_INUSE indicates no members are available.
2858  * AST_DEVICE_NOT_INUSE indicates a member is available.
2859  */
2861 }
struct ast_str * sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]
Definition: app_queue.c:1698
int servicelevel
Definition: app_queue.c:1731
static int member_hash_fn(const void *obj, const int flags)
Definition: app_queue.c:2740
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1432
int wrapuptime
Definition: app_queue.c:1737
int penaltymemberslimit
Definition: app_queue.c:1738
unsigned int setqueuevar
Definition: app_queue.c:1703
#define DEFAULT_RETRY
Definition: app_queue.c:1429
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition: app_queue.c:1437
unsigned int announceposition_only_up
Definition: app_queue.c:1710
int minannouncefrequency
Definition: app_queue.c:1721
int autopause
Definition: app_queue.c:1743
unsigned int ringinuse
Definition: app_queue.c:1700
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
unsigned int timeoutrestart
Definition: app_queue.c:1707
unsigned int announceholdtime
Definition: app_queue.c:1708
unsigned int setinterfacevar
Definition: app_queue.c:1702
#define NULL
Definition: resample.c:96
unsigned int announce_to_first_user
Definition: app_queue.c:1701
struct ao2_container * members
Definition: app_queue.c:1752
char monfmt[8]
Definition: app_queue.c:1733
int announcepositionlimit
Definition: app_queue.c:1719
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:1065
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
int periodicannouncefrequency
Definition: app_queue.c:1722
int memberdelay
Definition: app_queue.c:1749
int strategy
Definition: app_queue.c:1711
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1475
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition: app_queue.c:2756
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1472
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1651
unsigned int dead
Definition: app_queue.c:1699
int autopausedelay
Definition: app_queue.c:1744
const ast_string_field name
Definition: app_queue.c:1696
unsigned int reportholdtime
Definition: app_queue.c:1705
int autofill
Definition: app_queue.c:1750
int roundingseconds
Definition: app_queue.c:1725
#define ast_free(a)
Definition: astmm.h:182
struct penalty_rule::@68 list
#define DEFAULT_TIMEOUT
Definition: app_queue.c:1430
int timeoutpriority
Definition: app_queue.c:1745
unsigned int announceposition
Definition: app_queue.c:1709
unsigned int found
Definition: app_queue.c:1713
int randomperiodicannounce
Definition: app_queue.c:1724
unsigned int setqueueentryvar
Definition: app_queue.c:1704
int numperiodicannounce
Definition: app_queue.c:1723
enum empty_conditions leavewhenempty
Definition: app_queue.c:1718
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
enum empty_conditions joinempty
Definition: app_queue.c:1717
struct call_queue::@70 rules
int announcefrequency
Definition: app_queue.c:1720
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514

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

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

Referenced by join_queue().

1953 {
1954  struct queue_ent *cur;
1955 
1956  if (!q || !new)
1957  return;
1958  if (prev) {
1959  cur = prev->next;
1960  prev->next = new;
1961  } else {
1962  cur = q->head;
1963  q->head = new;
1964  }
1965  new->next = cur;
1966 
1967  /* every queue_ent must have a reference to it's parent call_queue, this
1968  * reference does not go away until the end of the queue_ent's life, meaning
1969  * that even when the queue_ent leaves the call_queue this ref must remain. */
1970  queue_ref(q);
1971  new->parent = q;
1972  new->pos = ++(*pos);
1973  new->opos = *pos;
1974 }
#define queue_ref(q)
Definition: app_queue.c:1918
struct queue_ent * head
Definition: app_queue.c:1753
struct queue_ent * next
Definition: app_queue.c:1589

◆ 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 fomatting, 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 2895 of file app_queue.c.

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, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, NULL, penalty_rule::raise_relative, penalty_rule::raise_value, rule_list::rules, and penalty_rule::time.

Referenced by reload_queue_rules().

2896 {
2897  char *timestr, *maxstr, *minstr, *raisestr, *contentdup;
2898  struct penalty_rule *rule = NULL, *rule_iter;
2899  struct rule_list *rl_iter;
2900  int penaltychangetime, inserted = 0;
2901 
2902  if (!(rule = ast_calloc(1, sizeof(*rule)))) {
2903  return -1;
2904  }
2905 
2906  contentdup = ast_strdupa(content);
2907 
2908  if (!(maxstr = strchr(contentdup, ','))) {
2909  ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
2910  ast_free(rule);
2911  return -1;
2912  }
2913 
2914  *maxstr++ = '\0';
2915  if ((minstr = strchr(maxstr,','))) {
2916  *minstr++ = '\0';
2917  if ((raisestr = strchr(minstr,','))) {
2918  *raisestr++ = '\0';
2919  }
2920  } else {
2921  raisestr = NULL;
2922  }
2923 
2924  timestr = contentdup;
2925  if ((penaltychangetime = atoi(timestr)) < 0) {
2926  ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
2927  ast_free(rule);
2928  return -1;
2929  }
2930 
2931  rule->time = penaltychangetime;
2932 
2933  /* The last check will evaluate true if either no penalty change is indicated for a given rule
2934  * OR if a min penalty change is indicated but no max penalty change is */
2935  if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
2936  rule->max_relative = 1;
2937  }
2938 
2939  rule->max_value = atoi(maxstr);
2940 
2941  if (!ast_strlen_zero(minstr)) {
2942  if (*minstr == '+' || *minstr == '-') {
2943  rule->min_relative = 1;
2944  }
2945  rule->min_value = atoi(minstr);
2946  } else { /*there was no minimum specified, so assume this means no change*/
2947  rule->min_relative = 1;
2948  }
2949 
2950  if (!ast_strlen_zero(raisestr)) {
2951  if (*raisestr == '+' || *raisestr == '-') {
2952  rule->raise_relative = 1;
2953  }
2954  rule->raise_value = atoi(raisestr);
2955  } else { /*there was no raise specified, so assume this means no change*/
2956  rule->raise_relative = 1;
2957  }
2958 
2959  /*We have the rule made, now we need to insert it where it belongs*/
2960  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
2961  if (strcasecmp(rl_iter->name, list_name)) {
2962  continue;
2963  }
2964 
2965  AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
2966  if (rule->time < rule_iter->time) {
2968  inserted = 1;
2969  break;
2970  }
2971  }
2973 
2974  if (!inserted) {
2975  AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
2976  inserted = 1;
2977  }
2978 
2979  break;
2980  }
2981 
2982  if (!inserted) {
2983  ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
2984  ast_free(rule);
2985  return -1;
2986  }
2987  return 0;
2988 }
int max_relative
Definition: app_queue.c:1645
char name[80]
Definition: app_queue.c:1759
int min_relative
Definition: app_queue.c:1646
#define LOG_WARNING
Definition: logger.h:274
struct rule_list::@71 rules
#define NULL
Definition: resample.c:96
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int raise_relative
Definition: app_queue.c:1647
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
struct rule_list::@72 list
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:598

◆ int2strat()

static const char* int2strat ( int  strategy)
static

Definition at line 1787 of file app_queue.c.

References ARRAY_LEN, strategy::name, and strategies.

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

1788 {
1789  int x;
1790 
1791  for (x = 0; x < ARRAY_LEN(strategies); x++) {
1792  if (strategy == strategies[x].strategy) {
1793  return strategies[x].name;
1794  }
1795  }
1796 
1797  return "<unknown>";
1798 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static const struct strategy strategies[]
const char * name
Definition: app_queue.c:1407

◆ interface_exists()

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

Definition at line 7242 of file app_queue.c.

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

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

7243 {
7244  struct member *mem;
7245  struct ao2_iterator mem_iter;
7246 
7247  if (!q) {
7248  return NULL;
7249  }
7250  mem_iter = ao2_iterator_init(q->members, 0);
7251  while ((mem = ao2_iterator_next(&mem_iter))) {
7252  if (!strcasecmp(interface, mem->interface)) {
7253  ao2_iterator_destroy(&mem_iter);
7254  return mem;
7255  }
7256  ao2_ref(mem, -1);
7257  }
7258  ao2_iterator_destroy(&mem_iter);
7259 
7260  return NULL;
7261 }
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define NULL
Definition: resample.c:96
struct ao2_container * members
Definition: app_queue.c:1752
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ is_member_available()

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

Definition at line 2468 of file app_queue.c.

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

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

2469 {
2470  int available = 0;
2471  int wrapuptime;
2472 
2473  switch (mem->status) {
2474  case AST_DEVICE_INVALID:
2476  break;
2477  case AST_DEVICE_INUSE:
2478  case AST_DEVICE_BUSY:
2479  case AST_DEVICE_RINGING:
2480  case AST_DEVICE_RINGINUSE:
2481  case AST_DEVICE_ONHOLD:
2482  if (!mem->ringinuse) {
2483  break;
2484  }
2485  /* else fall through */
2486  case AST_DEVICE_NOT_INUSE:
2487  case AST_DEVICE_UNKNOWN:
2488  if (!mem->paused) {
2489  available = 1;
2490  }
2491  break;
2492  }
2493 
2494  /* Let wrapuptimes override device state availability */
2495  wrapuptime = get_wrapuptime(q, mem);
2496  if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {
2497  available = 0;
2498  }
2499  return available;
2500 }
int paused
Definition: app_queue.c:1604
#define NULL
Definition: resample.c:96
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:1856
int status
Definition: app_queue.c:1603
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13058
unsigned int ringinuse
Definition: app_queue.c:1616
time_t lastcall
Definition: app_queue.c:1610

◆ is_our_turn()

static int is_our_turn ( struct queue_ent qe)
static

Check if we should start attempting to call queue members.

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

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

Definition at line 5487 of file app_queue.c.

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

Referenced by queue_exec(), and wait_our_turn().

5488 {
5489  struct queue_ent *ch;
5490  int res;
5491  int avl;
5492  int idx = 0;
5493  /* This needs a lock. How many members are available to be served? */
5494  ao2_lock(qe->parent);
5495 
5496  avl = num_available_members(qe->parent);
5497 
5498  ch = qe->parent->head;
5499 
5500  ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
5501 
5502  while ((idx < avl) && (ch) && (ch != qe)) {
5503  if (!ch->pending) {
5504  idx++;
5505  }
5506  ch = ch->next;
5507  }
5508 
5509  ao2_unlock(qe->parent);
5510  /* If the queue entry is within avl [the number of available members] calls from the top ...
5511  * Autofill and position check added to support autofill=no (as only calls
5512  * from the front of the queue are valid when autofill is disabled)
5513  */
5514  if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
5515  ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
5516  res = 1;
5517  } else {
5518  ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
5519  res = 0;
5520  }
5521 
5522  /* Update realtime members if this is the first call and number of avalable members is 0 */
5523  if (avl == 0 && qe->pos == 1) {
5525  }
5526 
5527  return res;
5528 }
struct call_queue * parent
Definition: app_queue.c:1561
struct ast_channel * chan
Definition: app_queue.c:1586
static void update_realtime_members(struct call_queue *q)
Definition: app_queue.c:3773
#define ao2_unlock(a)
Definition: astobj2.h:730
struct queue_ent * head
Definition: app_queue.c:1753
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ao2_lock(a)
Definition: astobj2.h:718
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:4290
int autofill
Definition: app_queue.c:1750
int pending
Definition: app_queue.c:1577
const char * ast_channel_name(const struct ast_channel *chan)
struct queue_ent * next
Definition: app_queue.c:1589

◆ join_queue()

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

Definition at line 3832 of file app_queue.c.

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

Referenced by queue_exec().

3833 {
3834  struct call_queue *q;
3835  struct queue_ent *cur, *prev = NULL;
3836  int res = -1;
3837  int pos = 0;
3838  int inserted = 0;
3839 
3840  if (!(q = find_load_queue_rt_friendly(queuename))) {
3841  return res;
3842  }
3843  ao2_lock(q);
3844 
3845  /* This is our one */
3846  if (q->joinempty) {
3847  int status = 0;
3848  if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, qe->raise_penalty, q->joinempty, 0))) {
3849  *reason = QUEUE_JOINEMPTY;
3850  ao2_unlock(q);
3851  queue_t_unref(q, "Done with realtime queue");
3852  return res;
3853  }
3854  }
3855  if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
3856  *reason = QUEUE_FULL;
3857  } else if (*reason == QUEUE_UNKNOWN) {
3858  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
3859 
3860  /* There's space for us, put us at the right position inside
3861  * the queue.
3862  * Take into account the priority of the calling user */
3863  inserted = 0;
3864  prev = NULL;
3865  cur = q->head;
3866  while (cur) {
3867  /* We have higher priority than the current user, enter
3868  * before him, after all the other users with priority
3869  * higher or equal to our priority. */
3870  if ((!inserted) && (qe->prio > cur->prio)) {
3871  insert_entry(q, prev, qe, &pos);
3872  inserted = 1;
3873  }
3874  /* <= is necessary for the position comparison because it may not be possible to enter
3875  * at our desired position since higher-priority callers may have taken the position we want
3876  */
3877  if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
3878  insert_entry(q, prev, qe, &pos);
3879  inserted = 1;
3880  /*pos is incremented inside insert_entry, so don't need to add 1 here*/
3881  if (position < pos) {
3882  ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
3883  }
3884  }
3885  cur->pos = ++pos;
3886  prev = cur;
3887  cur = cur->next;
3888  }
3889  /* No luck, join at the end of the queue */
3890  if (!inserted) {
3891  insert_entry(q, prev, qe, &pos);
3892  }
3893  ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
3894  ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
3895  ast_copy_string(qe->context, q->context, sizeof(qe->context));
3896  q->count++;
3897  if (q->count == 1) {
3899  }
3900 
3901  res = 0;
3902 
3903  blob = ast_json_pack("{s: s, s: i, s: i}",
3904  "Queue", q->name,
3905  "Position", qe->pos,
3906  "Count", q->count);
3907  ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
3908  ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
3909  }
3910  ao2_unlock(q);
3911  queue_t_unref(q, "Done with realtime queue");
3912 
3913  return res;
3914 }
int raise_penalty
Definition: app_queue.c:1580
struct ast_channel * chan
Definition: app_queue.c:1586
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
int min_penalty
Definition: app_queue.c:1579
int max_penalty
Definition: app_queue.c:1578
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
struct queue_ent * head
Definition: app_queue.c:1753
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
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
#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:911
const ast_string_field context
Definition: app_queue.c:1696
#define ao2_lock(a)
Definition: astobj2.h:718
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1562
const ast_string_field name
Definition: app_queue.c:1696
#define LOG_NOTICE
Definition: logger.h:263
const ast_string_field moh
Definition: app_queue.c:1696
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
const ast_string_field announce
Definition: app_queue.c:1696
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
static void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
Insert the &#39;new&#39; entry after the &#39;prev&#39; entry of queue &#39;q&#39;.
Definition: app_queue.c:1952
const char * ast_channel_name(const struct ast_channel *chan)
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:2284
Abstract JSON element (object, array, string, int, ...).
struct queue_ent * next
Definition: app_queue.c:1589
char context[AST_MAX_CONTEXT]
Definition: app_queue.c:1564
enum empty_conditions joinempty
Definition: app_queue.c:1717
char announce[PATH_MAX]
Definition: app_queue.c:1563
jack_status_t status
Definition: app_jack.c:146

◆ kill_dead_members()

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

Definition at line 9360 of file app_queue.c.

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

Referenced by reload_single_queue().

9361 {
9362  struct member *member = obj;
9363 
9364  if (!member->delme) {
9365  member->status = get_queue_member_status(member);
9366  return 0;
9367  } else {
9368  return CMP_MATCH;
9369  }
9370 }
unsigned int delme
Definition: app_queue.c:1614
int status
Definition: app_queue.c:1603
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:2671

◆ kill_if_unfound()

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

Definition at line 9516 of file app_queue.c.

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

Referenced by reload_queues().

9517 {
9518  struct call_queue *q = obj;
9519  char *queuename = arg;
9520  if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
9521  q->dead = 1;
9522  return CMP_MATCH;
9523  } else {
9524  return 0;
9525  }
9526 }
#define ast_strlen_zero(foo)
Definition: strings.h:52
unsigned int dead
Definition: app_queue.c:1699
const ast_string_field name
Definition: app_queue.c:1696
unsigned int found
Definition: app_queue.c:1713
unsigned int realtime
Definition: app_queue.c:1712

◆ leave_queue()

static void leave_queue ( struct queue_ent qe)
static

Caller leaving queue.

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

Definition at line 4151 of file app_queue.c.

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

Referenced by queue_exec(), and try_calling().

4152 {
4153  struct call_queue *q;
4154  struct queue_ent *current, *prev = NULL;
4155  struct penalty_rule *pr_iter;
4156  int pos = 0;
4157 
4158  if (!(q = qe->parent)) {
4159  return;
4160  }
4161  queue_t_ref(q, "Copy queue pointer from queue entry");
4162  ao2_lock(q);
4163 
4164  prev = NULL;
4165  for (current = q->head; current; current = current->next) {
4166  if (current == qe) {
4167  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4168  char posstr[20];
4169  q->count--;
4170  if (!q->count) {
4172  }
4173 
4174  blob = ast_json_pack("{s: s, s: i, s: i}",
4175  "Queue", q->name,
4176  "Position", qe->pos,
4177  "Count", q->count);
4178  ast_channel_publish_cached_blob(qe->chan, queue_caller_leave_type(), blob);
4179  ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
4180  /* Take us out of the queue */
4181  if (prev) {
4182  prev->next = current->next;
4183  } else {
4184  q->head = current->next;
4185  }
4186  /* Free penalty rules */
4187  while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
4188  ast_free(pr_iter);
4189  }
4190  qe->pr = NULL;
4191  snprintf(posstr, sizeof(posstr), "%d", qe->pos);
4192  pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
4193  } else {
4194  /* Renumber the people after us in the queue based on a new count */
4195  current->pos = ++pos;
4196  prev = current;
4197  }
4198  }
4199  ao2_unlock(q);
4200 
4201  /*If the queue is a realtime queue, check to see if it's still defined in real time*/
4202  if (q->realtime) {
4203  struct ast_variable *var;
4204  if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
4205  q->dead = 1;
4206  } else {
4207  ast_variables_destroy(var);
4208  }
4209  }
4210 
4211  if (q->dead) {
4212  /* It's dead and nobody is in it, so kill it */
4213  queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
4214  }
4215  /* unref the explicit ref earlier in the function */
4216  queue_t_unref(q, "Expire copied reference");
4217 }
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3339
struct call_queue * parent
Definition: app_queue.c:1561
struct ast_channel * chan
Definition: app_queue.c:1586
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
#define queue_t_ref(q, tag)
Definition: app_queue.c:1920
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
struct queue_ent * head
Definition: app_queue.c:1753
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define SENTINEL
Definition: compiler.h:87
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
static struct ao2_container * queues
Definition: app_queue.c:1766
#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:911
#define ao2_lock(a)
Definition: astobj2.h:718
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
unsigned int dead
Definition: app_queue.c:1699
const ast_string_field name
Definition: app_queue.c:1696
#define ast_free(a)
Definition: astmm.h:182
struct penalty_rule::@68 list
struct penalty_rule * pr
Definition: app_queue.c:1588
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...
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
unsigned int realtime
Definition: app_queue.c:1712
const char * ast_channel_name(const struct ast_channel *chan)
Abstract JSON element (object, array, string, int, ...).
struct queue_ent::@67 qe_rules
struct queue_ent * next
Definition: app_queue.c:1589
#define queues_t_unlink(c, q, tag)
Definition: app_queue.c:1923

◆ load_module()

static int load_module ( void  )
static

Load the module.

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

Definition at line 11324 of file app_queue.c.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, aqm_exec(), ARRAY_LEN, ast_channel_agent_login_type(), ast_channel_agent_logoff_type(), ast_channel_topic_all(), ast_cli_register_multiple, ast_config_destroy(), ast_custom_function_register, ast_device_state_message_type(), ast_device_state_topic_all(), AST_FLAGS_ALL, ast_load_realtime_multientry(), ast_log, ast_manager_get_topic(), ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_queue_topic_all(), ast_realtime_require_field(), ast_register_application_xml, ast_variable_retrieve(), device_state_cb(), EVENT_FLAG_AGENT, LOG_NOTICE, manager_add_queue_member(), manager_change_priority_caller_on_queue(), manager_pause_queue_member(), manager_queue_log_custom(), manager_queue_member_penalty(), manager_queue_member_ringinuse(), manager_queue_reload(), manager_queue_reset(), manager_queue_rule_show(), manager_queues_status(), manager_queues_summary(), manager_remove_queue_member(), manager_topic, MAX_CALL_ATTEMPT_BUCKETS, MAX_QUEUE_BUCKETS, NULL, pending_members_cmp(), pending_members_hash(), pqm_exec(), ql_exec(), queue_agent_cb(), queue_cmp_cb(), queue_exec(), queue_hash_cb(), qupd_exec(), reload_handler(), reload_queue_members(), RQ_INTEGER1, RQ_UINTEGER2, rqm_exec(), SENTINEL, stasis_forward_all(), stasis_message_router_add(), stasis_message_router_create, STASIS_MESSAGE_TYPE_INIT, stasis_subscribe, stasis_subscription_accept_message_type(), STASIS_SUBSCRIPTION_FILTER_SELECTIVE, stasis_subscription_set_filter(), unload_module(), and upqm_exec().

Referenced by find_member_by_queuename_and_interface().

11325 {
11326  int err = 0;
11327  struct ast_flags mask = {AST_FLAGS_ALL, };
11328  struct ast_config *member_config;
11329  struct stasis_topic *queue_topic;
11330  struct stasis_topic *manager_topic;
11331 
11334  if (!queues) {
11335  return AST_MODULE_LOAD_DECLINE;
11336  }
11337 
11340  if (!pending_members) {
11341  unload_module();
11342  return AST_MODULE_LOAD_DECLINE;
11343  }
11344 
11345  use_weight = 0;
11346 
11347  if (reload_handler(0, &mask, NULL)) {
11348  unload_module();
11349  return AST_MODULE_LOAD_DECLINE;
11350  }
11351 
11352  ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
11353 
11354  /*
11355  * This section is used to determine which name for 'ringinuse' to use in realtime members
11356  * Necessary for supporting older setups.
11357  */
11358  member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
11359  if (!member_config) {
11360  realtime_ringinuse_field = "ringinuse";
11361  } else {
11362  const char *config_val;
11363 
11364  if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
11365  ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
11366  realtime_ringinuse_field = "ringinuse";
11367  } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
11368  ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
11369  realtime_ringinuse_field = "ignorebusy";
11370  } else {
11371  ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
11372  realtime_ringinuse_field = "ringinuse";
11373  }
11374  }
11375  ast_config_destroy(member_config);
11376 
11379  }
11380 
11389  err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
11390  err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
11397  err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
11398  err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
11399  err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
11400  err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
11409 
11410  /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
11412  if (!device_state_sub) {
11413  err = -1;
11414  }
11417 
11418  manager_topic = ast_manager_get_topic();
11419  queue_topic = ast_queue_topic_all();
11420  if (!manager_topic || !queue_topic) {
11421  unload_module();
11422  return AST_MODULE_LOAD_DECLINE;
11423  }
11424  topic_forwarder = stasis_forward_all(queue_topic, manager_topic);
11425  if (!topic_forwarder) {
11426  unload_module();
11427  return AST_MODULE_LOAD_DECLINE;
11428  }
11429 
11432  unload_module();
11433  return AST_MODULE_LOAD_DECLINE;
11434  }
11436  if (!agent_router) {
11437  unload_module();
11438  return AST_MODULE_LOAD_DECLINE;
11439  }
11443  NULL);
11447  NULL);
11448 
11449  err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
11450  err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
11451  err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
11452 
11453  err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
11454  err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
11455  err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
11456  err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
11457  err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
11458  err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
11459 
11460  err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
11461  err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
11462  err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
11463  err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
11464  err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
11465 
11466  if (err) {
11467  unload_module();
11468  return AST_MODULE_LOAD_DECLINE;
11469  }
11470  return AST_MODULE_LOAD_SUCCESS;
11471 }
static struct ast_custom_function queuewaitingcount_function
Definition: app_queue.c:9105
static int qupd_exec(struct ast_channel *chan, const char *data)
Update Queue with data of an outgoing call.
Definition: app_queue.c:11157
static char * app_ql
Definition: app_queue.c:1458
static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
Definition: app_queue.c:10457
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition: app_queue.c:7954
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static char * app_qupd
Definition: app_queue.c:1460
static char * app_aqm
Definition: app_queue.c:1450
static struct ao2_container * pending_members
Definition: app_queue.c:2375
static struct ast_custom_function queuegetchannel_function
Definition: app_queue.c:9100
static int upqm_exec(struct ast_channel *chan, const char *data)
UnPauseQueueMember application.
Definition: app_queue.c:7918
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1501
static int manager_queue_reset(struct mansession *s, const struct message *m)
Definition: app_queue.c:10411
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
Definition: app_queue.c:10491
#define MAX_QUEUE_BUCKETS
Definition: app_queue.c:1439
struct stasis_topic * ast_queue_topic_all(void)
Get the Stasis Message Bus API topic for queue messages.
Definition: main/app.c:3184
static struct ast_custom_function queuemembercount_dep
Definition: app_queue.c:9095
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1079
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define NULL
Definition: resample.c:96
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition: manager.c:1490
static char * app_rqm
Definition: app_queue.c:1452
static struct ast_custom_function queueexists_function
Definition: app_queue.c:9079
static struct stasis_forward * topic_forwarder
Definition: app_queue.c:11248
static char * app
Definition: app_queue.c:1448
static int manager_queue_rule_show(struct mansession *s, const struct message *m)
Definition: app_queue.c:9990
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition: app_queue.c:1493
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
#define ast_log
Definition: astobj2.c:42
#define SENTINEL
Definition: compiler.h:87
static struct ast_custom_function queuemembercount_function
Definition: app_queue.c:9089
static struct ao2_container * queues
Definition: app_queue.c:1766
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3382
static struct ast_custom_function queuememberpenalty_function
Definition: app_queue.c:9115
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition: app_queue.c:7882
#define MAX_CALL_ATTEMPT_BUCKETS
Definition: app_queue.c:2376
static struct stasis_message_router * agent_router
Definition: app_queue.c:11247
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:9627
struct stasis_message_type * ast_channel_agent_login_type(void)
Message type for agent login on a channel.
struct stasis_message_type * ast_channel_agent_logoff_type(void)
Message type for agent logoff on a channel.
static int unload_module(void)
Definition: app_queue.c:11250
#define stasis_message_router_create(topic)
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:652
static int pending_members_hash(const void *obj, const int flags)
Definition: app_queue.c:2378
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3452
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition: app_queue.c:1843
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
Definition: app_queue.c:10358
static int manager_queue_reload(struct mansession *s, const struct message *m)
Definition: app_queue.c:10379
static struct ast_custom_function queuememberlist_function
Definition: app_queue.c:9110
#define EVENT_FLAG_AGENT
Definition: manager.h:76
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition: app_queue.c:8106
#define LOG_NOTICE
Definition: logger.h:263
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
Definition: devicestate.c:668
static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
set a member&#39;s status based on device state of that member&#39;s interface
Definition: app_queue.c:2503
static char * app_pqm
Definition: app_queue.c:1454
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:10517
#define AST_FLAGS_ALL
Definition: utils.h:196
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
Definition: app_queue.c:10104
Structure used to handle boolean flags.
Definition: utils.h:199
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1720
static int manager_queues_summary(struct mansession *s, const struct message *m)
Summary of queue info via the AMI.
Definition: app_queue.c:10026
static struct ast_cli_entry cli_queue[]
Definition: app_queue.c:11234
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
static struct ast_custom_function queuevar_function
Definition: app_queue.c:9084
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition: app_queue.c:8025
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1025
static int pending_members_cmp(void *obj, void *arg, int flags)
Definition: app_queue.c:2398
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1469
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition: app_queue.c:8183
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition: app_queue.c:7771
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:5895
static int queue_hash_cb(const void *obj, const int flags)
Definition: app_queue.c:1836
static int manager_add_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10222
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition: stasis.c:1578
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:186
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10333
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition: app_queue.c:1484
static char * app_upqm
Definition: app_queue.c:1456
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10286
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1466

◆ load_realtime_rules()

static int load_realtime_rules ( void  )
static

Load queue rules from realtime.

Check rule for errors with time or fomatting, 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 2999 of file app_queue.c.

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

Referenced by reload_queue_rules().

3000 {
3001  struct ast_config *cfg;
3002  struct rule_list *rl_iter, *new_rl;
3003  struct penalty_rule *pr_iter;
3004  char *rulecat = NULL;
3005 
3006  if (!ast_check_realtime("queue_rules")) {
3007  ast_log(LOG_WARNING, "Missing \"queue_rules\" in extconfig.conf\n");
3008  return 0;
3009  }
3010  if (!(cfg = ast_load_realtime_multientry("queue_rules", "rule_name LIKE", "%", SENTINEL))) {
3011  ast_log(LOG_WARNING, "Failed to load queue rules from realtime\n");
3012  return 0;
3013  }
3014  while ((rulecat = ast_category_browse(cfg, rulecat))) {
3015  const char *timestr, *maxstr, *minstr, *raisestr, *rule_name;
3016  int penaltychangetime, rule_exists = 0, inserted = 0;
3017  int max_penalty = 0, min_penalty = 0, raise_penalty = 0;
3018  int min_relative = 0, max_relative = 0, raise_relative = 0;
3019  struct penalty_rule *new_penalty_rule = NULL;
3020 
3021  rule_name = ast_variable_retrieve(cfg, rulecat, "rule_name");
3022  if (ast_strlen_zero(rule_name)) {
3023  continue;
3024  }
3025 
3026  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
3027  if (!(strcasecmp(rl_iter->name, rule_name))) {
3028  rule_exists = 1;
3029  new_rl = rl_iter;
3030  break;
3031  }
3032  }
3033  if (!rule_exists) {
3034  if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
3035  ast_config_destroy(cfg);
3036  return -1;
3037  }
3038  ast_copy_string(new_rl->name, rule_name, sizeof(new_rl->name));
3040  }
3041  timestr = ast_variable_retrieve(cfg, rulecat, "time");
3042  if (!(timestr) || sscanf(timestr, "%30d", &penaltychangetime) != 1) {
3043  ast_log(LOG_NOTICE, "Failed to parse time (%s) for one of the %s rules, skipping it\n",
3044  (ast_strlen_zero(timestr) ? "invalid value" : timestr), rule_name);
3045  continue;
3046  }
3047  if (!(new_penalty_rule = ast_calloc(1, sizeof(*new_penalty_rule)))) {
3048  ast_config_destroy(cfg);
3049  return -1;
3050  }
3051  if (!(maxstr = ast_variable_retrieve(cfg, rulecat, "max_penalty")) ||
3052  ast_strlen_zero(maxstr) || sscanf(maxstr, "%30d", &max_penalty) != 1) {
3053  max_penalty = 0;
3054  max_relative = 1;
3055  } else {
3056  if (*maxstr == '+' || *maxstr == '-') {
3057  max_relative = 1;
3058  }
3059  }
3060  if (!(minstr = ast_variable_retrieve(cfg, rulecat, "min_penalty")) ||
3061  ast_strlen_zero(minstr) || sscanf(minstr, "%30d", &min_penalty) != 1) {
3062  min_penalty = 0;
3063  min_relative = 1;
3064  } else {
3065  if (*minstr == '+' || *minstr == '-') {
3066  min_relative = 1;
3067  }
3068  }
3069  if (!(raisestr = ast_variable_retrieve(cfg, rulecat, "raise_penalty")) ||
3070  ast_strlen_zero(raisestr) || sscanf(raisestr, "%30d", &raise_penalty) != 1) {
3071  raise_penalty = 0;
3072  raise_relative = 1;
3073  } else {
3074  if (*raisestr == '+' || *raisestr == '-') {
3075  raise_relative = 1;
3076  }
3077  }
3078  new_penalty_rule->time = penaltychangetime;
3079  new_penalty_rule->max_relative = max_relative;
3080  new_penalty_rule->max_value = max_penalty;
3081  new_penalty_rule->min_relative = min_relative;
3082  new_penalty_rule->min_value = min_penalty;
3083  new_penalty_rule->raise_relative = raise_relative;
3084  new_penalty_rule->raise_value = raise_penalty;
3085  AST_LIST_TRAVERSE_SAFE_BEGIN(&new_rl->rules, pr_iter, list) {
3086  if (new_penalty_rule->time < pr_iter->time) {
3087  AST_LIST_INSERT_BEFORE_CURRENT(new_penalty_rule, list);
3088  inserted = 1;
3089  }
3090  }
3092  if (!inserted) {
3093  AST_LIST_INSERT_TAIL(&new_rl->rules, new_penalty_rule, list);
3094  }
3095  }
3096 
3097  ast_config_destroy(cfg);
3098  return 0;
3099 }
int max_relative
Definition: app_queue.c:1645
char name[80]
Definition: app_queue.c:1759
int min_relative
Definition: app_queue.c:1646
#define LOG_WARNING
Definition: logger.h:274
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3363
struct rule_list::@71 rules
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define SENTINEL
Definition: compiler.h:87
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3452
int raise_relative
Definition: app_queue.c:1647
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define LOG_NOTICE
Definition: logger.h:263
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
struct penalty_rule::@68 list
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:598

◆ log_attended_transfer()

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

Definition at line 6065 of file app_queue.c.

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

Referenced by handle_attended_transfer().

6067 {
6068  RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
6069 
6070  if (!transfer_str) {
6071  ast_log(LOG_WARNING, "Unable to log attended transfer to queue log\n");
6072  return;
6073  }
6074 
6075  switch (atxfer_msg->dest_type) {
6077  ast_str_set(&transfer_str, 0, "BRIDGE|%s", atxfer_msg->dest.bridge);
6078  break;
6081  ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
6082  break;
6084  ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
6085  atxfer_msg->dest.links[1]->base->name);
6086  break;
6089  /* Threeways are headed off and should not be logged here */
6090  ast_assert(0);
6091  return;
6092  }
6093 
6094  ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
6095  ast_str_buffer(transfer_str),
6096  (long) (queue_data->starttime - queue_data->holdstart),
6097  (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6098 }
struct ast_channel_snapshot_base * base
union ast_attended_transfer_message::@324 dest
#define LOG_WARNING
Definition: logger.h:274
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
#define ast_assert(a)
Definition: utils.h:695
char bridge[AST_UUID_STR_LEN]
#define NULL
Definition: resample.c:96
char membername[80]
Definition: app_queue.c:1598
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:1065
#define ast_log
Definition: astobj2.c:42
struct call_queue * queue
Definition: app_queue.c:5967
struct ast_channel_snapshot * links[2]
#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:911
struct member * member
Definition: app_queue.c:5969
enum ast_attended_transfer_dest_type dest_type
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
const ast_string_field name
Definition: app_queue.c:1696
const ast_string_field caller_uniqueid
Definition: app_queue.c:5965
#define ast_free(a)
Definition: astmm.h:182
const ast_string_field name
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ manager_add_queue_member()

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

Definition at line 10222 of file app_queue.c.

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

Referenced by load_module().

10223 {
10224  const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface, *wrapuptime_s;
10225  int paused, penalty, wrapuptime = 0;
10226 
10227  queuename = astman_get_header(m, "Queue");
10228  interface = astman_get_header(m, "Interface");
10229  penalty_s = astman_get_header(m, "Penalty");
10230  paused_s = astman_get_header(m, "Paused");
10231  membername = astman_get_header(m, "MemberName");
10232  state_interface = astman_get_header(m, "StateInterface");
10233  wrapuptime_s = astman_get_header(m, "Wrapuptime");
10234 
10235  if (ast_strlen_zero(queuename)) {
10236  astman_send_error(s, m, "'Queue' not specified.");
10237  return 0;
10238  }
10239 
10240  if (ast_strlen_zero(interface)) {
10241  astman_send_error(s, m, "'Interface' not specified.");
10242  return 0;
10243  }
10244 
10245  if (ast_strlen_zero(penalty_s)) {
10246  penalty = 0;
10247  } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
10248  penalty = 0;
10249  }
10250 
10251  if (ast_strlen_zero(wrapuptime_s)) {
10252  wrapuptime = 0;
10253  } else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
10254  wrapuptime = 0;
10255  }
10256 
10257  if (ast_strlen_zero(paused_s)) {
10258  paused = 0;
10259  } else {
10260  paused = abs(ast_true(paused_s));
10261  }
10262 
10263  switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, NULL, wrapuptime)) {
10264  case RES_OKAY:
10265  if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10266  ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10267  } else {
10268  ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10269  }
10270  astman_send_ack(s, m, "Added interface to queue");
10271  break;
10272  case RES_EXISTS:
10273  astman_send_error(s, m, "Unable to add interface: Already there");
10274  break;
10275  case RES_NOSUCHQUEUE:
10276  astman_send_error(s, m, "Unable to add interface to queue: No such queue");
10277  break;
10278  case RES_OUTOFMEMORY:
10279  astman_send_error(s, m, "Out of memory");
10280  break;
10281  }
10282 
10283  return 0;
10284 }
#define RES_OKAY
Definition: app_queue.c:1441
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1490
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
#define NULL
Definition: resample.c:96
#define RES_OUTOFMEMORY
Definition: app_queue.c:1443
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1444
#define abs(x)
Definition: f2c.h:195
#define RES_EXISTS
Definition: app_queue.c:1442
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
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:7377
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1466

◆ manager_change_priority_caller_on_queue()

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

Definition at line 10517 of file app_queue.c.

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

Referenced by load_module().

10518 {
10519  const char *queuename, *caller, *priority_s;
10520  int priority = 0;
10521 
10522  queuename = astman_get_header(m, "Queue");
10523  caller = astman_get_header(m, "Caller");
10524  priority_s = astman_get_header(m, "Priority");
10525 
10526  if (ast_strlen_zero(queuename)) {
10527  astman_send_error(s, m, "'Queue' not specified.");
10528  return 0;
10529  }
10530 
10531  if (ast_strlen_zero(caller)) {
10532  astman_send_error(s, m, "'Caller' not specified.");
10533  return 0;
10534  }
10535 
10536  if (ast_strlen_zero(priority_s)) {
10537  astman_send_error(s, m, "'Priority' not specified.");
10538  return 0;
10539  } else if (sscanf(priority_s, "%30d", &priority) != 1) {
10540  astman_send_error(s, m, "'Priority' need integer.");
10541  return 0;
10542  }
10543 
10544  switch (change_priority_caller_on_queue(queuename, caller, priority)) {
10545  case RES_OKAY:
10546  astman_send_ack(s, m, "Priority change for caller on queue");
10547  break;
10548  case RES_NOSUCHQUEUE:
10549  astman_send_error(s, m, "Unable to change priority caller on queue: No such queue");
10550  break;
10551  case RES_NOT_CALLER:
10552  astman_send_error(s, m, "Unable to change priority caller on queue: No such caller");
10553  break;
10554  }
10555 
10556  return 0;
10557 }
static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority)
Change priority caller into a queue.
Definition: app_queue.c:7430
#define RES_OKAY
Definition: app_queue.c:1441
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
static int priority
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define RES_NOT_CALLER
Definition: app_queue.c:1446
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1444
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ manager_pause_queue_member()

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

Definition at line 10333 of file app_queue.c.

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

Referenced by load_module().

10334 {
10335  const char *queuename, *interface, *paused_s, *reason;
10336  int paused;
10337 
10338  interface = astman_get_header(m, "Interface");
10339  paused_s = astman_get_header(m, "Paused");
10340  queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
10341  reason = astman_get_header(m, "Reason"); /* Optional */
10342 
10343  if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
10344  astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
10345  return 0;
10346  }
10347 
10348  paused = abs(ast_true(paused_s));
10349 
10350  if (set_member_paused(queuename, interface, reason, paused)) {
10351  astman_send_error(s, m, "Interface not found");
10352  } else {
10353  astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
10354  }
10355  return 0;
10356 }
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:7528
#define abs(x)
Definition: f2c.h:195
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ manager_queue_log_custom()

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

Definition at line 10358 of file app_queue.c.

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

Referenced by load_module().

10359 {
10360  const char *queuename, *event, *message, *interface, *uniqueid;
10361 
10362  queuename = astman_get_header(m, "Queue");
10363  uniqueid = astman_get_header(m, "UniqueId");
10364  interface = astman_get_header(m, "Interface");
10365  event = astman_get_header(m, "Event");
10366  message = astman_get_header(m, "Message");
10367 
10368  if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
10369  astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
10370  return 0;
10371  }
10372 
10373  ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
10374  astman_send_ack(s, m, "Event added successfully");
10375 
10376  return 0;
10377 }
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
Definition: astman.c:222
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ manager_queue_member_penalty()

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

Definition at line 10491 of file app_queue.c.

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

Referenced by load_module().

10492 {
10493  const char *queuename, *interface, *penalty_s;
10494  int penalty;
10495 
10496  interface = astman_get_header(m, "Interface");
10497  penalty_s = astman_get_header(m, "Penalty");
10498  /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
10499  queuename = astman_get_header(m, "Queue");
10500 
10501  if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
10502  astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
10503  return 0;
10504  }
10505 
10506  penalty = atoi(penalty_s);
10507 
10508  if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
10509  astman_send_error(s, m, "Invalid interface, queuename or penalty");
10510  } else {
10511  astman_send_ack(s, m, "Interface penalty set successfully");
10512  }
10513 
10514  return 0;
10515 }
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:7674
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ manager_queue_member_ringinuse()

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

Definition at line 10457 of file app_queue.c.

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

Referenced by load_module().

10458 {
10459  const char *queuename, *interface, *ringinuse_s;
10460  int ringinuse;
10461 
10462  interface = astman_get_header(m, "Interface");
10463  ringinuse_s = astman_get_header(m, "RingInUse");
10464 
10465  /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
10466  queuename = astman_get_header(m, "Queue");
10467 
10468  if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
10469  astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
10470  return 0;
10471  }
10472 
10473  if (ast_true(ringinuse_s)) {
10474  ringinuse = 1;
10475  } else if (ast_false(ringinuse_s)) {
10476  ringinuse = 0;
10477  } else {
10478  astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
10479  return 0;
10480  }
10481 
10482  if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
10483  astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
10484  } else {
10485  astman_send_ack(s, m, "Interface ringinuse set successfully");
10486  }
10487 
10488  return 0;
10489 }
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:7674
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ manager_queue_reload()

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

Definition at line 10379 of file app_queue.c.

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

Referenced by load_module().

10380 {
10381  struct ast_flags mask = {0,};
10382  const char *queuename = NULL;
10383  int header_found = 0;
10384 
10385  queuename = astman_get_header(m, "Queue");
10386  if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
10388  header_found = 1;
10389  }
10390  if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
10392  header_found = 1;
10393  }
10394  if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
10396  header_found = 1;
10397  }
10398 
10399  if (!header_found) {
10400  ast_set_flag(&mask, AST_FLAGS_ALL);
10401  }
10402 
10403  if (!reload_handler(1, &mask, queuename)) {
10404  astman_send_ack(s, m, "Queue reloaded successfully");
10405  } else {
10406  astman_send_error(s, m, "Error encountered while reloading queue");
10407  }
10408  return 0;
10409 }
#define ast_set_flag(p, flag)
Definition: utils.h:70
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
#define NULL
Definition: resample.c:96
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:9627
#define AST_FLAGS_ALL
Definition: utils.h:196
Structure used to handle boolean flags.
Definition: utils.h:199
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ manager_queue_reset()

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

Definition at line 10411 of file app_queue.c.

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

Referenced by load_module().

10412 {
10413  const char *queuename = NULL;
10414  struct ast_flags mask = {QUEUE_RESET_STATS,};
10415 
10416  queuename = astman_get_header(m, "Queue");
10417 
10418  if (!reload_handler(1, &mask, queuename)) {
10419  astman_send_ack(s, m, "Queue stats reset successfully");
10420  } else {
10421  astman_send_error(s, m, "Error encountered while resetting queue stats");
10422  }
10423  return 0;
10424 }
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
#define NULL
Definition: resample.c:96
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:9627
Structure used to handle boolean flags.
Definition: utils.h:199
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ manager_queue_rule_show()

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

Definition at line 9990 of file app_queue.c.

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

Referenced by load_module().

9991 {
9992  const char *rule = astman_get_header(m, "Rule");
9993  const char *id = astman_get_header(m, "ActionID");
9994  struct rule_list *rl_iter;
9995  struct penalty_rule *pr_iter;
9996 
9997  astman_append(s, "Response: Success\r\n");
9998  if (!ast_strlen_zero(id)) {
9999  astman_append(s, "ActionID: %s\r\n", id);
10000  }
10001 
10003  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10004  if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
10005  astman_append(s, "RuleList: %s\r\n", rl_iter->name);
10006  AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10007  astman_append(s, "Rule: %d,%s%d,%s%d\r\n", pr_iter->time, pr_iter->max_relative && pr_iter->max_value >= 0 ? "+" : "", pr_iter->max_value, pr_iter->min_relative && pr_iter->min_value >= 0 ? "+" : "", pr_iter->min_value );
10008  }
10009  if (!ast_strlen_zero(rule)) {
10010  break;
10011  }
10012  }
10013  }
10015 
10016  /*
10017  * Two blank lines instead of one because the Response and
10018  * ActionID headers used to not be present.
10019  */
10020  astman_append(s, "\r\n\r\n");
10021 
10022  return RESULT_SUCCESS;
10023 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
int max_relative
Definition: app_queue.c:1645
char name[80]
Definition: app_queue.c:1759
int min_relative
Definition: app_queue.c:1646
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
struct rule_list::@71 rules
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct penalty_rule::@68 list
#define RESULT_SUCCESS
Definition: cli.h:40

◆ manager_queues_status()

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

Queue status info via AMI.

Definition at line 10104 of file app_queue.c.

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

Referenced by load_module().

10105 {
10106  time_t now;
10107  int pos;
10108  int q_items = 0;
10109  const char *id = astman_get_header(m,"ActionID");
10110  const char *queuefilter = astman_get_header(m,"Queue");
10111  const char *memberfilter = astman_get_header(m,"Member");
10112  char idText[256];
10113  struct call_queue *q;
10114  struct queue_ent *qe;
10115  float sl = 0;
10116  float sl2 = 0;
10117  struct member *mem;
10118  struct ao2_iterator queue_iter;
10119  struct ao2_iterator mem_iter;
10120 
10121  astman_send_listack(s, m, "Queue status will follow", "start");
10122  time(&now);
10123  idText[0] = '\0';
10124  if (!ast_strlen_zero(id)) {
10125  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10126  }
10127 
10128  queue_iter = ao2_iterator_init(queues, 0);
10129  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10130  ao2_lock(q);
10131 
10132  /* List queue properties */
10133  if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10134  sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
10135  sl2 = (((q->callscompleted + q->callsabandoned) > 0) ? 100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)) : 0);
10136 
10137  astman_append(s, "Event: QueueParams\r\n"
10138  "Queue: %s\r\n"
10139  "Max: %d\r\n"
10140  "Strategy: %s\r\n"
10141  "Calls: %d\r\n"
10142  "Holdtime: %d\r\n"
10143  "TalkTime: %d\r\n"
10144  "Completed: %d\r\n"
10145  "Abandoned: %d\r\n"
10146  "ServiceLevel: %d\r\n"
10147  "ServicelevelPerf: %2.1f\r\n"
10148  "ServicelevelPerf2: %2.1f\r\n"
10149  "Weight: %d\r\n"
10150  "%s"
10151  "\r\n",
10152  q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
10153  q->callsabandoned, q->servicelevel, sl, sl2, q->weight, idText);
10154  ++q_items;
10155 
10156  /* List Queue Members */
10157  mem_iter = ao2_iterator_init(q->members, 0);
10158  while ((mem = ao2_iterator_next(&mem_iter))) {
10159  if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
10160  astman_append(s, "Event: QueueMember\r\n"
10161  "Queue: %s\r\n"
10162  "Name: %s\r\n"
10163  "Location: %s\r\n"
10164  "StateInterface: %s\r\n"
10165  "Membership: %s\r\n"
10166  "Penalty: %d\r\n"
10167  "CallsTaken: %d\r\n"
10168  "LastCall: %d\r\n"
10169  "LastPause: %d\r\n"
10170  "InCall: %d\r\n"
10171  "Status: %d\r\n"
10172  "Paused: %d\r\n"
10173  "PausedReason: %s\r\n"
10174  "Wrapuptime: %d\r\n"
10175  "%s"
10176  "\r\n",
10177  q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
10178  mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, mem->starttime ? 1 : 0, mem->status,
10179  mem->paused, mem->reason_paused, mem->wrapuptime, idText);
10180  ++q_items;
10181  }
10182  ao2_ref(mem, -1);
10183  }
10184  ao2_iterator_destroy(&mem_iter);
10185 
10186  /* List Queue Entries */
10187  pos = 1;
10188  for (qe = q->head; qe; qe = qe->next) {
10189  astman_append(s, "Event: QueueEntry\r\n"
10190  "Queue: %s\r\n"
10191  "Position: %d\r\n"
10192  "Channel: %s\r\n"
10193  "Uniqueid: %s\r\n"
10194  "CallerIDNum: %s\r\n"
10195  "CallerIDName: %s\r\n"
10196  "ConnectedLineNum: %s\r\n"
10197  "ConnectedLineName: %s\r\n"
10198  "Wait: %ld\r\n"
10199  "Priority: %d\r\n"
10200  "%s"
10201  "\r\n",
10202  q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
10207  (long) (now - qe->start), qe->prio, idText);
10208  ++q_items;
10209  }
10210  }
10211  ao2_unlock(q);
10212  queue_t_unref(q, "Done with iterator");
10213  }
10214  ao2_iterator_destroy(&queue_iter);
10215 
10216  astman_send_list_complete_start(s, m, "QueueStatusComplete", q_items);
10218 
10219  return RESULT_SUCCESS;
10220 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
int servicelevel
Definition: app_queue.c:1731
int dynamic
Definition: app_queue.c:1601
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
int callsabandonedinsl
Definition: app_queue.c:1730
int paused
Definition: app_queue.c:1604
struct ast_channel * chan
Definition: app_queue.c:1586
struct ast_party_id id
Connected party ID.
Definition: channel.h:459
time_t start
Definition: app_queue.c:1583
struct ast_party_name name
Subscriber name.
Definition: channel.h:341
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1596
int wrapuptime
Definition: app_queue.c:1608
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3237
char * str
Subscriber name (Malloced)
Definition: channel.h:265
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
struct ao2_container * members
Definition: app_queue.c:1752
struct queue_ent * head
Definition: app_queue.c:1753
int callscompletedinsl
Definition: app_queue.c:1732
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
int holdtime
Definition: app_queue.c:1726
struct ast_party_id id
Caller party ID.
Definition: channel.h:421
static struct ao2_container * queues
Definition: app_queue.c:1766
time_t lastpause
Definition: app_queue.c:1611
int penalty
Definition: app_queue.c:1599
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
#define ao2_lock(a)
Definition: astobj2.h:718
int strategy
Definition: app_queue.c:1711
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
const ast_string_field name
Definition: app_queue.c:1696
int talktime
Definition: app_queue.c:1727
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
char reason_paused[80]
Definition: app_queue.c:1605
time_t starttime
Definition: app_queue.c:1609
int calls
Definition: app_queue.c:1600
int status
Definition: app_queue.c:1603
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
int callsabandoned
Definition: app_queue.c:1729
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
const char * ast_channel_name(const struct ast_channel *chan)
struct queue_ent * next
Definition: app_queue.c:1589
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:280
#define RESULT_SUCCESS
Definition: cli.h:40
int callscompleted
Definition: app_queue.c:1728
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
time_t lastcall
Definition: app_queue.c:1610
static const char * int2strat(int strategy)
Definition: app_queue.c:1787
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3201
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343

◆ manager_queues_summary()

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

Summary of queue info via the AMI.

Definition at line 10026 of file app_queue.c.

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

Referenced by load_module().

10027 {
10028  time_t now;
10029  int qmemcount = 0;
10030  int qmemavail = 0;
10031  int qchancount = 0;
10032  int qlongestholdtime = 0;
10033  int qsummaries = 0;
10034  const char *id = astman_get_header(m, "ActionID");
10035  const char *queuefilter = astman_get_header(m, "Queue");
10036  char idText[256];
10037  struct call_queue *q;
10038  struct queue_ent *qe;
10039  struct member *mem;
10040  struct ao2_iterator queue_iter;
10041  struct ao2_iterator mem_iter;
10042 
10043  astman_send_listack(s, m, "Queue summary will follow", "start");
10044  time(&now);
10045  idText[0] = '\0';
10046  if (!ast_strlen_zero(id)) {
10047  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10048  }
10049  queue_iter = ao2_iterator_init(queues, 0);
10050  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10051  ao2_lock(q);
10052 
10053  /* List queue properties */
10054  if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10055  /* Reset the necessary local variables if no queuefilter is set*/
10056  qmemcount = 0;
10057  qmemavail = 0;
10058  qchancount = 0;
10059  qlongestholdtime = 0;
10060 
10061  /* List Queue Members */
10062  mem_iter = ao2_iterator_init(q->members, 0);
10063  while ((mem = ao2_iterator_next(&mem_iter))) {
10064  if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
10065  ++qmemcount;
10066  if (member_status_available(mem->status) && !mem->paused) {
10067  ++qmemavail;
10068  }
10069  }
10070  ao2_ref(mem, -1);
10071  }
10072  ao2_iterator_destroy(&mem_iter);
10073  for (qe = q->head; qe; qe = qe->next) {
10074  if ((now - qe->start) > qlongestholdtime) {
10075  qlongestholdtime = now - qe->start;
10076  }
10077  ++qchancount;
10078  }
10079  astman_append(s, "Event: QueueSummary\r\n"
10080  "Queue: %s\r\n"
10081  "LoggedIn: %d\r\n"
10082  "Available: %d\r\n"
10083  "Callers: %d\r\n"
10084  "HoldTime: %d\r\n"
10085  "TalkTime: %d\r\n"
10086  "LongestHoldTime: %d\r\n"
10087  "%s"
10088  "\r\n",
10089  q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
10090  ++qsummaries;
10091  }
10092  ao2_unlock(q);
10093  queue_t_unref(q, "Done with iterator");
10094  }
10095  ao2_iterator_destroy(&queue_iter);
10096 
10097  astman_send_list_complete_start(s, m, "QueueSummaryComplete", qsummaries);
10099 
10100  return RESULT_SUCCESS;
10101 }
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
int paused
Definition: app_queue.c:1604
time_t start
Definition: app_queue.c:1583
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3237
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
struct ao2_container * members
Definition: app_queue.c:1752
struct queue_ent * head
Definition: app_queue.c:1753
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
static int member_status_available(int status)
Definition: app_queue.c:4374
int holdtime
Definition: app_queue.c:1726
static struct ao2_container * queues
Definition: app_queue.c:1766
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
const ast_string_field name
Definition: app_queue.c:1696
int talktime
Definition: app_queue.c:1727
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
int status
Definition: app_queue.c:1603
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct queue_ent * next
Definition: app_queue.c:1589
#define RESULT_SUCCESS
Definition: cli.h:40
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3201

◆ manager_remove_queue_member()

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

Definition at line 10286 of file app_queue.c.

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

Referenced by load_module().

10287 {
10288  const char *queuename, *interface;
10289  struct member *mem = NULL;
10290 
10291  queuename = astman_get_header(m, "Queue");
10292  interface = astman_get_header(m, "Interface");
10293 
10294  if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
10295  astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
10296  return 0;
10297  }
10298 
10300  mem = find_member_by_queuename_and_interface(queuename, interface);
10301  }
10302 
10303  switch (remove_from_queue(queuename, interface)) {
10304  case RES_OKAY:
10305  if (!mem || ast_strlen_zero(mem->membername)) {
10306  ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
10307  } else {
10308  ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
10309  }
10310  astman_send_ack(s, m, "Removed interface from queue");
10311  break;
10312  case RES_EXISTS:
10313  astman_send_error(s, m, "Unable to remove interface: Not there");
10314  break;
10315  case RES_NOSUCHQUEUE:
10316  astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
10317  break;
10318  case RES_OUTOFMEMORY:
10319  astman_send_error(s, m, "Out of memory");
10320  break;
10321  case RES_NOT_DYNAMIC:
10322  astman_send_error(s, m, "Member not dynamic");
10323  break;
10324  }
10325 
10326  if (mem) {
10327  ao2_ref(mem, -1);
10328  }
10329 
10330  return 0;
10331 }
#define RES_OKAY
Definition: app_queue.c:1441
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1445
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1490
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
#define NULL
Definition: resample.c:96
char membername[80]
Definition: app_queue.c:1598
#define RES_OUTOFMEMORY
Definition: app_queue.c:1443
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
static struct member * find_member_by_queuename_and_interface(const char *queuename, const char *interface)
Definition: app_queue.c:11484
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1444
#define RES_EXISTS
Definition: app_queue.c:1442
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:7324
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159

◆ mark_member_dead()

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

Definition at line 9351 of file app_queue.c.

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

Referenced by reload_single_queue().

9352 {
9353  struct member *member = obj;
9354  if (!member->dynamic && !member->realtime) {
9355  member->delme = 1;
9356  }
9357  return 0;
9358 }
int dynamic
Definition: app_queue.c:1601
int realtime
Definition: app_queue.c:1602
unsigned int delme
Definition: app_queue.c:1614

◆ mark_unfound()

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

Definition at line 9506 of file app_queue.c.

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

Referenced by reload_queues().

9507 {
9508  struct call_queue *q = obj;
9509  char *queuename = arg;
9510  if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
9511  q->found = 0;
9512  }
9513  return 0;
9514 }
#define ast_strlen_zero(foo)
Definition: strings.h:52
const ast_string_field name
Definition: app_queue.c:1696
unsigned int found
Definition: app_queue.c:1713
unsigned int realtime
Definition: app_queue.c:1712

◆ member_add_to_queue()

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

Definition at line 3360 of file app_queue.c.

References ao2_container_count(), ao2_link, ao2_lock, ao2_unlock, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), member::interface, call_queue::members, call_queue::name, member::paused, QUEUE_PAUSED_DEVSTATE, QUEUE_UNPAUSED_DEVSTATE, and member::queuepos.

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

3361 {
3362  ao2_lock(queue->members);
3363  mem->queuepos = ao2_container_count(queue->members);
3364  ao2_link(queue->members, mem);
3366  AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", queue->name, mem->interface);
3367  ao2_unlock(queue->members);
3368 }
int queuepos
Definition: app_queue.c:1606
int paused
Definition: app_queue.c:1604
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_unlock(a)
Definition: astobj2.h:730
struct ao2_container * members
Definition: app_queue.c:1752
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
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
#define QUEUE_PAUSED_DEVSTATE
Definition: app_queue.c:3350
#define ao2_lock(a)
Definition: astobj2.h:718
#define QUEUE_UNPAUSED_DEVSTATE
Definition: app_queue.c:3351
const ast_string_field name
Definition: app_queue.c:1696
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ member_cmp_fn()

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

Definition at line 2756 of file app_queue.c.

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

Referenced by init_queue().

2757 {
2758  struct member *mem1 = obj1;
2759  struct member *mem2 = obj2;
2760  const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
2761 
2762  return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
2763 }
#define OBJ_KEY
Definition: astobj2.h:1155
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593

◆ member_hash_fn()

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

Definition at line 2740 of file app_queue.c.

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

Referenced by init_queue().

2741 {
2742  const struct member *mem = obj;
2743  const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
2744  const char *chname = strchr(interface, '/');
2745  int ret = 0, i;
2746 
2747  if (!chname) {
2748  chname = interface;
2749  }
2750  for (i = 0; i < 5 && chname[i]; i++) {
2751  ret += compress_char(chname[i]) << (i * 6);
2752  }
2753  return ret;
2754 }
#define OBJ_KEY
Definition: astobj2.h:1155
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
static int compress_char(const char c)
Definition: app_queue.c:2730

◆ member_remove_from_queue()

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

Definition at line 3376 of file app_queue.c.

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

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

3377 {
3379  ao2_lock(queue->members);
3381  queue_member_follower_removal(queue, mem);
3382  ao2_unlink(queue->members, mem);
3383  ao2_unlock(queue->members);
3384 }
#define ao2_unlock(a)
Definition: astobj2.h:730
struct ao2_container * members
Definition: app_queue.c:1752
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2426
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
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
#define ao2_lock(a)
Definition: astobj2.h:718
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition: app_queue.c:3352
const ast_string_field name
Definition: app_queue.c:1696
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:1905

◆ member_status_available()

static int member_status_available ( int  status)
static

Definition at line 4374 of file app_queue.c.

References AST_DEVICE_NOT_INUSE, and AST_DEVICE_UNKNOWN.

Referenced by can_ring_entry(), and manager_queues_summary().

4375 {
4377 }
jack_status_t status
Definition: app_jack.c:146

◆ num_available_members()

static int num_available_members ( struct call_queue q)
static

Get the number of members available to accept a call.

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

Definition at line 4290 of file app_queue.c.

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

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

4291 {
4292  struct member *mem;
4293  int avl = 0;
4294  struct ao2_iterator mem_iter;
4295 
4296  mem_iter = ao2_iterator_init(q->members, 0);
4297  while ((mem = ao2_iterator_next(&mem_iter))) {
4298 
4299  avl += is_member_available(q, mem);
4300  ao2_ref(mem, -1);
4301 
4302  /* If autofill is not enabled or if the queue's strategy is ringall, then
4303  * we really don't care about the number of available members so much as we
4304  * do that there is at least one available.
4305  *
4306  * In fact, we purposely will return from this function stating that only
4307  * one member is available if either of those conditions hold. That way,
4308  * functions which determine what action to take based on the number of available
4309  * members will operate properly. The reasoning is that even if multiple
4310  * members are available, only the head caller can actually be serviced.
4311  */
4312  if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
4313  break;
4314  }
4315  }
4316  ao2_iterator_destroy(&mem_iter);
4317 
4318  return avl;
4319 }
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
struct ao2_container * members
Definition: app_queue.c:1752
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int strategy
Definition: app_queue.c:1711
int autofill
Definition: app_queue.c:1750
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2468

◆ parse_empty_options()

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

Definition at line 3101 of file app_queue.c.

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

Referenced by queue_set_param().

3102 {
3103  char *value_copy = ast_strdupa(value);
3104  char *option = NULL;
3105  while ((option = strsep(&value_copy, ","))) {
3106  if (!strcasecmp(option, "paused")) {
3107  *empty |= QUEUE_EMPTY_PAUSED;
3108  } else if (!strcasecmp(option, "penalty")) {
3109  *empty |= QUEUE_EMPTY_PENALTY;
3110  } else if (!strcasecmp(option, "inuse")) {
3111  *empty |= QUEUE_EMPTY_INUSE;
3112  } else if (!strcasecmp(option, "ringing")) {
3113  *empty |= QUEUE_EMPTY_RINGING;
3114  } else if (!strcasecmp(option, "invalid")) {
3115  *empty |= QUEUE_EMPTY_INVALID;
3116  } else if (!strcasecmp(option, "wrapup")) {
3117  *empty |= QUEUE_EMPTY_WRAPUP;
3118  } else if (!strcasecmp(option, "unavailable")) {
3119  *empty |= QUEUE_EMPTY_UNAVAILABLE;
3120  } else if (!strcasecmp(option, "unknown")) {
3121  *empty |= QUEUE_EMPTY_UNKNOWN;
3122  } else if (!strcasecmp(option, "loose")) {
3124  } else if (!strcasecmp(option, "strict")) {
3126  } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
3128  } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
3129  *empty = 0;
3130  } else {
3131  ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
3132  }
3133  }
3134 }
#define LOG_WARNING
Definition: logger.h:274
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
char * strsep(char **str, const char *delims)
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968

◆ pending_members_cmp()

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

Definition at line 2398 of file app_queue.c.

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

Referenced by load_module().

2399 {
2400  const struct member *object_left = obj;
2401  const struct member *object_right = arg;
2402  const char *right_key = arg;
2403  int cmp;
2404 
2405  switch (flags & OBJ_SEARCH_MASK) {
2406  case OBJ_SEARCH_OBJECT:
2407  right_key = object_right->interface;
2408  /* Fall through */
2409  case OBJ_SEARCH_KEY:
2410  cmp = strcasecmp(object_left->interface, right_key);
2411  break;
2413  /* Not supported by container. */
2414  ast_assert(0);
2415  return 0;
2416  default:
2417  cmp = 0;
2418  break;
2419  }
2420  if (cmp) {
2421  return 0;
2422  }
2423  return CMP_MATCH;
2424 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
#define ast_assert(a)
Definition: utils.h:695
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1120
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
Search option field mask.
Definition: astobj2.h:1076

◆ pending_members_hash()

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

Definition at line 2378 of file app_queue.c.

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

Referenced by load_module().

2379 {
2380  const struct member *object;
2381  const char *key;
2382 
2383  switch (flags & OBJ_SEARCH_MASK) {
2384  case OBJ_SEARCH_KEY:
2385  key = obj;
2386  break;
2387  case OBJ_SEARCH_OBJECT:
2388  object = obj;
2389  key = object->interface;
2390  break;
2391  default:
2392  ast_assert(0);
2393  return 0;
2394  }
2395  return ast_str_case_hash(key);
2396 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
#define ast_assert(a)
Definition: utils.h:695
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
Search option field mask.
Definition: astobj2.h:1076
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1250

◆ pending_members_remove()

static void pending_members_remove ( struct member mem)
static

Definition at line 2426 of file app_queue.c.

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

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

2427 {
2428  ast_debug(3, "Removed %s from pending_members\n", mem->membername);
2430 }
static struct ao2_container * pending_members
Definition: app_queue.c:2375
#define OBJ_POINTER
Definition: astobj2.h:1154
char membername[80]
Definition: app_queue.c:1598
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756

◆ play_file()

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

Definition at line 3916 of file app_queue.c.

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

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

3917 {
3918  int res;
3919 
3920  if (ast_strlen_zero(filename)) {
3921  return 0;
3922  }
3923 
3924  if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
3925  return 0;
3926  }
3927 
3928  ast_stopstream(chan);
3929 
3930  res = ast_streamfile(chan, filename, ast_channel_language(chan));
3931  if (!res) {
3932  res = ast_waitstream(chan, AST_DIGIT_ANY);
3933  }
3934 
3935  ast_stopstream(chan);
3936 
3937  return res;
3938 }
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1250
#define AST_DIGIT_ANY
Definition: file.h:48
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1776
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1086
const char * ast_channel_language(const struct ast_channel *chan)
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:187

◆ pqm_exec()

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

PauseQueueMember application.

Definition at line 7882 of file app_queue.c.

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

Referenced by load_module().

7883 {
7884  char *parse;
7886  AST_APP_ARG(queuename);
7889  AST_APP_ARG(reason);
7890  );
7891 
7892  if (ast_strlen_zero(data)) {
7893  ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
7894  return -1;
7895  }
7896 
7897  parse = ast_strdupa(data);
7898 
7899  AST_STANDARD_APP_ARGS(args, parse);
7900 
7901  if (ast_strlen_zero(args.interface)) {
7902  ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
7903  return -1;
7904  }
7905 
7906  if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
7907  ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
7908  pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
7909  return 0;
7910  }
7911 
7912  pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
7913 
7914  return 0;
7915 }
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
const char * args
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:7528
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
static struct test_options options
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ print_queue()

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

Print a single queue to AMI or the CLI.

Definition at line 9654 of file app_queue.c.

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

Referenced by __queues_show().

9655 {
9656  float sl;
9657  float sl2;
9658  struct ao2_iterator mem_iter;
9659  struct ast_str *out = ast_str_alloca(512);
9660  time_t now = time(NULL);
9661 
9662  ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
9663  if (q->maxlen) {
9664  ast_str_append(&out, 0, "%d", q->maxlen);
9665  } else {
9666  ast_str_append(&out, 0, "unlimited");
9667  }
9668  sl = 0;
9669  sl2 = 0;
9670  if (q->callscompleted > 0) {
9671  sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
9672  }
9673  if (q->callscompleted + q->callsabandoned > 0) {
9674  sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted));
9675  }
9676 
9677  ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%%, SL2:%2.1f%% within %ds",
9678  int2strat(q->strategy), q->holdtime, q->talktime, q->weight, q->callscompleted, q->callsabandoned, sl, sl2, q->servicelevel);
9679  do_print(s, fd, ast_str_buffer(out));
9680  if (!ao2_container_count(q->members)) {
9681  do_print(s, fd, " No Members");
9682  } else {
9683  struct member *mem;
9684 
9685  do_print(s, fd, " Members: ");
9686  mem_iter = ao2_iterator_init(q->members, 0);
9687  while ((mem = ao2_iterator_next(&mem_iter))) {
9688  ast_str_set(&out, 0, " %s", mem->membername);
9689  if (strcasecmp(mem->membername, mem->interface)) {
9690  ast_str_append(&out, 0, " (%s", mem->interface);
9691  if (!ast_strlen_zero(mem->state_interface)
9692  && strcmp(mem->state_interface, mem->interface)) {
9693  ast_str_append(&out, 0, " from %s", mem->state_interface);
9694  }
9695  ast_str_append(&out, 0, ")");
9696  }
9697  if (mem->penalty) {
9698  ast_str_append(&out, 0, " with penalty %d", mem->penalty);
9699  }
9700 
9701  ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
9702 
9703  ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s",
9704  mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
9705  mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
9706  mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
9707 
9708  if (mem->paused) {
9709  ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
9711  ast_strlen_zero(mem->reason_paused) ? "" : ":",
9712  ast_strlen_zero(mem->reason_paused) ? "" : mem->reason_paused,
9713  (long) (now - mem->lastpause),
9714  ast_term_reset());
9715  }
9716 
9717  ast_str_append(&out, 0, " (%s%s%s)",
9722  if (mem->calls) {
9723  ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
9724  mem->calls, (long) (now - mem->lastcall));
9725  } else {
9726  ast_str_append(&out, 0, " has taken no calls yet");
9727  }
9728  do_print(s, fd, ast_str_buffer(out));
9729  ao2_ref(mem, -1);
9730  }
9731  ao2_iterator_destroy(&mem_iter);
9732  }
9733  if (!q->head) {
9734  do_print(s, fd, " No Callers");
9735  } else {
9736  struct queue_ent *qe;
9737  int pos = 1;
9738 
9739  do_print(s, fd, " Callers: ");
9740  for (qe = q->head; qe; qe = qe->next) {
9741  ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
9742  pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
9743  (long) (now - qe->start) % 60, qe->prio);
9744  do_print(s, fd, ast_str_buffer(out));
9745  }
9746  }
9747  do_print(s, fd, ""); /* blank line between entries */
9748 }
static void do_print(struct mansession *s, int fd, const char *str)
direct ouput to manager or cli with proper terminator
Definition: app_queue.c:9644
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Definition: devicestate.c:237
int servicelevel
Definition: app_queue.c:1731
int dynamic
Definition: app_queue.c:1601
int callsabandonedinsl
Definition: app_queue.c:1730
int paused
Definition: app_queue.c:1604
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
struct ast_channel * chan
Definition: app_queue.c:1586
time_t start
Definition: app_queue.c:1583
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1596
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define COLOR_CYAN
Definition: term.h:59
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:1091
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define COLOR_GREEN
Definition: term.h:51
int realtime
Definition: app_queue.c:1602
#define ast_str_alloca(init_len)
Definition: strings.h:800
#define NULL
Definition: resample.c:96
struct ao2_container * members
Definition: app_queue.c:1752
struct queue_ent * head
Definition: app_queue.c:1753
int callscompletedinsl
Definition: app_queue.c:1732
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_strlen_zero(foo)
Definition: strings.h:52
int holdtime
Definition: app_queue.c:1726
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:1065
time_t lastpause
Definition: app_queue.c:1611
int penalty
Definition: app_queue.c:1599
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int strategy
Definition: app_queue.c:1711
#define COLOR_RED
Definition: term.h:49
#define COLOR_BLACK
Definition: term.h:47
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
const ast_string_field name
Definition: app_queue.c:1696
int talktime
Definition: app_queue.c:1727
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
char reason_paused[80]
Definition: app_queue.c:1605
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:306
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition: term.c:290
time_t starttime
Definition: app_queue.c:1609
int calls
Definition: app_queue.c:1600
int status
Definition: app_queue.c:1603
int callsabandoned
Definition: app_queue.c:1729
FILE * out
Definition: utils/frame.c:33
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
const char * ast_channel_name(const struct ast_channel *chan)
struct queue_ent * next
Definition: app_queue.c:1589
unsigned int ringinuse
Definition: app_queue.c:1616
#define COLOR_BROWN
Definition: term.h:53
int callscompleted
Definition: app_queue.c:1728
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
time_t lastcall
Definition: app_queue.c:1610
static const char * int2strat(int strategy)
Definition: app_queue.c:1787
#define COLOR_MAGENTA
Definition: term.h:57

◆ publish_dial_end_event()

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

Definition at line 4238 of file app_queue.c.

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

Referenced by ring_entry(), and wait_for_answer().

4239 {
4240  struct callattempt *cur;
4241 
4242  for (cur = outgoing; cur; cur = cur->q_next) {
4243  if (cur->chan && cur->chan != exception) {
4245  }
4246  }
4247 }
struct callattempt * q_next
Definition: app_queue.c:1538
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...
#define NULL
Definition: resample.c:96
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1537
struct ast_channel * chan
Definition: app_queue.c:1540
jack_status_t status
Definition: app_jack.c:146

◆ publish_queue_member_pause()

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

Definition at line 7457 of file app_queue.c.

References queue_member_blob_create(), and queue_publish_member_blob().

Referenced by set_queue_member_pause().

7458 {
7459  struct ast_json *json_blob = queue_member_blob_create(q, member);
7460 
7461  if (!json_blob) {
7462  return -1;
7463  }
7464 
7465  queue_publish_member_blob(queue_member_pause_type(), json_blob);
7466 
7467  return 0;
7468 }
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2258
Abstract JSON element (object, array, string, int, ...).
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2234

◆ ql_exec()

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

QueueLog application.

Definition at line 8106 of file app_queue.c.

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

Referenced by load_module().

8107 {
8108  char *parse;
8109 
8111  AST_APP_ARG(queuename);
8112  AST_APP_ARG(uniqueid);
8113  AST_APP_ARG(membername);
8114  AST_APP_ARG(event);
8115  AST_APP_ARG(params);
8116  );
8117 
8118  if (ast_strlen_zero(data)) {
8119  ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
8120  return -1;
8121  }
8122 
8123  parse = ast_strdupa(data);
8124 
8125  AST_STANDARD_APP_ARGS(args, parse);
8126 
8127  if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
8128  || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
8129  ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
8130  return -1;
8131  }
8132 
8133  ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
8134  "%s", args.params ? args.params : "");
8135 
8136  return 0;
8137 }
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
Definition: astman.c:222
const char * args
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ queue_agent_called_to_ami()

static struct ast_manager_event_blob* queue_agent_called_to_ami ( struct stasis_message message)
static

Definition at line 2125 of file app_queue.c.

References queue_multi_channel_to_ami().

Referenced by queue_agent_ringnoanswer_to_ami().

2126 {
2127  return queue_multi_channel_to_ami("AgentCalled", message);
2128 }
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2084

◆ queue_agent_cb()

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

Definition at line 5895 of file app_queue.c.

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

Referenced by load_module().

5897 {
5898  struct ast_channel_blob *agent_blob;
5899 
5900  agent_blob = stasis_message_data(msg);
5901 
5903  ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
5904  ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
5905  "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
5906  } else if (ast_channel_agent_logoff_type() == stasis_message_type(msg)) {
5907  ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
5908  ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
5909  "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
5910  (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
5911  }
5912 }
struct ast_channel_snapshot_base * base
struct ast_json * blob
struct ast_channel_snapshot * snapshot
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
const ast_string_field uniqueid
Blob of data associated with a channel.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
struct stasis_message_type * ast_channel_agent_login_type(void)
Message type for agent login on a channel.
struct stasis_message_type * ast_channel_agent_logoff_type(void)
Message type for agent logoff on a channel.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
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
const ast_string_field name

◆ queue_agent_complete_to_ami()

static struct ast_manager_event_blob* queue_agent_complete_to_ami ( struct stasis_message message)
static

Definition at line 2135 of file app_queue.c.

References queue_multi_channel_to_ami().

Referenced by queue_agent_ringnoanswer_to_ami().

2136 {
2137  return queue_multi_channel_to_ami("AgentComplete", message);
2138 }
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2084

◆ queue_agent_connect_to_ami()

static struct ast_manager_event_blob* queue_agent_connect_to_ami ( struct stasis_message message)
static

Definition at line 2130 of file app_queue.c.

References queue_multi_channel_to_ami().

Referenced by queue_agent_ringnoanswer_to_ami().

2131 {
2132  return queue_multi_channel_to_ami("AgentConnect", message);
2133 }
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2084

◆ queue_agent_dump_to_ami()

static struct ast_manager_event_blob* queue_agent_dump_to_ami ( struct stasis_message message)
static

Definition at line 2140 of file app_queue.c.

References queue_multi_channel_to_ami().

Referenced by queue_agent_ringnoanswer_to_ami().

2141 {
2142  return queue_multi_channel_to_ami("AgentDump", message);
2143 }
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2084

◆ queue_agent_ringnoanswer_to_ami()

static struct ast_manager_event_blob* queue_agent_ringnoanswer_to_ami ( struct stasis_message message)
static

Definition at line 2145 of file app_queue.c.

References queue_agent_called_to_ami(), queue_agent_complete_to_ami(), queue_agent_connect_to_ami(), queue_agent_dump_to_ami(), queue_multi_channel_to_ami(), STASIS_MESSAGE_TYPE_DEFN_LOCAL(), and to_ami().

2146 {
2147  return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2148 }
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2084

◆ queue_bridge_cb()

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

Definition at line 6261 of file app_queue.c.

References ao2_cleanup, and stasis_subscription_final_message().

Referenced by setup_stasis_subs().

6263 {
6264  if (stasis_subscription_final_message(sub, msg)) {
6265  ao2_cleanup(userdata);
6266  }
6267 }
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition: stasis.c:1176
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ queue_caller_abandon_to_ami()

static struct ast_manager_event_blob* queue_caller_abandon_to_ami ( struct stasis_message message)
static

Definition at line 2005 of file app_queue.c.

References queue_caller_join_to_ami(), queue_caller_leave_to_ami(), queue_channel_to_ami(), STASIS_MESSAGE_TYPE_DEFN_LOCAL(), and to_ami().

2006 {
2007  return queue_channel_to_ami("QueueCallerAbandon", message);
2008 }
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:1976

◆ queue_caller_join_to_ami()

static struct ast_manager_event_blob* queue_caller_join_to_ami ( struct stasis_message message)
static

Definition at line 1995 of file app_queue.c.

References queue_channel_to_ami().

Referenced by queue_caller_abandon_to_ami().

1996 {
1997  return queue_channel_to_ami("QueueCallerJoin", message);
1998 }
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:1976

◆ queue_caller_leave_to_ami()

static struct ast_manager_event_blob* queue_caller_leave_to_ami ( struct stasis_message message)
static

Definition at line 2000 of file app_queue.c.

References queue_channel_to_ami().

Referenced by queue_caller_abandon_to_ami().

2001 {
2002  return queue_channel_to_ami("QueueCallerLeave", message);
2003 }
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:1976

◆ queue_channel_cb()

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

Definition at line 6489 of file app_queue.c.

References ao2_cleanup, and stasis_subscription_final_message().

Referenced by setup_stasis_subs().

6491 {
6492  if (stasis_subscription_final_message(sub, msg)) {
6493  ao2_cleanup(userdata);
6494  }
6495 }
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition: stasis.c:1176
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ queue_channel_to_ami()

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

Definition at line 1976 of file app_queue.c.

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

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

1977 {
1978  struct ast_channel_blob *obj = stasis_message_data(message);
1979  RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
1980  RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
1981 
1982  channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1983  event_string = ast_manager_str_from_json_object(obj->blob, NULL);
1984  if (!channel_string || !event_string) {
1985  return NULL;
1986  }
1987 
1989  "%s"
1990  "%s",
1991  ast_str_buffer(channel_string),
1992  ast_str_buffer(event_string));
1993 }
static const char type[]
Definition: chan_ooh323.c:109
struct ast_json * blob
struct ast_channel_snapshot * snapshot
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define NULL
Definition: resample.c:96
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:9727
Blob of data associated with a channel.
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:1821
#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:911
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define EVENT_FLAG_AGENT
Definition: manager.h:76
#define ast_free(a)
Definition: astmm.h:182

◆ queue_cmp_cb()

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

Definition at line 1843 of file app_queue.c.

References CMP_MATCH, CMP_STOP, and call_queue::name.

Referenced by load_module().

1844 {
1845  struct call_queue *q = obj, *q2 = arg;
1846  return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
1847 }
const ast_string_field name
Definition: app_queue.c:1696

◆ queue_delme_members_decrement_followers()

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

Definition at line 1887 of file app_queue.c.

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

Referenced by reload_single_queue().

1888 {
1889  struct member *mem = obj;
1890  struct call_queue *queue = arg;
1891  int rrpos = mem->queuepos;
1892 
1893  if (mem->delme) {
1895  }
1896 
1897  return 0;
1898 }
int queuepos
Definition: app_queue.c:1606
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
unsigned int delme
Definition: app_queue.c:1614
struct ao2_container * members
Definition: app_queue.c:1752
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:1869

◆ queue_exec()

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

The starting point for all queue calls.

The process involved here is to

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

Definition at line 8183 of file app_queue.c.

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

Referenced by load_module().

8184 {
8185  int res=-1;
8186  int ringing=0;
8187  const char *user_priority;
8188  const char *max_penalty_str;
8189  const char *min_penalty_str;
8190  const char *raise_penalty_str;
8191  int prio;
8192  int qcontinue = 0;
8193  int max_penalty, min_penalty, raise_penalty;
8194  enum queue_result reason = QUEUE_UNKNOWN;
8195  /* whether to exit Queue application after the timeout hits */
8196  int tries = 0;
8197  int noption = 0;
8198  char *parse;
8199  int makeannouncement = 0;
8200  int position = 0;
8202  AST_APP_ARG(queuename);
8204  AST_APP_ARG(url);
8205  AST_APP_ARG(announceoverride);
8206  AST_APP_ARG(queuetimeoutstr);
8207  AST_APP_ARG(agi);
8208  AST_APP_ARG(macro);
8209  AST_APP_ARG(gosub);
8210  AST_APP_ARG(rule);
8211  AST_APP_ARG(position);
8212  );
8213  /* Our queue entry */
8214  struct queue_ent qe = { 0 };
8215  struct ast_flags opts = { 0, };
8216  char *opt_args[OPT_ARG_ARRAY_SIZE];
8217  int max_forwards;
8218 
8219  if (ast_strlen_zero(data)) {
8220  ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
8221  return -1;
8222  }
8223 
8224  ast_channel_lock(chan);
8225  max_forwards = ast_max_forwards_get(chan);
8226  ast_channel_unlock(chan);
8227 
8228  if (max_forwards <= 0) {
8229  ast_log(LOG_WARNING, "Channel '%s' cannot enter queue. Max forwards exceeded\n", ast_channel_name(chan));
8230  return -1;
8231  }
8232 
8233  parse = ast_strdupa(data);
8234  AST_STANDARD_APP_ARGS(args, parse);
8235 
8236  ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, timeout: %s, agi: %s, macro: %s, gosub: %s, rule: %s, position: %s\n",
8237  args.queuename,
8238  S_OR(args.options, ""),
8239  S_OR(args.url, ""),
8240  S_OR(args.announceoverride, ""),
8241  S_OR(args.queuetimeoutstr, ""),
8242  S_OR(args.agi, ""),
8243  S_OR(args.macro, ""),
8244  S_OR(args.gosub, ""),
8245  S_OR(args.rule, ""),
8246  S_OR(args.position, ""));
8247 
8248  if (!ast_strlen_zero(args.options)) {
8249  ast_app_parse_options(queue_exec_options, &opts, opt_args, args.options);
8250  }
8251 
8252  /* Setup our queue entry */
8253  qe.start = time(NULL);
8254 
8255  pbx_builtin_setvar_helper(chan, "ABANDONED", NULL);
8256 
8257  /* set the expire time based on the supplied timeout; */
8258  if (!ast_strlen_zero(args.queuetimeoutstr)) {
8259  qe.expire = qe.start + atoi(args.queuetimeoutstr);
8260  } else {
8261  qe.expire = 0;
8262  }
8263 
8264  /* Get the priority from the variable ${QUEUE_PRIO} */
8265  ast_channel_lock(chan);
8266  user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
8267  if (user_priority) {
8268  if (sscanf(user_priority, "%30d", &prio) == 1) {
8269  ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", ast_channel_name(chan), prio);
8270  } else {
8271  ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
8272  user_priority, ast_channel_name(chan));
8273  prio = 0;
8274  }
8275  } else {
8276  ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
8277  prio = 0;
8278  }
8279 
8280  /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
8281 
8282  if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
8283  if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
8284  ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", ast_channel_name(chan), max_penalty);
8285  } else {
8286  ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
8287  max_penalty_str, ast_channel_name(chan));
8288  max_penalty = INT_MAX;
8289  }
8290  } else {
8291  max_penalty = INT_MAX;
8292  }
8293 
8294  if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
8295  if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
8296  ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", ast_channel_name(chan), min_penalty);
8297  } else {
8298  ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
8299  min_penalty_str, ast_channel_name(chan));
8300  min_penalty = INT_MAX;
8301  }
8302  } else {
8303  min_penalty = INT_MAX;
8304  }
8305 
8306  if ((raise_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_RAISE_PENALTY"))) {
8307  if (sscanf(raise_penalty_str, "%30d", &raise_penalty) == 1) {
8308  ast_debug(1, "%s: Got raise penalty %d from ${QUEUE_RAISE_PENALTY}.\n", ast_channel_name(chan), raise_penalty);
8309  } else {
8310  ast_log(LOG_WARNING, "${QUEUE_RAISE_PENALTY}: Invalid value (%s), channel %s.\n",
8311  raise_penalty_str, ast_channel_name(chan));
8312  raise_penalty = INT_MAX;
8313  }
8314  } else {
8315  raise_penalty = INT_MAX;
8316  }
8317  ast_channel_unlock(chan);
8318 
8319  if (ast_test_flag(&opts, OPT_RINGING)) {
8320  ringing = 1;
8321  }
8322 
8323  if (ringing != 1 && ast_test_flag(&opts, OPT_RING_WHEN_RINGING)) {
8324  qe.ring_when_ringing = 1;
8325  }
8326 
8327  if (ast_test_flag(&opts, OPT_GO_ON)) {
8328  qcontinue = 1;
8329  }
8330 
8331  if (args.position) {
8332  position = atoi(args.position);
8333  if (position < 0) {
8334  ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
8335  position = 0;
8336  }
8337  }
8338 
8339  ast_debug(1, "queue: %s, expires: %ld, priority: %d\n",
8340  args.queuename, (long)qe.expire, prio);
8341 
8342  qe.chan = chan;
8343  qe.prio = prio;
8344  qe.max_penalty = max_penalty;
8345  qe.min_penalty = min_penalty;
8346  qe.raise_penalty = raise_penalty;
8347  qe.last_pos_said = 0;
8348  qe.last_pos = 0;
8349  qe.last_periodic_announce_time = time(NULL);
8351  qe.valid_digits = 0;
8352  if (join_queue(args.queuename, &qe, &reason, position)) {
8353  ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
8354  set_queue_result(chan, reason);
8355  return 0;
8356  }
8357  ast_assert(qe.parent != NULL);
8358 
8359  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d",
8360  S_OR(args.url, ""),
8361  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
8362  qe.opos);
8363 
8364  /* PREDIAL: Preprocess any callee gosub arguments. */
8365  if (ast_test_flag(&opts, OPT_PREDIAL_CALLEE)
8366  && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])) {
8367  ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLEE]);
8368  qe.predial_callee = opt_args[OPT_ARG_PREDIAL_CALLEE];
8369  }
8370 
8371  /* PREDIAL: Run gosub on the caller's channel */
8372  if (ast_test_flag(&opts, OPT_PREDIAL_CALLER)
8373  && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) {
8374  ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLER]);
8375  ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER], 0);
8376  }
8377 
8378  copy_rules(&qe, args.rule);
8379  qe.pr = AST_LIST_FIRST(&qe.qe_rules);
8380 check_turns:
8381  if (ringing) {
8383  } else {
8384  ast_moh_start(chan, qe.moh, NULL);
8385  }
8386 
8387  /* This is the wait loop for callers 2 through maxlen */
8388  res = wait_our_turn(&qe, ringing, &reason);
8389  if (res) {
8390  goto stop;
8391  }
8392 
8393  makeannouncement = qe.parent->announce_to_first_user;
8394 
8395  for (;;) {
8396  /* This is the wait loop for the head caller*/
8397  /* To exit, they may get their call answered; */
8398  /* they may dial a digit from the queue context; */
8399  /* or, they may timeout. */
8400 
8401  /* Leave if we have exceeded our queuetimeout */
8402  if (qe.expire && (time(NULL) >= qe.expire)) {
8403  record_abandoned(&qe);
8404  reason = QUEUE_TIMEOUT;
8405  res = 0;
8406  ast_queue_log(args.queuename, ast_channel_uniqueid(chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
8407  qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8408  break;
8409  }
8410 
8411  if (makeannouncement) {
8412  /* Make a position announcement, if enabled */
8413  if (qe.parent->announcefrequency) {
8414  if ((res = say_position(&qe, ringing))) {
8415  goto stop;
8416  }
8417  }
8418  }
8419  makeannouncement = 1;
8420 
8421  /* Make a periodic announcement, if enabled */
8423  if ((res = say_periodic_announcement(&qe, ringing))) {
8424  goto stop;
8425  }
8426  }
8427 
8428  /* Leave if we have exceeded our queuetimeout */
8429  if (qe.expire && (time(NULL) >= qe.expire)) {
8430  record_abandoned(&qe);
8431  reason = QUEUE_TIMEOUT;
8432  res = 0;
8433  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
8434  "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8435  break;
8436  }
8437 
8438  /* see if we need to move to the next penalty level for this queue */
8439  while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
8440  update_qe_rule(&qe);
8441  }
8442 
8443  /* Try calling all queue members for 'timeout' seconds */
8444  res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
8445  if (res) {
8446  goto stop;
8447  }
8448 
8449  if (qe.parent->leavewhenempty) {
8450  int status = 0;
8451  if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.raise_penalty, qe.parent->leavewhenempty, 0))) {
8452  record_abandoned(&qe);
8453  reason = QUEUE_LEAVEEMPTY;
8454  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
8455  res = 0;
8456  break;
8457  }
8458  }
8459 
8460  /* exit after 'timeout' cycle if 'n' option enabled */
8461  if (noption && tries >= ao2_container_count(qe.parent->members)) {
8462  ast_verb(3, "Exiting on time-out cycle\n");
8463  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
8464  "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8465  record_abandoned(&qe);
8466  reason = QUEUE_TIMEOUT;
8467  res = 0;
8468  break;
8469  }
8470 
8471 
8472  /* Leave if we have exceeded our queuetimeout */
8473  if (qe.expire && (time(NULL) >= qe.expire)) {
8474  record_abandoned(&qe);
8475  reason = QUEUE_TIMEOUT;
8476  res = 0;
8477  ast_queue_log(qe.parent->name, ast_channel_uniqueid(qe.chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8478  break;
8479  }
8480 
8481  /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
8482  res = wait_a_bit(&qe);
8483  if (res) {
8484  goto stop;
8485  }
8486 
8487  /* If using dynamic realtime members, we should regenerate the member list for this queue */
8489 
8490  /* Since this is a priority queue and
8491  * it is not sure that we are still at the head
8492  * of the queue, go and check for our turn again.
8493  */
8494  if (!is_our_turn(&qe)) {
8495  ast_debug(1, "Darn priorities, going back in queue (%s)!\n", ast_channel_name(qe.chan));
8496  goto check_turns;
8497  }
8498  }
8499 
8500 stop:
8501  if (res) {
8502  if (res < 0) {
8503  if (!qe.handled) {
8504  record_abandoned(&qe);
8505  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ABANDON",
8506  "%d|%d|%ld", qe.pos, qe.opos,
8507  (long) (time(NULL) - qe.start));
8508  res = -1;
8509  } else if (reason == QUEUE_LEAVEEMPTY) {
8510  /* Return back to dialplan, don't hang up */
8511  res = 0;
8512  } else if (qcontinue) {
8513  reason = QUEUE_CONTINUE;
8514  res = 0;
8515  }
8516  } else if (qe.valid_digits) {
8517  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY",
8518  "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8519  }
8520  }
8521 
8522  /* Don't allow return code > 0 */
8523  if (res >= 0) {
8524  res = 0;
8525  if (ringing) {
8526  ast_indicate(chan, -1);
8527  } else {
8528  ast_moh_stop(chan);
8529  }
8530  ast_stopstream(chan);
8531  }
8532 
8534 
8535  leave_queue(&qe);
8536  if (reason != QUEUE_UNKNOWN)
8537  set_queue_result(chan, reason);
8538 
8539  /*
8540  * every queue_ent is given a reference to it's parent
8541  * call_queue when it joins the queue. This ref must be taken
8542  * away right before the queue_ent is destroyed. In this case
8543  * the queue_ent is about to be returned on the stack
8544  */
8545  qe.parent = queue_unref(qe.parent);
8546 
8547  return res;
8548 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
static int say_position(struct queue_ent *qe, int ringing)
Definition: app_queue.c:3980
struct call_queue * parent
Definition: app_queue.c:1561
#define ast_channel_lock(chan)
Definition: channel.h:2945
int ast_max_forwards_get(struct ast_channel *chan)
Get the current max forwards for a particular channel.
Definition: max_forwards.c:121
int raise_penalty
Definition: app_queue.c:1580
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
char digits[AST_MAX_EXTENSION]
Definition: app_queue.c:1565
struct ast_channel * chan
Definition: app_queue.c:1586
int min_penalty
Definition: app_queue.c:1579
int max_penalty
Definition: app_queue.c:1578
int last_periodic_announce_sound
Definition: app_queue.c:1573
time_t start
Definition: app_queue.c:1583
#define ast_test_flag(p, flag)
Definition: utils.h:63
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4322
static void update_realtime_members(struct call_queue *q)
Definition: app_queue.c:3773
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
int last_pos_said
Definition: app_queue.c:1570
#define LOG_WARNING
Definition: logger.h:274
time_t expire
Definition: app_queue.c:1584
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
unsigned int stop
Definition: app_meetme.c:1096
#define queue_unref(q)
Definition: app_queue.c:1919
queue_result
Definition: app_queue.c:1495
#define ast_assert(a)
Definition: utils.h:695
static void set_queue_result(struct ast_channel *chan, enum queue_result res)
sets the QUEUESTATUS channel variable
Definition: app_queue.c:1775
const char * args
static const struct ast_app_option queue_exec_options[128]
Definition: app_queue.c:1379
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
Playback announcement to queued members if period has elapsed.
Definition: app_queue.c:4747
#define NULL
Definition: resample.c:96
unsigned int announce_to_first_user
Definition: app_queue.c:1701
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7876
struct ao2_container * members
Definition: app_queue.c:1752
#define ast_verb(level,...)
Definition: logger.h:463
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define ast_strlen_zero(foo)
Definition: strings.h:52
Number structure.
Definition: app_followme.c:154
static int wait_a_bit(struct queue_ent *qe)
Definition: app_queue.c:7229
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
void ast_replace_subargument_delimiter(char *s)
Replace &#39;^&#39; in a string with &#39;,&#39;.
Definition: main/utils.c:2095
#define ast_log
Definition: astobj2.c:42
const char * predial_callee
Definition: app_queue.c:1566
int periodicannouncefrequency
Definition: app_queue.c:1722
int ring_when_ringing
Definition: app_queue.c:1571
static void ringing(struct ast_channel *chan)
Helper method to send a ringing indication to a channel in a bridge.
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int valid_digits
Definition: app_queue.c:1567
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:2906
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1562
const char * ast_channel_uniqueid(const struct ast_channel *chan)
static void leave_queue(struct queue_ent *qe)
Caller leaving queue.
Definition: app_queue.c:4151
static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
Definition: app_queue.c:3832
const ast_string_field name
Definition: app_queue.c:1696
Channel datastore data for max forwards.
Definition: max_forwards.c:29
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7866
time_t last_pos
Definition: app_queue.c:1574
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
struct penalty_rule * pr
Definition: app_queue.c:1588
Structure used to handle boolean flags.
Definition: utils.h:199
static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
The waiting areas for callers who are not actively calling members.
Definition: app_queue.c:5626
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
static void record_abandoned(struct queue_ent *qe)
Record that a caller gave up on waiting in queue.
Definition: app_queue.c:4808
time_t last_periodic_announce_time
Definition: app_queue.c:1572
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
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:2284
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:1926
int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args, int ignore_hangup)
Run a subroutine on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:370
enum empty_conditions leavewhenempty
Definition: app_queue.c:1718
struct queue_ent::@67 qe_rules
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)
Definition: app_queue.c:6722
static struct test_options options
int handled
Definition: app_queue.c:1576
static void copy_rules(struct queue_ent *qe, const char *rulename)
Copy rule from global list into specified queue.
Definition: app_queue.c:8140
static char url[512]
static void update_qe_rule(struct queue_ent *qe)
update rules for queues
Definition: app_queue.c:5536
static int is_our_turn(struct queue_ent *qe)
Check if we should start attempting to call queue members.
Definition: app_queue.c:5487
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
int announcefrequency
Definition: app_queue.c:1720
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:187
jack_status_t status
Definition: app_jack.c:146
#define AST_APP_ARG(name)
Define an application argument.

◆ queue_function_exists()

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

Check if a given queue exists.

Definition at line 8599 of file app_queue.c.

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

8600 {
8601  struct call_queue *q;
8602 
8603  buf[0] = '\0';
8604 
8605  if (ast_strlen_zero(data)) {
8606  ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
8607  return -1;
8608  }
8609  q = find_load_queue_rt_friendly(data);
8610  snprintf(buf, len, "%d", q != NULL? 1 : 0);
8611  if (q) {
8612  queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
8613  }
8614 
8615  return 0;
8616 }
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921

◆ queue_function_mem_read()

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

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

Get or set member properties penalty / paused / ringinuse

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

Definition at line 8641 of file app_queue.c.

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

8642 {
8643  int count = 0;
8644  struct member *m;
8645  struct ao2_iterator mem_iter;
8646  struct call_queue *q;
8647 
8649  AST_APP_ARG(queuename);
8650  AST_APP_ARG(option);
8651  AST_APP_ARG(interface);
8652  );
8653  /* Make sure the returned value on error is zero length string. */
8654  buf[0] = '\0';
8655 
8656  if (ast_strlen_zero(data)) {
8658  "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
8659  cmd);
8660  return -1;
8661  }
8662 
8663  AST_STANDARD_APP_ARGS(args, data);
8664 
8665  if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) {
8667  "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
8668  cmd);
8669  return -1;
8670  }
8671 
8672  if ((q = find_load_queue_rt_friendly(args.queuename))) {
8673  ao2_lock(q);
8674  if (!strcasecmp(args.option, "logged")) {
8675  mem_iter = ao2_iterator_init(q->members, 0);
8676  while ((m = ao2_iterator_next(&mem_iter))) {
8677  /* Count the agents who are logged in and presently answering calls */
8678  if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
8679  count++;
8680  }
8681  ao2_ref(m, -1);
8682  }
8683  ao2_iterator_destroy(&mem_iter);
8684  } else if (!strcasecmp(args.option, "free")) {
8685  mem_iter = ao2_iterator_init(q->members, 0);
8686  while ((m = ao2_iterator_next(&mem_iter))) {
8687  /* Count the agents who are logged in and presently answering calls */
8688  if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
8689  count++;
8690  }
8691  ao2_ref(m, -1);
8692  }
8693  ao2_iterator_destroy(&mem_iter);
8694  } else if (!strcasecmp(args.option, "ready")) {
8695  time_t now;
8696  time(&now);
8697  mem_iter = ao2_iterator_init(q->members, 0);
8698  while ((m = ao2_iterator_next(&mem_iter))) {
8699  /* Count the agents who are logged in, not paused and not wrapping up */
8700  if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
8701  !(m->lastcall && get_wrapuptime(q, m) && ((now - get_wrapuptime(q, m)) < m->lastcall))) {
8702  count++;
8703  }
8704  ao2_ref(m, -1);
8705  }
8706  ao2_iterator_destroy(&mem_iter);
8707  } else if (!strcasecmp(args.option, "count")) {
8708  count = ao2_container_count(q->members);
8709  } else if (!strcasecmp(args.option, "penalty")) {
8710  m = get_interface_helper(q, args.interface);
8711  if (m) {
8712  count = m->penalty;
8713  ao2_ref(m, -1);
8714  }
8715  } else if (!strcasecmp(args.option, "paused")) {
8716  m = get_interface_helper(q, args.interface);
8717  if (m) {
8718  count = m->paused;
8719  ao2_ref(m, -1);
8720  }
8721  } else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
8722  || !strcasecmp(args.option, "ringinuse"))) {
8723  m = get_interface_helper(q, args.interface);
8724  if (m) {
8725  count = m->ringinuse;
8726  ao2_ref(m, -1);
8727  }
8728  } else {
8729  ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
8730  }
8731  ao2_unlock(q);
8732  queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
8733  } else {
8734  ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
8735  }
8736 
8737  snprintf(buf, len, "%d", count);
8738 
8739  return 0;
8740 }
int paused
Definition: app_queue.c:1604
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
const char * args
struct ao2_container * members
Definition: app_queue.c:1752
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
int penalty
Definition: app_queue.c:1599
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:1856
#define LOG_ERROR
Definition: logger.h:285
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
int status
Definition: app_queue.c:1603
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
static struct member * get_interface_helper(struct call_queue *q, const char *interface)
Definition: app_queue.c:8618
unsigned int ringinuse
Definition: app_queue.c:1616
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
time_t lastcall
Definition: app_queue.c:1610
#define AST_APP_ARG(name)
Define an application argument.

◆ queue_function_mem_write()

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

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

Definition at line 8743 of file app_queue.c.

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

8744 {
8745  int memvalue;
8746 
8748  AST_APP_ARG(queuename);
8749  AST_APP_ARG(option);
8750  AST_APP_ARG(interface);
8751  );
8752 
8753  if (ast_strlen_zero(data)) {
8755  "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
8756  cmd);
8757  return -1;
8758  }
8759 
8760  AST_STANDARD_APP_ARGS(args, data);
8761 
8762  if (ast_strlen_zero(args.option)
8763  || ast_strlen_zero(args.interface)) {
8765  "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
8766  cmd);
8767  return -1;
8768  }
8769 
8770  /*
8771  * If queuename is empty then the option will be
8772  * set for the interface in all queues.
8773  */
8774 
8775  memvalue = atoi(value);
8776  if (!strcasecmp(args.option, "penalty")) {
8777  if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
8778  ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
8779  return -1;
8780  }
8781  } else if (!strcasecmp(args.option, "paused")) {
8782  memvalue = (memvalue <= 0) ? 0 : 1;
8783  if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
8784  ast_log(LOG_ERROR, "Invalid interface or queue\n");
8785  return -1;
8786  }
8787  } else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
8788  || !strcasecmp(args.option, "ringinuse")) {
8789  memvalue = (memvalue <= 0) ? 0 : 1;
8790  if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
8791  ast_log(LOG_ERROR, "Invalid interface or queue\n");
8792  return -1;
8793  }
8794  } else {
8795  ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
8796  return -1;
8797  }
8798  return 0;
8799 }
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
const char * args
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:7528
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:7674
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ queue_function_memberpenalty_read()

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

Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.

Definition at line 9011 of file app_queue.c.

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

9012 {
9013  int penalty;
9015  AST_APP_ARG(queuename);
9016  AST_APP_ARG(interface);
9017  );
9018  /* Make sure the returned value on error is NULL. */
9019  buf[0] = '\0';
9020 
9021  if (ast_strlen_zero(data)) {
9022  ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9023  return -1;
9024  }
9025 
9026  AST_STANDARD_APP_ARGS(args, data);
9027 
9028  if (args.argc < 2) {
9029  ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9030  return -1;
9031  }
9032 
9033  penalty = get_member_penalty (args.queuename, args.interface);
9034 
9035  if (penalty >= 0) { /* remember that buf is already '\0' */
9036  snprintf (buf, len, "%d", penalty);
9037  }
9038 
9039  return 0;
9040 }
static int get_member_penalty(char *queuename, char *interface)
Definition: app_queue.c:7740
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
const char * args
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ queue_function_memberpenalty_write()

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

Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.

Definition at line 9043 of file app_queue.c.

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

9044 {
9045  int penalty;
9047  AST_APP_ARG(queuename);
9048  AST_APP_ARG(interface);
9049  );
9050 
9051  if (ast_strlen_zero(data)) {
9052  ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9053  return -1;
9054  }
9055 
9056  AST_STANDARD_APP_ARGS(args, data);
9057 
9058  if (args.argc < 2) {
9059  ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9060  return -1;
9061  }
9062 
9063  penalty = atoi(value);
9064 
9065  if (ast_strlen_zero(args.interface)) {
9066  ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9067  return -1;
9068  }
9069 
9070  /* if queuename = NULL then penalty will be set for interface in all the queues. */
9071  if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9072  ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9073  return -1;
9074  }
9075 
9076  return 0;
9077 }
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
const char * args
int value
Definition: syslog.c:37
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:7674
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ queue_function_qac_dep()

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

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

Return values
numberof members
-1on error

Definition at line 8806 of file app_queue.c.

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

8807 {
8808  int count = 0;
8809  struct member *m;
8810  struct call_queue *q;
8811  struct ao2_iterator mem_iter;
8812  static int depflag = 1;
8813 
8814  if (depflag) {
8815  depflag = 0;
8816  ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
8817  }
8818 
8819  if (ast_strlen_zero(data)) {
8820  ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
8821  return -1;
8822  }
8823 
8824  if ((q = find_load_queue_rt_friendly(data))) {
8825  ao2_lock(q);
8826  mem_iter = ao2_iterator_init(q->members, 0);
8827  while ((m = ao2_iterator_next(&mem_iter))) {
8828  /* Count the agents who are logged in and presently answering calls */
8829  if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
8830  count++;
8831  }
8832  ao2_ref(m, -1);
8833  }
8834  ao2_iterator_destroy(&mem_iter);
8835  ao2_unlock(q);
8836  queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
8837  } else {
8838  ast_log(LOG_WARNING, "queue %s was not found\n", data);
8839  }
8840 
8841  snprintf(buf, len, "%d", count);
8842 
8843  return 0;
8844 }
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
struct ao2_container * members
Definition: app_queue.c:1752
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
#define LOG_ERROR
Definition: logger.h:285
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define LOG_NOTICE
Definition: logger.h:263
int status
Definition: app_queue.c:1603
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ queue_function_queuegetchannel()

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

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

Definition at line 8847 of file app_queue.c.

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

8848 {
8849  int position;
8850  char *parse;
8851  struct call_queue *q;
8852  struct ast_variable *var;
8853 
8855  AST_APP_ARG(queuename);
8856  AST_APP_ARG(position);
8857  );
8858 
8859  buf[0] = '\0';
8860 
8861  if (ast_strlen_zero(data)) {
8862  ast_log(LOG_ERROR, "Missing argument. QUEUE_GET_CHANNEL(<queuename>,<position>)\n");
8863  return -1;
8864  }
8865 
8866  parse = ast_strdupa(data);
8867  AST_STANDARD_APP_ARGS(args, parse);
8868 
8869  if (ast_strlen_zero(args.queuename)) {
8870  ast_log (LOG_ERROR, "The <queuename> parameter is required.\n");
8871  return -1;
8872  }
8873 
8874  if (ast_strlen_zero(args.position)) {
8875  position = 1;
8876  } else {
8877  if (sscanf(args.position, "%30d", &position) != 1) {
8878  ast_log (LOG_ERROR, "<position> parameter must be an integer.\n");
8879  return -1;
8880  }
8881  if (position < 1) {
8882  ast_log (LOG_ERROR, "<position> parameter must be an integer greater than zero.\n");
8883  return -1;
8884  }
8885  }
8886 
8887  {
8888  struct call_queue tmpq = {
8889  .name = args.queuename,
8890  };
8891 
8892  q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_GET_CHANNEL()");
8893  }
8894  if (q) {
8895  ao2_lock(q);
8896  if (q->count >= position) {
8897  struct queue_ent *qe;
8898 
8899  for (qe = q->head; qe; qe = qe->next) {
8900  if (qe->pos == position) {
8902  break;
8903  }
8904  }
8905  }
8906  ao2_unlock(q);
8907  queue_t_unref(q, "Done with reference in QUEUE_GET_CHANNEL()");
8908  return 0;
8909  }
8910 
8911  var = ast_load_realtime("queues", "name", args.queuename, SENTINEL);
8912  if (var) {
8913  /* if the queue is realtime but was not found in memory, this
8914  * means that the queue had been deleted from memory since it was
8915  * "dead."
8916  */
8917  ast_variables_destroy(var);
8918  return 0;
8919  }
8920 
8921  ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
8922  return 0;
8923 }
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3339
struct ast_channel * chan
Definition: app_queue.c:1586
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define OBJ_POINTER
Definition: astobj2.h:1154
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
#define ao2_unlock(a)
Definition: astobj2.h:730
const char * args
struct queue_ent * head
Definition: app_queue.c:1753
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define SENTINEL
Definition: compiler.h:87
static struct ao2_container * queues
Definition: app_queue.c:1766
#define ao2_lock(a)
Definition: astobj2.h:718
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define LOG_ERROR
Definition: logger.h:285
const ast_string_field name
Definition: app_queue.c:1696
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const char * ast_channel_name(const struct ast_channel *chan)
#define ao2_t_find(container, arg, flags, tag)
Definition: astobj2.h:1754
struct queue_ent * next
Definition: app_queue.c:1589
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ queue_function_queuememberlist()

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

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

Definition at line 8963 of file app_queue.c.

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

8964 {
8965  struct call_queue *q;
8966  struct member *m;
8967 
8968  /* Ensure an otherwise empty list doesn't return garbage */
8969  buf[0] = '\0';
8970 
8971  if (ast_strlen_zero(data)) {
8972  ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
8973  return -1;
8974  }
8975 
8976  if ((q = find_load_queue_rt_friendly(data))) {
8977  int buflen = 0, count = 0;
8978  struct ao2_iterator mem_iter;
8979 
8980  ao2_lock(q);
8981  mem_iter = ao2_iterator_init(q->members, 0);
8982  while ((m = ao2_iterator_next(&mem_iter))) {
8983  /* strcat() is always faster than printf() */
8984  if (count++) {
8985  strncat(buf + buflen, ",", len - buflen - 1);
8986  buflen++;
8987  }
8988  strncat(buf + buflen, m->interface, len - buflen - 1);
8989  buflen += strlen(m->interface);
8990  /* Safeguard against overflow (negative length) */
8991  if (buflen >= len - 2) {
8992  ao2_ref(m, -1);
8993  ast_log(LOG_WARNING, "Truncating list\n");
8994  break;
8995  }
8996  ao2_ref(m, -1);
8997  }
8998  ao2_iterator_destroy(&mem_iter);
8999  ao2_unlock(q);
9000  queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
9001  } else
9002  ast_log(LOG_WARNING, "queue %s was not found\n", data);
9003 
9004  /* We should already be terminated, but let's make sure. */
9005  buf[len - 1] = '\0';
9006 
9007  return 0;
9008 }
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
struct ao2_container * members
Definition: app_queue.c:1752
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
#define LOG_ERROR
Definition: logger.h:285
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ queue_function_queuewaitingcount()

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

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

Definition at line 8926 of file app_queue.c.

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

8927 {
8928  int count = 0;
8929  struct call_queue *q, tmpq = {
8930  .name = data,
8931  };
8932  struct ast_variable *var = NULL;
8933 
8934  buf[0] = '\0';
8935 
8936  if (ast_strlen_zero(data)) {
8937  ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
8938  return -1;
8939  }
8940 
8941  if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
8942  ao2_lock(q);
8943  count = q->count;
8944  ao2_unlock(q);
8945  queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
8946  } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
8947  /* if the queue is realtime but was not found in memory, this
8948  * means that the queue had been deleted from memory since it was
8949  * "dead." This means it has a 0 waiting count
8950  */
8951  count = 0;
8952  ast_variables_destroy(var);
8953  } else {
8954  ast_log(LOG_WARNING, "queue %s was not found\n", data);
8955  }
8956 
8957  snprintf(buf, len, "%d", count);
8958 
8959  return 0;
8960 }
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3339
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define OBJ_POINTER
Definition: astobj2.h:1154
#define LOG_WARNING
Definition: logger.h:274
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define SENTINEL
Definition: compiler.h:87
static struct ao2_container * queues
Definition: app_queue.c:1766
#define ao2_lock(a)
Definition: astobj2.h:718
#define LOG_ERROR
Definition: logger.h:285
const ast_string_field name
Definition: app_queue.c:1696
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
#define ao2_t_find(container, arg, flags, tag)
Definition: astobj2.h:1754

◆ queue_function_var()

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

create interface var with all queue details.

Return values
0on success
-1on error

Definition at line 8555 of file app_queue.c.

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

8556 {
8557  int res = -1;
8558  struct call_queue *q;
8559  char interfacevar[256] = "";
8560  float sl = 0;
8561 
8562  if (ast_strlen_zero(data)) {
8563  ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
8564  return -1;
8565  }
8566 
8567  if ((q = find_load_queue_rt_friendly(data))) {
8568  ao2_lock(q);
8569  if (q->setqueuevar) {
8570  sl = 0;
8571  res = 0;
8572 
8573  if (q->callscompleted > 0) {
8574  sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
8575  }
8576 
8577  snprintf(interfacevar, sizeof(interfacevar),
8578  "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
8580 
8581  pbx_builtin_setvar_multiple(chan, interfacevar);
8582  }
8583 
8584  ao2_unlock(q);
8585  queue_t_unref(q, "Done with QUEUE() function");
8586  } else {
8587  ast_log(LOG_WARNING, "queue %s was not found\n", data);
8588  }
8589 
8590  snprintf(buf, len, "%d", res);
8591 
8592  return 0;
8593 }
int servicelevel
Definition: app_queue.c:1731
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
unsigned int setqueuevar
Definition: app_queue.c:1703
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
#define ao2_unlock(a)
Definition: astobj2.h:730
int callscompletedinsl
Definition: app_queue.c:1732
#define ast_strlen_zero(foo)
Definition: strings.h:52
int holdtime
Definition: app_queue.c:1726
#define ast_log
Definition: astobj2.c:42
#define ao2_lock(a)
Definition: astobj2.h:718
int strategy
Definition: app_queue.c:1711
#define LOG_ERROR
Definition: logger.h:285
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *data)
Parse and set multiple channel variables, where the pairs are separated by the &#39;,&#39; character...
int talktime
Definition: app_queue.c:1727
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
int callsabandoned
Definition: app_queue.c:1729
int callscompleted
Definition: app_queue.c:1728
static const char * int2strat(int strategy)
Definition: app_queue.c:1787

◆ queue_hash_cb()

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

Definition at line 1836 of file app_queue.c.

References ast_str_case_hash(), and call_queue::name.

Referenced by load_module().

1837 {
1838  const struct call_queue *q = obj;
1839 
1840  return ast_str_case_hash(q->name);
1841 }
const ast_string_field name
Definition: app_queue.c:1696
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1250

◆ queue_member_added_to_ami()

static struct ast_manager_event_blob* queue_member_added_to_ami ( struct stasis_message message)
static

Definition at line 2040 of file app_queue.c.

References queue_member_to_ami().

Referenced by queue_member_ringinuse_to_ami().

2041 {
2042  return queue_member_to_ami("QueueMemberAdded", message);
2043 }
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2020

◆ queue_member_blob_create()

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

Definition at line 2258 of file app_queue.c.

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

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

2259 {
2260  return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: s, s: i, s: i}",
2261  "Queue", q->name,
2262  "MemberName", mem->membername,
2263  "Interface", mem->interface,
2264  "StateInterface", mem->state_interface,
2265  "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
2266  "Penalty", mem->penalty,
2267  "CallsTaken", mem->calls,
2268  "LastCall", (int)mem->lastcall,
2269  "LastPause", (int)mem->lastpause,
2270  "InCall", mem->starttime ? 1 : 0,
2271  "Status", mem->status,
2272  "Paused", mem->paused,
2273  "PausedReason", mem->reason_paused,
2274  "Ringinuse", mem->ringinuse,
2275  "Wrapuptime", mem->wrapuptime);
2276 }
int dynamic
Definition: app_queue.c:1601
int paused
Definition: app_queue.c:1604
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1596
int wrapuptime
Definition: app_queue.c:1608
int realtime
Definition: app_queue.c:1602
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
time_t lastpause
Definition: app_queue.c:1611
int penalty
Definition: app_queue.c:1599
const ast_string_field name
Definition: app_queue.c:1696
char reason_paused[80]
Definition: app_queue.c:1605
time_t starttime
Definition: app_queue.c:1609
int calls
Definition: app_queue.c:1600
int status
Definition: app_queue.c:1603
unsigned int ringinuse
Definition: app_queue.c:1616
time_t lastcall
Definition: app_queue.c:1610

◆ queue_member_decrement_followers()

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

Definition at line 1869 of file app_queue.c.

References member::queuepos.

Referenced by queue_delme_members_decrement_followers(), and queue_member_follower_removal().

1870 {
1871  struct member *mem = obj;
1872  int *decrement_followers_after = arg;
1873 
1874  if (mem->queuepos > *decrement_followers_after) {
1875  mem->queuepos--;
1876  }
1877 
1878  return 0;
1879 }
int queuepos
Definition: app_queue.c:1606

◆ queue_member_follower_removal()

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

Definition at line 1905 of file app_queue.c.

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

Referenced by member_remove_from_queue().

1906 {
1907  int pos = mem->queuepos;
1908 
1909  /* If the position being removed is less than the current place in the queue, reduce the queue position by one so that we don't skip the member
1910  * who would have been next otherwise. */
1911  if (pos < queue->rrpos) {
1912  queue->rrpos--;
1913  }
1914 
1916 }
int queuepos
Definition: app_queue.c:1606
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
struct ao2_container * members
Definition: app_queue.c:1752
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:1869

◆ queue_member_pause_to_ami()

static struct ast_manager_event_blob* queue_member_pause_to_ami ( struct stasis_message message)
static

Definition at line 2050 of file app_queue.c.

References queue_member_to_ami().

Referenced by queue_member_ringinuse_to_ami().

2051 {
2052  return queue_member_to_ami("QueueMemberPause", message);
2053 }
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2020

◆ queue_member_penalty_to_ami()

static struct ast_manager_event_blob* queue_member_penalty_to_ami ( struct stasis_message message)
static

Definition at line 2055 of file app_queue.c.

References queue_member_to_ami().

Referenced by queue_member_ringinuse_to_ami().

2056 {
2057  return queue_member_to_ami("QueueMemberPenalty", message);
2058 }
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2020

◆ queue_member_removed_to_ami()

static struct ast_manager_event_blob* queue_member_removed_to_ami ( struct stasis_message message)
static

Definition at line 2045 of file app_queue.c.

References queue_member_to_ami().

Referenced by queue_member_ringinuse_to_ami().

2046 {
2047  return queue_member_to_ami("QueueMemberRemoved", message);
2048 }
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2020

◆ queue_member_ringinuse_to_ami()

static struct ast_manager_event_blob* queue_member_ringinuse_to_ami ( struct stasis_message message)
static

Definition at line 2060 of file app_queue.c.

References queue_member_added_to_ami(), queue_member_pause_to_ami(), queue_member_penalty_to_ami(), queue_member_removed_to_ami(), queue_member_status_to_ami(), queue_member_to_ami(), STASIS_MESSAGE_TYPE_DEFN_LOCAL(), and to_ami().

2061 {
2062  return queue_member_to_ami("QueueMemberRinginuse", message);
2063 }
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2020

◆ queue_member_status_to_ami()

static struct ast_manager_event_blob* queue_member_status_to_ami ( struct stasis_message message)
static

Definition at line 2035 of file app_queue.c.

References queue_member_to_ami().

Referenced by queue_member_ringinuse_to_ami().

2036 {
2037  return queue_member_to_ami("QueueMemberStatus", message);
2038 }
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2020

◆ queue_member_to_ami()

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

Definition at line 2020 of file app_queue.c.

References ast_free, ast_manager_event_blob_create(), ast_manager_str_from_json_object(), ast_str_buffer(), EVENT_FLAG_AGENT, ast_json_payload::json, NULL, RAII_VAR, and stasis_message_data().

Referenced by queue_member_added_to_ami(), queue_member_pause_to_ami(), queue_member_penalty_to_ami(), queue_member_removed_to_ami(), queue_member_ringinuse_to_ami(), and queue_member_status_to_ami().

2021 {
2022  struct ast_json_payload *payload = stasis_message_data(message);
2023  RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2024 
2025  event_string = ast_manager_str_from_json_object(payload->json, NULL);
2026  if (!event_string) {
2027  return NULL;
2028  }
2029 
2031  "%s",
2032  ast_str_buffer(event_string));
2033 }
static const char type[]
Definition: chan_ooh323.c:109
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
struct ast_json * json
Definition: json.h:1025
#define NULL
Definition: resample.c:96
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:9727
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:1821
#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:911
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define EVENT_FLAG_AGENT
Definition: manager.h:76
#define ast_free(a)
Definition: astmm.h:182

◆ queue_multi_channel_to_ami()

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

Definition at line 2084 of file app_queue.c.

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

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

2085 {
2086  struct ast_multi_channel_blob *obj = stasis_message_data(message);
2087  struct ast_channel_snapshot *caller;
2088  struct ast_channel_snapshot *agent;
2089  RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2090  RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2091  RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2092 
2093  caller = ast_multi_channel_blob_get_channel(obj, "caller");
2094  if (caller) {
2095  caller_event_string = ast_manager_build_channel_state_string(caller);
2096  if (!caller_event_string) {
2097  ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2098  return NULL;
2099  }
2100  }
2101 
2102  agent = ast_multi_channel_blob_get_channel(obj, "agent");
2103  if (agent) {
2104  agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2105  if (!agent_event_string) {
2106  ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2107  return NULL;
2108  }
2109  }
2110 
2112  if (!event_string) {
2113  return NULL;
2114  }
2115 
2117  "%s"
2118  "%s"
2119  "%s",
2120  caller_event_string ? ast_str_buffer(caller_event_string) : "",
2121  agent_event_string ? ast_str_buffer(agent_event_string) : "",
2122  ast_str_buffer(event_string));
2123 }
static const char type[]
Definition: chan_ooh323.c:109
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
Structure representing a snapshot of channel state.
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
#define NULL
Definition: resample.c:96
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:9727
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_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:1821
#define ast_log
Definition: astobj2.c:42
#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:911
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
struct ast_channel_snapshot_caller * caller
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define EVENT_FLAG_AGENT
Definition: manager.h:76
#define LOG_NOTICE
Definition: logger.h:263
#define ast_free(a)
Definition: astmm.h:182
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.
A multi channel blob data structure for multi_channel_blob stasis messages.

◆ queue_publish_member_blob()

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

Definition at line 2234 of file app_queue.c.

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

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

2235 {
2236  RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2237  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2238 
2239  if (!blob || !type) {
2240  ast_json_unref(blob);
2241  return;
2242  }
2243 
2244  payload = ast_json_payload_create(blob);
2245  ast_json_unref(blob);
2246  if (!payload) {
2247  return;
2248  }
2249 
2250  msg = stasis_message_create(type, payload);
2251  if (!msg) {
2252  return;
2253  }
2254 
2256 }
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
Definition: json.c:735
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
#define NULL
Definition: resample.c:96
#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:911
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1720
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ queue_publish_multi_channel_blob()

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

Definition at line 2201 of file app_queue.c.

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

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

2203 {
2204  RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2205  RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2206 
2207  ast_channel_lock(caller);
2208  caller_snapshot = ast_channel_snapshot_create(caller);
2209  ast_channel_unlock(caller);
2210  ast_channel_lock(agent);
2211  agent_snapshot = ast_channel_snapshot_create(agent);
2212  ast_channel_unlock(agent);
2213 
2214  if (!caller_snapshot || !agent_snapshot) {
2215  return;
2216  }
2217 
2219  agent_snapshot, type, blob);
2220 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
static void queue_publish_multi_channel_snapshot_blob(struct stasis_topic *topic, struct ast_channel_snapshot *caller_snapshot, struct ast_channel_snapshot *agent_snapshot, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2166
Structure representing a snapshot of channel state.
#define NULL
Definition: resample.c:96
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate...
#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:911
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ queue_publish_multi_channel_snapshot_blob()

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

Definition at line 2166 of file app_queue.c.

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

Referenced by queue_publish_multi_channel_blob(), and send_agent_complete().

2170 {
2171  RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
2172  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2173 
2174  if (!type) {
2175  return;
2176  }
2177 
2178  payload = ast_multi_channel_blob_create(blob);
2179  if (!payload) {
2180  return;
2181  }
2182 
2183  if (caller_snapshot) {
2184  ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
2185  } else {
2186  ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
2187  }
2188 
2189  if (agent_snapshot) {
2190  ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
2191  }
2192 
2193  msg = stasis_message_create(type, payload);
2194  if (!msg) {
2195  return;
2196  }
2197 
2198  stasis_publish(topic, msg);
2199 }
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#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:911
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
A multi channel blob data structure for multi_channel_blob stasis messages.
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.

◆ queue_reset_global_params()

static void queue_reset_global_params ( void  )
static

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

Definition at line 9201 of file app_queue.c.

Referenced by reload_queues().

9202 {
9204  autofill_default = 0;
9205  montype_default = 0;
9206  shared_lastcall = 0;
9209 }
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1487
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1490
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1475
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1472
static int shared_lastcall
queues.conf [general] option
Definition: app_queue.c:1478
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1466

◆ queue_rules_reset_global_params()

static void queue_rules_reset_global_params ( void  )
static

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

Definition at line 9122 of file app_queue.c.

Referenced by reload_queue_rules().

9123 {
9124  realtime_rules = 0;
9125 }
static int realtime_rules
queuesrules.conf [general] option
Definition: app_queue.c:1481

◆ queue_rules_set_global_params()

static void queue_rules_set_global_params ( struct ast_config cfg)
static

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

Definition at line 9128 of file app_queue.c.

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

Referenced by reload_queue_rules().

9129 {
9130  const char *general_val = NULL;
9131  if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9132  realtime_rules = ast_true(general_val);
9133  }
9134 }
#define NULL
Definition: resample.c:96
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
static int realtime_rules
queuesrules.conf [general] option
Definition: app_queue.c:1481

◆ queue_set_global_params()

static void queue_set_global_params ( struct ast_config cfg)
static

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

Definition at line 9212 of file app_queue.c.

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

Referenced by reload_queues().

9213 {
9214  const char *general_val = NULL;
9215  if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
9216  queue_persistent_members = ast_true(general_val);
9217  }
9218  if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
9219  autofill_default = ast_true(general_val);
9220  }
9221  if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
9222  if (!strcasecmp(general_val, "mixmonitor"))
9223  montype_default = 1;
9224  }
9225  if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
9226  shared_lastcall = ast_true(general_val);
9227  }
9228  if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
9229  negative_penalty_invalid = ast_true(general_val);
9230  }
9231  if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
9232  log_membername_as_agent = ast_true(general_val);
9233  }
9234 }
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1487
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1490
#define NULL
Definition: resample.c:96
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1475
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1472
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
static int shared_lastcall
queues.conf [general] option
Definition: app_queue.c:1478
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1466

◆ queue_set_param()

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

Configure a queue parameter.

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

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

Definition at line 3144 of file app_queue.c.

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

Referenced by find_queue_by_name_rt(), and reload_single_queue().

3145 {
3146  if (!strcasecmp(param, "musicclass") ||
3147  !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
3148  ast_string_field_set(q, moh, val);
3149  } else if (!strcasecmp(param, "announce")) {
3150  ast_string_field_set(q, announce, val);
3151  } else if (!strcasecmp(param, "context")) {
3153  } else if (!strcasecmp(param, "timeout")) {
3154  q->timeout = atoi(val);
3155  if (q->timeout < 0) {
3156  q->timeout = DEFAULT_TIMEOUT;
3157  }
3158  } else if (!strcasecmp(param, "ringinuse")) {
3159  q->ringinuse = ast_true(val);
3160  } else if (!strcasecmp(param, "setinterfacevar")) {
3162  } else if (!strcasecmp(param, "setqueuevar")) {
3163  q->setqueuevar = ast_true(val);
3164  } else if (!strcasecmp(param, "setqueueentryvar")) {
3166  } else if (!strcasecmp(param, "monitor-format")) {
3167  ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
3168  } else if (!strcasecmp(param, "membermacro")) {
3169  ast_string_field_set(q, membermacro, val);
3170  } else if (!strcasecmp(param, "membergosub")) {
3171  ast_string_field_set(q, membergosub, val);
3172  } else if (!strcasecmp(param, "queue-youarenext")) {
3173  ast_string_field_set(q, sound_next, val);
3174  } else if (!strcasecmp(param, "queue-thereare")) {
3175  ast_string_field_set(q, sound_thereare, val);
3176  } else if (!strcasecmp(param, "queue-callswaiting")) {
3177  ast_string_field_set(q, sound_calls, val);
3178  } else if (!strcasecmp(param, "queue-quantity1")) {
3179  ast_string_field_set(q, queue_quantity1, val);
3180  } else if (!strcasecmp(param, "queue-quantity2")) {
3181  ast_string_field_set(q, queue_quantity2, val);
3182  } else if (!strcasecmp(param, "queue-holdtime")) {
3183  ast_string_field_set(q, sound_holdtime, val);
3184  } else if (!strcasecmp(param, "queue-minutes")) {
3185  ast_string_field_set(q, sound_minutes, val);
3186  } else if (!strcasecmp(param, "queue-minute")) {
3187  ast_string_field_set(q, sound_minute, val);
3188  } else if (!strcasecmp(param, "queue-seconds")) {
3189  ast_string_field_set(q, sound_seconds, val);
3190  } else if (!strcasecmp(param, "queue-thankyou")) {
3191  ast_string_field_set(q, sound_thanks, val);
3192  } else if (!strcasecmp(param, "queue-callerannounce")) {
3193  ast_string_field_set(q, sound_callerannounce, val);
3194  } else if (!strcasecmp(param, "queue-reporthold")) {
3195  ast_string_field_set(q, sound_reporthold, val);
3196  } else if (!strcasecmp(param, "announce-frequency")) {
3197  q->announcefrequency = atoi(val);
3198  } else if (!strcasecmp(param, "announce-to-first-user")) {
3200  } else if (!strcasecmp(param, "min-announce-frequency")) {
3201  q->minannouncefrequency = atoi(val);
3202  ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
3203  } else if (!strcasecmp(param, "announce-round-seconds")) {
3204  q->roundingseconds = atoi(val);
3205  /* Rounding to any other values just doesn't make sense... */
3206  if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
3207  || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
3208  if (linenum >= 0) {
3209  ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3210  "using 0 instead for queue '%s' at line %d of queues.conf\n",
3211  val, param, q->name, linenum);
3212  } else {
3213  ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3214  "using 0 instead for queue '%s'\n", val, param, q->name);
3215  }
3216  q->roundingseconds=0;
3217  }
3218  } else if (!strcasecmp(param, "announce-holdtime")) {
3219  if (!strcasecmp(val, "once")) {
3221  } else if (ast_true(val)) {
3223  } else {
3224  q->announceholdtime = 0;
3225  }
3226  } else if (!strcasecmp(param, "announce-position")) {
3227  if (!strcasecmp(val, "limit")) {
3229  } else if (!strcasecmp(val, "more")) {
3231  } else if (ast_true(val)) {
3233  } else {
3235  }
3236  } else if (!strcasecmp(param, "announce-position-only-up")) {
3238  } else if (!strcasecmp(param, "announce-position-limit")) {
3239  q->announcepositionlimit = atoi(val);
3240  } else if (!strcasecmp(param, "periodic-announce")) {
3241  if (strchr(val, ',')) {
3242  char *s, *buf = ast_strdupa(val);
3243  unsigned int i = 0;
3244 
3245  while ((s = strsep(&buf, ",|"))) {
3246  if (!q->sound_periodicannounce[i]) {
3248  }
3249  ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
3250  i++;
3251  if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
3252  break;
3253  }
3254  }
3255  q->numperiodicannounce = i;
3256  } else {
3257  ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
3258  q->numperiodicannounce = 1;
3259  }
3260  } else if (!strcasecmp(param, "periodic-announce-frequency")) {
3261  q->periodicannouncefrequency = atoi(val);
3262  } else if (!strcasecmp(param, "relative-periodic-announce")) {
3264  } else if (!strcasecmp(param, "random-periodic-announce")) {
3266  } else if (!strcasecmp(param, "retry")) {
3267  q->retry = atoi(val);
3268  if (q->retry <= 0) {
3269  q->retry = DEFAULT_RETRY;
3270  }
3271  } else if (!strcasecmp(param, "wrapuptime")) {
3272  q->wrapuptime = atoi(val);
3273  } else if (!strcasecmp(param, "penaltymemberslimit")) {
3274  if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
3275  q->penaltymemberslimit = 0;
3276  }
3277  } else if (!strcasecmp(param, "autofill")) {
3278  q->autofill = ast_true(val);
3279  } else if (!strcasecmp(param, "monitor-type")) {
3280  if (!strcasecmp(val, "mixmonitor")) {
3281  q->montype = 1;
3282  }
3283  } else if (!strcasecmp(param, "autopause")) {
3284  q->autopause = autopause2int(val);
3285  } else if (!strcasecmp(param, "autopausedelay")) {
3286  q->autopausedelay = atoi(val);
3287  } else if (!strcasecmp(param, "autopausebusy")) {
3288  q->autopausebusy = ast_true(val);
3289  } else if (!strcasecmp(param, "autopauseunavail")) {
3291  } else if (!strcasecmp(param, "maxlen")) {
3292  q->maxlen = atoi(val);
3293  if (q->maxlen < 0) {
3294  q->maxlen = 0;
3295  }
3296  } else if (!strcasecmp(param, "servicelevel")) {
3297  q->servicelevel= atoi(val);
3298  } else if (!strcasecmp(param, "strategy")) {
3299  int strategy;
3300 
3301  /* We are a static queue and already have set this, no need to do it again */
3302  if (failunknown) {
3303  return;
3304  }
3305  strategy = strat2int(val);
3306  if (strategy < 0) {
3307  ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3308  val, q->name);
3310  }
3311  if (strategy == q->strategy) {
3312  return;
3313  }
3314  if (strategy == QUEUE_STRATEGY_LINEAR) {
3315  ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
3316  return;
3317  }
3318  q->strategy = strategy;
3319  } else if (!strcasecmp(param, "joinempty")) {
3321  } else if (!strcasecmp(param, "leavewhenempty")) {
3323  } else if (!strcasecmp(param, "reportholdtime")) {
3324  q->reportholdtime = ast_true(val);
3325  } else if (!strcasecmp(param, "memberdelay")) {
3326  q->memberdelay = atoi(val);
3327  } else if (!strcasecmp(param, "weight")) {
3328  q->weight = atoi(val);
3329  } else if (!strcasecmp(param, "timeoutrestart")) {
3330  q->timeoutrestart = ast_true(val);
3331  } else if (!strcasecmp(param, "defaultrule")) {
3332  ast_string_field_set(q, defaultrule, val);
3333  } else if (!strcasecmp(param, "timeoutpriority")) {
3334  if (!strcasecmp(val, "conf")) {
3336  } else {
3338  }
3339  } else if (failunknown) {
3340  if (linenum >= 0) {
3341  ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
3342  q->name, param, linenum);
3343  } else {
3344  ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
3345  }
3346  }
3347 }
struct ast_str * sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]
Definition: app_queue.c:1698
int servicelevel
Definition: app_queue.c:1731
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1432
int wrapuptime
Definition: app_queue.c:1737
Definition: ast_expr2.c:325
int penaltymemberslimit
Definition: app_queue.c:1738
unsigned int autopauseunavail
Definition: app_queue.c:1716
unsigned int setqueuevar
Definition: app_queue.c:1703
#define DEFAULT_RETRY
Definition: app_queue.c:1429
#define ANNOUNCEPOSITION_NO
Definition: app_queue.c:1652
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
unsigned int announceposition_only_up
Definition: app_queue.c:1710
int minannouncefrequency
Definition: app_queue.c:1721
#define LOG_WARNING
Definition: logger.h:274
int autopause
Definition: app_queue.c:1743
unsigned int ringinuse
Definition: app_queue.c:1700
unsigned int timeoutrestart
Definition: app_queue.c:1707
unsigned int announceholdtime
Definition: app_queue.c:1708
unsigned int setinterfacevar
Definition: app_queue.c:1702
unsigned int announce_to_first_user
Definition: app_queue.c:1701
char monfmt[8]
Definition: app_queue.c:1733
int announcepositionlimit
Definition: app_queue.c:1719
static int strat2int(const char *strategy)
Definition: app_queue.c:1800
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:1065
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
int periodicannouncefrequency
Definition: app_queue.c:1722
int memberdelay
Definition: app_queue.c:1749
static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
Definition: app_queue.c:3101
unsigned int autopausebusy
Definition: app_queue.c:1715
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int strategy
Definition: app_queue.c:1711
#define ANNOUNCEPOSITION_MORE_THAN
Definition: app_queue.c:1653
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1651
int autopausedelay
Definition: app_queue.c:1744
const ast_string_field name
Definition: app_queue.c:1696
unsigned int reportholdtime
Definition: app_queue.c:1705
int autofill
Definition: app_queue.c:1750
int roundingseconds
Definition: app_queue.c:1725
#define DEFAULT_TIMEOUT
Definition: app_queue.c:1430
int timeoutpriority
Definition: app_queue.c:1745
unsigned int announceposition
Definition: app_queue.c:1709
int randomperiodicannounce
Definition: app_queue.c:1724
#define ANNOUNCEHOLDTIME_ALWAYS
Definition: app_queue.c:1636
unsigned int setqueueentryvar
Definition: app_queue.c:1704
#define ANNOUNCEPOSITION_LIMIT
Definition: app_queue.c:1654
char * strsep(char **str, const char *delims)
int numperiodicannounce
Definition: app_queue.c:1723
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
static int autopause2int(const char *autopause)
Definition: app_queue.c:1813
enum empty_conditions leavewhenempty
Definition: app_queue.c:1718
unsigned int relativeperiodicannounce
Definition: app_queue.c:1714
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
#define ANNOUNCEHOLDTIME_ONCE
Definition: app_queue.c:1637
enum empty_conditions joinempty
Definition: app_queue.c:1717
int announcefrequency
Definition: app_queue.c:1720
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514

◆ queue_show()

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

Definition at line 9974 of file app_queue.c.

References __queues_show(), ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, ast_cli_entry::command, complete_queue_show(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, NULL, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

9975 {
9976  switch ( cmd ) {
9977  case CLI_INIT:
9978  e->command = "queue show";
9979  e->usage =
9980  "Usage: queue show\n"
9981  " Provides summary information on a specified queue.\n";
9982  return NULL;
9983  case CLI_GENERATE:
9984  return complete_queue_show(a->line, a->word, a->pos, a->n);
9985  }
9986 
9987  return __queues_show(NULL, a->fd, a->argc, a->argv);
9988 }
const int argc
Definition: cli.h:160
Definition: cli.h:152
static char * __queues_show(struct mansession *s, int fd, int argc, const char *const *argv)
Show queue(s) status and statistics.
Definition: app_queue.c:9758
#define NULL
Definition: resample.c:96
const char * line
Definition: cli.h:162
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
const char *const * argv
Definition: cli.h:161
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
const char * usage
Definition: cli.h:177
const int pos
Definition: cli.h:164
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:9966

◆ queue_stasis_data_alloc()

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

Definition at line 6026 of file app_queue.c.

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

Referenced by setup_stasis_subs().

6029 {
6030  struct queue_stasis_data *queue_data;
6031 
6032  queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
6033  if (!queue_data) {
6034  return NULL;
6035  }
6036 
6037  if (ast_string_field_init(queue_data, 64)) {
6038  ao2_cleanup(queue_data);
6039  return NULL;
6040  }
6041 
6044  queue_data->queue = queue_ref(qe->parent);
6045  queue_data->starttime = starttime;
6046  queue_data->holdstart = holdstart;
6047  queue_data->callcompletedinsl = callcompletedinsl;
6048  queue_data->caller_pos = qe->opos;
6049  ao2_ref(mem, +1);
6050  queue_data->member = mem;
6051 
6052  return queue_data;
6053 }
static void queue_stasis_data_destructor(void *obj)
Definition: app_queue.c:5994
struct call_queue * parent
Definition: app_queue.c:1561
struct ast_channel * chan
Definition: app_queue.c:1586
#define queue_ref(q)
Definition: app_queue.c:1918
#define NULL
Definition: resample.c:96
struct call_queue * queue
Definition: app_queue.c:5967
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
struct member * member
Definition: app_queue.c:5969
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const ast_string_field member_uniqueid
Definition: app_queue.c:5965
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const ast_string_field caller_uniqueid
Definition: app_queue.c:5965
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:5957
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514

◆ queue_stasis_data_destructor()

static void queue_stasis_data_destructor ( void *  obj)
static

Definition at line 5994 of file app_queue.c.

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

Referenced by queue_stasis_data_alloc().

5995 {
5996  struct queue_stasis_data *queue_data = obj;
5997 
5998  /* This can only happen if refcounts for this object have got severely messed up */
5999  ast_assert(queue_data->bridge_router == NULL);
6000  ast_assert(queue_data->channel_router == NULL);
6001 
6002  ao2_cleanup(queue_data->member);
6003  queue_unref(queue_data->queue);
6004  ast_string_field_free_memory(queue_data);
6005 }
struct stasis_message_router * bridge_router
Definition: app_queue.c:5981
#define queue_unref(q)
Definition: app_queue.c:1919
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
struct call_queue * queue
Definition: app_queue.c:5967
struct member * member
Definition: app_queue.c:5969
struct stasis_message_router * channel_router
Definition: app_queue.c:5983
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:5957
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368

◆ qupd_exec()

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

Update Queue with data of an outgoing call.

Definition at line 11157 of file app_queue.c.

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

Referenced by load_module().

11158 {
11159  int oldtalktime;
11160  char *parse;
11161  struct call_queue *q;
11162  struct member *mem;
11163  int newtalktime = 0;
11164 
11166  AST_APP_ARG(queuename);
11167  AST_APP_ARG(uniqueid);
11168  AST_APP_ARG(agent);
11170  AST_APP_ARG(talktime);
11171  AST_APP_ARG(params););
11172 
11173  if (ast_strlen_zero(data)) {
11174  ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n");
11175  return -1;
11176  }
11177 
11178  parse = ast_strdupa(data);
11179 
11180  AST_STANDARD_APP_ARGS(args, parse);
11181 
11182  if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) {
11183  ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n");
11184  return -1;
11185  }
11186 
11187  if (!ast_strlen_zero(args.talktime)) {
11188  newtalktime = atoi(args.talktime);
11189  }
11190 
11191  q = find_load_queue_rt_friendly(args.queuename);
11192  if (!q) {
11193  ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename);
11194  return 0;
11195  }
11196 
11197  ao2_lock(q);
11198  if (q->members) {
11199  struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
11200  while ((mem = ao2_iterator_next(&mem_iter))) {
11201  if (!strcasecmp(mem->membername, args.agent)) {
11202  if (!strcasecmp(args.status, "ANSWER")) {
11203  oldtalktime = q->talktime;
11204  q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
11205  time(&mem->lastcall);
11206  mem->calls++;
11207  mem->lastqueue = q;
11208  q->callscompleted++;
11209 
11210  if (newtalktime <= q->servicelevel) {
11211  q->callscompletedinsl++;
11212  }
11213  } else {
11214 
11215  time(&mem->lastcall);
11216  q->callsabandoned++;
11217  }
11218 
11219  ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params);
11220  }
11221 
11222  ao2_ref(mem, -1);
11223  }
11224 
11225  ao2_iterator_destroy(&mem_iter);
11226  }
11227 
11228  ao2_unlock(q);
11229  queue_t_unref(q, "Done with temporary pointer");
11230 
11231  return 0;
11232 }
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
const char * args
struct ao2_container * members
Definition: app_queue.c:1752
int callscompletedinsl
Definition: app_queue.c:1732
char membername[80]
Definition: app_queue.c:1598
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
struct call_queue * lastqueue
Definition: app_queue.c:1612
int talktime
Definition: app_queue.c:1727
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
int calls
Definition: app_queue.c:1600
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
int callsabandoned
Definition: app_queue.c:1729
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
int callscompleted
Definition: app_queue.c:1728
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
time_t lastcall
Definition: app_queue.c:1610
jack_status_t status
Definition: app_jack.c:146
#define AST_APP_ARG(name)
Define an application argument.

◆ recalc_holdtime()

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

Definition at line 4128 of file app_queue.c.

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

Referenced by try_calling().

4129 {
4130  int oldvalue;
4131 
4132  /* Calculate holdtime using an exponential average */
4133  /* Thanks to SRT for this contribution */
4134  /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
4135 
4136  ao2_lock(qe->parent);
4137  if ((qe->parent->callscompleted + qe->parent->callsabandoned) == 0) {
4138  qe->parent->holdtime = newholdtime;
4139  } else {
4140  oldvalue = qe->parent->holdtime;
4141  qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
4142  }
4143  ao2_unlock(qe->parent);
4144 }
struct call_queue * parent
Definition: app_queue.c:1561
#define ao2_unlock(a)
Definition: astobj2.h:730
int holdtime
Definition: app_queue.c:1726
#define ao2_lock(a)
Definition: astobj2.h:718
int callsabandoned
Definition: app_queue.c:1729
int callscompleted
Definition: app_queue.c:1728

◆ record_abandoned()

static void record_abandoned ( struct queue_ent qe)
static

Record that a caller gave up on waiting in queue.

Definition at line 4808 of file app_queue.c.

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

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

4809 {
4810  int callabandonedinsl = 0;
4811  time_t now;
4812 
4813  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4814 
4815  pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE");
4816 
4817  set_queue_variables(qe->parent, qe->chan);
4818  ao2_lock(qe->parent);
4819  blob = ast_json_pack("{s: s, s: i, s: i, s: i}",
4820  "Queue", qe->parent->name,
4821  "Position", qe->pos,
4822  "OriginalPosition", qe->opos,
4823  "HoldTime", (int)(time(NULL) - qe->start));
4824 
4825 
4826  time(&now);
4827  callabandonedinsl = ((now - qe->start) <= qe->parent->servicelevel);
4828  if (callabandonedinsl) {
4829  qe->parent->callsabandonedinsl++;
4830  }
4831 
4832  qe->parent->callsabandoned++;
4833  ao2_unlock(qe->parent);
4834 
4835  ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
4836 }
int servicelevel
Definition: app_queue.c:1731
struct call_queue * parent
Definition: app_queue.c:1561
int callsabandonedinsl
Definition: app_queue.c:1730
struct ast_channel * chan
Definition: app_queue.c:1586
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
time_t start
Definition: app_queue.c:1583
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#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:911
#define ao2_lock(a)
Definition: astobj2.h:718
const ast_string_field name
Definition: app_queue.c:1696
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...
int callsabandoned
Definition: app_queue.c:1729
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:1926
Abstract JSON element (object, array, string, int, ...).

◆ reload()

static int reload ( void  )
static

Definition at line 11473 of file app_queue.c.

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

Referenced by find_member_by_queuename_and_interface().

11474 {
11475  struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
11476  ast_unload_realtime("queue_members");
11477  reload_handler(1, &mask, NULL);
11478  return 0;
11479 }
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3406
#define NULL
Definition: resample.c:96
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:9627
#define AST_FLAGS_ALL
Definition: utils.h:196
Structure used to handle boolean flags.
Definition: utils.h:199

◆ reload_handler()

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

The command center for all reload operations.

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

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

Definition at line 9627 of file app_queue.c.

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

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

9628 {
9629  int res = 0;
9630 
9631  if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
9632  res |= reload_queue_rules(reload);
9633  }
9634  if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
9635  res |= clear_stats(queuename);
9636  }
9638  res |= reload_queues(reload, mask, queuename);
9639  }
9640  return res;
9641 }
#define ast_test_flag(p, flag)
Definition: utils.h:63
static int reload(void)
Definition: app_queue.c:11473
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition: app_queue.c:9142
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
Definition: app_queue.c:9540
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
Definition: app_queue.c:9597

◆ reload_queue_members()

static void reload_queue_members ( void  )
static

Reload dynamic queue members persisted into the astdb.

Definition at line 7771 of file app_queue.c.

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

Referenced by load_module().

7772 {
7773  char *cur_ptr;
7774  const char *queue_name;
7775  char *member;
7776  char *interface;
7777  char *membername = NULL;
7778  char *state_interface;
7779  char *penalty_tok;
7780  int penalty = 0;
7781  char *paused_tok;
7782  int paused = 0;
7783  char *wrapuptime_tok;
7784  int wrapuptime = 0;
7785  char *reason_paused;
7786  struct ast_db_entry *db_tree;
7787  struct ast_db_entry *entry;
7788  struct call_queue *cur_queue;
7789  char *queue_data;
7790 
7791  /* Each key in 'pm_family' is the name of a queue */
7792  db_tree = ast_db_gettree(pm_family, NULL);
7793  for (entry = db_tree; entry; entry = entry->next) {
7794 
7795  queue_name = entry->key + strlen(pm_family) + 2;
7796 
7797  {
7798  struct call_queue tmpq = {
7799  .name = queue_name,
7800  };
7801  cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
7802  }
7803 
7804  if (!cur_queue) {
7805  cur_queue = find_load_queue_rt_friendly(queue_name);
7806  }
7807 
7808  if (!cur_queue) {
7809  /* If the queue no longer exists, remove it from the
7810  * database */
7811  ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
7812  ast_db_del(pm_family, queue_name);
7813  continue;
7814  }
7815 
7816  if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
7817  queue_t_unref(cur_queue, "Expire reload reference");
7818  continue;
7819  }
7820 
7821  cur_ptr = queue_data;
7822  while ((member = strsep(&cur_ptr, ",|"))) {
7823  if (ast_strlen_zero(member)) {
7824  continue;
7825  }
7826 
7827  interface = strsep(&member, ";");
7828  penalty_tok = strsep(&member, ";");
7829  paused_tok = strsep(&member, ";");
7830  membername = strsep(&member, ";");
7831  state_interface = strsep(&member, ";");
7832  reason_paused = strsep(&member, ";");
7833  wrapuptime_tok = strsep(&member, ";");
7834 
7835  if (!penalty_tok) {
7836  ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
7837  break;
7838  }
7839  penalty = strtol(penalty_tok, NULL, 10);
7840  if (errno == ERANGE) {
7841  ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
7842  break;
7843  }
7844 
7845  if (!paused_tok) {
7846  ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
7847  break;
7848  }
7849  paused = strtol(paused_tok, NULL, 10);
7850  if ((errno == ERANGE) || paused < 0 || paused > 1) {
7851  ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
7852  break;
7853  }
7854 
7855  if (!ast_strlen_zero(wrapuptime_tok)) {
7856  wrapuptime = strtol(wrapuptime_tok, NULL, 10);
7857  if (errno == ERANGE) {
7858  ast_log(LOG_WARNING, "Error converting wrapuptime: %s: Out of range.\n", wrapuptime_tok);
7859  break;
7860  }
7861  }
7862 
7863  ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s Wrapuptime: %d\n",
7864  queue_name, interface, membername, penalty, paused, reason_paused, wrapuptime);
7865 
7866  if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused, wrapuptime) == RES_OUTOFMEMORY) {
7867  ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
7868  break;
7869  }
7870  }
7871  queue_t_unref(cur_queue, "Expire reload reference");
7872  ast_free(queue_data);
7873  }
7874 
7875  if (db_tree) {
7876  ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
7877  ast_db_freetree(db_tree);
7878  }
7879 }
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
#define OBJ_POINTER
Definition: astobj2.h:1154
#define LOG_WARNING
Definition: logger.h:274
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition: main/db.c:598
int ast_db_get_allocated(const char *family, const char *key, char **out)
Get key value specified by family/key as a heap allocated string.
Definition: main/db.c:422
#define NULL
Definition: resample.c:96
#define RES_OUTOFMEMORY
Definition: app_queue.c:1443
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
struct ast_db_entry * next
Definition: astdb.h:32
static struct ao2_container * queues
Definition: app_queue.c:1766
#define LOG_ERROR
Definition: logger.h:285
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
Definition: main/db.c:531
const ast_string_field name
Definition: app_queue.c:1696
int errno
#define LOG_NOTICE
Definition: logger.h:263
Definition: astdb.h:31
#define ast_free(a)
Definition: astmm.h:182
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
char * strsep(char **str, const char *delims)
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: main/db.c:429
#define ao2_t_find(container, arg, flags, tag)
Definition: astobj2.h:1754
Definition: search.h:40
static const char *const pm_family
Persistent Members astdb family.
Definition: app_queue.c:1463
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:7377
char * key
Definition: astdb.h:33

◆ reload_queue_rules()

static int reload_queue_rules ( int  reload)
static

Reload the rules defined in queuerules.conf.

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

Definition at line 9142 of file app_queue.c.

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

Referenced by reload_handler().

9143 {
9144  struct ast_config *cfg;
9145  struct rule_list *rl_iter, *new_rl;
9146  struct penalty_rule *pr_iter;
9147  char *rulecat = NULL;
9148  struct ast_variable *rulevar = NULL;
9149  struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9150 
9151  if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
9152  ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
9153  return AST_MODULE_LOAD_SUCCESS;
9154  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9155  ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
9156  return AST_MODULE_LOAD_SUCCESS;
9157  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9158  ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
9159  return AST_MODULE_LOAD_SUCCESS;
9160  }
9161 
9163  while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
9164  while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
9165  ast_free(pr_iter);
9166  ast_free(rl_iter);
9167  }
9169  while ((rulecat = ast_category_browse(cfg, rulecat))) {
9170  if (!strcasecmp(rulecat, "general")) {
9172  continue;
9173  }
9174  if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
9176  ast_config_destroy(cfg);
9177  return AST_MODULE_LOAD_DECLINE;
9178  } else {
9179  ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
9180  AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
9181  for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
9182  if(!strcasecmp(rulevar->name, "penaltychange"))
9183  insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
9184  else
9185  ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
9186  }
9187  }
9188 
9189  ast_config_destroy(cfg);
9190 
9193  return AST_MODULE_LOAD_DECLINE;
9194  }
9195 
9197  return AST_MODULE_LOAD_SUCCESS;
9198 }
struct ast_variable * next
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
char name[80]
Definition: app_queue.c:1759
static int reload(void)
Definition: app_queue.c:11473
static void queue_rules_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9128
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define CONFIG_STATUS_FILEINVALID
Structure for variables, used for configurations and for channel variables.
struct rule_list::@71 rules
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition: app_queue.c:2895
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
#define CONFIG_STATUS_FILEUNCHANGED
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define LOG_NOTICE
Definition: logger.h:263
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Structure used to handle boolean flags.
Definition: utils.h:199
static int realtime_rules
queuesrules.conf [general] option
Definition: app_queue.c:1481
static void queue_rules_reset_global_params(void)
Definition: app_queue.c:9122
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
static int load_realtime_rules(void)
Load queue rules from realtime.
Definition: app_queue.c:2999

◆ reload_queues()

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

reload the queues.conf file

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

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

Definition at line 9540 of file app_queue.c.

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

Referenced by reload_handler().

9541 {
9542  struct ast_config *cfg;
9543  char *cat;
9544  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9545  const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
9546 
9547  if (!(cfg = ast_config_load("queues.conf", config_flags))) {
9548  ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
9549  return -1;
9550  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9551  return 0;
9552  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9553  ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
9554  return -1;
9555  }
9556 
9557  /* We've made it here, so it looks like we're doing operations on all queues. */
9558  ao2_lock(queues);
9559 
9560  /* Mark non-realtime queues not found at the beginning. */
9561  ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
9562 
9563  /* Chug through config file. */
9564  cat = NULL;
9566  while ((cat = ast_category_browse(cfg, cat)) ) {
9567  if (!strcasecmp(cat, "general") && queue_reload) {
9569  continue;
9570  }
9571  if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
9572  reload_single_queue(cfg, mask, cat);
9573  }
9574 
9575  ast_config_destroy(cfg);
9576  if (queue_reload) {
9577  /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
9579  }
9580  ao2_unlock(queues);
9581  return 0;
9582 }
#define ast_test_flag(p, flag)
Definition: utils.h:63
static int reload(void)
Definition: app_queue.c:11473
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
#define CONFIG_STATUS_FILEINVALID
static void queue_reset_global_params(void)
Definition: app_queue.c:9201
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
static int mark_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:9506
#define ao2_unlock(a)
Definition: astobj2.h:730
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
static struct ao2_container * queues
Definition: app_queue.c:1766
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define ao2_lock(a)
Definition: astobj2.h:718
static void queue_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9212
#define CONFIG_STATUS_FILEUNCHANGED
#define LOG_ERROR
Definition: logger.h:285
#define LOG_NOTICE
Definition: logger.h:263
Structure used to handle boolean flags.
Definition: utils.h:199
static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
Reload information pertaining to a particular queue.
Definition: app_queue.c:9383
static int kill_if_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:9516

◆ reload_single_member()

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

reload information pertaining to a single member

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

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

Definition at line 9244 of file app_queue.c.

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

Referenced by reload_single_queue().

9245 {
9246  char *membername, *interface, *state_interface, *tmp;
9247  char *parse;
9248  struct member *cur, *newm;
9249  struct member tmpmem;
9250  int penalty;
9251  int ringinuse;
9252  int wrapuptime;
9254  AST_APP_ARG(interface);
9255  AST_APP_ARG(penalty);
9256  AST_APP_ARG(membername);
9257  AST_APP_ARG(state_interface);
9258  AST_APP_ARG(ringinuse);
9259  AST_APP_ARG(wrapuptime);
9260  );
9261 
9262  if (ast_strlen_zero(memberdata)) {
9263  ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
9264  return;
9265  }
9266 
9267  /* Add a new member */
9268  parse = ast_strdupa(memberdata);
9269 
9270  AST_STANDARD_APP_ARGS(args, parse);
9271 
9272  interface = args.interface;
9273  if (!ast_strlen_zero(args.penalty)) {
9274  tmp = args.penalty;
9275  ast_strip(tmp);
9276  penalty = atoi(tmp);
9277  if (penalty < 0) {
9278  penalty = 0;
9279  }
9280  } else {
9281  penalty = 0;
9282  }
9283 
9284  if (!ast_strlen_zero(args.membername)) {
9285  membername = args.membername;
9286  ast_strip(membername);
9287  } else {
9288  membername = interface;
9289  }
9290 
9291  if (!ast_strlen_zero(args.state_interface)) {
9292  state_interface = args.state_interface;
9293  ast_strip(state_interface);
9294  } else {
9295  state_interface = interface;
9296  }
9297 
9298  if (!ast_strlen_zero(args.ringinuse)) {
9299  tmp = args.ringinuse;
9300  ast_strip(tmp);
9301  if (ast_true(tmp)) {
9302  ringinuse = 1;
9303  } else if (ast_false(tmp)) {
9304  ringinuse = 0;
9305  } else {
9306  ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n",
9307  membername, q->name);
9308  ringinuse = q->ringinuse;
9309  }
9310  } else {
9311  ringinuse = q->ringinuse;
9312  }
9313 
9314  if (!ast_strlen_zero(args.wrapuptime)) {
9315  tmp = args.wrapuptime;
9316  ast_strip(tmp);
9317  wrapuptime = atoi(tmp);
9318  if (wrapuptime < 0) {
9319  wrapuptime = 0;
9320  }
9321  } else {
9322  wrapuptime = 0;
9323  }
9324 
9325  /* Find the old position in the list */
9326  ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
9327  cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
9328 
9329  if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface, ringinuse, wrapuptime))) {
9330  newm->wrapuptime = wrapuptime;
9331  if (cur) {
9332  /* Round Robin Queue Position must be copied if this is replacing an existing member */
9333  ao2_lock(q->members);
9334  newm->queuepos = cur->queuepos;
9335  ao2_link(q->members, newm);
9336  ao2_unlink(q->members, cur);
9337  ao2_unlock(q->members);
9338  } else {
9339  /* Otherwise we need to add using the function that will apply a round robin queue position manually. */
9340  member_add_to_queue(q, newm);
9341  }
9342  ao2_ref(newm, -1);
9343  }
9344  newm = NULL;
9345 
9346  if (cur) {
9347  ao2_ref(cur, -1);
9348  }
9349 }
int queuepos
Definition: app_queue.c:1606
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:2686
int paused
Definition: app_queue.c:1604
int wrapuptime
Definition: app_queue.c:1608
#define OBJ_POINTER
Definition: astobj2.h:1154
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
unsigned int ringinuse
Definition: app_queue.c:1700
static int tmp()
Definition: bt_open.c:389
#define ao2_unlock(a)
Definition: astobj2.h:730
const char * args
#define NULL
Definition: resample.c:96
struct ao2_container * members
Definition: app_queue.c:1752
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3360
int penalty
Definition: app_queue.c:1599
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define LOG_ERROR
Definition: logger.h:285
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
const ast_string_field name
Definition: app_queue.c:1696
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
unsigned int ringinuse
Definition: app_queue.c:1616
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ reload_single_queue()

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

Reload information pertaining to a particular queue.

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

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

Definition at line 9383 of file app_queue.c.

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

Referenced by reload_queues().

9384 {
9385  int new;
9386  struct call_queue *q = NULL;
9387  struct member *member;
9388  /*We're defining a queue*/
9389  struct call_queue tmpq = {
9390  .name = queuename,
9391  };
9392  const char *tmpvar;
9393  const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
9394  const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
9395  int prev_weight = 0;
9396  struct ast_variable *var;
9397  struct ao2_iterator mem_iter;
9398 
9399  if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
9400  if (queue_reload) {
9401  /* Make one then */
9402  if (!(q = alloc_queue(queuename))) {
9403  return;
9404  }
9405  } else {
9406  /* Since we're not reloading queues, this means that we found a queue
9407  * in the configuration file which we don't know about yet. Just return.
9408  */
9409  return;
9410  }
9411  new = 1;
9412  } else {
9413  new = 0;
9414  }
9415 
9416  if (!new) {
9417  ao2_lock(q);
9418  prev_weight = q->weight ? 1 : 0;
9419  }
9420  /* Check if we already found a queue with this name in the config file */
9421  if (q->found) {
9422  ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
9423  if (!new) {
9424  /* It should be impossible to *not* hit this case*/
9425  ao2_unlock(q);
9426  }
9427  queue_t_unref(q, "We exist! Expiring temporary pointer");
9428  return;
9429  }
9430  /* Due to the fact that the "linear" strategy will have a different allocation
9431  * scheme for queue members, we must devise the queue's strategy before other initializations.
9432  * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
9433  * container used will have only a single bucket instead of the typical number.
9434  */
9435  if (queue_reload) {
9436  if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
9437  q->strategy = strat2int(tmpvar);
9438  if (q->strategy < 0) {
9439  ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
9440  tmpvar, q->name);
9442  }
9443  } else {
9445  }
9446  init_queue(q);
9447  }
9448  if (member_reload) {
9450  q->found = 1;
9451  }
9452 
9453  /* On the first pass we just read the parameters of the queue */
9454  for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
9455  if (queue_reload && strcasecmp(var->name, "member")) {
9456  queue_set_param(q, var->name, var->value, var->lineno, 1);
9457  }
9458  }
9459 
9460  /* On the second pass, we read members */
9461  for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
9462  if (member_reload && !strcasecmp(var->name, "member")) {
9463  reload_single_member(var->value, q);
9464  }
9465  }
9466 
9467  /* Update ringinuse for dynamic members */
9468  if (member_reload) {
9469  ao2_lock(q->members);
9471  while ((member = ao2_iterator_next(&mem_iter))) {
9472  if (member->dynamic) {
9473  member->ringinuse = q->ringinuse;
9474  }
9475  ao2_ref(member, -1);
9476  }
9477  ao2_iterator_destroy(&mem_iter);
9478  ao2_unlock(q->members);
9479  }
9480 
9481  /* At this point, we've determined if the queue has a weight, so update use_weight
9482  * as appropriate
9483  */
9484  if (!q->weight && prev_weight) {
9486  } else if (q->weight && !prev_weight) {
9488  }
9489 
9490  /* Free remaining members marked as delme */
9491  if (member_reload) {
9492  ao2_lock(q->members);
9495  ao2_unlock(q->members);
9496  }
9497 
9498  if (new) {
9499  queues_t_link(queues, q, "Add queue to container");
9500  } else {
9501  ao2_unlock(q);
9502  }
9503  queue_t_unref(q, "Expiring creation reference");
9504 }
struct ast_variable * next
int dynamic
Definition: app_queue.c:1601
static int mark_member_dead(void *obj, void *arg, int flags)
Definition: app_queue.c:9351
#define ast_test_flag(p, flag)
Definition: utils.h:63
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
#define OBJ_POINTER
Definition: astobj2.h:1154
#define LOG_WARNING
Definition: logger.h:274
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
unsigned int ringinuse
Definition: app_queue.c:1700
static int kill_dead_members(void *obj, void *arg, int flags)
Definition: app_queue.c:9360
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static void reload_single_member(const char *memberdata, struct call_queue *q)
reload information pertaining to a single member
Definition: app_queue.c:9244
#define ao2_unlock(a)
Definition: astobj2.h:730
static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:1887
#define NULL
Definition: resample.c:96
struct ao2_container * members
Definition: app_queue.c:1752
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
static int strat2int(const char *strategy)
Definition: app_queue.c:1800
#define ast_log
Definition: astobj2.c:42
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:3144
static struct ao2_container * queues
Definition: app_queue.c:1766
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
int strategy
Definition: app_queue.c:1711
const ast_string_field name
Definition: app_queue.c:1696
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
static struct call_queue * alloc_queue(const char *queuename)
Definition: app_queue.c:3534
#define queues_t_link(c, q, tag)
Definition: app_queue.c:1922
unsigned int found
Definition: app_queue.c:1713
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
Assume that the ao2_container is already locked.
Definition: astobj2.h:1872
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define ao2_t_find(container, arg, flags, tag)
Definition: astobj2.h:1754
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1469
static void init_queue(struct call_queue *q)
Initialize Queue default values.
Definition: app_queue.c:2769
unsigned int ringinuse
Definition: app_queue.c:1616
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ remove_from_queue()

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

Remove member from queue.

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

Definition at line 7324 of file app_queue.c.

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

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

7325 {
7326  struct call_queue *q, tmpq = {
7327  .name = queuename,
7328  };
7329  struct member *mem, tmpmem;
7330  int res = RES_NOSUCHQUEUE;
7331 
7332  ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7333  if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
7334  ao2_lock(q);
7335  if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
7336  /* XXX future changes should beware of this assumption!! */
7337  /*Change Penalty on realtime users*/
7339  update_realtime_member_field(mem, q->name, "penalty", "-1");
7340  } else if (!mem->dynamic) {
7341  ao2_ref(mem, -1);
7342  ao2_unlock(q);
7343  queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
7344  return RES_NOT_DYNAMIC;
7345  }
7346  queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
7347 
7348  member_remove_from_queue(q, mem);
7349  ao2_ref(mem, -1);
7350 
7352  dump_queue_members(q);
7353  }
7354 
7355  if (!num_available_members(q)) {
7357  }
7358 
7359  res = RES_OKAY;
7360  } else {
7361  res = RES_EXISTS;
7362  }
7363  ao2_unlock(q);
7364  queue_t_unref(q, "Expiring temporary reference");
7365  }
7366 
7367  return res;
7368 }
int dynamic
Definition: app_queue.c:1601
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:3757
#define RES_OKAY
Definition: app_queue.c:1441
#define OBJ_POINTER
Definition: astobj2.h:1154
static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3376
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1487
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1445
int realtime
Definition: app_queue.c:1602
#define ao2_unlock(a)
Definition: astobj2.h:730
struct ao2_container * members
Definition: app_queue.c:1752
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_strlen_zero(foo)
Definition: strings.h:52
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
static struct ao2_container * queues
Definition: app_queue.c:1766
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:4290
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2258
const ast_string_field name
Definition: app_queue.c:1696
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:7269
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1444
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char rt_uniqueid[80]
Definition: app_queue.c:1615
#define ao2_t_find(container, arg, flags, tag)
Definition: astobj2.h:1754
#define RES_EXISTS
Definition: app_queue.c:1442
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1466
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2234

◆ remove_stasis_subscriptions()

static void remove_stasis_subscriptions ( struct queue_stasis_data queue_data)
static

Definition at line 6011 of file app_queue.c.

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

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

6012 {
6013  SCOPED_AO2LOCK(lock, queue_data);
6014 
6015  queue_data->dying = 1;
6017  queue_data->bridge_router = NULL;
6019  queue_data->channel_router = NULL;
6020 }
struct stasis_message_router * bridge_router
Definition: app_queue.c:5981
#define NULL
Definition: resample.c:96
ast_mutex_t lock
Definition: app_meetme.c:1091
struct stasis_message_router * channel_router
Definition: app_queue.c:5983
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:602
void stasis_message_router_unsubscribe(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic.

◆ ring_entry()

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

Part 2 of ring_one.

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

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

Definition at line 4478 of file app_queue.c.

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

Referenced by ring_one().

4479 {
4480  int res;
4481  int status;
4482  char tech[256];
4483  char *location;
4484  const char *macrocontext, *macroexten;
4485  struct ast_format_cap *nativeformats;
4486  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4487 
4488  /* on entry here, we know that tmp->chan == NULL */
4489  if (!can_ring_entry(qe, tmp)) {
4490  tmp->stillgoing = 0;
4491  ++*busies;
4492  return 0;
4493  }
4494 
4495  ast_copy_string(tech, tmp->interface, sizeof(tech));
4496  if ((location = strchr(tech, '/'))) {
4497  *location++ = '\0';
4498  } else {
4499  location = "";
4500  }
4501 
4502  ast_channel_lock(qe->chan);
4503  nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
4504  ast_channel_unlock(qe->chan);
4505 
4506  /* Request the peer */
4507  tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
4508  ao2_cleanup(nativeformats);
4509  if (!tmp->chan) { /* If we can't, just go on to the next call */
4510  ao2_lock(qe->parent);
4511  qe->parent->rrpos++;
4512  qe->linpos++;
4513  ao2_unlock(qe->parent);
4514 
4516 
4517  publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
4518  tmp->stillgoing = 0;
4519  ++*busies;
4520  return 0;
4521  }
4522 
4523  ast_channel_lock_both(tmp->chan, qe->chan);
4524 
4527  if (qe->cancel_answered_elsewhere) {
4529  }
4530  ast_channel_appl_set(tmp->chan, "AppQueue");
4531  ast_channel_data_set(tmp->chan, "(Outgoing Line)");
4532  memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
4533 
4534  /* If the new channel has no callerid, try to guess what it should be */
4535  if (!ast_channel_caller(tmp->chan)->id.number.valid) {
4537  struct ast_party_caller caller;
4538 
4540  caller.id = ast_channel_connected(qe->chan)->id;
4541  caller.ani = ast_channel_connected(qe->chan)->ani;
4542  ast_channel_set_caller_event(tmp->chan, &caller, NULL);
4543  } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
4547  }
4548  tmp->dial_callerid_absent = 1;
4549  }
4550 
4552 
4554 
4556 
4557  /* Inherit specially named variables from parent channel */
4561 
4562  /* Presense of ADSI CPE on outgoing channel follows ours */
4564 
4565  /* Inherit context and extension */
4566  macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
4567  ast_channel_dialcontext_set(tmp->chan, ast_strlen_zero(macrocontext) ? ast_channel_context(qe->chan) : macrocontext);
4568  macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
4569  if (!ast_strlen_zero(macroexten)) {
4570  ast_channel_exten_set(tmp->chan, macroexten);
4571  } else {
4573  }
4574 
4575  /* Save the original channel name to detect call pickup masquerading in. */
4577 
4578  ast_channel_unlock(tmp->chan);
4579  ast_channel_unlock(qe->chan);
4580 
4581  /* PREDIAL: Run gosub on the callee's channel */
4582  if (qe->predial_callee) {
4583  ast_pre_call(tmp->chan, qe->predial_callee);
4584  }
4585 
4586  /* Place the call, but don't wait on the answer */
4587  if ((res = ast_call(tmp->chan, location, 0))) {
4588  /* Again, keep going even if there's an error */
4589  ast_verb(3, "Couldn't call %s\n", tmp->interface);
4590  do_hang(tmp);
4591  ++*busies;
4592  return 0;
4593  }
4594 
4595  ast_channel_lock_both(tmp->chan, qe->chan);
4596 
4597  blob = ast_json_pack("{s: s, s: s, s: s}",
4598  "Queue", qe->parent->name,
4599  "Interface", tmp->interface,
4600  "MemberName", tmp->member->membername);
4601  queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
4602 
4603  ast_channel_publish_dial(qe->chan, tmp->chan, tmp->interface, NULL);
4604 
4605  ast_channel_unlock(tmp->chan);
4606  ast_channel_unlock(qe->chan);
4607 
4608  ast_verb(3, "Called %s\n", tmp->interface);
4609 
4610  return 1;
4611 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition: channel.c:7434
struct call_queue * parent
Definition: app_queue.c:1561
#define ast_channel_lock(chan)
Definition: channel.h:2945
void ast_channel_req_accountcodes_precious(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition: channel.c:6531
struct ast_party_dialed::@246 number
Dialed/Called number.
char * str
Subscriber phone number (Malloced)
Definition: channel.h:387
void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update)
Set the caller id information in the Asterisk channel and generate an AMI event if the caller id name...
Definition: channel.c:7472
struct ast_channel * chan
Definition: app_queue.c:1586
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
struct ast_party_id id
Connected party ID.
Definition: channel.h:459
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
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...
void ast_channel_appl_set(struct ast_channel *chan, const char *value)
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6553
char interface[256]
Definition: app_queue.c:1541
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition: app_queue.c:4388
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2426
#define ast_verb(level,...)
Definition: logger.h:463
char membername[80]
Definition: app_queue.c:1598
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6444
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
#define ao2_bump(obj)
Definition: astobj2.h:491
struct ast_party_id id
Caller party ID.
Definition: channel.h:421
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2373
const char * predial_callee
Definition: app_queue.c:1566
#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:911
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition: causes.h:113
Caller Party information.
Definition: channel.h:419
#define ao2_lock(a)
Definition: astobj2.h:718
struct member * member
Definition: app_queue.c:1543
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:466
int linpos
Definition: app_queue.c:1581
int ast_pre_call(struct ast_channel *chan, const char *sub_args)
Execute a Gosub call on the channel before a call is placed.
Definition: channel.c:6536
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
const char * ast_channel_exten(const struct ast_channel *chan)
void ast_party_caller_set_init(struct ast_party_caller *init, const struct ast_party_caller *guide)
Initialize the given caller structure using the given guide for a set update operation.
Definition: channel.c:1999
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
char * orig_chan_name
Definition: app_queue.c:1556
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition: app_queue.c:4238
const ast_string_field name
Definition: app_queue.c:1696
ast_channel_adsicpe
Definition: channel.h:869
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
Definition: channel.c:6866
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2201
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2952
int transit_network_select
Transit Network Select.
Definition: channel.h:398
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Definition: max_forwards.c:135
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition: channel.c:8389
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
Abstract JSON element (object, array, string, int, ...).
const char * ast_channel_context(const struct ast_channel *chan)
static void do_hang(struct callattempt *o)
common hangup actions
Definition: app_queue.c:4358
int cancel_answered_elsewhere
Definition: app_queue.c:1585
unsigned int dial_callerid_absent
Definition: app_queue.c:1551
struct ast_channel * chan
Definition: app_queue.c:1540
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
unsigned int stillgoing
Definition: app_queue.c:1553
const char * ast_channel_macroexten(const struct ast_channel *chan)
void ast_channel_data_set(struct ast_channel *chan, const char *value)
void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
Copy the source redirecting information to the destination redirecting.
Definition: channel.c:2135
jack_status_t status
Definition: app_jack.c:146
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343

◆ ring_one()

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

Place a call to a queue member.

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

Return values
1if a member was called successfully
0otherwise

Definition at line 4639 of file app_queue.c.

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

Referenced by try_calling(), and wait_for_answer().

4640 {
4641  int ret = 0;
4642  struct callattempt *cur;
4643 
4644  if (qe->predial_callee) {
4646  for (cur = outgoing; cur; cur = cur->q_next) {
4647  if (cur->stillgoing && cur->chan) {
4649  }
4650  }
4651  }
4652 
4653  while (ret == 0) {
4654  struct callattempt *best = find_best(outgoing);
4655  if (!best) {
4656  ast_debug(1, "Nobody left to try ringing in queue\n");
4657  break;
4658  }
4659  if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
4660  /* Ring everyone who shares this best metric (for ringall) */
4661  for (cur = outgoing; cur; cur = cur->q_next) {
4662  if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
4663  ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
4664  ret |= ring_entry(qe, cur, busies);
4665  if (qe->predial_callee && cur->chan) {
4667  }
4668  }
4669  }
4670  } else {
4671  /* Ring just the best channel */
4672  ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
4673  ret = ring_entry(qe, best, busies);
4674  if (qe->predial_callee && best->chan) {
4675  ast_autoservice_start(best->chan);
4676  }
4677  }
4678 
4679  /* If we have timed out, break out */
4680  if (qe->expire && (time(NULL) >= qe->expire)) {
4681  ast_debug(1, "Queue timed out while ringing members.\n");
4682  ret = 0;
4683  break;
4684  }
4685  }
4686  if (qe->predial_callee) {
4687  for (cur = outgoing; cur; cur = cur->q_next) {
4688  if (cur->stillgoing && cur->chan) {
4689  ast_autoservice_stop(cur->chan);
4690  }
4691  }
4693  }
4694 
4695  return ret;
4696 }
struct callattempt * q_next
Definition: app_queue.c:1538
struct call_queue * parent
Definition: app_queue.c:1561
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
struct ast_channel * chan
Definition: app_queue.c:1586
time_t expire
Definition: app_queue.c:1584
char interface[256]
Definition: app_queue.c:1541
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
const char * predial_callee
Definition: app_queue.c:1566
static struct callattempt * find_best(struct callattempt *outgoing)
find the entry with the best metric, or NULL
Definition: app_queue.c:4614
int strategy
Definition: app_queue.c:1711
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
Part 2 of ring_one.
Definition: app_queue.c:4478
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1537
struct ast_channel * chan
Definition: app_queue.c:1540
unsigned int stillgoing
Definition: app_queue.c:1553

◆ rna()

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

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

Definition at line 4839 of file app_queue.c.

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

Referenced by wait_for_answer().

4840 {
4841  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4842 
4843  ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
4844 
4845  /* Stop ringing, and resume MOH if specified */
4846  if (qe->ring_when_ringing) {
4847  ast_indicate(qe->chan, -1);
4848  ast_moh_start(qe->chan, qe->moh, NULL);
4849  }
4850 
4851  blob = ast_json_pack("{s: s, s: s, s: s, s: i}",
4852  "Queue", qe->parent->name,
4853  "Interface", interface,
4854  "MemberName", membername,
4855  "RingTime", rnatime);
4856  queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_ringnoanswer_type(), blob);
4857 
4858  ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime);
4859  if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && autopause) {
4860  if (qe->parent->autopausedelay > 0) {
4861  struct member *mem;
4862  ao2_lock(qe->parent);
4863  if ((mem = interface_exists(qe->parent, interface))) {
4864  time_t idletime = time(&idletime)-mem->lastcall;
4865  if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
4866  ao2_unlock(qe->parent);
4867  ao2_ref(mem, -1);
4868  return;
4869  }
4870  ao2_ref(mem, -1);
4871  }
4872  ao2_unlock(qe->parent);
4873  }
4874  if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
4875  if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
4876  ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
4877  interface, qe->parent->name);
4878  } else {
4879  ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
4880  }
4881  } else {
4882  /* If queue autopause is mode all, just don't send any queue to stop.
4883  * the function will stop in all queues */
4884  if (!set_member_paused("", interface, "Auto-Pause", 1)) {
4885  ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
4886  interface, qe->parent->name);
4887  } else {
4888  ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
4889  }
4890  }
4891  }
4892  return;
4893 }
struct call_queue * parent
Definition: app_queue.c:1561
struct ast_channel * chan
Definition: app_queue.c:1586
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4322
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
int autopause
Definition: app_queue.c:1743
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
char interface[256]
Definition: app_queue.c:1541
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ast_verb(level,...)
Definition: logger.h:463
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#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:911
int ring_when_ringing
Definition: app_queue.c:1571
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7242
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1562
const char * ast_channel_uniqueid(const struct ast_channel *chan)
int autopausedelay
Definition: app_queue.c:1744
const ast_string_field name
Definition: app_queue.c:1696
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7866
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:7528
static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2201
Abstract JSON element (object, array, string, int, ...).
time_t lastcall
Definition: app_queue.c:1610

◆ rqm_exec()

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

RemoveQueueMember application.

Definition at line 7954 of file app_queue.c.

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

Referenced by load_module().

7955 {
7956  int res=-1;
7957  char *parse, *temppos = NULL;
7958  struct member *mem = NULL;
7959 
7961  AST_APP_ARG(queuename);
7963  );
7964 
7965 
7966  if (ast_strlen_zero(data)) {
7967  ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
7968  return -1;
7969  }
7970 
7971  parse = ast_strdupa(data);
7972 
7973  AST_STANDARD_APP_ARGS(args, parse);
7974 
7975  if (ast_strlen_zero(args.interface)) {
7976  args.interface = ast_strdupa(ast_channel_name(chan));
7977  temppos = strrchr(args.interface, '-');
7978  if (temppos) {
7979  *temppos = '\0';
7980  }
7981  }
7982 
7983  ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
7984 
7986  mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
7987  }
7988 
7989  switch (remove_from_queue(args.queuename, args.interface)) {
7990  case RES_OKAY:
7991  if (!mem || ast_strlen_zero(mem->membername)) {
7992  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
7993  } else {
7994  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
7995  }
7996  ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
7997  pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
7998  res = 0;
7999  break;
8000  case RES_EXISTS:
8001  ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
8002  pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
8003  res = 0;
8004  break;
8005  case RES_NOSUCHQUEUE:
8006  ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
8007  pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
8008  res = 0;
8009  break;
8010  case RES_NOT_DYNAMIC:
8011  ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
8012  pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
8013  res = 0;
8014  break;
8015  }
8016 
8017  if (mem) {
8018  ao2_ref(mem, -1);
8019  }
8020 
8021  return res;
8022 }
#define RES_OKAY
Definition: app_queue.c:1441
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1445
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1490
const char * args
#define NULL
Definition: resample.c:96
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static struct member * find_member_by_queuename_and_interface(const char *queuename, const char *interface)
Definition: app_queue.c:11484
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define LOG_NOTICE
Definition: logger.h:263
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
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...
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1444
const char * ast_channel_name(const struct ast_channel *chan)
#define RES_EXISTS
Definition: app_queue.c:1442
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:7324
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ rt_handle_member_record()

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

Find rt member record to update otherwise create one.

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

Definition at line 3392 of file app_queue.c.

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

Referenced by find_queue_by_name_rt(), and update_realtime_members().

3393 {
3394  struct member *m;
3395  struct ao2_iterator mem_iter;
3396  int penalty = 0;
3397  int paused = 0;
3398  int found = 0;
3399  int wrapuptime = 0;
3400  int ringinuse = q->ringinuse;
3401 
3402  const char *config_val;
3403  const char *interface = ast_variable_retrieve(member_config, category, "interface");
3404  const char *rt_uniqueid = ast_variable_retrieve(member_config, category, "uniqueid");
3405  const char *membername = S_OR(ast_variable_retrieve(member_config, category, "membername"), interface);
3406  const char *state_interface = S_OR(ast_variable_retrieve(member_config, category, "state_interface"), interface);
3407  const char *penalty_str = ast_variable_retrieve(member_config, category, "penalty");
3408  const char *paused_str = ast_variable_retrieve(member_config, category, "paused");
3409  const char *wrapuptime_str = ast_variable_retrieve(member_config, category, "wrapuptime");
3410 
3411  if (ast_strlen_zero(rt_uniqueid)) {
3412  ast_log(LOG_WARNING, "Realtime field 'uniqueid' is empty for member %s\n",
3413  S_OR(membername, "NULL"));
3414  return;
3415  }
3416 
3417  if (ast_strlen_zero(interface)) {
3418  ast_log(LOG_WARNING, "Realtime field 'interface' is empty for member %s\n",
3419  S_OR(membername, "NULL"));
3420  return;
3421  }
3422 
3423  if (penalty_str) {
3424  penalty = atoi(penalty_str);
3425  if ((penalty < 0) && negative_penalty_invalid) {
3426  return;
3427  } else if (penalty < 0) {
3428  penalty = 0;
3429  }
3430  }
3431 
3432  if (paused_str) {
3433  paused = atoi(paused_str);
3434  if (paused < 0) {
3435  paused = 0;
3436  }
3437  }
3438 
3439  if (wrapuptime_str) {
3440  wrapuptime = atoi(wrapuptime_str);
3441  if (wrapuptime < 0) {
3442  wrapuptime = 0;
3443  }
3444  }
3445 
3446  if ((config_val = ast_variable_retrieve(member_config, category, realtime_ringinuse_field))) {
3447  if (ast_true(config_val)) {
3448  ringinuse = 1;
3449  } else if (ast_false(config_val)) {
3450  ringinuse = 0;
3451  } else {
3452  ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name);
3453  }
3454  }
3455 
3456  /* Find member by realtime uniqueid and update */
3457  mem_iter = ao2_iterator_init(q->members, 0);
3458  while ((m = ao2_iterator_next(&mem_iter))) {
3459  if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
3460  m->dead = 0; /* Do not delete this one. */
3461  ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3462  if (paused_str) {
3463  m->paused = paused;
3464  if (paused && m->lastpause == 0) {
3465  time(&m->lastpause); /* XXX: Should this come from realtime? */
3466  }
3468  AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, m->interface);
3469  }
3470  if (strcasecmp(state_interface, m->state_interface)) {
3471  ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
3472  }
3473  m->penalty = penalty;
3474  m->ringinuse = ringinuse;
3475  m->wrapuptime = wrapuptime;
3476  found = 1;
3477  ao2_ref(m, -1);
3478  break;
3479  }
3480  ao2_ref(m, -1);
3481  }
3482  ao2_iterator_destroy(&mem_iter);
3483 
3484  /* Create a new member */
3485  if (!found) {
3486  if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
3487  m->dead = 0;
3488  m->realtime = 1;
3489  ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3490  if (!log_membername_as_agent) {
3491  ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3492  } else {
3493  ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3494  }
3495  member_add_to_queue(q, m);
3496  ao2_ref(m, -1);
3497  m = NULL;
3498  }
3499  }
3500 }
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:2686
int paused
Definition: app_queue.c:1604
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1596
int wrapuptime
Definition: app_queue.c:1608
#define LOG_WARNING
Definition: logger.h:274
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1487
unsigned int ringinuse
Definition: app_queue.c:1700
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1490
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int realtime
Definition: app_queue.c:1602
unsigned int dead
Definition: app_queue.c:1613
#define NULL
Definition: resample.c:96
struct ao2_container * members
Definition: app_queue.c:1752
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_strlen_zero(foo)
Definition: strings.h:52
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition: app_queue.c:1493
#define ast_log
Definition: astobj2.c:42
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3360
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
time_t lastpause
Definition: app_queue.c:1611
int penalty
Definition: app_queue.c:1599
#define QUEUE_PAUSED_DEVSTATE
Definition: app_queue.c:3350
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
#define QUEUE_UNPAUSED_DEVSTATE
Definition: app_queue.c:3351
const ast_string_field name
Definition: app_queue.c:1696
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char rt_uniqueid[80]
Definition: app_queue.c:1615
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
unsigned int ringinuse
Definition: app_queue.c:1616
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ say_periodic_announcement()

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

Playback announcement to queued members if period has elapsed.

Definition at line 4747 of file app_queue.c.

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

Referenced by queue_exec(), and wait_our_turn().

4748 {
4749  int res = 0;
4750  time_t now;
4751 
4752  /* Get the current time */
4753  time(&now);
4754 
4755  /* Check to see if it is time to announce */
4757  return 0;
4758  }
4759 
4760  /* Stop the music on hold so we can play our own file */
4761  if (ringing) {
4762  ast_indicate(qe->chan,-1);
4763  } else {
4764  ast_moh_stop(qe->chan);
4765  }
4766 
4767  ast_verb(3, "Playing periodic announcement\n");
4768 
4770  qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
4771  } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce ||
4774  }
4775 
4776  /* play the announcement */
4778 
4779  if (res > 0 && !valid_exit(qe, res)) {
4780  res = 0;
4781  }
4782 
4783  /* Resume Music on Hold if the caller is going to stay in the queue */
4784  if (!res) {
4785  if (ringing) {
4787  } else {
4788  ast_moh_start(qe->chan, qe->moh, NULL);
4789  }
4790  }
4791 
4792  /* update last_periodic_announce_time */
4793  if (qe->parent->relativeperiodicannounce) {
4794  time(&qe->last_periodic_announce_time);
4795  } else {
4796  qe->last_periodic_announce_time = now;
4797  }
4798 
4799  /* Update the current periodic announcement to the next announcement */
4800  if (!qe->parent->randomperiodicannounce) {
4802  }
4803 
4804  return res;
4805 }
struct ast_str * sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]
Definition: app_queue.c:1698
struct call_queue * parent
Definition: app_queue.c:1561
struct ast_channel * chan
Definition: app_queue.c:1586
int last_periodic_announce_sound
Definition: app_queue.c:1573
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4322
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define NULL
Definition: resample.c:96
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7876
#define ast_verb(level,...)
Definition: logger.h:463
int periodicannouncefrequency
Definition: app_queue.c:1722
static void ringing(struct ast_channel *chan)
Helper method to send a ringing indication to a channel in a bridge.
long int ast_random(void)
Definition: main/utils.c:2064
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1562
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7866
static int play_file(struct ast_channel *chan, const char *filename)
Definition: app_queue.c:3916
int randomperiodicannounce
Definition: app_queue.c:1724
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
int numperiodicannounce
Definition: app_queue.c:1723
time_t last_periodic_announce_time
Definition: app_queue.c:1572
unsigned int relativeperiodicannounce
Definition: app_queue.c:1714
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:3945

◆ say_position()

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

Definition at line 3980 of file app_queue.c.

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

Referenced by queue_exec(), and wait_our_turn().

3981 {
3982  int res = 0, announceposition = 0;
3983  long avgholdmins, avgholdsecs;
3984  int say_thanks = 1;
3985  time_t now;
3986 
3987  /* Let minannouncefrequency seconds pass between the start of each position announcement */
3988  time(&now);
3989  if ((now - qe->last_pos) < qe->parent->minannouncefrequency) {
3990  return 0;
3991  }
3992 
3993  /* If either our position has changed, or we are over the freq timer, say position */
3994  if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) {
3995  return 0;
3996  }
3997 
3998  /* Only announce if the caller's queue position has improved since last time */
3999  if (qe->parent->announceposition_only_up && qe->last_pos_said <= qe->pos) {
4000  return 0;
4001  }
4002 
4003  if (ringing) {
4004  ast_indicate(qe->chan,-1);
4005  } else {
4006  ast_moh_stop(qe->chan);
4007  }
4008 
4012  qe->pos <= qe->parent->announcepositionlimit)) {
4013  announceposition = 1;
4014  }
4015 
4016 
4017  if (announceposition == 1) {
4018  /* Say we're next, if we are */
4019  if (qe->pos == 1) {
4020  res = play_file(qe->chan, qe->parent->sound_next);
4021  if (!res) {
4022  goto posout;
4023  }
4024  /* Say there are more than N callers */
4026  res = (
4027  play_file(qe->chan, qe->parent->queue_quantity1) ||
4029  ast_channel_language(qe->chan), NULL) || /* Needs gender */
4030  play_file(qe->chan, qe->parent->queue_quantity2));
4031  /* Say there are currently N callers waiting */
4032  } else {
4033  res = (
4034  play_file(qe->chan, qe->parent->sound_thereare) ||
4036  ast_channel_language(qe->chan), NULL) || /* Needs gender */
4037  play_file(qe->chan, qe->parent->sound_calls));
4038  }
4039  if (res) {
4040  goto playout;
4041  }
4042  }
4043  /* Round hold time to nearest minute */
4044  avgholdmins = labs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
4045 
4046  /* If they have specified a rounding then round the seconds as well */
4047  if (qe->parent->roundingseconds) {
4048  avgholdsecs = (labs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
4049  avgholdsecs *= qe->parent->roundingseconds;
4050  } else {
4051  avgholdsecs = 0;
4052  }
4053 
4054  ast_verb(3, "Hold time for %s is %ld minute(s) %ld seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
4055 
4056  /* If the hold time is >1 min, if it's enabled, and if it's not
4057  supposed to be only once and we have already said it, say it */
4058  if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
4061  res = play_file(qe->chan, qe->parent->sound_holdtime);
4062  if (res) {
4063  goto playout;
4064  }
4065 
4066  if (avgholdmins >= 1) {
4067  res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL);
4068  if (res) {
4069  goto playout;
4070  }
4071 
4072  if (avgholdmins == 1) {
4073  res = play_file(qe->chan, qe->parent->sound_minute);
4074  if (res) {
4075  goto playout;
4076  }
4077  } else {
4078  res = play_file(qe->chan, qe->parent->sound_minutes);
4079  if (res) {
4080  goto playout;
4081  }
4082  }
4083  }
4084  if (avgholdsecs >= 1) {
4085  res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL);
4086  if (res) {
4087  goto playout;
4088  }
4089 
4090  res = play_file(qe->chan, qe->parent->sound_seconds);
4091  if (res) {
4092  goto playout;
4093  }
4094  }
4095  } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
4096  say_thanks = 0;
4097  }
4098 
4099 posout:
4100  if (qe->parent->announceposition) {
4101  ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
4102  ast_channel_name(qe->chan), qe->parent->name, qe->pos);
4103  }
4104  if (say_thanks) {
4105  res = play_file(qe->chan, qe->parent->sound_thanks);
4106  }
4107 playout:
4108 
4109  if ((res > 0 && !valid_exit(qe, res))) {
4110  res = 0;
4111  }
4112 
4113  /* Set our last_pos indicators */
4114  qe->last_pos = now;
4115  qe->last_pos_said = qe->pos;
4116 
4117  /* Don't restart music on hold if we're about to exit the caller from the queue */
4118  if (!res) {
4119  if (ringing) {
4121  } else {
4122  ast_moh_start(qe->chan, qe->moh, NULL);
4123  }
4124  }
4125  return res;
4126 }
struct call_queue * parent
Definition: app_queue.c:1561
const ast_string_field sound_holdtime
Definition: app_queue.c:1696
struct ast_channel * chan
Definition: app_queue.c:1586
#define AST_DIGIT_ANY
Definition: file.h:48
time_t start
Definition: app_queue.c:1583
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4322
unsigned int announceposition_only_up
Definition: app_queue.c:1710
int minannouncefrequency
Definition: app_queue.c:1721
int last_pos_said
Definition: app_queue.c:1570
unsigned int announceholdtime
Definition: app_queue.c:1708
#define NULL
Definition: resample.c:96
const ast_string_field sound_thanks
Definition: app_queue.c:1696
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7876
#define ast_verb(level,...)
Definition: logger.h:463
int announcepositionlimit
Definition: app_queue.c:1719
int holdtime
Definition: app_queue.c:1726
const ast_string_field sound_minute
Definition: app_queue.c:1696
const ast_string_field sound_thereare
Definition: app_queue.c:1696
static void ringing(struct ast_channel *chan)
Helper method to send a ringing indication to a channel in a bridge.
const ast_string_field sound_next
Definition: app_queue.c:1696
#define ANNOUNCEPOSITION_MORE_THAN
Definition: app_queue.c:1653
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1562
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1651
const ast_string_field name
Definition: app_queue.c:1696
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7866
time_t last_pos
Definition: app_queue.c:1574
int roundingseconds
Definition: app_queue.c:1725
static int play_file(struct ast_channel *chan, const char *filename)
Definition: app_queue.c:3916
const ast_string_field sound_seconds
Definition: app_queue.c:1696
unsigned int announceposition
Definition: app_queue.c:1709
#define ANNOUNCEPOSITION_LIMIT
Definition: app_queue.c:1654
const ast_string_field sound_calls
Definition: app_queue.c:1696
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition: channel.c:8337
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_language(const struct ast_channel *chan)
const ast_string_field sound_minutes
Definition: app_queue.c:1696
const ast_string_field queue_quantity2
Definition: app_queue.c:1696
#define ANNOUNCEHOLDTIME_ONCE
Definition: app_queue.c:1637
const ast_string_field queue_quantity1
Definition: app_queue.c:1696
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:3945
int announcefrequency
Definition: app_queue.c:1720

◆ send_agent_complete()

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

Send out AMI message with member call completion status information.

Definition at line 5864 of file app_queue.c.

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

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

5867 {
5868  const char *reason = NULL; /* silence dumb compilers */
5869  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5870 
5871  switch (rsn) {
5872  case CALLER:
5873  reason = "caller";
5874  break;
5875  case AGENT:
5876  reason = "agent";
5877  break;
5878  case TRANSFER:
5879  reason = "transfer";
5880  break;
5881  }
5882 
5883  blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
5884  "Queue", queuename,
5885  "Interface", member->interface,
5886  "MemberName", member->membername,
5887  "HoldTime", (ast_json_int_t)(callstart - holdstart),
5888  "TalkTime", (ast_json_int_t)(time(NULL) - callstart),
5889  "Reason", reason ?: "");
5890 
5892  queue_agent_complete_type(), blob);
5893 }
static void queue_publish_multi_channel_snapshot_blob(struct stasis_topic *topic, struct ast_channel_snapshot *caller_snapshot, struct ast_channel_snapshot *agent_snapshot, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2166
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87
#define NULL
Definition: resample.c:96
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#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:911
Abstract JSON element (object, array, string, int, ...).
struct stasis_topic * ast_queue_topic(const char *queuename)
Get the Stasis Message Bus API topic for queue messages for a particular queue name.
Definition: main/app.c:3189

◆ set_member_paused()

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

Definition at line 7528 of file app_queue.c.

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

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

7529 {
7530  int found = 0;
7531  struct call_queue *q;
7532  struct ao2_iterator queue_iter;
7533 
7534  queue_iter = ao2_iterator_init(queues, 0);
7535  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
7536  ao2_lock(q);
7537  if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
7538  struct member *mem;
7539 
7540  if ((mem = interface_exists(q, interface))) {
7541  /*
7542  * Before we do the PAUSE/UNPAUSE, log if this was a
7543  * PAUSEALL/UNPAUSEALL but only on the first found entry.
7544  */
7545  ++found;
7546  if (found == 1
7547  && ast_strlen_zero(queuename)) {
7548  /*
7549  * XXX In all other cases, we use the queue name,
7550  * but since this affects all queues, we cannot.
7551  */
7552  ast_queue_log("NONE", "NONE", mem->membername,
7553  (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", S_OR(reason, ""));
7554  }
7555 
7556  set_queue_member_pause(q, mem, reason, paused);
7557  ao2_ref(mem, -1);
7558  }
7559 
7560  if (!ast_strlen_zero(queuename)) {
7561  ao2_unlock(q);
7562  queue_t_unref(q, "Done with iterator");
7563  break;
7564  }
7565  }
7566 
7567  ao2_unlock(q);
7568  queue_t_unref(q, "Done with iterator");
7569  }
7570  ao2_iterator_destroy(&queue_iter);
7571 
7572  return found ? RESULT_SUCCESS : RESULT_FAILURE;
7573 }
int paused
Definition: app_queue.c:1604
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_strlen_zero(foo)
Definition: strings.h:52
static struct ao2_container * queues
Definition: app_queue.c:1766
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7242
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
const ast_string_field name
Definition: app_queue.c:1696
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
#define RESULT_SUCCESS
Definition: cli.h:40
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define RESULT_FAILURE
Definition: cli.h:42
static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
Definition: app_queue.c:7483

◆ set_member_penalty_help_members()

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

Definition at line 7584 of file app_queue.c.

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

Referenced by set_member_value_help_members().

7585 {
7586  struct member *mem;
7587  int foundinterface = 0;
7588 
7589  ao2_lock(q);
7590  if ((mem = interface_exists(q, interface))) {
7591  foundinterface++;
7592  if (mem->realtime) {
7593  char rtpenalty[80];
7594 
7595  sprintf(rtpenalty, "%i", penalty);
7596  update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
7597  }
7598 
7599  mem->penalty = penalty;
7600 
7601  ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
7602  queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem));
7603  ao2_ref(mem, -1);
7604  }
7605  ao2_unlock(q);
7606 
7607  return foundinterface;
7608 }
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:3757
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
int realtime
Definition: app_queue.c:1602
#define ao2_unlock(a)
Definition: astobj2.h:730
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
int penalty
Definition: app_queue.c:1599
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7242
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2258
const ast_string_field name
Definition: app_queue.c:1696
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2234

◆ set_member_ringinuse_help_members()

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

Definition at line 7635 of file app_queue.c.

References ao2_lock, ao2_ref, ao2_unlock, interface_exists(), and set_queue_member_ringinuse().

Referenced by set_member_value_help_members().

7636 {
7637  struct member *mem;
7638  int foundinterface = 0;
7639 
7640  ao2_lock(q);
7641  if ((mem = interface_exists(q, interface))) {
7642  foundinterface++;
7644  ao2_ref(mem, -1);
7645  }
7646  ao2_unlock(q);
7647 
7648  return foundinterface;
7649 }
#define ao2_unlock(a)
Definition: astobj2.h:730
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7242
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
Definition: app_queue.c:7622
unsigned int ringinuse
Definition: app_queue.c:1616

◆ set_member_value()

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

Definition at line 7674 of file app_queue.c.

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

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

7675 {
7676  int foundinterface = 0, foundqueue = 0;
7677  struct call_queue *q;
7678  struct ast_config *queue_config = NULL;
7679  struct ao2_iterator queue_iter;
7680 
7681  /* property dependent restrictions on values should be checked in this switch */
7682  switch (property) {
7683  case MEMBER_PENALTY:
7684  if (value < 0 && !negative_penalty_invalid) {
7685  ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value);
7686  return RESULT_FAILURE;
7687  }
7688  }
7689 
7690  if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */
7691  if (ast_check_realtime("queues")) {
7692  queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
7693  if (queue_config) {
7694  char *category = NULL;
7695  while ((category = ast_category_browse(queue_config, category))) {
7696  const char *name = ast_variable_retrieve(queue_config, category, "name");
7697  if (ast_strlen_zero(name)) {
7698  ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
7699  continue;
7700  }
7701  if ((q = find_load_queue_rt_friendly(name))) {
7702  foundqueue++;
7703  foundinterface += set_member_value_help_members(q, interface, property, value);
7704  queue_unref(q);
7705  }
7706  }
7707  }
7708  }
7709 
7710  /* After hitting realtime queues, go back and get the regular ones. */
7711  queue_iter = ao2_iterator_init(queues, 0);
7712  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
7713  foundqueue++;
7714  foundinterface += set_member_value_help_members(q, interface, property, value);
7715  queue_unref(q);
7716  }
7717  ao2_iterator_destroy(&queue_iter);
7718  } else { /* We actually have a queuename, so we can just act on the single queue. */
7719  if ((q = find_load_queue_rt_friendly(queuename))) {
7720  foundqueue++;
7721  foundinterface += set_member_value_help_members(q, interface, property, value);
7722  queue_unref(q);
7723  }
7724  }
7725 
7726  if (foundinterface) {
7727  return RESULT_SUCCESS;
7728  } else if (!foundqueue) {
7729  ast_log (LOG_ERROR, "Invalid queuename\n");
7730  } else {
7731  ast_log (LOG_ERROR, "Invalid interface\n");
7732  }
7733 
7734  return RESULT_FAILURE;
7735 }
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
#define LOG_WARNING
Definition: logger.h:274
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1487
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3363
#define queue_unref(q)
Definition: app_queue.c:1919
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define SENTINEL
Definition: compiler.h:87
static struct ao2_container * queues
Definition: app_queue.c:1766
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3452
#define LOG_ERROR
Definition: logger.h:285
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
static const char name[]
Definition: cdr_mysql.c:74
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
Definition: app_queue.c:7651
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define RESULT_SUCCESS
Definition: cli.h:40
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define RESULT_FAILURE
Definition: cli.h:42

◆ set_member_value_help_members()

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

Definition at line 7651 of file app_queue.c.

References ast_log, LOG_ERROR, MEMBER_PENALTY, MEMBER_RINGINUSE, set_member_penalty_help_members(), and set_member_ringinuse_help_members().

Referenced by set_member_value().

7652 {
7653  switch(property) {
7654  case MEMBER_PENALTY:
7655  return set_member_penalty_help_members(q, interface, value);
7656 
7657  case MEMBER_RINGINUSE:
7658  return set_member_ringinuse_help_members(q, interface, value);
7659 
7660  default:
7661  ast_log(LOG_ERROR, "Attempted to set invalid property\n");
7662  return 0;
7663  }
7664 }
static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
Definition: app_queue.c:7635
int value
Definition: syslog.c:37
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
Definition: app_queue.c:7584

◆ set_queue_member_pause()

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

Definition at line 7483 of file app_queue.c.

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

Referenced by set_member_paused().

7484 {
7485  if (mem->paused == paused) {
7486  ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
7487  (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
7488  }
7489 
7490  if (mem->realtime) {
7491  if (update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0")) {
7492  ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
7493  (paused ? "" : "un"), q->name, mem->interface);
7494  }
7495  }
7496 
7497  mem->paused = paused;
7498  if (paused) {
7499  time(&mem->lastpause); /* update last pause field */
7500  }
7501  if (paused && !ast_strlen_zero(reason)) {
7502  ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7503  } else {
7504  mem->reason_paused[0] = '\0';
7505  }
7506 
7508  AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
7509 
7511  dump_queue_members(q);
7512  }
7513 
7514  if (is_member_available(q, mem)) {
7516  "Queue:%s_avail", q->name);
7517  } else if (!num_available_members(q)) {
7519  "Queue:%s_avail", q->name);
7520  }
7521 
7522  ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"),
7523  "%s", S_OR(reason, ""));
7524 
7526 }
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:3757
int paused
Definition: app_queue.c:1604
#define LOG_WARNING
Definition: logger.h:274
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
int realtime
Definition: app_queue.c:1602
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
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
time_t lastpause
Definition: app_queue.c:1611
#define QUEUE_PAUSED_DEVSTATE
Definition: app_queue.c:3350
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:4290
#define QUEUE_UNPAUSED_DEVSTATE
Definition: app_queue.c:3351
const ast_string_field name
Definition: app_queue.c:1696
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:7269
char reason_paused[80]
Definition: app_queue.c:1605
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
static int publish_queue_member_pause(struct call_queue *q, struct member *member)
Definition: app_queue.c:7457
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1466
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2468

◆ set_queue_member_ringinuse()

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

Definition at line 7622 of file app_queue.c.

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

Referenced by set_member_ringinuse_help_members().

7623 {
7624  if (mem->realtime) {
7626  ringinuse ? "1" : "0");
7627  }
7628 
7629  mem->ringinuse = ringinuse;
7630 
7631  ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
7632  queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
7633 }
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:3757
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
int realtime
Definition: app_queue.c:1602
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition: app_queue.c:1493
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2258
const ast_string_field name
Definition: app_queue.c:1696
unsigned int ringinuse
Definition: app_queue.c:1616
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2234

◆ set_queue_result()

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

sets the QUEUESTATUS channel variable

Definition at line 1775 of file app_queue.c.

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

Referenced by queue_exec().

1776 {
1777  int i;
1778 
1779  for (i = 0; i < ARRAY_LEN(queue_results); i++) {
1780  if (queue_results[i].id == res) {
1781  pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
1782  return;
1783  }
1784  }
1785 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static const struct @66 queue_results[]
char * text
Definition: app_queue.c:1508
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...

◆ set_queue_variables()

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

Set variables of queue.

Definition at line 1926 of file app_queue.c.

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

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

1927 {
1928  char interfacevar[256]="";
1929  float sl = 0;
1930 
1931  ao2_lock(q);
1932 
1933  if (q->setqueuevar) {
1934  sl = 0;
1935  if (q->callscompleted > 0) {
1936  sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
1937  }
1938 
1939  snprintf(interfacevar, sizeof(interfacevar),
1940  "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
1941  q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
1942 
1943  ao2_unlock(q);
1944 
1945  pbx_builtin_setvar_multiple(chan, interfacevar);
1946  } else {
1947  ao2_unlock(q);
1948  }
1949 }
int servicelevel
Definition: app_queue.c:1731
unsigned int setqueuevar
Definition: app_queue.c:1703
#define ao2_unlock(a)
Definition: astobj2.h:730
int callscompletedinsl
Definition: app_queue.c:1732
int holdtime
Definition: app_queue.c:1726
#define ao2_lock(a)
Definition: astobj2.h:718
int strategy
Definition: app_queue.c:1711
const ast_string_field name
Definition: app_queue.c:1696
int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *data)
Parse and set multiple channel variables, where the pairs are separated by the &#39;,&#39; character...
int talktime
Definition: app_queue.c:1727
int callsabandoned
Definition: app_queue.c:1729
int callscompleted
Definition: app_queue.c:1728
static const char * int2strat(int strategy)
Definition: app_queue.c:1787

◆ setup_mixmonitor()

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

Definition at line 6648 of file app_queue.c.

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

Referenced by try_calling().

6649 {
6650  char escaped_filename[256];
6651  char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
6652  char mixmonargs[1512];
6653  char escaped_monitor_exec[1024];
6654  const char *monitor_options;
6655  const char *monitor_exec;
6656 
6657  escaped_monitor_exec[0] = '\0';
6658 
6659  if (filename) {
6660  escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
6661  } else {
6662  ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
6663  }
6664 
6665  ast_channel_lock(qe->chan);
6666  if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
6667  monitor_exec = ast_strdupa(monitor_exec);
6668  }
6669  if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
6670  monitor_options = ast_strdupa(monitor_options);
6671  } else {
6672  monitor_options = "";
6673  }
6674  ast_channel_unlock(qe->chan);
6675 
6676  if (monitor_exec) {
6677  escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
6678  }
6679 
6680  snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
6681 
6682  if (!ast_strlen_zero(escaped_monitor_exec)) {
6683  snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
6684  } else {
6685  snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
6686  }
6687 
6688  ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
6689 
6690  if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
6691  ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
6692  }
6693 }
struct call_queue * parent
Definition: app_queue.c:1561
#define ast_channel_lock(chan)
Definition: channel.h:2945
struct ast_channel * chan
Definition: app_queue.c:1586
#define LOG_WARNING
Definition: logger.h:274
int ast_start_mixmonitor(struct ast_channel *chan, const char *filename, const char *options)
Start a mixmonitor on a channel with the given parameters.
Definition: mixmonitor.c:74
char monfmt[8]
Definition: app_queue.c:1733
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition: app_queue.c:6617
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401

◆ setup_peer_after_bridge_goto()

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

Definition at line 6600 of file app_queue.c.

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

Referenced by try_calling().

6601 {
6602  const char *context;
6603  const char *extension;
6604  int priority;
6605 
6606  if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
6607  ast_channel_lock(chan);
6608  context = ast_strdupa(ast_channel_context(chan));
6609  extension = ast_strdupa(ast_channel_exten(chan));
6610  priority = ast_channel_priority(chan);
6611  ast_channel_unlock(chan);
6612  ast_bridge_set_after_go_on(peer, context, extension, priority,
6613  opt_args[OPT_ARG_CALLEE_GO_ON]);
6614  }
6615 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define ast_test_flag(p, flag)
Definition: utils.h:63
static int priority
int ast_channel_priority(const struct ast_channel *chan)
structure to hold extensions
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2946
const char * ast_channel_context(const struct ast_channel *chan)
void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
Set channel to go on in the dialplan after the bridge.
Definition: bridge_after.c:636
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116

◆ setup_stasis_subs()

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

Definition at line 6514 of file app_queue.c.

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

Referenced by try_calling().

6516 {
6517  struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6518 
6519  if (!queue_data) {
6520  return -1;
6521  }
6522 
6524  if (!queue_data->bridge_router) {
6525  ao2_ref(queue_data, -1);
6526  return -1;
6527  }
6528 
6530  handle_bridge_enter, queue_data);
6532  handle_blind_transfer, queue_data);
6534  handle_attended_transfer, queue_data);
6536  queue_bridge_cb, queue_data);
6537 
6539  if (!queue_data->channel_router) {
6540  /* Unsubscribing from the bridge router will remove the only ref of queue_data,
6541  * thus beginning the destruction process
6542  */
6544  queue_data->bridge_router = NULL;
6545  return -1;
6546  }
6547 
6548  ao2_ref(queue_data, +1);
6550  handle_local_optimization_begin, queue_data);
6552  handle_local_optimization_end, queue_data);
6554  handle_hangup, queue_data);
6556  handle_masquerade, queue_data);
6558  queue_channel_cb, queue_data);
6559 
6560  return 0;
6561 }
struct stasis_message_type * ast_blind_transfer_type(void)
Message type for ast_blind_transfer_message.
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition: app_queue.c:6146
#define stasis_message_router_create_pool(topic)
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for channel enter bridge blob messages.
struct stasis_message_router * bridge_router
Definition: app_queue.c:5981
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6398
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6261
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
#define NULL
Definition: resample.c:96
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6455
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6112
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition: app_queue.c:6206
struct stasis_message_type * ast_local_optimization_end_type(void)
Message type for when a local channel optimization completes.
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6333
struct stasis_message_router * channel_router
Definition: app_queue.c:5983
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6489
struct stasis_message_type * ast_attended_transfer_type(void)
Message type for ast_attended_transfer_message.
int stasis_message_router_set_default(struct stasis_message_router *router, stasis_subscription_cb callback, void *data)
Sets the default route of a router.
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
struct stasis_message_type * ast_local_optimization_begin_type(void)
Message type for when a local channel optimization begins.
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6281
void stasis_message_router_unsubscribe(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic.
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:5957
static struct queue_stasis_data * queue_stasis_data_alloc(struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
Definition: app_queue.c:6026
struct stasis_message_type * ast_channel_hangup_request_type(void)
Message type for when a hangup is requested on a channel.
struct stasis_message_type * ast_channel_masquerade_type(void)
Message type for when a channel is being masqueraded.

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [1/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_join_type  ,
to_ami = queue_caller_join_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [2/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_leave_type  ,
to_ami = queue_caller_leave_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [3/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_caller_abandon_type  ,
to_ami = queue_caller_abandon_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [4/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_status_type  ,
to_ami = queue_member_status_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [5/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_added_type  ,
to_ami = queue_member_added_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [6/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_removed_type  ,
to_ami = queue_member_removed_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [7/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_pause_type  ,
to_ami = queue_member_pause_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [8/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_penalty_type  ,
to_ami = queue_member_penalty_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [9/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_member_ringinuse_type  ,
to_ami = queue_member_ringinuse_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [10/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_called_type  ,
to_ami = queue_agent_called_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [11/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_connect_type  ,
to_ami = queue_agent_connect_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [12/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_complete_type  ,
to_ami = queue_agent_complete_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [13/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_dump_type  ,
to_ami = queue_agent_dump_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [14/14]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( queue_agent_ringnoanswer_type  ,
to_ami = queue_agent_ringnoanswer_to_ami 
)

◆ store_next_lin()

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

Search for best metric and add to Linear queue.

Definition at line 4723 of file app_queue.c.

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

Referenced by try_calling().

4724 {
4725  struct callattempt *best = find_best(outgoing);
4726 
4727  if (best) {
4728  /* Ring just the best channel */
4729  ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
4730  qe->linpos = best->metric % 1000;
4731  } else {
4732  /* Just increment rrpos */
4733  if (qe->linwrapped) {
4734  /* No more channels, start over */
4735  qe->linpos = 0;
4736  } else {
4737  /* Prioritize next entry */
4738  qe->linpos++;
4739  }
4740  }
4741  qe->linwrapped = 0;
4742 
4743  return 0;
4744 }
int linwrapped
Definition: app_queue.c:1582
char interface[256]
Definition: app_queue.c:1541
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static struct callattempt * find_best(struct callattempt *outgoing)
find the entry with the best metric, or NULL
Definition: app_queue.c:4614
int linpos
Definition: app_queue.c:1581
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1537

◆ store_next_rr()

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

Search for best metric and add to Round Robbin queue.

Definition at line 4699 of file app_queue.c.

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

Referenced by try_calling().

4700 {
4701  struct callattempt *best = find_best(outgoing);
4702 
4703  if (best) {
4704  /* Ring just the best channel */
4705  ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
4706  qe->parent->rrpos = best->metric % 1000;
4707  } else {
4708  /* Just increment rrpos */
4709  if (qe->parent->wrapped) {
4710  /* No more channels, start over */
4711  qe->parent->rrpos = 0;
4712  } else {
4713  /* Prioritize next entry */
4714  qe->parent->rrpos++;
4715  }
4716  }
4717  qe->parent->wrapped = 0;
4718 
4719  return 0;
4720 }
struct call_queue * parent
Definition: app_queue.c:1561
char interface[256]
Definition: app_queue.c:1541
unsigned int wrapped
Definition: app_queue.c:1706
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static struct callattempt * find_best(struct callattempt *outgoing)
find the entry with the best metric, or NULL
Definition: app_queue.c:4614
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1537

◆ strat2int()

static int strat2int ( const char *  strategy)
static

Definition at line 1800 of file app_queue.c.

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

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

1801 {
1802  int x;
1803 
1804  for (x = 0; x < ARRAY_LEN(strategies); x++) {
1805  if (!strcasecmp(strategy, strategies[x].name)) {
1806  return strategies[x].strategy;
1807  }
1808  }
1809 
1810  return -1;
1811 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static const struct strategy strategies[]
static const char name[]
Definition: cdr_mysql.c:74
int strategy
Definition: app_queue.c:1406

◆ try_calling()

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

Definition at line 6722 of file app_queue.c.

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

Referenced by queue_exec().

6723 {
6724  struct member *cur;
6725  struct callattempt *outgoing = NULL; /* the list of calls we are building */
6726  int to, orig;
6727  char oldexten[AST_MAX_EXTENSION]="";
6728  char oldcontext[AST_MAX_CONTEXT]="";
6729  char queuename[256]="";
6730  struct ast_channel *peer;
6731  struct ast_channel *which;
6732  struct callattempt *lpeer;
6733  struct member *member;
6734  struct ast_app *application;
6735  int res = 0, bridge = 0;
6736  int numbusies = 0;
6737  int x=0;
6738  char *announce = NULL;
6739  char digit = 0;
6740  time_t now = time(NULL);
6741  struct ast_bridge_config bridge_config;
6742  char nondataquality = 1;
6743  char *agiexec = NULL;
6744  char *macroexec = NULL;
6745  char *gosubexec = NULL;
6746  const char *monitorfilename;
6747  char tmpid[256];
6748  int forwardsallowed = 1;
6749  int block_connected_line = 0;
6750  struct ao2_iterator memi;
6752  int callcompletedinsl;
6753  time_t starttime;
6754 
6755  memset(&bridge_config, 0, sizeof(bridge_config));
6756  tmpid[0] = 0;
6757  time(&now);
6758 
6759  /* If we've already exceeded our timeout, then just stop
6760  * This should be extremely rare. queue_exec will take care
6761  * of removing the caller and reporting the timeout as the reason.
6762  */
6763  if (qe->expire && now >= qe->expire) {
6764  res = 0;
6765  goto out;
6766  }
6767 
6768  if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) {
6769  ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
6770  }
6771  if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) {
6772  ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
6773  }
6774  if (ast_test_flag(&opts, OPT_CALLEE_AUTOMON)) {
6775  ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
6776  }
6777  if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
6778  ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
6779  }
6780  if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
6781  nondataquality = 0;
6782  }
6783  if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) {
6784  ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
6785  }
6786  if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) {
6787  ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
6788  }
6789  if (ast_test_flag(&opts, OPT_CALLEE_PARK)) {
6790  ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
6791  }
6792  if (ast_test_flag(&opts, OPT_CALLER_PARK)) {
6793  ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
6794  }
6795  if (ast_test_flag(&opts, OPT_NO_RETRY)) {
6798  (*tries)++;
6799  } else {
6800  *tries = ao2_container_count(qe->parent->members);
6801  }
6802  *noption = 1;
6803  }
6804  if (ast_test_flag(&opts, OPT_IGNORE_CALL_FW)) {
6805  forwardsallowed = 0;
6806  }
6808  block_connected_line = 1;
6809  }
6810  if (ast_test_flag(&opts, OPT_CALLEE_AUTOMIXMON)) {
6811  ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
6812  }
6813  if (ast_test_flag(&opts, OPT_CALLER_AUTOMIXMON)) {
6814  ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
6815  }
6816  if (ast_test_flag(&opts, OPT_MARK_AS_ANSWERED)) {
6817  qe->cancel_answered_elsewhere = 1;
6818  }
6819 
6820  /* if the calling channel has AST_CAUSE_ANSWERED_ELSEWHERE set, make sure this is inherited.
6821  (this is mainly to support unreal/local channels)
6822  */
6824  qe->cancel_answered_elsewhere = 1;
6825  }
6826 
6827  ao2_lock(qe->parent);
6828  ast_debug(1, "%s is trying to call a queue member.\n",
6829  ast_channel_name(qe->chan));
6830  ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
6831  if (!ast_strlen_zero(qe->announce)) {
6832  announce = qe->announce;
6833  }
6834  if (!ast_strlen_zero(announceoverride)) {
6835  announce = announceoverride;
6836  }
6837 
6838  memi = ao2_iterator_init(qe->parent->members, 0);
6839  while ((cur = ao2_iterator_next(&memi))) {
6840  struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
6841  if (!tmp) {
6842  ao2_ref(cur, -1);
6843  ao2_iterator_destroy(&memi);
6844  ao2_unlock(qe->parent);
6845  goto out;
6846  }
6847 
6848  /*
6849  * Seed the callattempt's connected line information with previously
6850  * acquired connected line info from the queued channel. The
6851  * previously acquired connected line info could have been set
6852  * through the CONNECTED_LINE dialplan function.
6853  */
6854  ast_channel_lock(qe->chan);
6856  ast_channel_unlock(qe->chan);
6857 
6858  tmp->block_connected_update = block_connected_line;
6859  tmp->stillgoing = 1;
6860  tmp->member = cur; /* Place the reference for cur into callattempt. */
6861  ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
6862  /* Calculate the metric for the appropriate strategy. */
6863  if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
6864  /* Put them in the list of outgoing thingies... We're ready now.
6865  XXX If we're forcibly removed, these outgoing calls won't get
6866  hung up XXX */
6867  tmp->q_next = outgoing;
6868  outgoing = tmp;
6869  } else {
6870  callattempt_free(tmp);
6871  }
6872  }
6873  ao2_iterator_destroy(&memi);
6874 
6876  /* Application arguments have higher timeout priority (behaviour for <=1.6) */
6877  if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) {
6878  to = (qe->expire - now) * 1000;
6879  } else {
6880  to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
6881  }
6882  } else {
6883  /* Config timeout is higher priority thatn application timeout */
6884  if (qe->expire && qe->expire<=now) {
6885  to = 0;
6886  } else if (qe->parent->timeout) {
6887  to = qe->parent->timeout * 1000;
6888  } else {
6889  to = -1;
6890  }
6891  }
6892  orig = to;
6893  ++qe->pending;
6894  ao2_unlock(qe->parent);
6895  /* Call the queue members with the best metric now. */
6896  ring_one(qe, outgoing, &numbusies);
6897  lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
6898  ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT),
6899  forwardsallowed);
6900 
6901  ao2_lock(qe->parent);
6903  store_next_rr(qe, outgoing);
6904 
6905  }
6906  if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
6907  store_next_lin(qe, outgoing);
6908  }
6909  ao2_unlock(qe->parent);
6910  peer = lpeer ? lpeer->chan : NULL;
6911  if (!peer) {
6912  qe->pending = 0;
6913  if (to) {
6914  /* Must gotten hung up */
6915  res = -1;
6916  } else {
6917  /* User exited by pressing a digit */
6918  res = digit;
6919  }
6920  if (res == -1) {
6921  ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
6922  }
6923  } else { /* peer is valid */
6924  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
6925  RAII_VAR(struct ast_str *, interfacevar, ast_str_create(325), ast_free);
6926  /* Ah ha! Someone answered within the desired timeframe. Of course after this
6927  we will always return with -1 so that it is hung up properly after the
6928  conversation. */
6929  if (!strcmp(ast_channel_tech(qe->chan)->type, "DAHDI")) {
6930  ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
6931  }
6932  if (!strcmp(ast_channel_tech(peer)->type, "DAHDI")) {
6933  ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
6934  }
6935  /* Update parameters for the queue */
6936  time(&now);
6937  recalc_holdtime(qe, (now - qe->start));
6938  member = lpeer->member;
6939  ao2_lock(qe->parent);
6940  callcompletedinsl = member->callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
6941  ao2_unlock(qe->parent);
6942  /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
6943  ao2_ref(member, 1);
6944  hangupcalls(qe, outgoing, peer, qe->cancel_answered_elsewhere);
6945  outgoing = NULL;
6946  if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
6947  int res2;
6948 
6949  res2 = ast_autoservice_start(qe->chan);
6950  if (!res2) {
6951  if (qe->parent->memberdelay) {
6952  ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
6953  res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
6954  }
6955  if (!res2 && announce) {
6956  if (play_file(peer, announce) < 0) {
6957  ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", announce, ast_channel_name(peer));
6958  }
6959  }
6960  if (!res2 && qe->parent->reportholdtime) {
6961  if (!play_file(peer, qe->parent->sound_reporthold)) {
6962  long holdtime, holdtimesecs;
6963 
6964  time(&now);
6965  holdtime = labs((now - qe->start) / 60);
6966  holdtimesecs = labs((now - qe->start) % 60);
6967  if (holdtime > 0) {
6968  ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), NULL);
6969  if (play_file(peer, qe->parent->sound_minutes) < 0) {
6970  ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, ast_channel_name(peer));
6971  }
6972  }
6973  if (holdtimesecs > 1) {
6974  ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), NULL);
6975  if (play_file(peer, qe->parent->sound_seconds) < 0) {
6976  ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, ast_channel_name(peer));
6977  }
6978  }
6979  }
6980  }
6982  }
6983  if (ast_check_hangup(peer)) {
6984  /* Agent must have hung up */
6985  ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer));
6986  ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", "");
6987 
6988  blob = ast_json_pack("{s: s, s: s, s: s}",
6989  "Queue", queuename,
6990  "Interface", member->interface,
6991  "MemberName", member->membername);
6992  queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_dump_type(), blob);
6993 
6996  pending_members_remove(member);
6997  ao2_ref(member, -1);
6998  goto out;
6999  } else if (ast_check_hangup(qe->chan)) {
7000  /* Caller must have hung up just before being connected */
7001  ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer));
7002  ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
7003  record_abandoned(qe);
7004  qe->handled = -1;
7007  pending_members_remove(member);
7008  ao2_ref(member, -1);
7009  return -1;
7010  }
7011  }
7012  /* Stop music on hold */
7013  if (ringing) {
7014  ast_indicate(qe->chan,-1);
7015  } else {
7016  ast_moh_stop(qe->chan);
7017  }
7018 
7019  /* Make sure channels are compatible */
7020  res = ast_channel_make_compatible(qe->chan, peer);
7021  if (res < 0) {
7022  ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", "");
7023  ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(qe->chan), ast_channel_name(peer));
7024  record_abandoned(qe);
7027  pending_members_remove(member);
7028  ao2_ref(member, -1);
7029  return -1;
7030  }
7031 
7032  /* Play announcement to the caller telling it's his turn if defined */
7034  if (play_file(qe->chan, qe->parent->sound_callerannounce)) {
7035  ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
7036  }
7037  }
7038 
7039  ao2_lock(qe->parent);
7040  /* if setinterfacevar is defined, make member variables available to the channel */
7041  /* use pbx_builtin_setvar to set a load of variables with one call */
7042  if (qe->parent->setinterfacevar && interfacevar) {
7043  ast_str_set(&interfacevar, 0, "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
7044  member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime);
7045  pbx_builtin_setvar_multiple(qe->chan, ast_str_buffer(interfacevar));
7046  pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7047  }
7048 
7049  /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
7050  /* use pbx_builtin_setvar to set a load of variables with one call */
7051  if (qe->parent->setqueueentryvar && interfacevar) {
7052  ast_str_set(&interfacevar, 0, "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
7053  (long) (time(NULL) - qe->start), qe->opos);
7054  pbx_builtin_setvar_multiple(qe->chan, ast_str_buffer(interfacevar));
7055  pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7056  }
7057 
7058  ao2_unlock(qe->parent);
7059 
7060  /* try to set queue variables if configured to do so*/
7061  set_queue_variables(qe->parent, qe->chan);
7062  set_queue_variables(qe->parent, peer);
7063 
7064  setup_peer_after_bridge_goto(qe->chan, peer, &opts, opt_args);
7065  ast_channel_lock(qe->chan);
7066  if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
7067  monitorfilename = ast_strdupa(monitorfilename);
7068  }
7069  ast_channel_unlock(qe->chan);
7070 
7071  /* Begin Monitoring */
7072  if (*qe->parent->monfmt) {
7073  if (!qe->parent->montype) {
7074  const char *monexec;
7075  ast_debug(1, "Starting Monitor as requested.\n");
7076  ast_channel_lock(qe->chan);
7077  if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) {
7078  which = qe->chan;
7079  monexec = monexec ? ast_strdupa(monexec) : NULL;
7080  } else {
7081  which = peer;
7082  }
7083  ast_channel_unlock(qe->chan);
7084  if (monitorfilename) {
7085  ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT, NULL);
7086  } else if (qe->chan) {
7088  } else {
7089  /* Last ditch effort -- no channel, make up something */
7090  snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random());
7091  ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT, NULL);
7092  }
7093  if (!ast_strlen_zero(monexec)) {
7094  ast_monitor_setjoinfiles(which, 1);
7095  }
7096  } else {
7097  setup_mixmonitor(qe, monitorfilename);
7098  }
7099  }
7100  /* Drop out of the queue at this point, to prepare for next caller */
7101  leave_queue(qe);
7103  ast_debug(1, "app_queue: sendurl=%s.\n", url);
7104  ast_channel_sendurl(peer, url);
7105  }
7106 
7107  /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
7108  /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
7109  if (!ast_strlen_zero(macro)) {
7110  macroexec = ast_strdupa(macro);
7111  } else {
7112  if (qe->parent->membermacro) {
7113  macroexec = ast_strdupa(qe->parent->membermacro);
7114  }
7115  }
7116 
7117  if (!ast_strlen_zero(macroexec)) {
7118  ast_debug(1, "app_queue: macro=%s.\n", macroexec);
7119  ast_app_exec_macro(qe->chan, peer, macroexec);
7120  }
7121 
7122  /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
7123  /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
7124  if (!ast_strlen_zero(gosub)) {
7125  gosubexec = ast_strdupa(gosub);
7126  } else {
7127  if (qe->parent->membergosub) {
7128  gosubexec = ast_strdupa(qe->parent->membergosub);
7129  }
7130  }
7131 
7132  if (!ast_strlen_zero(gosubexec)) {
7133  char *gosub_args = NULL;
7134  char *gosub_argstart;
7135 
7136  ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
7137 
7138  gosub_argstart = strchr(gosubexec, ',');
7139  if (gosub_argstart) {
7140  const char *what_is_s = "s";
7141  *gosub_argstart = 0;
7142  if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
7143  ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7144  what_is_s = "~~s~~";
7145  }
7146  if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
7147  gosub_args = NULL;
7148  }
7149  *gosub_argstart = ',';
7150  } else {
7151  const char *what_is_s = "s";
7152  if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
7153  ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7154  what_is_s = "~~s~~";
7155  }
7156  if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
7157  gosub_args = NULL;
7158  }
7159  }
7160  if (gosub_args) {
7161  ast_app_exec_sub(qe->chan, peer, gosub_args, 0);
7162  ast_free(gosub_args);
7163  } else {
7164  ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
7165  }
7166  }
7167 
7168  if (!ast_strlen_zero(agi)) {
7169  ast_debug(1, "app_queue: agi=%s.\n", agi);
7170  application = pbx_findapp("agi");
7171  if (application) {
7172  agiexec = ast_strdupa(agi);
7173  pbx_exec(qe->chan, application, agiexec);
7174  } else {
7175  ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
7176  }
7177  }
7178  qe->handled++;
7179 
7180  ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
7181  (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
7182 
7183  blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I}",
7184  "Queue", queuename,
7185  "Interface", member->interface,
7186  "MemberName", member->membername,
7187  "HoldTime", (ast_json_int_t)(time(NULL) - qe->start),
7188  "RingTime", (ast_json_int_t)(orig - to > 0 ? (orig - to) / 1000 : 0));
7189  queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_connect_type(), blob);
7190 
7191  ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
7192  ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten));
7193 
7194  if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
7195  queue_end_bridge->q = qe->parent;
7196  queue_end_bridge->chan = qe->chan;
7197  bridge_config.end_bridge_callback = end_bridge_callback;
7198  bridge_config.end_bridge_callback_data = queue_end_bridge;
7199  bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
7200  /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
7201  * to make sure to increase the refcount of this queue so it cannot be freed until we
7202  * are done with it. We remove this reference in end_bridge_callback.
7203  */
7204  queue_t_ref(qe->parent, "For bridge_config reference");
7205  }
7206 
7207  ao2_lock(qe->parent);
7208  time(&member->starttime);
7209  starttime = member->starttime;
7210  ao2_unlock(qe->parent);
7211  /* As a queue member may end up in multiple calls at once if a transfer occurs with
7212  * a Local channel in the mix we pass the current call information (starttime) to the
7213  * Stasis subscriptions so when they update the queue member data it becomes a noop
7214  * if this call is no longer between the caller and the queue member.
7215  */
7216  setup_stasis_subs(qe, peer, member, qe->start, starttime, callcompletedinsl);
7217  bridge = ast_bridge_call_with_flags(qe->chan, peer, &bridge_config,
7219 
7220  res = bridge ? bridge : 1;
7221  ao2_ref(member, -1);
7222  }
7223 out:
7224  hangupcalls(qe, outgoing, NULL, qe->cancel_answered_elsewhere);
7225 
7226  return res;
7227 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1574
struct callattempt * q_next
Definition: app_queue.c:1538
static const char type[]
Definition: chan_ooh323.c:109
char digit
int servicelevel
Definition: app_queue.c:1731
struct call_queue * parent
Definition: app_queue.c:1561
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define X_REC_IN
Definition: monitor.h:30
int dynamic
Definition: app_queue.c:1601
Main Channel structure associated with a channel.
static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
Search for best metric and add to Round Robbin queue.
Definition: app_queue.c:4699
const char *const type
Definition: channel.h:630
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
Definition: app_queue.c:6568
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
struct ast_channel * chan
Definition: app_queue.c:1586
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
const ast_string_field membergosub
Definition: app_queue.c:1696
#define AST_DIGIT_ANY
Definition: file.h:48
time_t start
Definition: app_queue.c:1583
#define ast_test_flag(p, flag)
Definition: utils.h:63
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4322
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
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...
int ast_channel_supports_html(struct ast_channel *channel)
Checks for HTML support on a channel.
Definition: channel.c:6720
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:274
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87
static int tmp()
Definition: bt_open.c:389
time_t expire
Definition: app_queue.c:1584
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
Calculate the metric of each member in the outgoing callattempts.
Definition: app_queue.c:5779
char interface[256]
Definition: app_queue.c:1541
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
const char * ast_hangup_cause_to_dial_status(int hangup_cause)
Convert a hangup cause to a publishable dial status.
Definition: dial.c:753
#define queue_t_ref(q, tag)
Definition: app_queue.c:1920
int realtime
Definition: app_queue.c:1602
#define ao2_unlock(a)
Definition: astobj2.h:730
unsigned int setinterfacevar
Definition: app_queue.c:1702
static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
Definition: app_queue.c:6514
#define NULL
Definition: resample.c:96
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7522
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7876
struct ao2_container * members
Definition: app_queue.c:1752
char monfmt[8]
Definition: app_queue.c:1733
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2426
static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
Definition: app_queue.c:4128
const ast_string_field membermacro
Definition: app_queue.c:1696
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define X_REC_OUT
Definition: monitor.h:31
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
#define ast_strlen_zero(foo)
Definition: strings.h:52
Number structure.
Definition: app_followme.c:154
static struct callattempt * wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
Wait for a member to answer the call.
Definition: app_queue.c:4937
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:1065
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
struct ast_party_connected_line connected
Definition: app_queue.c:1545
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Definition: channel.c:6817
static void end_bridge_callback(void *data)
Definition: app_queue.c:6575
int penalty
Definition: app_queue.c:1599
#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:911
int memberdelay
Definition: app_queue.c:1749
struct call_queue * q
Definition: app_queue.c:6564
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
unsigned int block_connected_update
Definition: app_queue.c:1549
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition: causes.h:113
static void ringing(struct ast_channel *chan)
Helper method to send a ringing indication to a channel in a bridge.
#define AST_MAX_EXTENSION
Definition: channel.h:135
int AST_OPTIONAL_API_NAME() ast_monitor_start(struct ast_channel *chan, const char *format_spec, const char *fname_base, int need_lock, int stream_action, const char *beep_id)
Start monitoring a channel.
Definition: res_monitor.c:305
bridge configuration
Definition: channel.h:1077
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
long int ast_random(void)
Definition: main/utils.c:2064
#define ao2_lock(a)
Definition: astobj2.h:718
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
struct member * member
Definition: app_queue.c:1543
int strategy
Definition: app_queue.c:1711
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4179
int ast_app_exec_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char *macro_args)
Run a macro on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:273
const char * ast_channel_exten(const struct ast_channel *chan)
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags)
Bridge a call, and add additional flags to the bridge.
Definition: features.c:633
const char * ast_channel_uniqueid(const struct ast_channel *chan)
static void leave_queue(struct queue_ent *qe)
Caller leaving queue.
Definition: app_queue.c:4151
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1537
#define LOG_ERROR
Definition: logger.h:285
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
const ast_string_field name
Definition: app_queue.c:1696
static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
Definition: app_queue.c:6600
unsigned int reportholdtime
Definition: app_queue.c:1705
struct ast_channel * chan
Definition: app_queue.c:6565
int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *data)
Parse and set multiple channel variables, where the pairs are separated by the &#39;,&#39; character...
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
#define LOG_NOTICE
Definition: logger.h:263
int ast_channel_sendurl(struct ast_channel *channel, const char *url)
Sends a URL on a given link Send URL on link.
Definition: channel.c:6732
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define AST_MAX_CONTEXT
Definition: channel.h:136
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static int play_file(struct ast_channel *chan, const char *filename)
Definition: app_queue.c:3916
int timeoutpriority
Definition: app_queue.c:1745
const ast_string_field sound_seconds
Definition: app_queue.c:1696
void ast_autoservice_chan_hangup_peer(struct ast_channel *chan, struct ast_channel *peer)
Put chan into autoservice while hanging up peer.
Definition: autoservice.c:342
int pending
Definition: app_queue.c:1577
static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2201
time_t starttime
Definition: app_queue.c:1609
int calls
Definition: app_queue.c:1600
unsigned int setqueueentryvar
Definition: app_queue.c:1704
const ast_string_field sound_reporthold
Definition: app_queue.c:1696
static void callattempt_free(struct callattempt *doomed)
Definition: app_queue.c:4228
static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
Search for best metric and add to Linear queue.
Definition: app_queue.c:4723
void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
Copy the source connected line information to the destination connected line.
Definition: channel.c:2031
static void record_abandoned(struct queue_ent *qe)
Record that a caller gave up on waiting in queue.
Definition: app_queue.c:4808
FILE * out
Definition: utils/frame.c:33
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition: channel.c:8337
void AST_OPTIONAL_API_NAME() ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
Definition: res_monitor.c:926
int ast_channel_hangupcause(const struct ast_channel *chan)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
ast_app: A registered application
Definition: pbx_app.c:45
const char * ast_channel_name(const struct ast_channel *chan)
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:1926
static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
Hang up a list of outgoing calls.
Definition: app_queue.c:4250
int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args, int ignore_hangup)
Run a subroutine on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:370
const char * ast_channel_language(const struct ast_channel *chan)
Abstract JSON element (object, array, string, int, ...).
#define AST_OPTION_TONE_VERIFY
const char * ast_channel_context(const struct ast_channel *chan)
const ast_string_field sound_minutes
Definition: app_queue.c:1696
int handled
Definition: app_queue.c:1576
int cancel_answered_elsewhere
Definition: app_queue.c:1585
static char url[512]
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
int callcompletedinsl
Definition: app_queue.c:1607
struct ast_channel * chan
Definition: app_queue.c:1540
static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
Definition: app_queue.c:6648
const ast_string_field sound_callerannounce
Definition: app_queue.c:1696
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
time_t lastcall
Definition: app_queue.c:1610
unsigned int stillgoing
Definition: app_queue.c:1553
char announce[PATH_MAX]
Definition: app_queue.c:1563
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
Place a call to a queue member.
Definition: app_queue.c:4639
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 11250 of file app_queue.c.

References ao2_cleanup, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_manager_unregister(), ast_unload_realtime(), ast_unregister_application(), NULL, stasis_forward_cancel(), stasis_message_router_unsubscribe_and_join(), STASIS_MESSAGE_TYPE_CLEANUP, and stasis_unsubscribe_and_join().

Referenced by find_member_by_queuename_and_interface(), and load_module().

11251 {
11253  agent_router = NULL;
11254 
11256 
11257  STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
11258  STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
11259  STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
11260 
11261  STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
11262  STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
11263  STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
11264  STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
11265  STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
11266  STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
11267 
11268  STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
11269  STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
11270  STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
11271  STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
11272  STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
11273 
11275  ast_manager_unregister("QueueStatus");
11276  ast_manager_unregister("QueueRule");
11277  ast_manager_unregister("QueueSummary");
11278  ast_manager_unregister("QueueAdd");
11279  ast_manager_unregister("QueueRemove");
11280  ast_manager_unregister("QueuePause");
11281  ast_manager_unregister("QueueLog");
11282  ast_manager_unregister("QueueUpdate");
11283  ast_manager_unregister("QueuePenalty");
11284  ast_manager_unregister("QueueReload");
11285  ast_manager_unregister("QueueReset");
11286  ast_manager_unregister("QueueMemberRingInUse");
11287  ast_manager_unregister("QueueChangePriorityCaller");
11303 
11305 
11306  ast_unload_realtime("queue_members");
11309 
11310  queues = NULL;
11311  return 0;
11312 }
static struct ast_custom_function queuewaitingcount_function
Definition: app_queue.c:9105
static char * app_ql
Definition: app_queue.c:1458
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static char * app_qupd
Definition: app_queue.c:1460
static char * app_aqm
Definition: app_queue.c:1450
static struct ao2_container * pending_members
Definition: app_queue.c:2375
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
static struct ast_custom_function queuegetchannel_function
Definition: app_queue.c:9100
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3406
void stasis_message_router_unsubscribe_and_join(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic, blocking until the final message has been processed...
static struct ast_custom_function queuemembercount_dep
Definition: app_queue.c:9095
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1523
#define NULL
Definition: resample.c:96
static char * app_rqm
Definition: app_queue.c:1452
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
static struct ast_custom_function queueexists_function
Definition: app_queue.c:9079
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
static struct stasis_forward * topic_forwarder
Definition: app_queue.c:11248
static char * app
Definition: app_queue.c:1448
static struct ast_custom_function queuemembercount_function
Definition: app_queue.c:9089
static struct ao2_container * queues
Definition: app_queue.c:1766
static struct ast_custom_function queuememberpenalty_function
Definition: app_queue.c:9115
static struct stasis_message_router * agent_router
Definition: app_queue.c:11247
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7258
static struct ast_custom_function queuememberlist_function
Definition: app_queue.c:9110
static char * app_pqm
Definition: app_queue.c:1454
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition: stasis.c:1548
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1136
static struct ast_cli_entry cli_queue[]
Definition: app_queue.c:11234
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static struct ast_custom_function queuevar_function
Definition: app_queue.c:9084
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition: app_queue.c:1484
static char * app_upqm
Definition: app_queue.c:1456

◆ update_connected_line_from_peer()

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

Definition at line 4906 of file app_queue.c.

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

Referenced by wait_for_answer().

4907 {
4908  struct ast_party_connected_line connected_caller;
4909 
4910  ast_party_connected_line_init(&connected_caller);
4911 
4912  ast_channel_lock(peer);
4913  ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(peer));
4914  ast_channel_unlock(peer);
4915  connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
4916  if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)
4917  && ast_channel_connected_line_macro(peer, chan, &connected_caller, is_caller, 0)) {
4918  ast_channel_update_connected_line(chan, &connected_caller, NULL);
4919  }
4920  ast_party_connected_line_free(&connected_caller);
4921 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:2022
#define ast_channel_lock(chan)
Definition: channel.h:2945
int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int frame)
Run a connected line interception macro and update a channel&#39;s connected line information.
Definition: channel.c:10435
void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Indicate that the connected line information has changed.
Definition: channel.c:9189
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2072
#define NULL
Definition: resample.c:96
int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int frame)
Run a connected line interception subroutine and update a channel&#39;s connected line information...
Definition: channel.c:10539
Connected Line/Party information.
Definition: channel.h:457
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition: channel.c:8389

◆ update_qe_rule()

static void update_qe_rule ( struct queue_ent qe)
static

update rules for queues

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

Definition at line 5536 of file app_queue.c.

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

Referenced by queue_exec(), and wait_our_turn().

5537 {
5538  int max_penalty = INT_MAX;
5539 
5540  if (qe->max_penalty != INT_MAX) {
5541  char max_penalty_str[20];
5542 
5543  if (qe->pr->max_relative) {
5544  max_penalty = qe->max_penalty + qe->pr->max_value;
5545  } else {
5546  max_penalty = qe->pr->max_value;
5547  }
5548 
5549  /* a relative change to the penalty could put it below 0 */
5550  if (max_penalty < 0) {
5551  max_penalty = 0;
5552  }
5553 
5554  snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
5555  pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
5556  qe->max_penalty = max_penalty;
5557  ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n",
5558  qe->max_penalty, ast_channel_name(qe->chan), qe->pr->time);
5559  }
5560 
5561  if (qe->min_penalty != INT_MAX) {
5562  char min_penalty_str[20];
5563  int min_penalty;
5564 
5565  if (qe->pr->min_relative) {
5566  min_penalty = qe->min_penalty + qe->pr->min_value;
5567  } else {
5568  min_penalty = qe->pr->min_value;
5569  }
5570 
5571  /* a relative change to the penalty could put it below 0 */
5572  if (min_penalty < 0) {
5573  min_penalty = 0;
5574  }
5575 
5576  if (max_penalty != INT_MAX && min_penalty > max_penalty) {
5577  min_penalty = max_penalty;
5578  }
5579 
5580  snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
5581  pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
5582  qe->min_penalty = min_penalty;
5583  ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n",
5584  qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time);
5585  }
5586 
5587  if (qe->raise_penalty != INT_MAX) {
5588  char raise_penalty_str[20];
5589  int raise_penalty;
5590 
5591  if (qe->pr->raise_relative) {
5592  raise_penalty = qe->raise_penalty + qe->pr->raise_value;
5593  } else {
5594  raise_penalty = qe->pr->raise_value;
5595  }
5596 
5597  /* a relative change to the penalty could put it below 0 */
5598  if (raise_penalty < 0) {
5599  raise_penalty = 0;
5600  }
5601 
5602  if (max_penalty != INT_MAX && raise_penalty > max_penalty) {
5603  raise_penalty = max_penalty;
5604  }
5605 
5606  snprintf(raise_penalty_str, sizeof(raise_penalty_str), "%d", raise_penalty);
5607  pbx_builtin_setvar_helper(qe->chan, "QUEUE_RAISE_PENALTY", raise_penalty_str);
5608  qe->raise_penalty = raise_penalty;
5609  ast_debug(3, "Setting raised penalty to %d for caller %s since %d seconds have elapsed\n",
5610  qe->raise_penalty, ast_channel_name(qe->chan), qe->pr->time);
5611  }
5612 
5613  qe->pr = AST_LIST_NEXT(qe->pr, list);
5614 }
int raise_penalty
Definition: app_queue.c:1580
struct ast_channel * chan
Definition: app_queue.c:1586
int min_penalty
Definition: app_queue.c:1579
int max_relative
Definition: app_queue.c:1645
int max_penalty
Definition: app_queue.c:1578
int min_relative
Definition: app_queue.c:1646
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
int raise_relative
Definition: app_queue.c:1647
struct penalty_rule * pr
Definition: app_queue.c:1588
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...
const char * ast_channel_name(const struct ast_channel *chan)

◆ update_queue()

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

update the queue status

Return values
Always0

Definition at line 5707 of file app_queue.c.

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

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

5708 {
5709  int oldtalktime;
5710  int newtalktime = time(NULL) - starttime;
5711  struct member *mem;
5712  struct call_queue *qtmp;
5713  struct ao2_iterator queue_iter;
5714 
5715  /* It is possible for us to be called when a call has already been considered terminated
5716  * and data updated, so to ensure we only act on the call that the agent is currently in
5717  * we check when the call was bridged.
5718  */
5719  if (!starttime || (member->starttime != starttime)) {
5720  return 0;
5721  }
5722 
5723  if (shared_lastcall) {
5724  queue_iter = ao2_iterator_init(queues, 0);
5725  while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
5726  ao2_lock(qtmp);
5727  if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
5728  time(&mem->lastcall);
5729  mem->calls++;
5730  mem->callcompletedinsl = 0;
5731  mem->starttime = 0;
5732  mem->lastqueue = q;
5733  ao2_ref(mem, -1);
5734  }
5735  ao2_unlock(qtmp);
5736  queue_t_unref(qtmp, "Done with iterator");
5737  }
5738  ao2_iterator_destroy(&queue_iter);
5739  } else {
5740  ao2_lock(q);
5741  time(&member->lastcall);
5742  member->callcompletedinsl = 0;
5743  member->calls++;
5744  member->starttime = 0;
5745  member->lastqueue = q;
5746  ao2_unlock(q);
5747  }
5748  /* Member might never experience any direct status change (local
5749  * channel with forwarding in particular). If that's the case,
5750  * this is the last chance to remove it from pending or subsequent
5751  * calls will not occur.
5752  */
5753  pending_members_remove(member);
5754 
5755  ao2_lock(q);
5756  q->callscompleted++;
5757  if (callcompletedinsl) {
5758  q->callscompletedinsl++;
5759  }
5760  if (q->callscompleted == 1) {
5761  q->talktime = newtalktime;
5762  } else {
5763  /* Calculate talktime using the same exponential average as holdtime code */
5764  oldtalktime = q->talktime;
5765  q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
5766  }
5767  ao2_unlock(q);
5768  return 0;
5769 }
#define OBJ_POINTER
Definition: astobj2.h:1154
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
struct ao2_container * members
Definition: app_queue.c:1752
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2426
int callscompletedinsl
Definition: app_queue.c:1732
static struct ao2_container * queues
Definition: app_queue.c:1766
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
struct call_queue * lastqueue
Definition: app_queue.c:1612
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
int talktime
Definition: app_queue.c:1727
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
time_t starttime
Definition: app_queue.c:1609
int calls
Definition: app_queue.c:1600
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
int callcompletedinsl
Definition: app_queue.c:1607
int callscompleted
Definition: app_queue.c:1728
static int shared_lastcall
queues.conf [general] option
Definition: app_queue.c:1478
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
time_t lastcall
Definition: app_queue.c:1610

◆ update_realtime_member_field()

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

Definition at line 3757 of file app_queue.c.

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

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

3758 {
3759  int ret = -1;
3760 
3761  if (ast_strlen_zero(mem->rt_uniqueid)) {
3762  return ret;
3763  }
3764 
3765  if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0) {
3766  ret = 0;
3767  }
3768 
3769  return ret;
3770 }
int value
Definition: syslog.c:37
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3489
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define SENTINEL
Definition: compiler.h:87
char rt_uniqueid[80]
Definition: app_queue.c:1615

◆ update_realtime_members()

static void update_realtime_members ( struct call_queue q)
static

Definition at line 3773 of file app_queue.c.

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

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

3774 {
3775  struct ast_config *member_config = NULL;
3776  struct member *m;
3777  char *category = NULL;
3778  struct ao2_iterator mem_iter;
3779 
3780  if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
3781  /* This queue doesn't have realtime members. If the queue still has any realtime
3782  * members in memory, they need to be removed.
3783  */
3784  ao2_lock(q);
3785  mem_iter = ao2_iterator_init(q->members, 0);
3786  while ((m = ao2_iterator_next(&mem_iter))) {
3787  if (m->realtime) {
3789  }
3790  ao2_ref(m, -1);
3791  }
3792  ao2_iterator_destroy(&mem_iter);
3793  ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
3794  ao2_unlock(q);
3795  return;
3796  }
3797 
3798  ao2_lock(q);
3799 
3800  /* Temporarily set realtime members dead so we can detect deleted ones.*/
3801  mem_iter = ao2_iterator_init(q->members, 0);
3802  while ((m = ao2_iterator_next(&mem_iter))) {
3803  if (m->realtime) {
3804  m->dead = 1;
3805  }
3806  ao2_ref(m, -1);
3807  }
3808  ao2_iterator_destroy(&mem_iter);
3809 
3810  while ((category = ast_category_browse(member_config, category))) {
3811  rt_handle_member_record(q, category, member_config);
3812  }
3813 
3814  /* Delete all realtime members that have been deleted in DB. */
3815  mem_iter = ao2_iterator_init(q->members, 0);
3816  while ((m = ao2_iterator_next(&mem_iter))) {
3817  if (m->dead) {
3819  ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
3820  } else {
3821  ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
3822  }
3824  }
3825  ao2_ref(m, -1);
3826  }
3827  ao2_iterator_destroy(&mem_iter);
3828  ao2_unlock(q);
3829  ast_config_destroy(member_config);
3830 }
static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3376
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1490
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int realtime
Definition: app_queue.c:1602
#define ao2_unlock(a)
Definition: astobj2.h:730
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
unsigned int dead
Definition: app_queue.c:1613
#define NULL
Definition: resample.c:96
struct ao2_container * members
Definition: app_queue.c:1752
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:3392
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define SENTINEL
Definition: compiler.h:87
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define ao2_lock(a)
Definition: astobj2.h:718
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3452
const ast_string_field name
Definition: app_queue.c:1696
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ update_status()

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

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

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

Definition at line 2437 of file app_queue.c.

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

Referenced by device_state_cb(), and extension_state_cb().

2438 {
2439  if (m->status != status) {
2440  /* If this member has transitioned to being available then update their queue
2441  * information. If they are currently in a call then the leg to the agent will be
2442  * considered done and the call finished.
2443  */
2444  if (status == AST_DEVICE_NOT_INUSE) {
2446  }
2447 
2448  m->status = status;
2449 
2450  /* Remove the member from the pending members pool only when the status changes.
2451  * This is not done unconditionally because we can occasionally see multiple
2452  * device state notifications of not in use after a previous call has ended,
2453  * including after we have initiated a new call. This is more likely to
2454  * happen when there is latency in the connection to the member.
2455  */
2457 
2458  queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m));
2459  }
2460 }
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2426
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:5707
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2258
time_t starttime
Definition: app_queue.c:1609
int status
Definition: app_queue.c:1603
int callcompletedinsl
Definition: app_queue.c:1607
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2234
jack_status_t status
Definition: app_jack.c:146

◆ upqm_exec()

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

UnPauseQueueMember application.

Definition at line 7918 of file app_queue.c.

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

Referenced by load_module().

7919 {
7920  char *parse;
7922  AST_APP_ARG(queuename);
7923  AST_APP_ARG(interface);
7925  AST_APP_ARG(reason);
7926  );
7927 
7928  if (ast_strlen_zero(data)) {
7929  ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
7930  return -1;
7931  }
7932 
7933  parse = ast_strdupa(data);
7934 
7935  AST_STANDARD_APP_ARGS(args, parse);
7936 
7937  if (ast_strlen_zero(args.interface)) {
7938  ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
7939  return -1;
7940  }
7941 
7942  if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
7943  ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
7944  pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
7945  return 0;
7946  }
7947 
7948  pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
7949 
7950  return 0;
7951 }
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
const char * args
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:7528
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
static struct test_options options
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ valid_exit()

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

Check for valid exit from queue via goto.

Return values
0if failure
1if successful

Definition at line 3945 of file app_queue.c.

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

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

3946 {
3947  int digitlen = strlen(qe->digits);
3948 
3949  /* Prevent possible buffer overflow */
3950  if (digitlen < sizeof(qe->digits) - 2) {
3951  qe->digits[digitlen] = digit;
3952  qe->digits[digitlen + 1] = '\0';
3953  } else {
3954  qe->digits[0] = '\0';
3955  return 0;
3956  }
3957 
3958  /* If there's no context to goto, short-circuit */
3959  if (ast_strlen_zero(qe->context)) {
3960  return 0;
3961  }
3962 
3963  /* If the extension is bad, then reset the digits to blank */
3964  if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
3966  qe->digits[0] = '\0';
3967  return 0;
3968  }
3969 
3970  /* We have an exact match */
3971  if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
3972  qe->valid_digits = 1;
3973  /* Return 1 on a successful goto */
3974  return 1;
3975  }
3976 
3977  return 0;
3978 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
char digit
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
char digits[AST_MAX_EXTENSION]
Definition: app_queue.c:1565
struct ast_channel * chan
Definition: app_queue.c:1586
#define NULL
Definition: resample.c:96
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition: pbx.c:4194
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_party_id id
Caller party ID.
Definition: channel.h:421
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
int valid_digits
Definition: app_queue.c:1567
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8793
char context[AST_MAX_CONTEXT]
Definition: app_queue.c:1564
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343

◆ wait_a_bit()

static int wait_a_bit ( struct queue_ent qe)
static

Definition at line 7229 of file app_queue.c.

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

Referenced by queue_exec().

7230 {
7231  /* Don't need to hold the lock while we setup the outgoing calls */
7232  int retrywait = qe->parent->retry * 1000;
7233 
7234  int res = ast_waitfordigit(qe->chan, retrywait);
7235  if (res > 0 && !valid_exit(qe, res)) {
7236  res = 0;
7237  }
7238 
7239  return res;
7240 }
struct call_queue * parent
Definition: app_queue.c:1561
struct ast_channel * chan
Definition: app_queue.c:1586
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3184
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:3945

◆ wait_for_answer()

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

Wait for a member to answer the call.

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

Definition at line 4937 of file app_queue.c.

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

Referenced by try_calling().

4938 {
4939  const char *queue = qe->parent->name;
4940  struct callattempt *o, *start = NULL, *prev = NULL;
4941  int status;
4942  int numbusies = prebusies;
4943  int numnochan = 0;
4944  int stillgoing = 0;
4945  int orig = *to;
4946  struct ast_frame *f;
4947  struct callattempt *peer = NULL;
4948  struct ast_channel *winner;
4949  struct ast_channel *in = qe->chan;
4950  char on[80] = "";
4951  char membername[80] = "";
4952  long starttime = 0;
4953  long endtime = 0;
4954  char *inchan_name;
4955  struct timeval start_time_tv = ast_tvnow();
4956  int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */
4957 
4958  ast_channel_lock(qe->chan);
4959  inchan_name = ast_strdupa(ast_channel_name(qe->chan));
4960  ast_channel_unlock(qe->chan);
4961 
4962  starttime = (long) time(NULL);
4963 
4964  while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
4965  int numlines, retry, pos = 1;
4966  struct ast_channel *watchers[AST_MAX_WATCHERS];
4967  watchers[0] = in;
4968  start = NULL;
4969 
4970  for (retry = 0; retry < 2; retry++) {
4971  numlines = 0;
4972  for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
4973  if (o->stillgoing) { /* Keep track of important channels */
4974  stillgoing = 1;
4975  if (o->chan) {
4976  if (pos < AST_MAX_WATCHERS) {
4977  watchers[pos++] = o->chan;
4978  }
4979  if (!start) {
4980  start = o;
4981  } else {
4982  prev->call_next = o;
4983  }
4984  prev = o;
4985  }
4986  } else if (prev) {
4987  prev->call_next = NULL;
4988  }
4989  numlines++;
4990  }
4991  if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
4992  (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) {
4993  break;
4994  }
4995  /* On "ringall" strategy we only move to the next penalty level
4996  when *all* ringing phones are done in the current penalty level */
4997  ring_one(qe, outgoing, &numbusies);
4998  /* and retry... */
4999  }
5000  if (pos == 1 /* not found */) {
5001  if (numlines == (numbusies + numnochan)) {
5002  ast_debug(1, "Everyone is busy at this time\n");
5003  } else {
5004  ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
5005  }
5006  *to = 0;
5007  return NULL;
5008  }
5009 
5010  /* Poll for events from both the incoming channel as well as any outgoing channels */
5011  winner = ast_waitfor_n(watchers, pos, to);
5012 
5013  /* Service all of the outgoing channels */
5014  for (o = start; o; o = o->call_next) {
5015  /* We go with a fixed buffer here instead of using ast_strdupa. Using
5016  * ast_strdupa in a loop like this one can cause a stack overflow
5017  */
5018  char ochan_name[AST_CHANNEL_NAME];
5019 
5020  if (o->chan) {
5021  ast_channel_lock(o->chan);
5022  ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
5024  }
5025  if (o->stillgoing && (o->chan) && (ast_channel_state(o->chan) == AST_STATE_UP)) {
5026  if (!peer) {
5027  ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5028  if (o->orig_chan_name
5029  && strcmp(o->orig_chan_name, ochan_name)) {
5030  /*
5031  * The channel name changed so we must generate COLP update.
5032  * Likely because a call pickup channel masqueraded in.
5033  */
5035  } else if (!o->block_connected_update) {
5036  if (o->pending_connected_update) {
5037  if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) &&
5038  ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
5040  }
5041  } else if (!o->dial_callerid_absent) {
5043  }
5044  }
5045  if (o->aoc_s_rate_list) {
5046  size_t encoded_size;
5047  struct ast_aoc_encoded *encoded;
5048  if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5049  ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5050  ast_aoc_destroy_encoded(encoded);
5051  }
5052  }
5053  peer = o;
5054  }
5055  } else if (o->chan && (o->chan == winner)) {
5056 
5057  ast_copy_string(on, o->member->interface, sizeof(on));
5058  ast_copy_string(membername, o->member->membername, sizeof(membername));
5059 
5060  /* Before processing channel, go ahead and check for forwarding */
5061  if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
5062  ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
5064  "CANCEL", ast_channel_call_forward(o->chan));
5065  numnochan++;
5066  do_hang(o);
5067  winner = NULL;
5068  continue;
5069  } else if (!ast_strlen_zero(ast_channel_call_forward(o->chan))) {
5070  struct ast_channel *original = o->chan;
5071  char forwarder[AST_CHANNEL_NAME];
5072  char tmpchan[256];
5073  char *stuff;
5074  char *tech;
5075  int failed = 0;
5076 
5077  ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
5078  ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder));
5079  if ((stuff = strchr(tmpchan, '/'))) {
5080  *stuff++ = '\0';
5081  tech = tmpchan;
5082  } else {
5083  const char *forward_context;
5084  ast_channel_lock(o->chan);
5085  forward_context = pbx_builtin_getvar_helper(o->chan, "FORWARD_CONTEXT");
5086  snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), forward_context ? forward_context : ast_channel_context(o->chan));
5088  stuff = tmpchan;
5089  tech = "Local";
5090  }
5091  if (!strcasecmp(tech, "Local")) {
5092  /*
5093  * Drop the connected line update block for local channels since
5094  * this is going to run dialplan and the user can change his
5095  * mind about what connected line information he wants to send.
5096  */
5097  o->block_connected_update = 0;
5098  }
5099 
5100  ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
5101  /* Setup parameters */
5102  o->chan = ast_request(tech, ast_channel_nativeformats(in), NULL, in, stuff, &status);
5103  if (!o->chan) {
5105  "Forwarding failed to create channel to dial '%s/%s'\n",
5106  tech, stuff);
5107  o->stillgoing = 0;
5108  numnochan++;
5109  } else {
5110  ast_channel_lock_both(o->chan, original);
5112  ast_channel_redirecting(original));
5114  ast_channel_unlock(original);
5115 
5116  ast_channel_lock_both(o->chan, in);
5119  pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
5121 
5122  if (o->pending_connected_update) {
5123  /*
5124  * Re-seed the callattempt's connected line information with
5125  * previously acquired connected line info from the queued
5126  * channel. The previously acquired connected line info could
5127  * have been set through the CONNECTED_LINE dialplan function.
5128  */
5129  o->pending_connected_update = 0;
5131  }
5132 
5135 
5137 
5140  /*
5141  * The call was not previously redirected so it is
5142  * now redirected from this number.
5143  */
5149  }
5150 
5152 
5156  ast_channel_caller(in));
5157 
5158  ast_channel_unlock(in);
5160  && !o->block_connected_update) {
5161  struct ast_party_redirecting redirecting;
5162 
5163  /*
5164  * Redirecting updates to the caller make sense only on single
5165  * call at a time strategies.
5166  *
5167  * We must unlock o->chan before calling
5168  * ast_channel_redirecting_macro, because we put o->chan into
5169  * autoservice there. That is pretty much a guaranteed
5170  * deadlock. This is why the handling of o->chan's lock may
5171  * seem a bit unusual here.
5172  */
5173  ast_party_redirecting_init(&redirecting);
5176  if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0) &&
5177  ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0)) {
5178  ast_channel_update_redirecting(in, &redirecting, NULL);
5179  }
5180  ast_party_redirecting_free(&redirecting);
5181  } else {
5183  }
5184 
5185  if (ast_call(o->chan, stuff, 0)) {
5186  ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
5187  tech, stuff);
5188  failed = 1;
5189  }
5190  }
5191 
5192  ast_channel_publish_dial_forward(qe->chan, original, o->chan, NULL,
5193  "CANCEL", ast_channel_call_forward(original));
5194  if (o->chan) {
5195  ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
5196  }
5197 
5198  if (failed) {
5199  do_hang(o);
5200  numnochan++;
5201  }
5202 
5203  /* Hangup the original channel now, in case we needed it */
5204  ast_hangup(winner);
5205  continue;
5206  }
5207  f = ast_read(winner);
5208  if (f) {
5209  if (f->frametype == AST_FRAME_CONTROL) {
5210  switch (f->subclass.integer) {
5211  case AST_CONTROL_ANSWER:
5212  /* This is our guy if someone answered. */
5213  if (!peer) {
5214  ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5215  ast_channel_publish_dial(qe->chan, o->chan, on, "ANSWER");
5216  publish_dial_end_event(qe->chan, outgoing, o->chan, "CANCEL");
5217  if (o->orig_chan_name
5218  && strcmp(o->orig_chan_name, ochan_name)) {
5219  /*
5220  * The channel name changed so we must generate COLP update.
5221  * Likely because a call pickup channel masqueraded in.
5222  */
5224  } else if (!o->block_connected_update) {
5225  if (o->pending_connected_update) {
5226  if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) &&
5227  ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
5229  }
5230  } else if (!o->dial_callerid_absent) {
5232  }
5233  }
5234  if (o->aoc_s_rate_list) {
5235  size_t encoded_size;
5236  struct ast_aoc_encoded *encoded;
5237  if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5238  ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5239  ast_aoc_destroy_encoded(encoded);
5240  }
5241  }
5242  peer = o;
5243  }
5244  break;
5245  case AST_CONTROL_BUSY:
5246  ast_verb(3, "%s is busy\n", ochan_name);
5247  ast_channel_publish_dial(qe->chan, o->chan, on, "BUSY");
5248  endtime = (long) time(NULL);
5249  endtime -= starttime;
5250  rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopausebusy);
5251  do_hang(o);
5252  if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
5253  if (qe->parent->timeoutrestart) {
5254  start_time_tv = ast_tvnow();
5255  }
5256  /* Have enough time for a queue member to answer? */
5257  if (ast_remaining_ms(start_time_tv, orig) > 500) {
5258  ring_one(qe, outgoing, &numbusies);
5259  starttime = (long) time(NULL);
5260  }
5261  }
5262  numbusies++;
5263  break;
5265  ast_verb(3, "%s is circuit-busy\n", ochan_name);
5266  ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION");
5267  endtime = (long) time(NULL);
5268  endtime -= starttime;
5269  rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopauseunavail);
5270  do_hang(o);
5271  if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
5272  if (qe->parent->timeoutrestart) {
5273  start_time_tv = ast_tvnow();
5274  }
5275  if (ast_remaining_ms(start_time_tv, orig) > 500) {
5276  ring_one(qe, outgoing, &numbusies);
5277  starttime = (long) time(NULL);
5278  }
5279  }
5280  numbusies++;
5281  break;
5282  case AST_CONTROL_RINGING:
5283  ast_verb(3, "%s is ringing\n", ochan_name);
5284 
5285  ast_channel_publish_dial(qe->chan, o->chan, on, "RINGING");
5286 
5287  /* Start ring indication when the channel is ringing, if specified */
5288  if (qe->ring_when_ringing) {
5289  ast_moh_stop(qe->chan);
5291  }
5292  break;
5293  case AST_CONTROL_OFFHOOK:
5294  /* Ignore going off hook */
5295  break;
5297  if (o->block_connected_update) {
5298  ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
5299  break;
5300  }
5301  if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
5303 
5304  ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
5309  o->pending_connected_update = 1;
5310  break;
5311  }
5312 
5313  /*
5314  * Prevent using the CallerID from the outgoing channel since we
5315  * got a connected line update from it.
5316  */
5317  o->dial_callerid_absent = 1;
5318 
5319  if (ast_channel_connected_line_sub(o->chan, in, f, 1) &&
5320  ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
5322  }
5323  break;
5324  case AST_CONTROL_AOC:
5325  {
5326  struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
5327  if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
5329  o->aoc_s_rate_list = decoded;
5330  } else {
5331  ast_aoc_destroy_decoded(decoded);
5332  }
5333  }
5334  break;
5336  if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
5337  /*
5338  * Redirecting updates to the caller make sense only on single
5339  * call at a time strategies.
5340  */
5341  break;
5342  }
5343  if (o->block_connected_update) {
5344  ast_verb(3, "Redirecting update to %s prevented\n",
5345  inchan_name);
5346  break;
5347  }
5348  ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
5349  ochan_name, inchan_name);
5350  if (ast_channel_redirecting_sub(o->chan, in, f, 1) &&
5351  ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
5353  }
5354  break;
5357  break;
5358  default:
5359  ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
5360  break;
5361  }
5362  }
5363  ast_frfree(f);
5364  } else { /* ast_read() returned NULL */
5365  endtime = (long) time(NULL) - starttime;
5366  ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER");
5367  rna(endtime * 1000, qe, o->chan, on, membername, 1);
5368  do_hang(o);
5369  if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
5370  if (qe->parent->timeoutrestart) {
5371  start_time_tv = ast_tvnow();
5372  }
5373  if (ast_remaining_ms(start_time_tv, orig) > 500) {
5374  ring_one(qe, outgoing, &numbusies);
5375  starttime = (long) time(NULL);
5376  }
5377  }
5378  }
5379  }
5380  }
5381 
5382  /* If we received an event from the caller, deal with it. */
5383  if (winner == in) {
5384  f = ast_read(in);
5385  if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
5386  /* Got hung up */
5387  *to = -1;
5388  if (f) {
5389  if (f->data.uint32) {
5391  }
5392  ast_frfree(f);
5393  }
5394  canceled_by_caller = 1;
5395  } else if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
5396  ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
5397  *to = 0;
5398  ast_frfree(f);
5399  canceled_by_caller = 1;
5400  } else if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
5401  ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
5402  *to = 0;
5403  *digit = f->subclass.integer;
5404  ast_frfree(f);
5405  canceled_by_caller = 1;
5406  }
5407  /* When caller hung up or pressed * or digit. */
5408  if (canceled_by_caller) {
5409  publish_dial_end_event(in, outgoing, NULL, "CANCEL");
5410  for (o = start; o; o = o->call_next) {
5411  if (o->chan) {
5412  ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), o->member->membername, "RINGCANCELED", "%d", (int) ast_tvdiff_ms(ast_tvnow(), start_time_tv));
5413  }
5414  }
5415  return NULL;
5416  }
5417 
5418  /* Send the frame from the in channel to all outgoing channels. */
5419  for (o = start; o; o = o->call_next) {
5420  if (!o->stillgoing || !o->chan) {
5421  /* This outgoing channel has died so don't send the frame to it. */
5422  continue;
5423  }
5424  switch (f->frametype) {
5425  case AST_FRAME_CONTROL:
5426  switch (f->subclass.integer) {
5428  if (o->block_connected_update) {
5429  ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
5430  break;
5431  }
5432  if (ast_channel_connected_line_sub(in, o->chan, f, 1) &&
5433  ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) {
5435  }
5436  break;
5438  if (o->block_connected_update) {
5439  ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
5440  break;
5441  }
5442  if (ast_channel_redirecting_sub(in, o->chan, f, 1) &&
5443  ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) {
5445  }
5446  break;
5447  default:
5448  /* We are not going to do anything with this frame. */
5449  goto skip_frame;
5450  }
5451  break;
5452  default:
5453  /* We are not going to do anything with this frame. */
5454  goto skip_frame;
5455  }
5456  }
5457 skip_frame:;
5458 
5459  ast_frfree(f);
5460  }
5461  }
5462 
5463  if (!*to) {
5464  for (o = start; o; o = o->call_next) {
5465  if (o->chan) {
5466  rna(orig, qe, o->chan, o->interface, o->member->membername, 1);
5467  }
5468  }
5469 
5470  publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER");
5471  }
5472 
5473  return peer;
5474 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
struct ast_channel * ast_waitfor_n(struct ast_channel **chan, int n, int *ms)
Waits for input on a group of channels Wait for input on an array of channels for a given # of millis...
Definition: channel.c:3166
struct callattempt * q_next
Definition: app_queue.c:1538
char digit
struct call_queue * parent
Definition: app_queue.c:1561
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int frame)
Run a connected line interception macro and update a channel&#39;s connected line information.
Definition: channel.c:10435
struct ast_channel * chan
Definition: app_queue.c:1586
void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
Initialize the given connected line structure using the given guide for a set update operation...
Definition: channel.c:2045
unsigned int autopauseunavail
Definition: app_queue.c:1716
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4322
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:528
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...
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update)
Indicate that the redirecting id has changed.
Definition: channel.c:10379
#define AST_MAX_WATCHERS
Definition: app_queue.c:4923
void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Indicate that the connected line information has changed.
Definition: channel.c:9189
unsigned int timeoutrestart
Definition: app_queue.c:1707
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6553
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:307
ast_channel_state
ast_channel states
Definition: channelstate.h:35
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4698
char interface[256]
Definition: app_queue.c:1541
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2072
struct ast_aoc_decoded * aoc_s_rate_list
Definition: app_queue.c:1554
#define NULL
Definition: resample.c:96
#define AST_FRAME_DTMF
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7876
const char * ast_channel_call_forward(const struct ast_channel *chan)
#define ast_verb(level,...)
Definition: logger.h:463
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
Definition: app_queue.c:4906
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
struct ast_frame_subclass subclass
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6444
const struct ast_channel_tech * tech
struct ast_party_id id
Caller party ID.
Definition: channel.h:421
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2373
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
struct ast_party_connected_line connected
Definition: app_queue.c:1545
struct ast_aoc_decoded * ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
decodes an encoded aoc payload.
Definition: aoc.c:449
FILE * in
Definition: utils/frame.c:33
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
struct ast_aoc_encoded * ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
encodes a decoded aoc structure so it can be passed on the wire
Definition: aoc.c:650
unsigned int block_connected_update
Definition: app_queue.c:1549
int ring_when_ringing
Definition: app_queue.c:1571
int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *redirecting_info, int is_frame)
Run a redirecting interception subroutine and update a channel&#39;s redirecting information.
Definition: channel.c:10584
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition: channel.c:1644
unsigned int autopausebusy
Definition: app_queue.c:1715
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
struct member * member
Definition: app_queue.c:1543
int strategy
Definition: app_queue.c:1711
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&#39;t answer...
Definition: app_queue.c:4839
void ast_channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition: channel.c:6526
const char * ast_channel_exten(const struct ast_channel *chan)
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition: channel.c:1691
const char * ast_channel_uniqueid(const struct ast_channel *chan)
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1537
int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected)
Parse connected line indication frame data.
Definition: channel.c:8881
char * orig_chan_name
Definition: app_queue.c:1556
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition: app_queue.c:4238
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: main/utils.c:2033
int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int frame)
Run a connected line interception subroutine and update a channel&#39;s connected line information...
Definition: channel.c:10539
const ast_string_field name
Definition: app_queue.c:1696
void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src, const struct ast_set_party_connected_line *update)
Set the connected line information based on another connected line source.
Definition: channel.c:2054
Connected Line/Party information.
Definition: channel.h:457
unsigned int pending_connected_update
Definition: app_queue.c:1547
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
Definition: channel.h:523
#define LOG_NOTICE
Definition: logger.h:263
void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring, const char *dialstatus, const char *forward)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
Definition: channel.c:6866
#define ast_free(a)
Definition: astmm.h:182
#define AST_CHANNEL_NAME
Definition: channel.h:172
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:313
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
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...
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2952
int transit_network_select
Transit Network Select.
Definition: channel.h:398
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition: channel.c:2179
void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
Copy the source connected line information to the destination connected line.
Definition: channel.c:2031
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Definition: max_forwards.c:135
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition: channel.c:8389
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition: channel.c:2122
#define ast_frfree(fr)
Data structure associated with a single frame of data.
Definition: aoc.h:64
const char * ast_channel_context(const struct ast_channel *chan)
enum ast_aoc_type ast_aoc_get_msg_type(struct ast_aoc_decoded *decoded)
get the message type, AOC-D, AOC-E, or AOC Request
Definition: aoc.c:892
union ast_frame::@263 data
enum ast_frame_type frametype
static void do_hang(struct callattempt *o)
common hangup actions
Definition: app_queue.c:4358
struct callattempt * call_next
Definition: app_queue.c:1539
unsigned int dial_callerid_absent
Definition: app_queue.c:1551
struct ast_channel * chan
Definition: app_queue.c:1540
char connected
Definition: eagi_proxy.c:82
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:3945
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
unsigned int stillgoing
Definition: app_queue.c:1553
const char * ast_channel_macroexten(const struct ast_channel *chan)
void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
Copy the source redirecting information to the destination redirecting.
Definition: channel.c:2135
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
Place a call to a queue member.
Definition: app_queue.c:4639
jack_status_t status
Definition: app_jack.c:146
int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *redirecting_info, int is_caller, int is_frame)
Run a redirecting interception macro and update a channel&#39;s redirecting information.
Definition: channel.c:10487
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343

◆ wait_our_turn()

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

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

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

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

Definition at line 5626 of file app_queue.c.

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

Referenced by queue_exec().

5627 {
5628  int res = 0;
5629 
5630  /* This is the holding pen for callers 2 through maxlen */
5631  for (;;) {
5632 
5633  if (is_our_turn(qe)) {
5634  break;
5635  }
5636 
5637  /* If we have timed out, break out */
5638  if (qe->expire && (time(NULL) >= qe->expire)) {
5639  *reason = QUEUE_TIMEOUT;
5640  break;
5641  }
5642 
5643  if (qe->parent->leavewhenempty) {
5644  int status = 0;
5645 
5646  if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->raise_penalty, qe->parent->leavewhenempty, 0))) {
5647  record_abandoned(qe);
5648  *reason = QUEUE_LEAVEEMPTY;
5649  ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
5650  res = -1;
5651  qe->handled = -1;
5652  break;
5653  }
5654  }
5655 
5656  /* Make a position announcement, if enabled */
5657  if (qe->parent->announcefrequency &&
5658  (res = say_position(qe,ringing))) {
5659  break;
5660  }
5661 
5662  /* If we have timed out, break out */
5663  if (qe->expire && (time(NULL) >= qe->expire)) {
5664  *reason = QUEUE_TIMEOUT;
5665  break;
5666  }
5667 
5668  /* Make a periodic announcement, if enabled */
5669  if (qe->parent->periodicannouncefrequency &&
5670  (res = say_periodic_announcement(qe,ringing)))
5671  break;
5672 
5673  /* see if we need to move to the next penalty level for this queue */
5674  while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
5675  update_qe_rule(qe);
5676  }
5677 
5678  /* If we have timed out, break out */
5679  if (qe->expire && (time(NULL) >= qe->expire)) {
5680  *reason = QUEUE_TIMEOUT;
5681  break;
5682  }
5683 
5684  /* Wait a second before checking again */
5685  if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
5686  if (res > 0 && !valid_exit(qe, res)) {
5687  res = 0;
5688  } else {
5689  break;
5690  }
5691  }
5692 
5693  /* If we have timed out, break out */
5694  if (qe->expire && (time(NULL) >= qe->expire)) {
5695  *reason = QUEUE_TIMEOUT;
5696  break;
5697  }
5698  }
5699 
5700  return res;
5701 }
static int say_position(struct queue_ent *qe, int ringing)
Definition: app_queue.c:3980
struct call_queue * parent
Definition: app_queue.c:1561
int raise_penalty
Definition: app_queue.c:1580
struct ast_channel * chan
Definition: app_queue.c:1586
int min_penalty
Definition: app_queue.c:1579
int max_penalty
Definition: app_queue.c:1578
time_t start
Definition: app_queue.c:1583
time_t expire
Definition: app_queue.c:1584
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
Playback announcement to queued members if period has elapsed.
Definition: app_queue.c:4747
#define NULL
Definition: resample.c:96
int periodicannouncefrequency
Definition: app_queue.c:1722
static void ringing(struct ast_channel *chan)
Helper method to send a ringing indication to a channel in a bridge.
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const ast_string_field name
Definition: app_queue.c:1696
struct penalty_rule * pr
Definition: app_queue.c:1588
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3184
static void record_abandoned(struct queue_ent *qe)
Record that a caller gave up on waiting in queue.
Definition: app_queue.c:4808
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:2284
enum empty_conditions leavewhenempty
Definition: app_queue.c:1718
#define RECHECK
Definition: app_queue.c:1431
int handled
Definition: app_queue.c:1576
static void update_qe_rule(struct queue_ent *qe)
update rules for queues
Definition: app_queue.c:5536
static int is_our_turn(struct queue_ent *qe)
Check if we should start attempting to call queue members.
Definition: app_queue.c:5487
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:3945
int announcefrequency
Definition: app_queue.c:1720
jack_status_t status
Definition: app_jack.c:146

◆ word_in_list()

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

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

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

Definition at line 9870 of file app_queue.c.

Referenced by complete_queue().

9870  {
9871  int list_len, word_len = strlen(word);
9872  const char *find, *end_find, *end_list;
9873 
9874  /* strip whitespace from front */
9875  while(isspace(*list)) {
9876  list++;
9877  }
9878 
9879  while((find = strstr(list, word))) {
9880  /* beginning of find starts inside another word? */
9881  if (find != list && *(find - 1) != ' ') {
9882  list = find;
9883  /* strip word from front */
9884  while(!isspace(*list) && *list != '\0') {
9885  list++;
9886  }
9887  /* strip whitespace from front */
9888  while(isspace(*list)) {
9889  list++;
9890  }
9891  continue;
9892  }
9893 
9894  /* end of find ends inside another word or at very end of list? */
9895  list_len = strlen(list);
9896  end_find = find + word_len;
9897  end_list = list + list_len;
9898  if (end_find == end_list || *end_find != ' ') {
9899  list = find;
9900  /* strip word from front */
9901  while(!isspace(*list) && *list != '\0') {
9902  list++;
9903  }
9904  /* strip whitespace from front */
9905  while(isspace(*list)) {
9906  list++;
9907  }
9908  continue;
9909  }
9910 
9911  /* terminating conditions satisfied, word at beginning or separated by ' ' */
9912  return 1;
9913  }
9914 
9915  return 0;
9916 }
short word

Variable Documentation

◆ __mod_info

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

Definition at line 11505 of file app_queue.c.

◆ agent_router

struct stasis_message_router* agent_router
static

Definition at line 11247 of file app_queue.c.

◆ app

char* app = "Queue"
static

Definition at line 1448 of file app_queue.c.

◆ app_aqm

char* app_aqm = "AddQueueMember"
static

Definition at line 1450 of file app_queue.c.

◆ app_pqm

char* app_pqm = "PauseQueueMember"
static

Definition at line 1454 of file app_queue.c.

◆ app_ql

char* app_ql = "QueueLog"
static

Definition at line 1458 of file app_queue.c.

◆ app_qupd

char* app_qupd = "QueueUpdate"
static

Definition at line 1460 of file app_queue.c.

◆ app_rqm

char* app_rqm = "RemoveQueueMember"
static

Definition at line 1452 of file app_queue.c.

◆ app_upqm

char* app_upqm = "UnpauseQueueMember"
static

Definition at line 1456 of file app_queue.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 11505 of file app_queue.c.

◆ autofill_default

int autofill_default
static

queues.conf [general] option

Definition at line 1472 of file app_queue.c.

Referenced by init_queue().

◆ autopausesmodes

const struct autopause autopausesmodes[]
static

◆ cli_queue

struct ast_cli_entry cli_queue[]
static

Definition at line 11234 of file app_queue.c.

◆ device_state_sub

struct stasis_subscription* device_state_sub
static

Subscription to device state change messages.

Definition at line 1484 of file app_queue.c.

◆ id

enum queue_result id

◆ log_membername_as_agent

int log_membername_as_agent
static

queues.conf [general] option

Definition at line 1490 of file app_queue.c.

◆ montype_default

int montype_default
static

queues.conf [general] option

Definition at line 1475 of file app_queue.c.

Referenced by init_queue().

◆ negative_penalty_invalid

int negative_penalty_invalid
static

queues.conf [general] option

Definition at line 1487 of file app_queue.c.

◆ pending_members

struct ao2_container* pending_members
static

Definition at line 2375 of file app_queue.c.

◆ pm_family

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

Persistent Members astdb family.

Definition at line 1463 of file app_queue.c.

◆ queue_exec_options

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

Definition at line 1379 of file app_queue.c.

Referenced by queue_exec().

◆ queue_persistent_members

int queue_persistent_members
static

queues.conf [general] option

Definition at line 1466 of file app_queue.c.

◆ queue_results

const { ... } queue_results[]

Referenced by set_queue_result().

◆ queueexists_function

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

Definition at line 9079 of file app_queue.c.

◆ queuegetchannel_function

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

Definition at line 9100 of file app_queue.c.

◆ queuemembercount_dep

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

Definition at line 9095 of file app_queue.c.

◆ queuemembercount_function

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

Definition at line 9089 of file app_queue.c.

◆ queuememberlist_function

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

Definition at line 9110 of file app_queue.c.

◆ queuememberpenalty_function

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

Definition at line 9115 of file app_queue.c.

◆ queues

struct ao2_container* queues
static

Definition at line 1766 of file app_queue.c.

◆ queuevar_function

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

Definition at line 9084 of file app_queue.c.

◆ queuewaitingcount_function

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

Definition at line 9105 of file app_queue.c.

◆ realtime_ringinuse_field

char* realtime_ringinuse_field
static

name of the ringinuse field in the realtime database

Definition at line 1493 of file app_queue.c.

◆ realtime_rules

int realtime_rules
static

queuesrules.conf [general] option

Definition at line 1481 of file app_queue.c.

Referenced by reload_queue_rules().

◆ rule_lists

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

◆ shared_lastcall

int shared_lastcall
static

queues.conf [general] option

Definition at line 1478 of file app_queue.c.

◆ strategies

const struct strategy strategies[]
static

Referenced by int2strat(), and strat2int().

◆ text

char* text

◆ topic_forwarder

struct stasis_forward* topic_forwarder
static

Definition at line 11248 of file app_queue.c.

◆ use_weight

int use_weight
static

Records that one or more queues use weight.

Definition at line 1469 of file app_queue.c.