app_queue.c File Reference

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

#include "asterisk.h"
#include <sys/time.h>
#include <sys/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/global_datastores.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/aoc.h"
#include "asterisk/callerid.h"
#include "asterisk/data.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/core_unreal.h"
#include "asterisk/bridge_basic.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

Defines

#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 DATA_EXPORT_CALL_QUEUE(MEMBER)
#define DATA_EXPORT_MEMBER(MEMBER)
#define DATA_EXPORT_QUEUE_ENT(MEMBER)
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY   15
 The minimum number of seconds between position announcements.
#define DEFAULT_RETRY   5
#define DEFAULT_TIMEOUT   15
#define MAX_PERIODIC_ANNOUNCEMENTS   10
#define MAX_QUEUE_BUCKETS   53
#define QUEUE_EVENT_VARIABLES   3
#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE
#define queue_t_ref(q, tag)   queue_ref(q)
#define queue_t_unref(q, tag)   queue_unref(q)
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE
#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE
#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_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)
}
enum  { OPT_ARG_CALLEE_GO_ON = 0, 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.
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)
 Add member to queue.
static struct call_queuealloc_queue (const char *queuename)
static int aqm_exec (struct ast_channel *chan, const char *data)
 AddQueueMember application.
 AST_DATA_STRUCTURE (queue_ent, DATA_EXPORT_QUEUE_ENT)
 AST_DATA_STRUCTURE (member, DATA_EXPORT_MEMBER)
 AST_DATA_STRUCTURE (call_queue, DATA_EXPORT_CALL_QUEUE)
static int autopause2int (const char *autopause)
static int calc_metric (struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
 Calculate the metric of each member in the outgoing callattempts.
static void callattempt_free (struct callattempt *doomed)
static int can_ring_entry (struct queue_ent *qe, struct callattempt *call)
static void clear_queue (struct call_queue *q)
static int clear_stats (const char *queuename)
 Facilitates resetting statistics for a queue.
static int compare_weight (struct call_queue *rq, struct member *member)
static char * complete_queue (const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
 Check if a given word is in a space-delimited list.
static char * complete_queue_add_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_pause_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_remove_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_rule_show (const char *line, const char *word, int pos, int state)
static char * complete_queue_set_member_value (const char *line, const char *word, int pos, int state)
static char * complete_queue_show (const char *line, const char *word, int pos, int state)
static int compress_char (const char c)
static void copy_rules (struct queue_ent *qe, const char *rulename)
 Copy rule from global list into specified queue.
static struct membercreate_queue_member (const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse)
 allocate space for new queue member and set fields based on parameters passed
static void destroy_queue (void *obj)
 Free queue's member list then its string fields.
static void device_state_cb (void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
 set a member's status based on device state of that member's interface
static void do_hang (struct callattempt *o)
 common hangup actions
static void do_print (struct mansession *s, int fd, const char *str)
 direct ouput to manager or cli with proper terminator
static void dump_queue_members (struct call_queue *pm_queue)
 Dump all members in a specific queue to the database.
static void end_bridge_callback (void *data)
static void end_bridge_callback_data_fixup (struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
static void escape_and_substitute (struct ast_channel *chan, const char *input, char *output, size_t size)
static int extension_state_cb (char *context, char *exten, struct ast_state_cb_info *info, void *data)
static int extensionstate2devicestate (int state)
 Helper function which converts from extension state to device state values.
static struct callattemptfind_best (struct callattempt *outgoing)
 find the entry with the best metric, or NULL
static struct call_queuefind_load_queue_rt_friendly (const char *queuename)
static struct memberfind_member_by_queuename_and_interface (const char *queuename, const char *interface)
static struct call_queuefind_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
 Reload a single queue via realtime.
static void free_members (struct call_queue *q, int all)
 Iterate through queue's member list and delete them.
static int get_member_penalty (char *queuename, char *interface)
static int get_member_status (struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions, int devstate)
 Check if members are available.
static int get_queue_member_status (struct member *cur)
 Return the current state of a member.
static void handle_attended_transfer (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 Handle an attended transfer event.
static void handle_blind_transfer (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
 Handle a blind transfer event.
static void handle_bridge_enter (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
static void handle_hangup (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
static void handle_local_optimization_begin (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
static void handle_local_optimization_end (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
static char * handle_queue_add_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_pause_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_remove_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_reset (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_rule_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_set_member_penalty (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_set_member_ringinuse (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void hangupcalls (struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
 Hang up a list of outgoing calls.
static void init_queue (struct call_queue *q)
 Initialize Queue default values.
static void insert_entry (struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
 Insert the 'new' entry after the 'prev' entry of queue 'q'.
static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
 Change queue penalty by adding rule.
static const char * int2strat (int strategy)
static struct memberinterface_exists (struct call_queue *q, const char *interface)
static int is_member_available (struct call_queue *q, struct member *mem)
static int is_our_turn (struct queue_ent *qe)
 Check if we should start attempting to call queue members.
static int join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
static int kill_dead_members (void *obj, void *arg, int flags)
static int kill_dead_queues (void *obj, void *arg, int flags)
static void leave_queue (struct queue_ent *qe)
 Caller leaving queue.
static int load_module (void)
 Load the module.
static int load_realtime_rules (void)
 Load queue rules from realtime.
static void log_attended_transfer (struct queue_stasis_data *queue_data, struct ast_channel_snapshot *caller, struct ast_attended_transfer_message *atxfer_msg)
static int manager_add_queue_member (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_show (struct mansession *s, const struct message *m)
static int manager_queues_status (struct mansession *s, const struct message *m)
 Queue status info via AMI.
static int manager_queues_summary (struct mansession *s, const struct message *m)
 Summary of queue info via the AMI.
static int manager_remove_queue_member (struct mansession *s, const struct message *m)
static int mark_dead_and_unfound (void *obj, void *arg, int flags)
static int mark_member_dead (void *obj, void *arg, int flags)
static void member_add_to_queue (struct call_queue *queue, struct member *mem)
static void member_call_pending_clear (struct member *mem)
static int member_call_pending_set (struct member *mem)
static int member_cmp_fn (void *obj1, void *obj2, int flags)
static int member_hash_fn (const void *obj, const int flags)
static void member_remove_from_queue (struct call_queue *queue, struct member *mem)
static int member_status_available (int status)
static int num_available_members (struct call_queue *q)
 Get the number of members available to accept a call.
static void parse_empty_options (const char *value, enum empty_conditions *empty, int joinempty)
static int play_file (struct ast_channel *chan, const char *filename)
static int pqm_exec (struct ast_channel *chan, const char *data)
 PauseQueueMember application.
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, const char *reason)
static int ql_exec (struct ast_channel *chan, const char *data)
 QueueLog application.
static struct
ast_manager_event_blob
queue_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_blob
queue_agent_complete_to_ami (struct stasis_message *message)
static struct
ast_manager_event_blob
queue_agent_connect_to_ami (struct stasis_message *message)
static struct
ast_manager_event_blob
queue_agent_dump_to_ami (struct stasis_message *message)
static struct
ast_manager_event_blob
queue_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_blob
queue_caller_abandon_to_ami (struct stasis_message *message)
static struct
ast_manager_event_blob
queue_caller_join_to_ami (struct stasis_message *message)
static struct
ast_manager_event_blob
queue_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_blob
queue_channel_to_ami (const char *type, struct stasis_message *message)
static int queue_cmp_cb (void *obj, void *arg, int flags)
static int queue_delme_members_decrement_followers (void *obj, void *arg, int flag)
static int queue_exec (struct ast_channel *chan, const char *data)
 The starting point for all queue calls.
static int queue_function_exists (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Check if a given queue exists.
static int queue_function_mem_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Get number either busy / free / ready or total members of a specific queue.
static int queue_function_mem_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse.
static int queue_function_memberpenalty_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.
static int queue_function_memberpenalty_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.
static int queue_function_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).
static int queue_function_queuegetchannel (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue.
static int queue_function_queuememberlist (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue.
static int queue_function_queuewaitingcount (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue.
static int queue_function_var (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 create interface var with all queue details.
static int queue_hash_cb (const void *obj, const int flags)
static struct
ast_manager_event_blob
queue_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_blob
queue_member_pause_to_ami (struct stasis_message *message)
static struct
ast_manager_event_blob
queue_member_penalty_to_ami (struct stasis_message *message)
static struct
ast_manager_event_blob
queue_member_removed_to_ami (struct stasis_message *message)
static struct
ast_manager_event_blob
queue_member_ringinuse_to_ami (struct stasis_message *message)
static struct
ast_manager_event_blob
queue_member_status_to_ami (struct stasis_message *message)
static struct
ast_manager_event_blob
queue_member_to_ami (const char *type, struct stasis_message *message)
static struct
ast_manager_event_blob
queue_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 struct call_queuequeue_ref (struct call_queue *q)
static void queue_rules_set_global_params (struct ast_config *cfg)
static void queue_set_global_params (struct ast_config *cfg)
static void queue_set_param (struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
 Configure a queue parameter.
static char * queue_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct queue_stasis_dataqueue_stasis_data_alloc (struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
static void queue_stasis_data_destructor (void *obj)
static struct call_queuequeue_unref (struct call_queue *q)
static int queues_data_provider_get (const struct ast_data_search *search, struct ast_data *data_root)
static void queues_data_provider_get_helper (const struct ast_data_search *search, struct ast_data *data_root, struct call_queue *queue)
static void recalc_holdtime (struct queue_ent *qe, int newholdtime)
static void record_abandoned (struct queue_ent *qe)
 Record that a caller gave up on waiting in queue.
static int reload (void)
static int reload_handler (int reload, struct ast_flags *mask, const char *queuename)
 The command center for all reload operations.
static void reload_queue_members (void)
 Reload dynamic queue members persisted into the astdb.
static int reload_queue_rules (int reload)
 Reload the rules defined in queuerules.conf.
static int reload_queues (int reload, struct ast_flags *mask, const char *queuename)
 reload the queues.conf file
static void reload_single_member (const char *memberdata, struct call_queue *q)
 reload information pertaining to a single member
static void reload_single_queue (struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
 Reload information pertaining to a particular queue.
static int remove_from_queue (const char *queuename, const char *interface)
 Remove member from queue.
static int remove_members_and_mark_unfound (void *obj, void *arg, int flags)
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.
static int ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies)
 Place a call to a queue member.
static void rna (int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause)
 RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.
static int rqm_exec (struct ast_channel *chan, const char *data)
 RemoveQueueMember application.
static void rt_handle_member_record (struct call_queue *q, char *interface, struct ast_config *member_config)
 Find rt member record to update otherwise create one.
static int say_periodic_announcement (struct queue_ent *qe, int ringing)
 Playback announcement to queued members if period has elapsed.
static int say_position (struct queue_ent *qe, int ringing)
static void send_agent_complete (const char *queuename, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const struct member *member, time_t holdstart, time_t callstart, enum agent_complete_reason rsn)
 Send out AMI message with member call completion status information.
static 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_result (struct ast_channel *chan, enum queue_result res)
 sets the QUEUESTATUS channel variable
static void set_queue_variables (struct call_queue *q, struct ast_channel *chan)
 Set variables of queue.
static void setup_mixmonitor (struct queue_ent *qe, const char *filename)
static void setup_peer_after_bridge_goto (struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
static int setup_stasis_subs (struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_ringnoanswer_type,.to_ami=queue_agent_ringnoanswer_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_complete_type,.to_ami=queue_agent_complete_to_ami,)
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_connect_type,.to_ami=queue_agent_connect_to_ami,)
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_agent_called_type,.to_ami=queue_agent_called_to_ami,)
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_ringinuse_type,.to_ami=queue_member_ringinuse_to_ami,)
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_member_penalty_type,.to_ami=queue_member_penalty_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_removed_type,.to_ami=queue_member_removed_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_status_type,.to_ami=queue_member_status_to_ami,)
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_caller_abandon_type,.to_ami=queue_caller_abandon_to_ami,)
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_caller_leave_type,.to_ami=queue_caller_leave_to_ami,)
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (queue_caller_join_type,.to_ami=queue_caller_join_to_ami,)
static int store_next_lin (struct queue_ent *qe, struct callattempt *outgoing)
 Search for best metric and add to Linear queue.
static int store_next_rr (struct queue_ent *qe, struct callattempt *outgoing)
 Search for best metric and add to Round Robbin queue.
static int strat2int (const char *strategy)
static int try_calling (struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
static int unload_module (void)
static void update_qe_rule (struct queue_ent *qe)
 update rules for queues
static int update_queue (struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime)
 update the queue status
static int update_realtime_member_field (struct member *mem, const char *queue_name, const char *field, const char *value)
static void update_realtime_members (struct call_queue *q)
static void update_status (struct call_queue *q, struct member *m, const int status)
 set a member's status based on device state of that member's state_interface.
static int upqm_exec (struct ast_channel *chan, const char *data)
 UnPauseQueueMember application.
static int valid_exit (struct queue_ent *qe, char digit)
 Check for valid exit from queue via goto.
static int wait_a_bit (struct queue_ent *qe)
static struct callattemptwait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int ringing)
 Wait for a member to answer the call.
static int wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason)
 The waiting areas for callers who are not actively calling members.
static int word_in_list (const char *list, const char *word)
 Check if a given word is in a space-delimited list.

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, .nonoptreq = "res_monitor", }
static struct
stasis_message_router
agent_router
static char * app = "Queue"
static char * app_aqm = "AddQueueMember"
static char * app_pqm = "PauseQueueMember"
static char * app_ql = "QueueLog"
static char * app_rqm = "RemoveQueueMember"
static char * app_upqm = "UnpauseQueueMember"
static struct ast_module_infoast_module_info = &__mod_info
static int autofill_default = 1
 queues.conf [general] option
static struct autopause autopausesmodes []
static struct ast_cli_entry cli_queue []
static struct stasis_subscriptiondevice_state_sub
 Subscription to device state change messages.
static int log_membername_as_agent = 0
 queues.conf [general] option
static int montype_default = 0
 queues.conf [general] option
static int negative_penalty_invalid = 0
 queues.conf [general] option
static const char *const pm_family = "Queue/PersistentMembers"
 Persistent Members astdb family.
static struct ast_data_entry queue_data_providers []
static struct ast_app_option queue_exec_options [128] = { [ '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 = 0
 queues.conf [general] option
struct {
   enum queue_result   id
   char *   text
queue_results []
static struct ast_custom_function queueexists_function
static struct ast_custom_function queuegetchannel_function
static struct ast_custom_function queuemembercount_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_data_handler queues_data_provider
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
static int realtime_rules = 0
 queuesrules.conf [general] option
static int shared_lastcall = 1
 queues.conf [general] option
static struct strategy strategies []
static struct stasis_forwardtopic_forwarder
static int update_cdr = 0
 queues.conf [general] option
static int use_weight = 0
 queues.conf per-queue weight option


Detailed Description

True call queues with optional send URL on answer.

Author:
Mark Spencer <markster@digium.com>
Development notes
Note:
2004-11-25: Persistent Dynamic Members added by: NetNation Communications (www.netnation.com) Kevin Lindsay <kevinl@netnation.com>
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@toad.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 <michiel@betel.nl> Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>

Fixed to work with CVS as of 2004-02-25 and released as 1.07a by Matthew Enger <m.enger@xi.com.au>

Definition in file app_queue.c.


Define Documentation

#define ANNOUNCEHOLDTIME_ALWAYS   1

Definition at line 1555 of file app_queue.c.

Referenced by queue_set_param().

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1556 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1571 of file app_queue.c.

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

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 1570 of file app_queue.c.

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

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1569 of file app_queue.c.

Referenced by queue_set_param(), and queues_data_provider_get_helper().

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1568 of file app_queue.c.

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

#define AST_MAX_WATCHERS   256

Definition at line 4597 of file app_queue.c.

#define DATA_EXPORT_CALL_QUEUE ( MEMBER   ) 

Definition at line 10489 of file app_queue.c.

#define DATA_EXPORT_MEMBER ( MEMBER   ) 

Definition at line 10552 of file app_queue.c.

#define DATA_EXPORT_QUEUE_ENT ( MEMBER   ) 

Definition at line 10566 of file app_queue.c.

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

Referenced by init_queue().

#define DEFAULT_RETRY   5

Definition at line 1355 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

#define DEFAULT_TIMEOUT   15

Definition at line 1356 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 1358 of file app_queue.c.

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

#define MAX_QUEUE_BUCKETS   53

Definition at line 1365 of file app_queue.c.

Referenced by load_module().

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1557 of file app_queue.c.

#define QUEUE_PAUSED_DEVSTATE   AST_DEVICE_INUSE

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

Definition at line 1841 of file app_queue.c.

Referenced by leave_queue(), and try_calling().

#define queue_t_unref ( q,
tag   )     queue_unref(q)

#define QUEUE_UNKNOWN_PAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

Definition at line 3119 of file app_queue.c.

Referenced by member_remove_from_queue().

#define QUEUE_UNPAUSED_DEVSTATE   AST_DEVICE_NOT_INUSE

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

Definition at line 1843 of file app_queue.c.

Referenced by find_queue_by_name_rt(), and reload_single_queue().

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

Definition at line 1844 of file app_queue.c.

Referenced by find_queue_by_name_rt(), and leave_queue().

#define RECHECK   1

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

Definition at line 1357 of file app_queue.c.

Referenced by wait_our_turn().

#define RES_EXISTS   (-1)

#define RES_NOSUCHQUEUE   (-3)

#define RES_NOT_DYNAMIC   (-4)

#define RES_OKAY   0

#define RES_OUTOFMEMORY   (-2)


Enumeration Type Documentation

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 

Definition at line 1257 of file app_queue.c.

01257      {
01258    OPT_MARK_AS_ANSWERED =       (1 << 0),
01259    OPT_GO_ON =                  (1 << 1),
01260    OPT_DATA_QUALITY =           (1 << 2),
01261    OPT_CALLEE_GO_ON =           (1 << 3),
01262    OPT_CALLEE_HANGUP =          (1 << 4),
01263    OPT_CALLER_HANGUP =          (1 << 5),
01264    OPT_IGNORE_CALL_FW =         (1 << 6),
01265    OPT_IGNORE_CONNECTEDLINE =   (1 << 7),
01266    OPT_CALLEE_PARK =            (1 << 8),
01267    OPT_CALLER_PARK =            (1 << 9),
01268    OPT_NO_RETRY =               (1 << 10),
01269    OPT_RINGING =                (1 << 11),
01270    OPT_RING_WHEN_RINGING =      (1 << 12),
01271    OPT_CALLEE_TRANSFER =        (1 << 13),
01272    OPT_CALLER_TRANSFER =        (1 << 14),
01273    OPT_CALLEE_AUTOMIXMON =      (1 << 15),
01274    OPT_CALLER_AUTOMIXMON =      (1 << 16),
01275    OPT_CALLEE_AUTOMON =         (1 << 17),
01276    OPT_CALLER_AUTOMON =         (1 << 18),
01277 };

anonymous enum

Enumerator:
OPT_ARG_CALLEE_GO_ON 
OPT_ARG_ARRAY_SIZE 

Definition at line 1279 of file app_queue.c.

01279      {
01280    OPT_ARG_CALLEE_GO_ON = 0,
01281    /* note: this entry _MUST_ be the last one in the enum */
01282    OPT_ARG_ARRAY_SIZE
01283 };

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

anonymous enum

Enumerator:
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 1318 of file app_queue.c.

01318      {
01319      QUEUE_AUTOPAUSE_OFF = 0,
01320      QUEUE_AUTOPAUSE_ON,
01321      QUEUE_AUTOPAUSE_ALL
01322 };

Enumerator:
CALLER 
AGENT 
TRANSFER 

Definition at line 5468 of file app_queue.c.

05468                            {
05469    CALLER,
05470    AGENT,
05471    TRANSFER
05472 };

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

01538                       {
01539    QUEUE_EMPTY_PENALTY = (1 << 0),
01540    QUEUE_EMPTY_PAUSED = (1 << 1),
01541    QUEUE_EMPTY_INUSE = (1 << 2),
01542    QUEUE_EMPTY_RINGING = (1 << 3),
01543    QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
01544    QUEUE_EMPTY_INVALID = (1 << 5),
01545    QUEUE_EMPTY_UNKNOWN = (1 << 6),
01546    QUEUE_EMPTY_WRAPUP = (1 << 7),
01547 };

Enumerator:
MEMBER_PENALTY 
MEMBER_RINGINUSE 

Definition at line 1549 of file app_queue.c.

01549                        {
01550    MEMBER_PENALTY = 0,
01551    MEMBER_RINGINUSE = 1,
01552 };

Enumerator:
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 1324 of file app_queue.c.

01324                        {
01325    QUEUE_RELOAD_PARAMETERS = (1 << 0),
01326    QUEUE_RELOAD_MEMBER = (1 << 1),
01327    QUEUE_RELOAD_RULES = (1 << 2),
01328    QUEUE_RESET_STATS = (1 << 3),
01329 };

Enumerator:
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 

Definition at line 1421 of file app_queue.c.

01421                   {
01422    QUEUE_UNKNOWN = 0,
01423    QUEUE_TIMEOUT = 1,
01424    QUEUE_JOINEMPTY = 2,
01425    QUEUE_LEAVEEMPTY = 3,
01426    QUEUE_JOINUNAVAIL = 4,
01427    QUEUE_LEAVEUNAVAIL = 5,
01428    QUEUE_FULL = 6,
01429    QUEUE_CONTINUE = 7,
01430 };

Enumerator:
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 1446 of file app_queue.c.

01446                             {
01447    TIMEOUT_PRIORITY_APP,
01448    TIMEOUT_PRIORITY_CONF,
01449 };


Function Documentation

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

References ao2_container_count(), ao2_iterator_destroy(), AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_category_browse(), ast_channel_name(), ast_check_realtime(), ast_config_destroy(), AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_devstate2str(), ast_load_realtime_multientry(), 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::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, CLI_SHOWUSAGE, CLI_SUCCESS, COLOR_BLACK, COLOR_BROWN, COLOR_CYAN, COLOR_GREEN, COLOR_MAGENTA, COLOR_RED, call_queue::count, do_print(), member::dynamic, find_load_queue_rt_friendly(), call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, call_queue::maxlen, member::membername, call_queue::members, call_queue::name, queue_ent::next, NULL, out, member::paused, member::penalty, queue_ent::pos, queue_ent::prio, queue_t_unref, queues, member::realtime, call_queue::realtime, member::ringinuse, SENTINEL, call_queue::servicelevel, queue_ent::start, member::state_interface, member::status, call_queue::strategy, call_queue::talktime, and call_queue::weight.

Referenced by manager_queues_show(), and queue_show().

09131 {
09132    struct call_queue *q;
09133    struct ast_str *out = ast_str_alloca(240);
09134    int found = 0;
09135    time_t now = time(NULL);
09136    struct ao2_iterator queue_iter;
09137    struct ao2_iterator mem_iter;
09138 
09139    if (argc != 2 && argc != 3) {
09140       return CLI_SHOWUSAGE;
09141    }
09142 
09143    if (argc == 3) { /* specific queue */
09144       if ((q = find_load_queue_rt_friendly(argv[2]))) {
09145          queue_t_unref(q, "Done with temporary pointer");
09146       }
09147    } else if (ast_check_realtime("queues")) {
09148       /* This block is to find any queues which are defined in realtime but
09149        * which have not yet been added to the in-core container
09150        */
09151       struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
09152       char *queuename;
09153       if (cfg) {
09154          for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
09155             if ((q = find_load_queue_rt_friendly(queuename))) {
09156                queue_t_unref(q, "Done with temporary pointer");
09157             }
09158          }
09159          ast_config_destroy(cfg);
09160       }
09161    }
09162 
09163    ao2_lock(queues);
09164    queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
09165    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
09166       float sl;
09167       struct call_queue *realtime_queue = NULL;
09168 
09169       ao2_lock(q);
09170       /* This check is to make sure we don't print information for realtime
09171        * queues which have been deleted from realtime but which have not yet
09172        * been deleted from the in-core container. Only do this if we're not
09173        * looking for a specific queue.
09174        */
09175       if (argc < 3 && q->realtime) {
09176          realtime_queue = find_load_queue_rt_friendly(q->name);
09177          if (!realtime_queue) {
09178             ao2_unlock(q);
09179             queue_t_unref(q, "Done with iterator");
09180             continue;
09181          }
09182          queue_t_unref(realtime_queue, "Queue is already in memory");
09183       }
09184 
09185       if (argc == 3 && strcasecmp(q->name, argv[2])) {
09186          ao2_unlock(q);
09187          queue_t_unref(q, "Done with iterator");
09188          continue;
09189       }
09190       found = 1;
09191 
09192       ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
09193       if (q->maxlen) {
09194          ast_str_append(&out, 0, "%d", q->maxlen);
09195       } else {
09196          ast_str_append(&out, 0, "unlimited");
09197       }
09198       sl = 0;
09199       if (q->callscompleted > 0) {
09200          sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
09201       }
09202       ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
09203          int2strat(q->strategy), q->holdtime, q->talktime, q->weight,
09204          q->callscompleted, q->callsabandoned,sl,q->servicelevel);
09205       do_print(s, fd, ast_str_buffer(out));
09206       if (!ao2_container_count(q->members)) {
09207          do_print(s, fd, "   No Members");
09208       } else {
09209          struct member *mem;
09210 
09211          do_print(s, fd, "   Members: ");
09212          mem_iter = ao2_iterator_init(q->members, 0);
09213          while ((mem = ao2_iterator_next(&mem_iter))) {
09214             ast_str_set(&out, 0, "      %s", mem->membername);
09215             if (strcasecmp(mem->membername, mem->interface)) {
09216                ast_str_append(&out, 0, " (%s", mem->interface);
09217                if (!ast_strlen_zero(mem->state_interface)) {
09218                   ast_str_append(&out, 0, " from %s", mem->state_interface);
09219                }
09220                ast_str_append(&out, 0, ")");
09221             }
09222             if (mem->penalty) {
09223                ast_str_append(&out, 0, " with penalty %d", mem->penalty);
09224             }
09225 
09226             ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
09227 
09228             ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s (%s%s%s)",
09229                mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
09230                mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
09231                mem->paused ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->paused ? " (paused)" : "", ast_term_reset(),
09232                ast_term_color(
09233                   mem->status == AST_DEVICE_UNAVAILABLE || mem->status == AST_DEVICE_UNKNOWN ?
09234                      COLOR_RED : COLOR_GREEN, COLOR_BLACK),
09235                   ast_devstate2str(mem->status), ast_term_reset());
09236             if (mem->calls) {
09237                ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
09238                   mem->calls, (long) (time(NULL) - mem->lastcall));
09239             } else {
09240                ast_str_append(&out, 0, " has taken no calls yet");
09241             }
09242             do_print(s, fd, ast_str_buffer(out));
09243             ao2_ref(mem, -1);
09244          }
09245          ao2_iterator_destroy(&mem_iter);
09246       }
09247       if (!q->head) {
09248          do_print(s, fd, "   No Callers");
09249       } else {
09250          struct queue_ent *qe;
09251          int pos = 1;
09252 
09253          do_print(s, fd, "   Callers: ");
09254          for (qe = q->head; qe; qe = qe->next) {
09255             ast_str_set(&out, 0, "      %d. %s (wait: %ld:%2.2ld, prio: %d)",
09256                pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
09257                (long) (now - qe->start) % 60, qe->prio);
09258             do_print(s, fd, ast_str_buffer(out));
09259          }
09260       }
09261       do_print(s, fd, ""); /* blank line between entries */
09262       ao2_unlock(q);
09263       queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
09264    }
09265    ao2_iterator_destroy(&queue_iter);
09266    ao2_unlock(queues);
09267    if (!found) {
09268       if (argc == 3) {
09269          ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
09270       } else {
09271          ast_str_set(&out, 0, "No queues.");
09272       }
09273       do_print(s, fd, ast_str_buffer(out));
09274    }
09275    return CLI_SUCCESS;
09276 }

static void __reg_module ( void   )  [static]

Definition at line 11008 of file app_queue.c.

static void __unreg_module ( void   )  [static]

Definition at line 11008 of file app_queue.c.

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

Add member to queue.

Return values:
RES_NOT_DYNAMIC when they aren't a RT member
RES_NOSUCHQUEUE queue does not exist
RES_OKAY added member from queue
RES_EXISTS queue exists but no members
RES_OUT_OF_MEMORY queue 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 7023 of file app_queue.c.

References ao2_lock, ao2_ref, ao2_unlock, 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, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, member::ringinuse, and call_queue::ringinuse.

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

07024 {
07025    struct call_queue *q;
07026    struct member *new_member, *old_member;
07027    int res = RES_NOSUCHQUEUE;
07028 
07029    /*! \note Ensure the appropriate realtime queue is loaded.  Note that this
07030     * short-circuits if the queue is already in memory. */
07031    if (!(q = find_load_queue_rt_friendly(queuename))) {
07032       return res;
07033    }
07034 
07035    ao2_lock(q);
07036    if ((old_member = interface_exists(q, interface)) == NULL) {
07037       if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface, q->ringinuse))) {
07038          new_member->ringinuse = q->ringinuse;
07039          new_member->dynamic = 1;
07040          member_add_to_queue(q, new_member);
07041          queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
07042 
07043          if (is_member_available(q, new_member)) {
07044             ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
07045          }
07046 
07047          ao2_ref(new_member, -1);
07048          new_member = NULL;
07049 
07050          if (dump) {
07051             dump_queue_members(q);
07052          }
07053 
07054          res = RES_OKAY;
07055       } else {
07056          res = RES_OUTOFMEMORY;
07057       }
07058    } else {
07059       ao2_ref(old_member, -1);
07060       res = RES_EXISTS;
07061    }
07062    ao2_unlock(q);
07063    queue_t_unref(q, "Expiring temporary reference");
07064 
07065    return res;
07066 }

static struct call_queue* alloc_queue ( const char *  queuename  )  [static, read]

Definition at line 3279 of file app_queue.c.

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

Referenced by find_queue_by_name_rt(), and reload_single_queue().

03280 {
03281    struct call_queue *q;
03282 
03283    if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
03284       if (ast_string_field_init(q, 64)) {
03285          queue_t_unref(q, "String field allocation failed");
03286          return NULL;
03287       }
03288       ast_string_field_set(q, name, queuename);
03289    }
03290    return q;
03291 }

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

AddQueueMember application.

Definition at line 7577 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_strlen_zero, member::interface, LOG_ERROR, LOG_NOTICE, LOG_WARNING, member::membername, NULL, parse(), pbx_builtin_setvar_helper(), member::penalty, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and member::state_interface.

Referenced by load_module().

07578 {
07579    int res=-1;
07580    char *parse, *temppos = NULL;
07581    AST_DECLARE_APP_ARGS(args,
07582       AST_APP_ARG(queuename);
07583       AST_APP_ARG(interface);
07584       AST_APP_ARG(penalty);
07585       AST_APP_ARG(options);
07586       AST_APP_ARG(membername);
07587       AST_APP_ARG(state_interface);
07588    );
07589    int penalty = 0;
07590 
07591    if (ast_strlen_zero(data)) {
07592       ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n");
07593       return -1;
07594    }
07595 
07596    parse = ast_strdupa(data);
07597 
07598    AST_STANDARD_APP_ARGS(args, parse);
07599 
07600    if (ast_strlen_zero(args.interface)) {
07601       args.interface = ast_strdupa(ast_channel_name(chan));
07602       temppos = strrchr(args.interface, '-');
07603       if (temppos) {
07604          *temppos = '\0';
07605       }
07606    }
07607 
07608    if (!ast_strlen_zero(args.penalty)) {
07609       if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
07610          ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
07611          penalty = 0;
07612       }
07613    }
07614 
07615    switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
07616    case RES_OKAY:
07617       if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
07618          ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", "");
07619       } else {
07620          ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", "");
07621       }
07622       ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
07623       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
07624       res = 0;
07625       break;
07626    case RES_EXISTS:
07627       ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
07628       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
07629       res = 0;
07630       break;
07631    case RES_NOSUCHQUEUE:
07632       ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
07633       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
07634       res = 0;
07635       break;
07636    case RES_OUTOFMEMORY:
07637       ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
07638       break;
07639    }
07640 
07641    return res;
07642 }

AST_DATA_STRUCTURE ( queue_ent  ,
DATA_EXPORT_QUEUE_ENT   
)

AST_DATA_STRUCTURE ( member  ,
DATA_EXPORT_MEMBER   
)

AST_DATA_STRUCTURE ( call_queue  ,
DATA_EXPORT_CALL_QUEUE   
)

static int autopause2int ( const char *  autopause  )  [static]

Definition at line 1727 of file app_queue.c.

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

Referenced by queue_set_param().

01728 {
01729    int x;
01730    /*This 'double check' that default value is OFF */
01731    if (ast_strlen_zero(autopause)) {
01732       return QUEUE_AUTOPAUSE_OFF;
01733    }
01734 
01735    /*This 'double check' is to ensure old values works */
01736    if(ast_true(autopause)) {
01737       return QUEUE_AUTOPAUSE_ON;
01738    }
01739 
01740    for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
01741       if (!strcasecmp(autopause, autopausesmodes[x].name)) {
01742          return autopausesmodes[x].autopause;
01743       }
01744    }
01745 
01746    /*This 'double check' that default value is OFF */
01747    return QUEUE_AUTOPAUSE_OFF;
01748 }

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:
-1 if penalties are exceeded
0 otherwise

Definition at line 5395 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, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.

Referenced by try_calling().

05396 {
05397    /* disregarding penalty on too few members? */
05398    int membercount = ao2_container_count(q->members);
05399    unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
05400 
05401    if (usepenalty) {
05402       if ((qe->max_penalty != INT_MAX && mem->penalty > qe->max_penalty) ||
05403          (qe->min_penalty != INT_MAX && mem->penalty < qe->min_penalty)) {
05404          return -1;
05405       }
05406    } else {
05407       ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
05408            membercount, q->penaltymemberslimit);
05409    }
05410 
05411    switch (q->strategy) {
05412    case QUEUE_STRATEGY_RINGALL:
05413       /* Everyone equal, except for penalty */
05414       tmp->metric = mem->penalty * 1000000 * usepenalty;
05415       break;
05416    case QUEUE_STRATEGY_LINEAR:
05417       if (pos < qe->linpos) {
05418          tmp->metric = 1000 + pos;
05419       } else {
05420          if (pos > qe->linpos) {
05421             /* Indicate there is another priority */
05422             qe->linwrapped = 1;
05423          }
05424          tmp->metric = pos;
05425       }
05426       tmp->metric += mem->penalty * 1000000 * usepenalty;
05427       break;
05428    case QUEUE_STRATEGY_RRORDERED:
05429    case QUEUE_STRATEGY_RRMEMORY:
05430       pos = mem->queuepos;
05431       if (pos < q->rrpos) {
05432          tmp->metric = 1000 + pos;
05433       } else {
05434          if (pos > q->rrpos) {
05435             /* Indicate there is another priority */
05436             q->wrapped = 1;
05437          }
05438          tmp->metric = pos;
05439       }
05440       tmp->metric += mem->penalty * 1000000 * usepenalty;
05441       break;
05442    case QUEUE_STRATEGY_RANDOM:
05443       tmp->metric = ast_random() % 1000;
05444       tmp->metric += mem->penalty * 1000000 * usepenalty;
05445       break;
05446    case QUEUE_STRATEGY_WRANDOM:
05447       tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
05448       break;
05449    case QUEUE_STRATEGY_FEWESTCALLS:
05450       tmp->metric = mem->calls;
05451       tmp->metric += mem->penalty * 1000000 * usepenalty;
05452       break;
05453    case QUEUE_STRATEGY_LEASTRECENT:
05454       if (!mem->lastcall) {
05455          tmp->metric = 0;
05456       } else {
05457          tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
05458       }
05459       tmp->metric += mem->penalty * 1000000 * usepenalty;
05460       break;
05461    default:
05462       ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
05463       break;
05464    }
05465    return 0;
05466 }

static void callattempt_free ( struct callattempt doomed  )  [static]

Definition at line 3982 of file app_queue.c.

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

Referenced by hangupcalls(), and try_calling().

03983 {
03984    if (doomed->member) {
03985       ao2_ref(doomed->member, -1);
03986    }
03987    ast_party_connected_line_free(&doomed->connected);
03988    ast_free(doomed);
03989 }

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

Definition at line 4164 of file app_queue.c.

References ast_debug, compare_weight(), get_queue_member_status(), callattempt::interface, callattempt::lastcall, callattempt::lastqueue, callattempt::member, member_call_pending_clear(), member_call_pending_set(), member_status_available(), call_queue::name, NULL, queue_ent::parent, member::paused, member::ringinuse, member::status, and call_queue::wrapuptime.

Referenced by ring_entry().

04165 {
04166    if (call->member->paused) {
04167       ast_debug(1, "%s paused, can't receive call\n", call->interface);
04168       return 0;
04169    }
04170 
04171    if (!call->member->ringinuse && !member_status_available(call->member->status)) {
04172       ast_debug(1, "%s not available, can't receive call\n", call->interface);
04173       return 0;
04174    }
04175 
04176    if ((call->lastqueue && call->lastqueue->wrapuptime && (time(NULL) - call->lastcall < call->lastqueue->wrapuptime))
04177       || (!call->lastqueue && qe->parent->wrapuptime && (time(NULL) - call->lastcall < qe->parent->wrapuptime))) {
04178       ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
04179          (call->lastqueue ? call->lastqueue->name : qe->parent->name),
04180          call->interface);
04181       return 0;
04182    }
04183 
04184    if (use_weight && compare_weight(qe->parent, call->member)) {
04185       ast_debug(1, "Priority queue delaying call to %s:%s\n",
04186          qe->parent->name, call->interface);
04187       return 0;
04188    }
04189 
04190    if (!call->member->ringinuse) {
04191       if (member_call_pending_set(call->member)) {
04192          ast_debug(1, "%s has another call pending, can't receive call\n",
04193             call->interface);
04194          return 0;
04195       }
04196 
04197       /*
04198        * The queue member is available.  Get current status to be sure
04199        * because the device state and extension state callbacks may
04200        * not have updated the status yet.
04201        */
04202       if (!member_status_available(get_queue_member_status(call->member))) {
04203          ast_debug(1, "%s actually not available, can't receive call\n",
04204             call->interface);
04205          member_call_pending_clear(call->member);
04206          return 0;
04207       }
04208    }
04209 
04210    return 1;
04211 }

static void clear_queue ( struct call_queue q  )  [static]

Definition at line 2666 of file app_queue.c.

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

Referenced by clear_stats(), and find_queue_by_name_rt().

02667 {
02668    q->holdtime = 0;
02669    q->callscompleted = 0;
02670    q->callsabandoned = 0;
02671    q->callscompletedinsl = 0;
02672    q->talktime = 0;
02673 
02674    if (q->members) {
02675       struct member *mem;
02676       struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
02677       while ((mem = ao2_iterator_next(&mem_iter))) {
02678          mem->calls = 0;
02679          mem->lastcall = 0;
02680          ao2_ref(mem, -1);
02681       }
02682       ao2_iterator_destroy(&mem_iter);
02683    }
02684 }

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:
queuename The 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 9068 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, queue_t_unref, and queues.

Referenced by reload_handler().

09069 {
09070    struct call_queue *q;
09071    struct ao2_iterator queue_iter;
09072 
09073    queue_iter = ao2_iterator_init(queues, 0);
09074    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
09075       ao2_lock(q);
09076       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
09077          clear_queue(q);
09078       ao2_unlock(q);
09079       queue_t_unref(q, "Done with iterator");
09080    }
09081    ao2_iterator_destroy(&queue_iter);
09082    return 0;
09083 }

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

Definition at line 4065 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, queues, and call_queue::weight.

Referenced by can_ring_entry().

04066 {
04067    struct call_queue *q;
04068    struct member *mem;
04069    int found = 0;
04070    struct ao2_iterator queue_iter;
04071 
04072    queue_iter = ao2_iterator_init(queues, 0);
04073    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
04074       if (q == rq) { /* don't check myself, could deadlock */
04075          queue_t_unref(q, "Done with iterator");
04076          continue;
04077       }
04078       ao2_lock(q);
04079       if (q->count && q->members) {
04080          if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
04081             ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
04082             if (q->weight > rq->weight && q->count >= num_available_members(q)) {
04083                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);
04084                found = 1;
04085             }
04086             ao2_ref(mem, -1);
04087          }
04088       }
04089       ao2_unlock(q);
04090       queue_t_unref(q, "Done with iterator");
04091       if (found) {
04092          break;
04093       }
04094    }
04095    ao2_iterator_destroy(&queue_iter);
04096    return found;
04097 }

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:
line The line as typed not including the current word being completed
word The word currently being completed
pos The number of completed words in line
state The nth desired completion option
word_list_offset Offset 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 9350 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, queues, and word_in_list().

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

09351 {
09352    struct call_queue *q;
09353    char *ret = NULL;
09354    int which = 0;
09355    int wordlen = strlen(word);
09356    struct ao2_iterator queue_iter;
09357    const char *word_list = NULL;
09358 
09359    /* for certain commands, already completed items should be left out of
09360     * the list */
09361    if (word_list_offset && strlen(line) >= word_list_offset) {
09362       word_list = line + word_list_offset;
09363    }
09364 
09365    queue_iter = ao2_iterator_init(queues, 0);
09366    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
09367       if (!strncasecmp(word, q->name, wordlen) && ++which > state
09368          && (!word_list_offset || !word_in_list(word_list, q->name))) {
09369          ret = ast_strdup(q->name);
09370          queue_t_unref(q, "Done with iterator");
09371          break;
09372       }
09373       queue_t_unref(q, "Done with iterator");
09374    }
09375    ao2_iterator_destroy(&queue_iter);
09376 
09377    /* Pretend "rules" is at the end of the queues list in certain
09378     * circumstances since it is an alternate command that should be
09379     * tab-completable for "queue show" */
09380    if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
09381       ret = ast_strdup("rules");
09382    }
09383 
09384    return ret;
09385 }

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

Definition at line 9843 of file app_queue.c.

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

Referenced by handle_queue_add_member().

09844 {
09845    /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
09846    switch (pos) {
09847    case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
09848       return NULL;
09849    case 4: /* only one possible match, "to" */
09850       return state == 0 ? ast_strdup("to") : NULL;
09851    case 5: /* <queue> */
09852       return complete_queue(line, word, pos, state, 0);
09853    case 6: /* only one possible match, "penalty" */
09854       return state == 0 ? ast_strdup("penalty") : NULL;
09855    case 7:
09856       if (state < 100) {      /* 0-99 */
09857          char *num;
09858          if ((num = ast_malloc(3))) {
09859             sprintf(num, "%d", state);
09860          }
09861          return num;
09862       } else {
09863          return NULL;
09864       }
09865    case 8: /* only one possible match, "as" */
09866       return state == 0 ? ast_strdup("as") : NULL;
09867    case 9: /* Don't attempt to complete name of member (infinite possibilities) */
09868       return NULL;
09869    default:
09870       return NULL;
09871    }
09872 }

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

Definition at line 10121 of file app_queue.c.

References ast_strdup, complete_queue(), and NULL.

Referenced by handle_queue_pause_member().

10122 {
10123    /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
10124    switch (pos) {
10125    case 3:  /* Don't attempt to complete name of interface (infinite possibilities) */
10126       return NULL;
10127    case 4:  /* only one possible match, "queue" */
10128       return state == 0 ? ast_strdup("queue") : NULL;
10129    case 5:  /* <queue> */
10130       return complete_queue(line, word, pos, state, 0);
10131    case 6: /* "reason" */
10132       return state == 0 ? ast_strdup("reason") : NULL;
10133    case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
10134       return NULL;
10135    default:
10136       return NULL;
10137    }
10138 }

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

Definition at line 10012 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, queues, and tmp().

Referenced by handle_queue_remove_member().

10013 {
10014    int which = 0;
10015    struct call_queue *q;
10016    struct member *m;
10017    struct ao2_iterator queue_iter;
10018    struct ao2_iterator mem_iter;
10019    int wordlen = strlen(word);
10020 
10021    /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
10022    if (pos > 5 || pos < 3) {
10023       return NULL;
10024    }
10025    if (pos == 4) {   /* only one possible match, 'from' */
10026       return (state == 0 ? ast_strdup("from") : NULL);
10027    }
10028 
10029    if (pos == 5) {   /* No need to duplicate code */
10030       return complete_queue(line, word, pos, state, 0);
10031    }
10032 
10033    /* here is the case for 3, <member> */
10034    queue_iter = ao2_iterator_init(queues, 0);
10035    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10036       ao2_lock(q);
10037       mem_iter = ao2_iterator_init(q->members, 0);
10038       while ((m = ao2_iterator_next(&mem_iter))) {
10039          if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
10040             char *tmp;
10041             tmp = ast_strdup(m->interface);
10042             ao2_ref(m, -1);
10043             ao2_iterator_destroy(&mem_iter);
10044             ao2_unlock(q);
10045             queue_t_unref(q, "Done with iterator, returning interface name");
10046             ao2_iterator_destroy(&queue_iter);
10047             return tmp;
10048          }
10049          ao2_ref(m, -1);
10050       }
10051       ao2_iterator_destroy(&mem_iter);
10052       ao2_unlock(q);
10053       queue_t_unref(q, "Done with iterator");
10054    }
10055    ao2_iterator_destroy(&queue_iter);
10056 
10057    return NULL;
10058 }

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

Definition at line 10316 of file app_queue.c.

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

Referenced by handle_queue_rule_show().

10317 {
10318    int which = 0;
10319    struct rule_list *rl_iter;
10320    int wordlen = strlen(word);
10321    char *ret = NULL;
10322    if (pos != 3) /* Wha? */ {
10323       return NULL;
10324    }
10325 
10326    AST_LIST_LOCK(&rule_lists);
10327    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10328       if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
10329          ret = ast_strdup(rl_iter->name);
10330          break;
10331       }
10332    }
10333    AST_LIST_UNLOCK(&rule_lists);
10334 
10335    return ret;
10336 }

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

Definition at line 10195 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().

10196 {
10197    /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
10198    switch (pos) {
10199    case 4:
10200       if (state == 0) {
10201          return ast_strdup("on");
10202       } else {
10203          return NULL;
10204       }
10205    case 6:
10206       if (state == 0) {
10207          return ast_strdup("in");
10208       } else {
10209          return NULL;
10210       }
10211    case 7:
10212       return complete_queue(line, word, pos, state, 0);
10213    default:
10214       return NULL;
10215    }
10216 }

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

Definition at line 9387 of file app_queue.c.

References complete_queue(), and NULL.

Referenced by queue_show().

09388 {
09389    if (pos == 2) {
09390       return complete_queue(line, word, pos, state, 0);
09391    }
09392    return NULL;
09393 }

static int compress_char ( const char  c  )  [static]

Definition at line 2539 of file app_queue.c.

Referenced by member_hash_fn().

02540 {
02541    if (c < 32) {
02542       return 0;
02543    } else if (c > 96) {
02544       return c - 64;
02545    }
02546    return c - 32;
02547 }

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

Copy rule from global list into specified queue.

Definition at line 7679 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, 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, rule_list::rules, penalty_rule::time, and tmp().

Referenced by queue_exec().

07680 {
07681    struct penalty_rule *pr_iter;
07682    struct rule_list *rl_iter;
07683    const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
07684    AST_LIST_LOCK(&rule_lists);
07685    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
07686       if (!strcasecmp(rl_iter->name, tmp)) {
07687          break;
07688       }
07689    }
07690    if (rl_iter) {
07691       AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
07692          struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
07693          if (!new_pr) {
07694             ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
07695             break;
07696          }
07697          new_pr->time = pr_iter->time;
07698          new_pr->max_value = pr_iter->max_value;
07699          new_pr->min_value = pr_iter->min_value;
07700          new_pr->max_relative = pr_iter->max_relative;
07701          new_pr->min_relative = pr_iter->min_relative;
07702          AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
07703       }
07704    }
07705    AST_LIST_UNLOCK(&rule_lists);
07706 }

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

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

Definition at line 2503 of file app_queue.c.

References ao2_alloc, ast_copy_string(), ast_log, ast_strdupa, ast_strlen_zero, queue_ent::context, exten, get_queue_member_status(), member::interface, LOG_WARNING, member::membername, NULL, member::paused, member::penalty, member::ringinuse, S_OR, member::state_context, member::state_exten, member::state_interface, member::status, strsep(), and tmp().

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

02504 {
02505    struct member *cur;
02506 
02507    if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
02508       cur->ringinuse = ringinuse;
02509       cur->penalty = penalty;
02510       cur->paused = paused;
02511       ast_copy_string(cur->interface, interface, sizeof(cur->interface));
02512       if (!ast_strlen_zero(state_interface)) {
02513          ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
02514       } else {
02515          ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
02516       }
02517       if (!ast_strlen_zero(membername)) {
02518          ast_copy_string(cur->membername, membername, sizeof(cur->membername));
02519       } else {
02520          ast_copy_string(cur->membername, interface, sizeof(cur->membername));
02521       }
02522       if (!strchr(cur->interface, '/')) {
02523          ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
02524       }
02525       if (!strncmp(cur->state_interface, "hint:", 5)) {
02526          char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
02527          char *exten = strsep(&context, "@") + 5;
02528 
02529          ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
02530          ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
02531       }
02532       cur->status = get_queue_member_status(cur);
02533    }
02534 
02535    return cur;
02536 }

static void destroy_queue ( void *  obj  )  [static]

Free queue's member list then its string fields.

Definition at line 3264 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().

03265 {
03266    struct call_queue *q = obj;
03267    int i;
03268 
03269    free_members(q, 1);
03270    ast_string_field_free_memory(q);
03271    for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
03272       if (q->sound_periodicannounce[i]) {
03273          ast_free(q->sound_periodicannounce[i]);
03274       }
03275    }
03276    ao2_ref(q->members, -1);
03277 }

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

Referenced by load_module(), load_pbx(), and subscribe_device_state().

02336 {
02337    struct ao2_iterator miter, qiter;
02338    struct ast_device_state_message *dev_state;
02339    struct member *m;
02340    struct call_queue *q;
02341    char interface[80], *slash_pos;
02342    int found = 0;       /* Found this member in any queue */
02343    int found_member;    /* Found this member in this queue */
02344    int avail = 0;       /* Found an available member in this queue */
02345 
02346    if (ast_device_state_message_type() != stasis_message_type(msg)) {
02347       return;
02348    }
02349 
02350    dev_state = stasis_message_data(msg);
02351    if (dev_state->eid) {
02352       /* ignore non-aggregate states */
02353       return;
02354    }
02355 
02356    qiter = ao2_iterator_init(queues, 0);
02357    while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
02358       ao2_lock(q);
02359 
02360       avail = 0;
02361       found_member = 0;
02362       miter = ao2_iterator_init(q->members, 0);
02363       for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
02364          if (!found_member) {
02365             ast_copy_string(interface, m->state_interface, sizeof(interface));
02366 
02367             if ((slash_pos = strchr(interface, '/'))) {
02368                if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
02369                   *slash_pos = '\0';
02370                }
02371             }
02372 
02373             if (!strcasecmp(interface, dev_state->device)) {
02374                found_member = 1;
02375                update_status(q, m, dev_state->state);
02376             }
02377          }
02378 
02379          /* check every member until we find one NOT_INUSE */
02380          if (!avail) {
02381             avail = is_member_available(q, m);
02382          }
02383          if (avail && found_member) {
02384             /* early exit as we've found an available member and the member of interest */
02385             ao2_ref(m, -1);
02386             break;
02387          }
02388       }
02389 
02390       if (found_member) {
02391          found = 1;
02392          if (avail) {
02393             ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
02394          } else {
02395             ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
02396          }
02397       }
02398 
02399       ao2_iterator_destroy(&miter);
02400 
02401       ao2_unlock(q);
02402       queue_t_unref(q, "Done with iterator");
02403    }
02404    ao2_iterator_destroy(&qiter);
02405 
02406    if (found) {
02407       ast_debug(1, "Device '%s' changed to state '%u' (%s)\n",
02408          dev_state->device,
02409          dev_state->state,
02410          ast_devstate2str(dev_state->state));
02411    } else {
02412       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",
02413          dev_state->device,
02414          dev_state->state,
02415          ast_devstate2str(dev_state->state));
02416    }
02417 
02418    return;
02419 }

static void do_hang ( struct callattempt o  )  [static]

common hangup actions

Definition at line 4100 of file app_queue.c.

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

Referenced by ring_entry(), and wait_for_answer().

04101 {
04102    o->stillgoing = 0;
04103    ast_hangup(o->chan);
04104    o->chan = NULL;
04105 }

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

References ast_cli(), and astman_append().

Referenced by __queues_show().

09116 {
09117    if (s) {
09118       astman_append(s, "%s\r\n", str);
09119    } else {
09120       ast_cli(fd, "%s\n", str);
09121    }
09122 }

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 6917 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::state_interface, and value.

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

06918 {
06919    struct member *cur_member;
06920    struct ast_str *value;
06921    struct ao2_iterator mem_iter;
06922 
06923    if (!pm_queue) {
06924       return;
06925    }
06926 
06927    /* 4K is a reasonable default for most applications, but we grow to
06928     * accommodate more if necessary. */
06929    if (!(value = ast_str_create(4096))) {
06930       return;
06931    }
06932 
06933    mem_iter = ao2_iterator_init(pm_queue->members, 0);
06934    while ((cur_member = ao2_iterator_next(&mem_iter))) {
06935       if (!cur_member->dynamic) {
06936          ao2_ref(cur_member, -1);
06937          continue;
06938       }
06939 
06940       ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s",
06941          ast_str_strlen(value) ? "|" : "",
06942          cur_member->interface,
06943          cur_member->penalty,
06944          cur_member->paused,
06945          cur_member->membername,
06946          cur_member->state_interface);
06947 
06948       ao2_ref(cur_member, -1);
06949    }
06950    ao2_iterator_destroy(&mem_iter);
06951 
06952    if (ast_str_strlen(value) && !cur_member) {
06953       if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
06954          ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
06955       }
06956    } else {
06957       /* Delete the entry if the queue is empty or there is an error */
06958       ast_db_del(pm_family, pm_queue->name);
06959    }
06960 
06961    ast_free(value);
06962 }

static void end_bridge_callback ( void *  data  )  [static]

Definition at line 6152 of file app_queue.c.

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

06153 {
06154    struct queue_end_bridge *qeb = data;
06155    struct call_queue *q = qeb->q;
06156    struct ast_channel *chan = qeb->chan;
06157 
06158    if (ao2_ref(qeb, -1) == 1) {
06159       set_queue_variables(q, chan);
06160       /* This unrefs the reference we made in try_calling when we allocated qeb */
06161       queue_t_unref(q, "Expire bridge_config reference");
06162    }
06163 }

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

Definition at line 6145 of file app_queue.c.

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

06146 {
06147    struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
06148    ao2_ref(qeb, +1);
06149    qeb->chan = originator;
06150 }

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

Definition at line 6194 of file app_queue.c.

References pbx_substitute_variables_helper().

Referenced by setup_mixmonitor().

06196 {
06197    const char *m = input;
06198    char escaped[size];
06199    char *p;
06200 
06201    for (p = escaped; p < escaped + size - 1; p++, m++) {
06202       switch (*m) {
06203       case '^':
06204          if (*(m + 1) == '{') {
06205             *p = '$';
06206          }
06207          break;
06208       case ',':
06209          *p++ = '\\';
06210          /* Fall through */
06211       default:
06212          *p = *m;
06213       }
06214       if (*m == '\0')
06215          break;
06216    }
06217 
06218    if (p == escaped + size) {
06219       escaped[size - 1] = '\0';
06220    }
06221 
06222    pbx_substitute_variables_helper(chan, escaped, output, size - 1);
06223 }

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

Definition at line 2453 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, queues, ast_state_cb_info::reason, member::state_context, member::state_exten, and update_status().

Referenced by load_module(), and unload_module().

02454 {
02455    struct ao2_iterator miter, qiter;
02456    struct member *m;
02457    struct call_queue *q;
02458    int state = info->exten_state;
02459    int found = 0, device_state = extensionstate2devicestate(state);
02460 
02461    /* only interested in extension state updates involving device states */
02462    if (info->reason != AST_HINT_UPDATE_DEVICE) {
02463       return 0;
02464    }
02465 
02466    qiter = ao2_iterator_init(queues, 0);
02467    while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
02468       ao2_lock(q);
02469 
02470       miter = ao2_iterator_init(q->members, 0);
02471       for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
02472          if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
02473             update_status(q, m, device_state);
02474             ao2_ref(m, -1);
02475             found = 1;
02476             break;
02477          }
02478       }
02479       ao2_iterator_destroy(&miter);
02480 
02481       ao2_unlock(q);
02482       queue_t_unref(q, "Done with iterator");
02483    }
02484    ao2_iterator_destroy(&qiter);
02485 
02486         if (found) {
02487       ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
02488    } else {
02489       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",
02490            exten, context, device_state, ast_devstate2str(device_state));
02491    }
02492 
02493    return 0;
02494 }

static int extensionstate2devicestate ( int  state  )  [static]

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

Definition at line 2422 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_UNAVAILABLE, AST_EXTENSION_BUSY, AST_EXTENSION_DEACTIVATED, AST_EXTENSION_INUSE, AST_EXTENSION_NOT_INUSE, AST_EXTENSION_ONHOLD, AST_EXTENSION_REMOVED, AST_EXTENSION_RINGING, and AST_EXTENSION_UNAVAILABLE.

Referenced by extension_state_cb(), and get_queue_member_status().

02423 {
02424    switch (state) {
02425    case AST_EXTENSION_NOT_INUSE:
02426       state = AST_DEVICE_NOT_INUSE;
02427       break;
02428    case AST_EXTENSION_INUSE:
02429       state = AST_DEVICE_INUSE;
02430       break;
02431    case AST_EXTENSION_BUSY:
02432       state = AST_DEVICE_BUSY;
02433       break;
02434    case AST_EXTENSION_RINGING:
02435       state = AST_DEVICE_RINGING;
02436       break;
02437    case AST_EXTENSION_ONHOLD:
02438       state = AST_DEVICE_ONHOLD;
02439       break;
02440    case AST_EXTENSION_UNAVAILABLE:
02441       state = AST_DEVICE_UNAVAILABLE;
02442       break;
02443    case AST_EXTENSION_REMOVED:
02444    case AST_EXTENSION_DEACTIVATED:
02445    default:
02446       state = AST_DEVICE_INVALID;
02447       break;
02448    }
02449 
02450    return state;
02451 }

static struct callattempt* find_best ( struct callattempt outgoing  )  [static, read]

find the entry with the best metric, or NULL

Definition at line 4351 of file app_queue.c.

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

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

04352 {
04353    struct callattempt *best = NULL, *cur;
04354 
04355    for (cur = outgoing; cur; cur = cur->q_next) {
04356       if (cur->stillgoing &&              /* Not already done */
04357          !cur->chan &&              /* Isn't already going */
04358          (!best || cur->metric < best->metric)) {     /* We haven't found one yet, or it's better */
04359          best = cur;
04360       }
04361    }
04362 
04363    return best;
04364 }

static struct call_queue* find_load_queue_rt_friendly ( const char *  queuename  )  [static, read]

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

Referenced by __queues_show(), add_to_queue(), find_member_by_queuename_and_interface(), join_queue(), queue_function_exists(), queue_function_mem_read(), queue_function_mem_write(), queue_function_qac_dep(), queues_data_provider_get(), reload_queue_members(), and set_member_value().

03448 {
03449    struct ast_variable *queue_vars;
03450    struct ast_config *member_config = NULL;
03451    struct call_queue *q = NULL, tmpq = {
03452       .name = queuename,
03453    };
03454    int prev_weight = 0;
03455 
03456    /* Find the queue in the in-core list first. */
03457    q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
03458 
03459    if (!q || q->realtime) {
03460       /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
03461          queue operations while waiting for the DB.
03462 
03463          This will be two separate database transactions, so we might
03464          see queue parameters as they were before another process
03465          changed the queue and member list as it was after the change.
03466          Thus we might see an empty member list when a queue is
03467          deleted. In practise, this is unlikely to cause a problem. */
03468 
03469       queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
03470       if (queue_vars) {
03471          member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
03472          if (!member_config) {
03473             ast_debug(1, "No queue_members defined in config extconfig.conf\n");
03474             member_config = ast_config_new();
03475          }
03476       }
03477       if (q) {
03478          prev_weight = q->weight ? 1 : 0;
03479          queue_t_unref(q, "Need to find realtime queue");
03480       }
03481 
03482       q = find_queue_by_name_rt(queuename, queue_vars, member_config);
03483       ast_config_destroy(member_config);
03484       ast_variables_destroy(queue_vars);
03485 
03486       /* update the use_weight value if the queue's has gained or lost a weight */
03487       if (q) {
03488          if (!q->weight && prev_weight) {
03489             ast_atomic_fetchadd_int(&use_weight, -1);
03490          }
03491          if (q->weight && !prev_weight) {
03492             ast_atomic_fetchadd_int(&use_weight, +1);
03493          }
03494       }
03495       /* Other cases will end up with the proper value for use_weight */
03496    } else {
03497       update_realtime_members(q);
03498    }
03499    return q;
03500 }

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

Definition at line 10987 of file app_queue.c.

References ao2_find, ao2_lock, ao2_unlock, find_load_queue_rt_friendly(), call_queue::members, NULL, OBJ_KEY, and queue_t_unref.

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

10988 {
10989    struct member *mem = NULL;
10990    struct call_queue *q;
10991 
10992    if ((q = find_load_queue_rt_friendly(queuename))) {
10993       ao2_lock(q);
10994       mem = ao2_find(q->members, interface, OBJ_KEY);
10995       ao2_unlock(q);
10996       queue_t_unref(q, "Expiring temporary reference.");
10997    }
10998    return mem;
10999 }

static struct call_queue* find_queue_by_name_rt ( const char *  queuename,
struct ast_variable queue_vars,
struct ast_config member_config 
) [static, read]

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:
the queue,
NULL if 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 3303 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, 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().

03304 {
03305    struct ast_variable *v;
03306    struct call_queue *q, tmpq = {
03307       .name = queuename,
03308    };
03309    struct member *m;
03310    struct ao2_iterator mem_iter;
03311    char *interface = NULL;
03312    const char *tmp_name;
03313    char *tmp;
03314    char tmpbuf[64];  /* Must be longer than the longest queue param name. */
03315 
03316    /* Static queues override realtime. */
03317    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
03318       ao2_lock(q);
03319       if (!q->realtime) {
03320          if (q->dead) {
03321             ao2_unlock(q);
03322             queue_t_unref(q, "Queue is dead; can't return it");
03323             return NULL;
03324          }
03325          ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
03326          ao2_unlock(q);
03327          return q;
03328       }
03329    } else if (!member_config) {
03330       /* Not found in the list, and it's not realtime ... */
03331       return NULL;
03332    }
03333    /* Check if queue is defined in realtime. */
03334    if (!queue_vars) {
03335       /* Delete queue from in-core list if it has been deleted in realtime. */
03336       if (q) {
03337          /*! \note Hmm, can't seem to distinguish a DB failure from a not
03338             found condition... So we might delete an in-core queue
03339             in case of DB failure. */
03340          ast_debug(1, "Queue %s not found in realtime.\n", queuename);
03341 
03342          q->dead = 1;
03343          /* Delete if unused (else will be deleted when last caller leaves). */
03344          queues_t_unlink(queues, q, "Unused; removing from container");
03345          ao2_unlock(q);
03346          queue_t_unref(q, "Queue is dead; can't return it");
03347       }
03348       return NULL;
03349    }
03350 
03351    /* Create a new queue if an in-core entry does not exist yet. */
03352    if (!q) {
03353       struct ast_variable *tmpvar = NULL;
03354       if (!(q = alloc_queue(queuename))) {
03355          return NULL;
03356       }
03357       ao2_lock(q);
03358       clear_queue(q);
03359       q->realtime = 1;
03360       /*Before we initialize the queue, we need to set the strategy, so that linear strategy
03361        * will allocate the members properly
03362        */
03363       for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
03364          if (!strcasecmp(tmpvar->name, "strategy")) {
03365             q->strategy = strat2int(tmpvar->value);
03366             if (q->strategy < 0) {
03367                ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
03368                tmpvar->value, q->name);
03369                q->strategy = QUEUE_STRATEGY_RINGALL;
03370             }
03371             break;
03372          }
03373       }
03374       /* We traversed all variables and didn't find a strategy */
03375       if (!tmpvar) {
03376          q->strategy = QUEUE_STRATEGY_RINGALL;
03377       }
03378       queues_t_link(queues, q, "Add queue to container");
03379    }
03380    init_queue(q);    /* Ensure defaults for all parameters not set explicitly. */
03381 
03382    memset(tmpbuf, 0, sizeof(tmpbuf));
03383    for (v = queue_vars; v; v = v->next) {
03384       /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
03385       if (strchr(v->name, '_')) {
03386          ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
03387          tmp_name = tmpbuf;
03388          tmp = tmpbuf;
03389          while ((tmp = strchr(tmp, '_'))) {
03390             *tmp++ = '-';
03391          }
03392       } else {
03393          tmp_name = v->name;
03394       }
03395 
03396       /* NULL values don't get returned from realtime; blank values should
03397        * still get set.  If someone doesn't want a value to be set, they
03398        * should set the realtime column to NULL, not blank. */
03399       queue_set_param(q, tmp_name, v->value, -1, 0);
03400    }
03401 
03402    /* Temporarily set realtime members dead so we can detect deleted ones. */
03403    mem_iter = ao2_iterator_init(q->members, 0);
03404    while ((m = ao2_iterator_next(&mem_iter))) {
03405       if (m->realtime) {
03406          m->dead = 1;
03407       }
03408       ao2_ref(m, -1);
03409    }
03410    ao2_iterator_destroy(&mem_iter);
03411 
03412    while ((interface = ast_category_browse(member_config, interface))) {
03413       rt_handle_member_record(q, interface, member_config);
03414    }
03415 
03416    /* Delete all realtime members that have been deleted in DB. */
03417    mem_iter = ao2_iterator_init(q->members, 0);
03418    while ((m = ao2_iterator_next(&mem_iter))) {
03419       if (m->dead) {
03420          if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
03421             ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
03422          } else {
03423             ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
03424          }
03425          member_remove_from_queue(q, m);
03426       }
03427       ao2_ref(m, -1);
03428    }
03429    ao2_iterator_destroy(&mem_iter);
03430 
03431    ao2_unlock(q);
03432 
03433    return q;
03434 }

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

Iterate through queue's member list and delete them.

Definition at line 3248 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().

03249 {
03250    /* Free non-dynamic members */
03251    struct member *cur;
03252    struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
03253 
03254    while ((cur = ao2_iterator_next(&mem_iter))) {
03255       if (all || !cur->dynamic) {
03256          member_remove_from_queue(q, cur);
03257       }
03258       ao2_ref(cur, -1);
03259    }
03260    ao2_iterator_destroy(&mem_iter);
03261 }

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

Definition at line 7304 of file app_queue.c.

References ao2_lock, ao2_ref, ao2_t_find, ao2_unlock, ast_log, interface_exists(), LOG_ERROR, call_queue::name, OBJ_POINTER, member::penalty, queue_t_unref, queues, and RESULT_FAILURE.

Referenced by queue_function_memberpenalty_read().

07305 {
07306    int foundqueue = 0, penalty;
07307    struct call_queue *q, tmpq = {
07308       .name = queuename,
07309    };
07310    struct member *mem;
07311 
07312    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) {
07313       foundqueue = 1;
07314       ao2_lock(q);
07315       if ((mem = interface_exists(q, interface))) {
07316          penalty = mem->penalty;
07317          ao2_ref(mem, -1);
07318          ao2_unlock(q);
07319          queue_t_unref(q, "Search complete");
07320          return penalty;
07321       }
07322       ao2_unlock(q);
07323       queue_t_unref(q, "Search complete");
07324    }
07325 
07326    /* some useful debuging */
07327    if (foundqueue) {
07328       ast_log (LOG_ERROR, "Invalid queuename\n");
07329    } else {
07330       ast_log (LOG_ERROR, "Invalid interface\n");
07331    }
07332 
07333    return RESULT_FAILURE;
07334 }

static int get_member_status ( struct call_queue q,
int  max_penalty,
int  min_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 2210 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, 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, member::status, and call_queue::wrapuptime.

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

02211 {
02212    struct member *member;
02213    struct ao2_iterator mem_iter;
02214 
02215    ao2_lock(q);
02216    mem_iter = ao2_iterator_init(q->members, 0);
02217    for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
02218       if ((max_penalty != INT_MAX && member->penalty > max_penalty) || (min_penalty != INT_MAX && member->penalty < min_penalty)) {
02219          if (conditions & QUEUE_EMPTY_PENALTY) {
02220             ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
02221             continue;
02222          }
02223       }
02224 
02225       switch (devstate ? ast_device_state(member->state_interface) : member->status) {
02226       case AST_DEVICE_INVALID:
02227          if (conditions & QUEUE_EMPTY_INVALID) {
02228             ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
02229             break;
02230          }
02231          goto default_case;
02232       case AST_DEVICE_UNAVAILABLE:
02233          if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
02234             ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
02235             break;
02236          }
02237          goto default_case;
02238       case AST_DEVICE_INUSE:
02239          if (conditions & QUEUE_EMPTY_INUSE) {
02240             ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
02241             break;
02242          }
02243          goto default_case;
02244       case AST_DEVICE_RINGING:
02245          if (conditions & QUEUE_EMPTY_RINGING) {
02246             ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
02247             break;
02248          }
02249          goto default_case;
02250       case AST_DEVICE_UNKNOWN:
02251          if (conditions & QUEUE_EMPTY_UNKNOWN) {
02252             ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
02253             break;
02254          }
02255          /* Fall-through */
02256       default:
02257       default_case:
02258          if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
02259             ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
02260             break;
02261          } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
02262             ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
02263             break;
02264          } else {
02265             ao2_ref(member, -1);
02266             ao2_iterator_destroy(&mem_iter);
02267             ao2_unlock(q);
02268             ast_debug(4, "%s is available.\n", member->membername);
02269             return 0;
02270          }
02271          break;
02272       }
02273    }
02274    ao2_iterator_destroy(&mem_iter);
02275    ao2_unlock(q);
02276 
02277    if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
02278       /* member state still may be RINGING due to lag in event message - check again with device state */
02279       return get_member_status(q, max_penalty, min_penalty, conditions, 1);
02280    }
02281    return -1;
02282 }

static int get_queue_member_status ( struct member cur  )  [static]

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:
userdata Data pertaining to the particular call in the queue.
sub The stasis subscription on which the message occurred.
topic The topic for this event.
msg The stasis message for the attended transfer event.

Definition at line 5815 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().

05817 {
05818    struct queue_stasis_data *queue_data = userdata;
05819    struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
05820    RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
05821    RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
05822 
05823    if (queue_data->dying) {
05824       return;
05825    }
05826 
05827    if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
05828          atxfer_msg->dest_type == AST_ATTENDED_TRANSFER_DEST_THREEWAY) {
05829       return;
05830    }
05831 
05832    ao2_lock(queue_data);
05833 
05834    if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
05835       ao2_unlock(queue_data);
05836       return;
05837    }
05838 
05839    if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
05840                atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
05841           (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
05842              atxfer_msg->to_transfer_target.bridge_snapshot->uniqueid))) {
05843       ao2_unlock(queue_data);
05844       return;
05845    }
05846 
05847    caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
05848    member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
05849 
05850    ao2_unlock(queue_data);
05851 
05852    ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
05853 
05854    log_attended_transfer(queue_data, caller_snapshot, atxfer_msg);
05855 
05856    send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
05857          queue_data->holdstart, queue_data->starttime, TRANSFER);
05858    update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
05859          time(NULL) - queue_data->starttime);
05860    remove_stasis_subscriptions(queue_data);
05861 }

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:
userdata Data pertaining to the particular call in the queue.
sub The stasis subscription on which the message occurred.
topic The topic for this event.
msg The stasis message for the blind transfer event

Definition at line 5756 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, ast_blind_transfer_message::context, queue_ent::context, queue_stasis_data::dying, ast_blind_transfer_message::exten, 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().

05758 {
05759    struct queue_stasis_data *queue_data = userdata;
05760    struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
05761    const char *exten;
05762    const char *context;
05763    RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
05764    RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
05765 
05766    if (queue_data->dying) {
05767       return;
05768    }
05769 
05770    if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
05771       return;
05772    }
05773 
05774    ao2_lock(queue_data);
05775 
05776    if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
05777          strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
05778       ao2_unlock(queue_data);
05779       return;
05780    }
05781 
05782    caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
05783    member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
05784 
05785    ao2_unlock(queue_data);
05786 
05787    exten = transfer_msg->exten;
05788    context = transfer_msg->context;
05789 
05790    ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
05791    ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
05792          "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
05793          exten, context,
05794          (long) (queue_data->starttime - queue_data->holdstart),
05795          (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
05796 
05797    send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
05798          queue_data->holdstart, queue_data->starttime, TRANSFER);
05799    update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
05800          time(NULL) - queue_data->starttime);
05801    remove_stasis_subscriptions(queue_data);
05802 }

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

Definition at line 5723 of file app_queue.c.

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

Referenced by setup_stasis_subs().

05725 {
05726    struct queue_stasis_data *queue_data = userdata;
05727    struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
05728 
05729    if (queue_data->dying) {
05730       return;
05731    }
05732 
05733    if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
05734       return;
05735    }
05736 
05737    if (!strcmp(enter_blob->channel->uniqueid, queue_data->caller_uniqueid)) {
05738       ast_string_field_set(queue_data, bridge_uniqueid,
05739             enter_blob->bridge->uniqueid);
05740       ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
05741             enter_blob->channel->name, queue_data->bridge_uniqueid);
05742    }
05743 }

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

Definition at line 6007 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_TRANSFERER_ROLE_NAME, queue_stasis_data::callcompletedinsl, CALLER, queue_stasis_data::caller_pos, queue_stasis_data::caller_uniqueid, queue_ent::chan, queue_stasis_data::dying, queue_stasis_data::holdstart, queue_stasis_data::member, queue_stasis_data::member_uniqueid, member::membername, call_queue::name, ast_channel_snapshot::name, NULL, 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::uniqueid, and update_queue().

Referenced by setup_stasis_subs().

06009 {
06010    struct queue_stasis_data *queue_data = userdata;
06011    struct ast_channel_blob *channel_blob = stasis_message_data(msg);
06012    RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
06013    RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
06014    RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
06015    enum agent_complete_reason reason;
06016 
06017    if (queue_data->dying) {
06018       return;
06019    }
06020 
06021    ao2_lock(queue_data);
06022 
06023    if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->caller_uniqueid)) {
06024       reason = CALLER;
06025    } else if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->member_uniqueid)) {
06026       reason = AGENT;
06027    } else {
06028       ao2_unlock(queue_data);
06029       return;
06030    }
06031 
06032    chan = ast_channel_get_by_name(channel_blob->snapshot->name);
06033    if (chan && ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME)) {
06034       /* Channel that is hanging up is doing it as part of a transfer.
06035        * We'll get a transfer event later
06036        */
06037       ao2_unlock(queue_data);
06038       return;
06039    }
06040 
06041    caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
06042    member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
06043 
06044    ao2_unlock(queue_data);
06045 
06046    ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
06047          channel_blob->snapshot->name);
06048 
06049    ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
06050          reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
06051       (long) (queue_data->starttime - queue_data->holdstart),
06052       (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
06053 
06054    send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
06055          queue_data->holdstart, queue_data->starttime, reason);
06056    update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
06057          time(NULL) - queue_data->starttime);
06058    remove_stasis_subscriptions(queue_data);
06059 }

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

Definition at line 5890 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, queue_stasis_data::caller_optimize, queue_stasis_data::caller_uniqueid, queue_stasis_data::dying, local_optimization::id, id, local_optimization::in_progress, lock, LOG_ERROR, queue_stasis_data::member_optimize, queue_stasis_data::member_uniqueid, ast_channel_snapshot::name, NULL, SCOPED_AO2LOCK, local_optimization::source_chan_uniqueid, stasis_message_data(), and ast_channel_snapshot::uniqueid.

Referenced by setup_stasis_subs().

05892 {
05893    struct queue_stasis_data *queue_data = userdata;
05894    struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
05895    struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
05896    struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
05897    struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
05898    struct local_optimization *optimization;
05899    unsigned int id;
05900    SCOPED_AO2LOCK(lock, queue_data);
05901 
05902    if (queue_data->dying) {
05903       return;
05904    }
05905 
05906    if (!strcmp(local_one->uniqueid, queue_data->member_uniqueid)) {
05907       optimization = &queue_data->member_optimize;
05908    } else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
05909       optimization = &queue_data->caller_optimize;
05910    } else {
05911       return;
05912    }
05913 
05914    /* We only allow move-swap optimizations, so there had BETTER be a source */
05915    ast_assert(source != NULL);
05916 
05917    optimization->source_chan_uniqueid = ast_strdup(source->uniqueid);
05918    if (!optimization->source_chan_uniqueid) {
05919       ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->name);
05920       return;
05921    }
05922    id = ast_json_integer_get(ast_json_object_get(ast_multi_channel_blob_get_json(optimization_blob), "id"));
05923 
05924    optimization->id = id;
05925    optimization->in_progress = 1;
05926 }

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

Definition at line 5942 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, queue_stasis_data::caller_optimize, queue_stasis_data::caller_uniqueid, queue_stasis_data::dying, local_optimization::id, 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::uniqueid.

Referenced by setup_stasis_subs().

05944 {
05945    struct queue_stasis_data *queue_data = userdata;
05946    struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
05947    struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
05948    struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
05949    struct local_optimization *optimization;
05950    int is_caller;
05951    unsigned int id;
05952    SCOPED_AO2LOCK(lock, queue_data);
05953 
05954    if (queue_data->dying) {
05955       return;
05956    }
05957 
05958    if (!strcmp(local_one->uniqueid, queue_data->member_uniqueid)) {
05959       optimization = &queue_data->member_optimize;
05960       is_caller = 0;
05961    } else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
05962       optimization = &queue_data->caller_optimize;
05963       is_caller = 1;
05964    } else {
05965       return;
05966    }
05967 
05968    id = ast_json_integer_get(ast_json_object_get(ast_multi_channel_blob_get_json(optimization_blob), "id"));
05969 
05970    if (!optimization->in_progress) {
05971       ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
05972       return;
05973    }
05974 
05975    if (id != optimization->id) {
05976       ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
05977             id, optimization->id);
05978       return;
05979    }
05980 
05981    if (is_caller) {
05982       ast_debug(3, "Local optimization: Changing queue caller uniqueid from %s to %s\n",
05983             queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
05984       ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
05985    } else {
05986       ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
05987             queue_data->member_uniqueid, optimization->source_chan_uniqueid);
05988       ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
05989    }
05990 
05991    optimization->in_progress = 0;
05992 }

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

Definition at line 9934 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.

09935 {
09936    const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
09937    int penalty;
09938 
09939    switch ( cmd ) {
09940    case CLI_INIT:
09941       e->command = "queue add member";
09942       e->usage =
09943          "Usage: queue add member <dial string> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"
09944          "       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";
09945       return NULL;
09946    case CLI_GENERATE:
09947       return complete_queue_add_member(a->line, a->word, a->pos, a->n);
09948    }
09949 
09950    if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
09951       return CLI_SHOWUSAGE;
09952    } else if (strcmp(a->argv[4], "to")) {
09953       return CLI_SHOWUSAGE;
09954    } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
09955       return CLI_SHOWUSAGE;
09956    } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
09957       return CLI_SHOWUSAGE;
09958    } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
09959       return CLI_SHOWUSAGE;
09960    }
09961 
09962    queuename = a->argv[5];
09963    interface = a->argv[3];
09964    if (a->argc >= 8) {
09965       if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
09966          if (penalty < 0) {
09967             ast_cli(a->fd, "Penalty must be >= 0\n");
09968             penalty = 0;
09969          }
09970       } else {
09971          ast_cli(a->fd, "Penalty must be an integer >= 0\n");
09972          penalty = 0;
09973       }
09974    } else {
09975       penalty = 0;
09976    }
09977 
09978    if (a->argc >= 10) {
09979       membername = a->argv[9];
09980    }
09981 
09982    if (a->argc >= 12) {
09983       state_interface = a->argv[11];
09984    }
09985 
09986    switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
09987    case RES_OKAY:
09988       if (ast_strlen_zero(membername) || !log_membername_as_agent) {
09989          ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
09990       } else {
09991          ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", "");
09992       }
09993       ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
09994       return CLI_SUCCESS;
09995    case RES_EXISTS:
09996       ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
09997       return CLI_FAILURE;
09998    case RES_NOSUCHQUEUE:
09999       ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
10000       return CLI_FAILURE;
10001    case RES_OUTOFMEMORY:
10002       ast_cli(a->fd, "Out of memory\n");
10003       return CLI_FAILURE;
10004    case RES_NOT_DYNAMIC:
10005       ast_cli(a->fd, "Member not dynamic\n");
10006       return CLI_FAILURE;
10007    default:
10008       return CLI_FAILURE;
10009    }
10010 }

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

Definition at line 10140 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, member::interface, ast_cli_args::line, ast_cli_args::n, NULL, member::paused, ast_cli_args::pos, RESULT_SUCCESS, set_member_paused(), and ast_cli_entry::usage.

10141 {
10142    const char *queuename, *interface, *reason;
10143    int paused;
10144 
10145    switch (cmd) {
10146    case CLI_INIT:
10147       e->command = "queue {pause|unpause} member";
10148       e->usage =
10149          "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
10150          "  Pause or unpause a queue member. Not specifying a particular queue\n"
10151          "  will pause or unpause a member across all queues to which the member\n"
10152          "  belongs.\n";
10153       return NULL;
10154    case CLI_GENERATE:
10155       return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
10156    }
10157 
10158    if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
10159       return CLI_SHOWUSAGE;
10160    } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
10161       return CLI_SHOWUSAGE;
10162    } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
10163       return CLI_SHOWUSAGE;
10164    }
10165 
10166 
10167    interface = a->argv[3];
10168    queuename = a->argc >= 6 ? a->argv[5] : NULL;
10169    reason = a->argc == 8 ? a->argv[7] : NULL;
10170    paused = !strcasecmp(a->argv[1], "pause");
10171 
10172    if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
10173       ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
10174       if (!ast_strlen_zero(queuename)) {
10175          ast_cli(a->fd, " in queue '%s'", queuename);
10176       }
10177       if (!ast_strlen_zero(reason)) {
10178          ast_cli(a->fd, " for reason '%s'", reason);
10179       }
10180       ast_cli(a->fd, "\n");
10181       return CLI_SUCCESS;
10182    } else {
10183       ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
10184       if (!ast_strlen_zero(queuename)) {
10185          ast_cli(a->fd, " in queue '%s'", queuename);
10186       }
10187       if (!ast_strlen_zero(reason)) {
10188          ast_cli(a->fd, " for reason '%s'", reason);
10189       }
10190       ast_cli(a->fd, "\n");
10191       return CLI_FAILURE;
10192    }
10193 }

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

Definition at line 10412 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.

10413 {
10414    struct ast_flags mask = {0,};
10415    int i;
10416 
10417    switch (cmd) {
10418       case CLI_INIT:
10419          e->command = "queue reload {parameters|members|rules|all}";
10420          e->usage =
10421             "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
10422             "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
10423             "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
10424             "specified in order to know what information to reload. Below is an explanation\n"
10425             "of each of these qualifiers.\n"
10426             "\n"
10427             "\t'members' - reload queue members from queues.conf\n"
10428             "\t'parameters' - reload all queue options except for queue members\n"
10429             "\t'rules' - reload the queuerules.conf file\n"
10430             "\t'all' - reload queue rules, parameters, and members\n"
10431             "\n"
10432             "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
10433             "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
10434             "one queue is specified when using this command, reloading queue rules may cause\n"
10435             "other queues to be affected\n";
10436          return NULL;
10437       case CLI_GENERATE:
10438          if (a->pos >= 3) {
10439             /* find the point at which the list of queue names starts */
10440             const char *command_end = a->line + strlen("queue reload ");
10441             command_end = strchr(command_end, ' ');
10442             if (!command_end) {
10443                command_end = a->line + strlen(a->line);
10444             }
10445             return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
10446          } else {
10447             return NULL;
10448          }
10449    }
10450 
10451    if (a->argc < 3)
10452       return CLI_SHOWUSAGE;
10453 
10454    if (!strcasecmp(a->argv[2], "rules")) {
10455       ast_set_flag(&mask, QUEUE_RELOAD_RULES);
10456    } else if (!strcasecmp(a->argv[2], "members")) {
10457       ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
10458    } else if (!strcasecmp(a->argv[2], "parameters")) {
10459       ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
10460    } else if (!strcasecmp(a->argv[2], "all")) {
10461       ast_set_flag(&mask, AST_FLAGS_ALL);
10462    }
10463 
10464    if (a->argc == 3) {
10465       reload_handler(1, &mask, NULL);
10466       return CLI_SUCCESS;
10467    }
10468 
10469    for (i = 3; i < a->argc; ++i) {
10470       reload_handler(1, &mask, a->argv[i]);
10471    }
10472 
10473    return CLI_SUCCESS;
10474 }

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

Definition at line 10060 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.

10061 {
10062    const char *queuename, *interface;
10063    struct member *mem = NULL;
10064    char *res = CLI_FAILURE;
10065 
10066    switch (cmd) {
10067    case CLI_INIT:
10068       e->command = "queue remove member";
10069       e->usage =
10070          "Usage: queue remove member <channel> from <queue>\n"
10071          "       Remove a specific channel from a queue.\n";
10072       return NULL;
10073    case CLI_GENERATE:
10074       return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
10075    }
10076 
10077    if (a->argc != 6) {
10078       return CLI_SHOWUSAGE;
10079    } else if (strcmp(a->argv[4], "from")) {
10080       return CLI_SHOWUSAGE;
10081    }
10082 
10083    queuename = a->argv[5];
10084    interface = a->argv[3];
10085 
10086    if (log_membername_as_agent) {
10087       mem = find_member_by_queuename_and_interface(queuename, interface);
10088    }
10089 
10090    switch (remove_from_queue(queuename, interface)) {
10091    case RES_OKAY:
10092       if (!mem || ast_strlen_zero(mem->membername)) {
10093          ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
10094       } else {
10095          ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
10096       }
10097       ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
10098       res = CLI_SUCCESS;
10099       break;
10100    case RES_EXISTS:
10101       ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
10102       break;
10103    case RES_NOSUCHQUEUE:
10104       ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
10105       break;
10106    case RES_OUTOFMEMORY:
10107       ast_cli(a->fd, "Out of memory\n");
10108       break;
10109    case RES_NOT_DYNAMIC:
10110       ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
10111       break;
10112    }
10113 
10114    if (mem) {
10115       ao2_ref(mem, -1);
10116    }
10117 
10118    return res;
10119 }

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

Definition at line 10373 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.

10374 {
10375    struct ast_flags mask = {QUEUE_RESET_STATS,};
10376    int i;
10377 
10378    switch (cmd) {
10379       case CLI_INIT:
10380          e->command = "queue reset stats";
10381          e->usage =
10382             "Usage: queue reset stats [<queuenames>]\n"
10383             "\n"
10384             "Issuing this command will reset statistics for\n"
10385             "<queuenames>, or for all queues if no queue is\n"
10386             "specified.\n";
10387          return NULL;
10388       case CLI_GENERATE:
10389          if (a->pos >= 3) {
10390             return complete_queue(a->line, a->word, a->pos, a->n, 17);
10391          } else {
10392             return NULL;
10393          }
10394    }
10395 
10396    if (a->argc < 3) {
10397       return CLI_SHOWUSAGE;
10398    }
10399 
10400    if (a->argc == 3) {
10401       reload_handler(1, &mask, NULL);
10402       return CLI_SUCCESS;
10403    }
10404 
10405    for (i = 3; i < a->argc; ++i) {
10406       reload_handler(1, &mask, a->argv[i]);
10407    }
10408 
10409    return CLI_SUCCESS;
10410 }

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

Definition at line 10338 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::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, rule_list::rules, penalty_rule::time, ast_cli_entry::usage, and ast_cli_args::word.

10339 {
10340    const char *rule;
10341    struct rule_list *rl_iter;
10342    struct penalty_rule *pr_iter;
10343    switch (cmd) {
10344    case CLI_INIT:
10345       e->command = "queue show rules";
10346       e->usage =
10347       "Usage: queue show rules [rulename]\n"
10348       "  Show the list of rules associated with rulename. If no\n"
10349       "  rulename is specified, list all rules defined in queuerules.conf\n";
10350       return NULL;
10351    case CLI_GENERATE:
10352       return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
10353    }
10354 
10355    if (a->argc != 3 && a->argc != 4) {
10356       return CLI_SHOWUSAGE;
10357    }
10358 
10359    rule = a->argc == 4 ? a->argv[3] : "";
10360    AST_LIST_LOCK(&rule_lists);
10361    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10362       if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
10363          ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
10364          AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10365             ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d and adjust QUEUE_MIN_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);
10366          }
10367       }
10368    }
10369    AST_LIST_UNLOCK(&rule_lists);
10370    return CLI_SUCCESS;
10371 }

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

Definition at line 10275 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, member::interface, ast_cli_args::line, MEMBER_PENALTY, ast_cli_args::n, NULL, member::penalty, ast_cli_args::pos, RESULT_FAILURE, RESULT_SUCCESS, set_member_value(), ast_cli_entry::usage, and ast_cli_args::word.

10276 {
10277    const char *queuename = NULL, *interface;
10278    int penalty = 0;
10279 
10280    switch (cmd) {
10281    case CLI_INIT:
10282       e->command = "queue set penalty";
10283       e->usage =
10284       "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
10285       "  Set a member's penalty in the queue specified. If no queue is specified\n"
10286       "  then that interface's penalty is set in all queues to which that interface is a member\n";
10287       return NULL;
10288    case CLI_GENERATE:
10289       return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
10290    }
10291 
10292    if (a->argc != 6 && a->argc != 8) {
10293       return CLI_SHOWUSAGE;
10294    } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
10295       return CLI_SHOWUSAGE;
10296    }
10297 
10298    if (a->argc == 8) {
10299       queuename = a->argv[7];
10300    }
10301    interface = a->argv[5];
10302    penalty = atoi(a->argv[3]);
10303 
10304    switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
10305    case RESULT_SUCCESS:
10306       ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
10307       return CLI_SUCCESS;
10308    case RESULT_FAILURE:
10309       ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
10310       return CLI_FAILURE;
10311    default:
10312       return CLI_FAILURE;
10313    }
10314 }

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

Definition at line 10218 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, member::interface, ast_cli_args::line, MEMBER_RINGINUSE, ast_cli_args::n, NULL, ast_cli_args::pos, RESULT_FAILURE, RESULT_SUCCESS, member::ringinuse, set_member_value(), ast_cli_entry::usage, and ast_cli_args::word.

10219 {
10220    const char *queuename = NULL, *interface;
10221    int ringinuse;
10222 
10223    switch (cmd) {
10224    case CLI_INIT:
10225       e->command = "queue set ringinuse";
10226       e->usage =
10227       "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
10228       "  Set a member's ringinuse in the queue specified. If no queue is specified\n"
10229       "  then that interface's penalty is set in all queues to which that interface is a member.\n";
10230       break;
10231       return NULL;
10232    case CLI_GENERATE:
10233       return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
10234    }
10235 
10236    /* Sensible argument counts */
10237    if (a->argc != 6 && a->argc != 8) {
10238       return CLI_SHOWUSAGE;
10239    }
10240 
10241    /* Uses proper indicational words */
10242    if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
10243       return CLI_SHOWUSAGE;
10244    }
10245 
10246    /* Set the queue name if applicale */
10247    if (a->argc == 8) {
10248       queuename = a->argv[7];
10249    }
10250 
10251    /* Interface being set */
10252    interface = a->argv[5];
10253 
10254    /* Check and set the ringinuse value */
10255    if (ast_true(a->argv[3])) {
10256       ringinuse = 1;
10257    } else if (ast_false(a->argv[3])) {
10258       ringinuse = 0;
10259    } else {
10260       return CLI_SHOWUSAGE;
10261    }
10262 
10263    switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
10264    case RESULT_SUCCESS:
10265       ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
10266       return CLI_SUCCESS;
10267    case RESULT_FAILURE:
10268       ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
10269       return CLI_FAILURE;
10270    default:
10271       return CLI_FAILURE;
10272    }
10273 }

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 4003 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_hangup(), callattempt_free(), queue_ent::chan, callattempt::chan, callattempt::interface, and callattempt::q_next.

Referenced by try_calling().

04004 {
04005    struct callattempt *oo;
04006 
04007    while (outgoing) {
04008       /* If someone else answered the call we should indicate this in the CANCEL */
04009       /* Hangup any existing lines we have open */
04010       if (outgoing->chan && (outgoing->chan != exception)) {
04011          if (exception || cancel_answered_elsewhere) {
04012             ast_channel_hangupcause_set(outgoing->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
04013          }
04014          ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
04015          ast_hangup(outgoing->chan);
04016       }
04017       oo = outgoing;
04018       outgoing = outgoing->q_next;
04019       ast_aoc_destroy_decoded(oo->aoc_s_rate_list);
04020       callattempt_free(oo);
04021    }
04022 }

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

References call_queue::announce_to_first_user, call_queue::announcefrequency, call_queue::announceholdtime, call_queue::announceposition, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, ao2_container_alloc, 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, call_queue::autopause, call_queue::autopausedelay, call_queue::dead, DEFAULT_MIN_ANNOUNCE_FREQUENCY, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, 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, call_queue::name, 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().

02579 {
02580    int i;
02581    struct penalty_rule *pr_iter;
02582 
02583    q->dead = 0;
02584    q->retry = DEFAULT_RETRY;
02585    q->timeout = DEFAULT_TIMEOUT;
02586    q->maxlen = 0;
02587    q->announcefrequency = 0;
02588    q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
02589    q->announceholdtime = 1;
02590    q->announcepositionlimit = 10; /* Default 10 positions */
02591    q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
02592    q->roundingseconds = 0; /* Default - don't announce seconds */
02593    q->servicelevel = 0;
02594    q->ringinuse = 1;
02595    q->announce_to_first_user = 0;
02596    q->setinterfacevar = 0;
02597    q->setqueuevar = 0;
02598    q->setqueueentryvar = 0;
02599    q->autofill = autofill_default;
02600    q->montype = montype_default;
02601    q->monfmt[0] = '\0';
02602    q->reportholdtime = 0;
02603    q->wrapuptime = 0;
02604    q->penaltymemberslimit = 0;
02605    q->joinempty = 0;
02606    q->leavewhenempty = 0;
02607    q->memberdelay = 0;
02608    q->weight = 0;
02609    q->timeoutrestart = 0;
02610    q->periodicannouncefrequency = 0;
02611    q->randomperiodicannounce = 0;
02612    q->numperiodicannounce = 0;
02613    q->autopause = QUEUE_AUTOPAUSE_OFF;
02614    q->timeoutpriority = TIMEOUT_PRIORITY_APP;
02615    q->autopausedelay = 0;
02616    if (!q->members) {
02617       if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) {
02618          /* linear strategy depends on order, so we have to place all members in a single bucket */
02619          q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
02620       } else {
02621          q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
02622       }
02623    }
02624    q->found = 1;
02625 
02626    ast_string_field_set(q, sound_next, "queue-youarenext");
02627    ast_string_field_set(q, sound_thereare, "queue-thereare");
02628    ast_string_field_set(q, sound_calls, "queue-callswaiting");
02629    ast_string_field_set(q, queue_quantity1, "queue-quantity1");
02630    ast_string_field_set(q, queue_quantity2, "queue-quantity2");
02631    ast_string_field_set(q, sound_holdtime, "queue-holdtime");
02632    ast_string_field_set(q, sound_minutes, "queue-minutes");
02633    ast_string_field_set(q, sound_minute, "queue-minute");
02634    ast_string_field_set(q, sound_seconds, "queue-seconds");
02635    ast_string_field_set(q, sound_thanks, "queue-thankyou");
02636    ast_string_field_set(q, sound_reporthold, "queue-reporthold");
02637 
02638    if (!q->sound_periodicannounce[0]) {
02639       q->sound_periodicannounce[0] = ast_str_create(32);
02640    }
02641 
02642    if (q->sound_periodicannounce[0]) {
02643       ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
02644    }
02645 
02646    for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
02647       if (q->sound_periodicannounce[i]) {
02648          ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
02649       }
02650    }
02651 
02652    while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
02653       ast_free(pr_iter);
02654    }
02655 
02656    /* On restart assume no members are available.
02657     * The queue_avail hint is a boolean state to indicate whether a member is available or not.
02658     *
02659     * This seems counter intuitive, but is required to light a BLF
02660     * AST_DEVICE_INUSE indicates no members are available.
02661     * AST_DEVICE_NOT_INUSE indicates a member is available.
02662     */
02663    ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
02664 }

static void insert_entry ( struct call_queue q,
struct queue_ent prev,
struct queue_ent new,
int *  pos 
) [inline, static]

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

Definition at line 1888 of file app_queue.c.

References call_queue::head, queue_ent::next, and queue_ref().

Referenced by join_queue().

01889 {
01890    struct queue_ent *cur;
01891 
01892    if (!q || !new)
01893       return;
01894    if (prev) {
01895       cur = prev->next;
01896       prev->next = new;
01897    } else {
01898       cur = q->head;
01899       q->head = new;
01900    }
01901    new->next = cur;
01902 
01903    /* every queue_ent must have a reference to it's parent call_queue, this
01904     * reference does not go away until the end of the queue_ent's life, meaning
01905     * that even when the queue_ent leaves the call_queue this ref must remain. */
01906    queue_ref(q);
01907    new->parent = q;
01908    new->pos = ++(*pos);
01909    new->opos = *pos;
01910 }

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:
-1 on failure
0 on success
Note:
Call this with the rule_lists locked

Definition at line 2695 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, LOG_WARNING, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, NULL, rule_list::rules, and penalty_rule::time.

Referenced by reload_queue_rules().

02696 {
02697    char *timestr, *maxstr, *minstr, *contentdup;
02698    struct penalty_rule *rule = NULL, *rule_iter;
02699    struct rule_list *rl_iter;
02700    int penaltychangetime, inserted = 0;
02701 
02702    if (!(rule = ast_calloc(1, sizeof(*rule)))) {
02703       return -1;
02704    }
02705 
02706    contentdup = ast_strdupa(content);
02707 
02708    if (!(maxstr = strchr(contentdup, ','))) {
02709       ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
02710       ast_free(rule);
02711       return -1;
02712    }
02713 
02714    *maxstr++ = '\0';
02715    timestr = contentdup;
02716 
02717    if ((penaltychangetime = atoi(timestr)) < 0) {
02718       ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
02719       ast_free(rule);
02720       return -1;
02721    }
02722 
02723    rule->time = penaltychangetime;
02724 
02725    if ((minstr = strchr(maxstr,','))) {
02726       *minstr++ = '\0';
02727    }
02728 
02729    /* The last check will evaluate true if either no penalty change is indicated for a given rule
02730     * OR if a min penalty change is indicated but no max penalty change is */
02731    if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
02732       rule->max_relative = 1;
02733    }
02734 
02735    rule->max_value = atoi(maxstr);
02736 
02737    if (!ast_strlen_zero(minstr)) {
02738       if (*minstr == '+' || *minstr == '-') {
02739          rule->min_relative = 1;
02740       }
02741       rule->min_value = atoi(minstr);
02742    } else { /*there was no minimum specified, so assume this means no change*/
02743       rule->min_relative = 1;
02744    }
02745 
02746    /*We have the rule made, now we need to insert it where it belongs*/
02747    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
02748       if (strcasecmp(rl_iter->name, list_name)) {
02749          continue;
02750       }
02751 
02752       AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
02753          if (rule->time < rule_iter->time) {
02754             AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
02755             inserted = 1;
02756             break;
02757          }
02758       }
02759       AST_LIST_TRAVERSE_SAFE_END;
02760 
02761       if (!inserted) {
02762          AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
02763          inserted = 1;
02764       }
02765 
02766       break;
02767    }
02768 
02769    if (!inserted) {
02770       ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
02771       ast_free(rule);
02772       return -1;
02773    }
02774    return 0;
02775 }

static const char* int2strat ( int  strategy  )  [static]

Definition at line 1701 of file app_queue.c.

References ARRAY_LEN, strategy::name, and strategies.

Referenced by __queues_show(), manager_queues_status(), queue_function_var(), queues_data_provider_get_helper(), and set_queue_variables().

01702 {
01703    int x;
01704 
01705    for (x = 0; x < ARRAY_LEN(strategies); x++) {
01706       if (strategy == strategies[x].strategy) {
01707          return strategies[x].name;
01708       }
01709    }
01710 
01711    return "<unknown>";
01712 }

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

Definition at line 6890 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_member_penalty(), queue_function_mem_read(), queue_function_mem_write(), rna(), set_member_paused(), set_member_penalty_help_members(), and set_member_ringinuse_help_members().

06891 {
06892    struct member *mem;
06893    struct ao2_iterator mem_iter;
06894 
06895    if (!q) {
06896       return NULL;
06897    }
06898    mem_iter = ao2_iterator_init(q->members, 0);
06899    while ((mem = ao2_iterator_next(&mem_iter))) {
06900       if (!strcasecmp(interface, mem->interface)) {
06901          ao2_iterator_destroy(&mem_iter);
06902          return mem;
06903       }
06904       ao2_ref(mem, -1);
06905    }
06906    ao2_iterator_destroy(&mem_iter);
06907 
06908    return NULL;
06909 }

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

Definition at line 2302 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(), member::lastcall, NULL, member::paused, member::ringinuse, member::status, and call_queue::wrapuptime.

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

02303 {
02304    int available = 0;
02305 
02306    switch (mem->status) {
02307       case AST_DEVICE_INVALID:
02308       case AST_DEVICE_UNAVAILABLE:
02309          break;
02310       case AST_DEVICE_INUSE:
02311       case AST_DEVICE_BUSY:
02312       case AST_DEVICE_RINGING:
02313       case AST_DEVICE_RINGINUSE:
02314       case AST_DEVICE_ONHOLD:
02315          if (!mem->ringinuse) {
02316             break;
02317          }
02318          /* else fall through */
02319       case AST_DEVICE_NOT_INUSE:
02320       case AST_DEVICE_UNKNOWN:
02321          if (!mem->paused) {
02322             available = 1;
02323          }
02324          break;
02325    }
02326 
02327    /* Let wrapuptimes override device state availability */
02328    if (mem->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < mem->lastcall)) {
02329       available = 0;
02330    }
02331    return available;
02332 }

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] qe The caller who wants to know if it is his turn
Return values:
0 It is not our turn
1 It is our turn

Definition at line 5159 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, and queue_ent::pos.

Referenced by queue_exec(), and wait_our_turn().

05160 {
05161    struct queue_ent *ch;
05162    int res;
05163    int avl;
05164    int idx = 0;
05165    /* This needs a lock. How many members are available to be served? */
05166    ao2_lock(qe->parent);
05167 
05168    avl = num_available_members(qe->parent);
05169 
05170    ch = qe->parent->head;
05171 
05172    ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
05173 
05174    while ((idx < avl) && (ch) && (ch != qe)) {
05175       if (!ch->pending) {
05176          idx++;
05177       }
05178       ch = ch->next;
05179    }
05180 
05181    ao2_unlock(qe->parent);
05182    /* If the queue entry is within avl [the number of available members] calls from the top ...
05183     * Autofill and position check added to support autofill=no (as only calls
05184     * from the front of the queue are valid when autofill is disabled)
05185     */
05186    if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
05187       ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
05188       res = 1;
05189    } else {
05190       ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
05191       res = 0;
05192    }
05193 
05194    return res;
05195 }

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

Definition at line 3577 of file app_queue.c.

References call_queue::announce, queue_ent::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, call_queue::context, queue_ent::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, call_queue::moh, queue_ent::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, and status.

Referenced by queue_exec().

03578 {
03579    struct call_queue *q;
03580    struct queue_ent *cur, *prev = NULL;
03581    int res = -1;
03582    int pos = 0;
03583    int inserted = 0;
03584 
03585    if (!(q = find_load_queue_rt_friendly(queuename))) {
03586       return res;
03587    }
03588    ao2_lock(q);
03589 
03590    /* This is our one */
03591    if (q->joinempty) {
03592       int status = 0;
03593       if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty, 0))) {
03594          *reason = QUEUE_JOINEMPTY;
03595          ao2_unlock(q);
03596          queue_t_unref(q, "Done with realtime queue");
03597          return res;
03598       }
03599    }
03600    if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
03601       *reason = QUEUE_FULL;
03602    } else if (*reason == QUEUE_UNKNOWN) {
03603       RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
03604 
03605       /* There's space for us, put us at the right position inside
03606        * the queue.
03607        * Take into account the priority of the calling user */
03608       inserted = 0;
03609       prev = NULL;
03610       cur = q->head;
03611       while (cur) {
03612          /* We have higher priority than the current user, enter
03613           * before him, after all the other users with priority
03614           * higher or equal to our priority. */
03615          if ((!inserted) && (qe->prio > cur->prio)) {
03616             insert_entry(q, prev, qe, &pos);
03617             inserted = 1;
03618          }
03619          /* <= is necessary for the position comparison because it may not be possible to enter
03620           * at our desired position since higher-priority callers may have taken the position we want
03621           */
03622          if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
03623             insert_entry(q, prev, qe, &pos);
03624             inserted = 1;
03625             /*pos is incremented inside insert_entry, so don't need to add 1 here*/
03626             if (position < pos) {
03627                ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
03628             }
03629          }
03630          cur->pos = ++pos;
03631          prev = cur;
03632          cur = cur->next;
03633       }
03634       /* No luck, join at the end of the queue */
03635       if (!inserted) {
03636          insert_entry(q, prev, qe, &pos);
03637       }
03638       ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
03639       ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
03640       ast_copy_string(qe->context, q->context, sizeof(qe->context));
03641       q->count++;
03642       if (q->count == 1) {
03643          ast_devstate_changed(AST_DEVICE_RINGING, AST_DEVSTATE_CACHABLE, "Queue:%s", q->name);
03644       }
03645 
03646       res = 0;
03647 
03648       blob = ast_json_pack("{s: s, s: i, s: i}",
03649                  "Queue", q->name,
03650                  "Position", qe->pos,
03651                  "Count", q->count);
03652       ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
03653       ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
03654    }
03655    ao2_unlock(q);
03656    queue_t_unref(q, "Done with realtime queue");
03657 
03658    return res;
03659 }

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

Definition at line 8829 of file app_queue.c.

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

Referenced by reload_single_queue().

08830 {
08831    struct member *member = obj;
08832 
08833    if (!member->delme) {
08834       member->status = get_queue_member_status(member);
08835       return 0;
08836    } else {
08837       return CMP_MATCH;
08838    }
08839 }

static int kill_dead_queues ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 8980 of file app_queue.c.

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

Referenced by reload_queues().

08981 {
08982    struct call_queue *q = obj;
08983    char *queuename = arg;
08984    if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
08985       return CMP_MATCH;
08986    } else {
08987       return 0;
08988    }
08989 }

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 3905 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, call_queue::name, queue_ent::next, NULL, queue_ent::parent, pbx_builtin_setvar_helper(), queue_ent::pos, queue_ent::pr, queue_ent::qe_rules, queue_t_ref, queue_t_unref, queues, queues_t_unlink, RAII_VAR, call_queue::realtime, SENTINEL, and var.

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

03906 {
03907    struct call_queue *q;
03908    struct queue_ent *current, *prev = NULL;
03909    struct penalty_rule *pr_iter;
03910    int pos = 0;
03911 
03912    if (!(q = qe->parent)) {
03913       return;
03914    }
03915    queue_t_ref(q, "Copy queue pointer from queue entry");
03916    ao2_lock(q);
03917 
03918    prev = NULL;
03919    for (current = q->head; current; current = current->next) {
03920       if (current == qe) {
03921          RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
03922          char posstr[20];
03923          q->count--;
03924          if (!q->count) {
03925             ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s", q->name);
03926          }
03927 
03928          blob = ast_json_pack("{s: s, s: i, s: i}",
03929                     "Queue", q->name,
03930                     "Position", qe->pos,
03931                     "Count", q->count);
03932          ast_channel_publish_cached_blob(qe->chan, queue_caller_leave_type(), blob);
03933          ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
03934          /* Take us out of the queue */
03935          if (prev) {
03936             prev->next = current->next;
03937          } else {
03938             q->head = current->next;
03939          }
03940          /* Free penalty rules */
03941          while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
03942             ast_free(pr_iter);
03943          }
03944          qe->pr = NULL;
03945          snprintf(posstr, sizeof(posstr), "%d", qe->pos);
03946          pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
03947       } else {
03948          /* Renumber the people after us in the queue based on a new count */
03949          current->pos = ++pos;
03950          prev = current;
03951       }
03952    }
03953    ao2_unlock(q);
03954 
03955    /*If the queue is a realtime queue, check to see if it's still defined in real time*/
03956    if (q->realtime) {
03957       struct ast_variable *var;
03958       if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
03959          q->dead = 1;
03960       } else {
03961          ast_variables_destroy(var);
03962       }
03963    }
03964 
03965    if (q->dead) {
03966       /* It's dead and nobody is in it, so kill it */
03967       queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
03968    }
03969    /* unref the explicit ref earlier in the function */
03970    queue_t_unref(q, "Expire copied reference");
03971 }

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

References ao2_container_alloc, 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_data_register_multiple, ast_device_state_topic_all(), ast_extension_state_add(), 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, extension_state_cb(), LOG_NOTICE, manager_add_queue_member(), 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_show(), manager_queues_status(), manager_queues_summary(), manager_remove_queue_member(), manager_topic, MAX_QUEUE_BUCKETS, NULL, pqm_exec(), ql_exec(), queue_agent_cb(), queue_cmp_cb(), queue_exec(), queue_hash_cb(), queues, 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(), unload_module, and upqm_exec().

10835 {
10836    int err = 0;
10837    struct ast_flags mask = {AST_FLAGS_ALL, };
10838    struct ast_config *member_config;
10839    struct stasis_topic *queue_topic;
10840    struct stasis_topic *manager_topic;
10841 
10842    queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
10843    if (!queues) {
10844       return AST_MODULE_LOAD_DECLINE;
10845    }
10846 
10847    use_weight = 0;
10848 
10849    if (reload_handler(0, &mask, NULL)) {
10850       unload_module();
10851       return AST_MODULE_LOAD_DECLINE;
10852    }
10853 
10854    ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
10855 
10856    /*
10857     * This section is used to determine which name for 'ringinuse' to use in realtime members
10858     * Necessary for supporting older setups.
10859     */
10860    member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
10861    if (!member_config) {
10862       realtime_ringinuse_field = "ringinuse";
10863    } else {
10864       const char *config_val;
10865 
10866       if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
10867          ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
10868          realtime_ringinuse_field = "ringinuse";
10869       } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
10870          ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
10871          realtime_ringinuse_field = "ignorebusy";
10872       } else {
10873          ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
10874          realtime_ringinuse_field = "ringinuse";
10875       }
10876    }
10877    ast_config_destroy(member_config);
10878 
10879    if (queue_persistent_members) {
10880       reload_queue_members();
10881    }
10882 
10883    ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers));
10884 
10885    err |= ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue));
10886    err |= ast_register_application_xml(app, queue_exec);
10887    err |= ast_register_application_xml(app_aqm, aqm_exec);
10888    err |= ast_register_application_xml(app_rqm, rqm_exec);
10889    err |= ast_register_application_xml(app_pqm, pqm_exec);
10890    err |= ast_register_application_xml(app_upqm, upqm_exec);
10891    err |= ast_register_application_xml(app_ql, ql_exec);
10892    err |= ast_manager_register_xml("Queues", 0, manager_queues_show);
10893    err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
10894    err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
10895    err |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member);
10896    err |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member);
10897    err |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member);
10898    err |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom);
10899    err |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty);
10900    err |= ast_manager_register_xml("QueueMemberRingInUse", EVENT_FLAG_AGENT, manager_queue_member_ringinuse);
10901    err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
10902    err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
10903    err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
10904    err |= ast_custom_function_register(&queuevar_function);
10905    err |= ast_custom_function_register(&queueexists_function);
10906    err |= ast_custom_function_register(&queuemembercount_function);
10907    err |= ast_custom_function_register(&queuemembercount_dep);
10908    err |= ast_custom_function_register(&queuememberlist_function);
10909    err |= ast_custom_function_register(&queuegetchannel_function);
10910    err |= ast_custom_function_register(&queuewaitingcount_function);
10911    err |= ast_custom_function_register(&queuememberpenalty_function);
10912 
10913    /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
10914    device_state_sub = stasis_subscribe(ast_device_state_topic_all(), device_state_cb, NULL);
10915    if (!device_state_sub) {
10916       err = -1;
10917    }
10918 
10919    manager_topic = ast_manager_get_topic();
10920    queue_topic = ast_queue_topic_all();
10921    if (!manager_topic || !queue_topic) {
10922       unload_module();
10923       return AST_MODULE_LOAD_DECLINE;
10924    }
10925    topic_forwarder = stasis_forward_all(queue_topic, manager_topic);
10926    if (!topic_forwarder) {
10927       unload_module();
10928       return AST_MODULE_LOAD_DECLINE;
10929    }
10930 
10931    if (!ast_channel_agent_login_type()
10932       || !ast_channel_agent_logoff_type()) {
10933       unload_module();
10934       return AST_MODULE_LOAD_DECLINE;
10935    }
10936    agent_router = stasis_message_router_create(ast_channel_topic_all());
10937    if (!agent_router) {
10938       unload_module();
10939       return AST_MODULE_LOAD_DECLINE;
10940    }
10941    err |= stasis_message_router_add(agent_router,
10942       ast_channel_agent_login_type(),
10943       queue_agent_cb,
10944       NULL);
10945    err |= stasis_message_router_add(agent_router,
10946       ast_channel_agent_logoff_type(),
10947       queue_agent_cb,
10948       NULL);
10949 
10950    err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
10951    err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
10952    err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
10953 
10954    err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
10955    err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
10956    err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
10957    err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
10958    err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
10959    err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
10960 
10961    err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
10962    err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
10963    err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
10964    err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
10965    err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
10966 
10967    ast_extension_state_add(NULL, NULL, extension_state_cb, NULL);
10968 
10969    if (err) {
10970       unload_module();
10971       return AST_MODULE_LOAD_DECLINE;
10972    }
10973    return AST_MODULE_LOAD_SUCCESS;
10974 }

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:
-1 on failure
0 on success
Note:
Call this with the rule_lists locked

Definition at line 2786 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(), LOG_NOTICE, LOG_WARNING, queue_ent::max_penalty, penalty_rule::max_relative, penalty_rule::max_value, queue_ent::min_penalty, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, NULL, rule_list::rules, SENTINEL, and penalty_rule::time.

Referenced by reload_queue_rules().

02787 {
02788    struct ast_config *cfg;
02789         struct rule_list *rl_iter, *new_rl;
02790         struct penalty_rule *pr_iter;
02791         char *rulecat = NULL;
02792 
02793    if (!ast_check_realtime("queue_rules")) {
02794       ast_log(LOG_WARNING, "Missing \"queue_rules\" in extconfig.conf\n");
02795       return 0;
02796    }
02797    if (!(cfg = ast_load_realtime_multientry("queue_rules", "rule_name LIKE", "%", SENTINEL))) {
02798       ast_log(LOG_WARNING, "Failed to load queue rules from realtime\n");
02799       return 0;
02800    }
02801    while ((rulecat = ast_category_browse(cfg, rulecat)) && !ast_strlen_zero(rulecat)) {
02802       const char *timestr, *maxstr, *minstr;
02803       int penaltychangetime, rule_exists = 0, inserted = 0;
02804       int max_penalty = 0, min_penalty = 0, min_relative = 0, max_relative = 0;
02805       struct penalty_rule *new_penalty_rule = NULL;
02806       AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
02807          if (!(strcasecmp(rl_iter->name, rulecat))) {
02808             rule_exists = 1;
02809             new_rl = rl_iter;
02810             break;
02811          }
02812       }
02813       if (!rule_exists) {
02814          if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
02815             ast_config_destroy(cfg);
02816             return -1;
02817          }
02818          ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
02819          AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
02820       }
02821       timestr = ast_variable_retrieve(cfg, rulecat, "time");
02822       if (!(timestr) || sscanf(timestr, "%30d", &penaltychangetime) != 1) {
02823          ast_log(LOG_NOTICE, "Failed to parse time (%s) for one of the %s rules, skipping it\n",
02824             (ast_strlen_zero(timestr) ? "invalid value" : timestr), rulecat);
02825          continue;
02826       }
02827       if (!(new_penalty_rule = ast_calloc(1, sizeof(*new_penalty_rule)))) {
02828          ast_config_destroy(cfg);
02829          return -1;
02830       }
02831       if (!(maxstr = ast_variable_retrieve(cfg, rulecat, "max_penalty")) ||
02832          ast_strlen_zero(maxstr) || sscanf(maxstr, "%30d", &max_penalty) != 1) {
02833          max_penalty = 0;
02834          max_relative = 1;
02835       } else {
02836          if (*maxstr == '+' || *maxstr == '-') {
02837             max_relative = 1;
02838          }
02839       }
02840       if (!(minstr = ast_variable_retrieve(cfg, rulecat, "min_penalty")) ||
02841          ast_strlen_zero(minstr) || sscanf(minstr, "%30d", &min_penalty) != 1) {
02842          min_penalty = 0;
02843          min_relative = 1;
02844       } else {
02845          if (*minstr == '+' || *minstr == '-') {
02846             min_relative = 1;
02847          }
02848       }
02849       new_penalty_rule->time = penaltychangetime;
02850       new_penalty_rule->max_relative = max_relative;
02851       new_penalty_rule->max_value = max_penalty;
02852       new_penalty_rule->min_relative = min_relative;
02853       new_penalty_rule->min_value = min_penalty;
02854       AST_LIST_TRAVERSE_SAFE_BEGIN(&new_rl->rules, pr_iter, list) {
02855          if (new_penalty_rule->time < pr_iter->time) {
02856             AST_LIST_INSERT_BEFORE_CURRENT(new_penalty_rule, list);
02857             inserted = 1;
02858          }
02859       }
02860       AST_LIST_TRAVERSE_SAFE_END;
02861       if (!inserted) {
02862          AST_LIST_INSERT_TAIL(&new_rl->rules, new_penalty_rule, list);
02863       }
02864    }
02865 
02866    ast_config_destroy(cfg);
02867    return 0;
02868 }

static void log_attended_transfer ( struct queue_stasis_data queue_data,
struct ast_channel_snapshot caller,
struct ast_attended_transfer_message atxfer_msg 
) [static]

Definition at line 5676 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_attended_transfer_message::bridge, queue_stasis_data::caller_pos, ast_attended_transfer_message::dest, ast_attended_transfer_message::dest_type, queue_stasis_data::holdstart, ast_attended_transfer_message::links, LOG_WARNING, queue_stasis_data::member, member::membername, call_queue::name, ast_channel_snapshot::name, NULL, queue_stasis_data::queue, RAII_VAR, queue_stasis_data::starttime, and ast_channel_snapshot::uniqueid.

Referenced by handle_attended_transfer().

05678 {
05679    RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
05680 
05681    if (!transfer_str) {
05682       ast_log(LOG_WARNING, "Unable to log attended transfer to queue log\n");
05683       return;
05684    }
05685 
05686    switch (atxfer_msg->dest_type) {
05687    case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
05688       ast_str_set(&transfer_str, 0, "BRIDGE|%s", atxfer_msg->dest.bridge);
05689       break;
05690    case AST_ATTENDED_TRANSFER_DEST_APP:
05691    case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
05692       ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
05693       break;
05694    case AST_ATTENDED_TRANSFER_DEST_LINK:
05695       ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->name,
05696             atxfer_msg->dest.links[1]->name);
05697       break;
05698    case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
05699    case AST_ATTENDED_TRANSFER_DEST_FAIL:
05700       /* Threeways are headed off and should not be logged here */
05701       ast_assert(0);
05702       return;
05703    }
05704 
05705    ast_queue_log(queue_data->queue->name, caller->uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
05706          ast_str_buffer(transfer_str),
05707          (long) (queue_data->starttime - queue_data->holdstart),
05708          (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
05709 }

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

Definition at line 9646 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(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.

Referenced by load_module().

09647 {
09648    const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
09649    int paused, penalty = 0;
09650 
09651    queuename = astman_get_header(m, "Queue");
09652    interface = astman_get_header(m, "Interface");
09653    penalty_s = astman_get_header(m, "Penalty");
09654    paused_s = astman_get_header(m, "Paused");
09655    membername = astman_get_header(m, "MemberName");
09656    state_interface = astman_get_header(m, "StateInterface");
09657 
09658    if (ast_strlen_zero(queuename)) {
09659       astman_send_error(s, m, "'Queue' not specified.");
09660       return 0;
09661    }
09662 
09663    if (ast_strlen_zero(interface)) {
09664       astman_send_error(s, m, "'Interface' not specified.");
09665       return 0;
09666    }
09667 
09668    if (ast_strlen_zero(penalty_s)) {
09669       penalty = 0;
09670    } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
09671       penalty = 0;
09672    }
09673 
09674    if (ast_strlen_zero(paused_s)) {
09675       paused = 0;
09676    } else {
09677       paused = abs(ast_true(paused_s));
09678    }
09679 
09680    switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
09681    case RES_OKAY:
09682       if (ast_strlen_zero(membername) || !log_membername_as_agent) {
09683          ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
09684       } else {
09685          ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
09686       }
09687       astman_send_ack(s, m, "Added interface to queue");
09688       break;
09689    case RES_EXISTS:
09690       astman_send_error(s, m, "Unable to add interface: Already there");
09691       break;
09692    case RES_NOSUCHQUEUE:
09693       astman_send_error(s, m, "Unable to add interface to queue: No such queue");
09694       break;
09695    case RES_OUTOFMEMORY:
09696       astman_send_error(s, m, "Out of memory");
09697       break;
09698    }
09699 
09700    return 0;
09701 }

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

Definition at line 9750 of file app_queue.c.

References abs, ast_strlen_zero, ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), member::interface, member::paused, and set_member_paused().

Referenced by load_module().

09751 {
09752    const char *queuename, *interface, *paused_s, *reason;
09753    int paused;
09754 
09755    interface = astman_get_header(m, "Interface");
09756    paused_s = astman_get_header(m, "Paused");
09757    queuename = astman_get_header(m, "Queue");      /* Optional - if not supplied, pause the given Interface in all queues */
09758    reason = astman_get_header(m, "Reason");        /* Optional - Only used for logging purposes */
09759 
09760    if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
09761       astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
09762       return 0;
09763    }
09764 
09765    paused = abs(ast_true(paused_s));
09766 
09767    if (set_member_paused(queuename, interface, reason, paused)) {
09768       astman_send_error(s, m, "Interface not found");
09769    } else {
09770       astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
09771    }
09772    return 0;
09773 }

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

Definition at line 9775 of file app_queue.c.

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

Referenced by load_module().

09776 {
09777    const char *queuename, *event, *message, *interface, *uniqueid;
09778 
09779    queuename = astman_get_header(m, "Queue");
09780    uniqueid = astman_get_header(m, "UniqueId");
09781    interface = astman_get_header(m, "Interface");
09782    event = astman_get_header(m, "Event");
09783    message = astman_get_header(m, "Message");
09784 
09785    if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
09786       astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
09787       return 0;
09788    }
09789 
09790    ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
09791    astman_send_ack(s, m, "Event added successfully");
09792 
09793    return 0;
09794 }

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

Definition at line 9908 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().

09909 {
09910    const char *queuename, *interface, *penalty_s;
09911    int penalty;
09912 
09913    interface = astman_get_header(m, "Interface");
09914    penalty_s = astman_get_header(m, "Penalty");
09915    /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
09916    queuename = astman_get_header(m, "Queue");
09917 
09918    if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
09919       astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
09920       return 0;
09921    }
09922 
09923    penalty = atoi(penalty_s);
09924 
09925    if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
09926       astman_send_error(s, m, "Invalid interface, queuename or penalty");
09927    } else {
09928       astman_send_ack(s, m, "Interface penalty set successfully");
09929    }
09930 
09931    return 0;
09932 }

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

Definition at line 9874 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().

09875 {
09876    const char *queuename, *interface, *ringinuse_s;
09877    int ringinuse;
09878 
09879    interface = astman_get_header(m, "Interface");
09880    ringinuse_s = astman_get_header(m, "RingInUse");
09881 
09882    /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
09883    queuename = astman_get_header(m, "Queue");
09884 
09885    if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
09886       astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
09887       return 0;
09888    }
09889 
09890    if (ast_true(ringinuse_s)) {
09891       ringinuse = 1;
09892    } else if (ast_false(ringinuse_s)) {
09893       ringinuse = 0;
09894    } else {
09895       astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
09896       return 0;
09897    }
09898 
09899    if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
09900       astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
09901    } else {
09902       astman_send_ack(s, m, "Interface ringinuse set successfully");
09903    }
09904 
09905    return 0;
09906 }

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

Definition at line 9796 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().

09797 {
09798    struct ast_flags mask = {0,};
09799    const char *queuename = NULL;
09800    int header_found = 0;
09801 
09802    queuename = astman_get_header(m, "Queue");
09803    if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
09804       ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
09805       header_found = 1;
09806    }
09807    if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
09808       ast_set_flag(&mask, QUEUE_RELOAD_RULES);
09809       header_found = 1;
09810    }
09811    if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
09812       ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
09813       header_found = 1;
09814    }
09815 
09816    if (!header_found) {
09817       ast_set_flag(&mask, AST_FLAGS_ALL);
09818    }
09819 
09820    if (!reload_handler(1, &mask, queuename)) {
09821       astman_send_ack(s, m, "Queue reloaded successfully");
09822    } else {
09823       astman_send_error(s, m, "Error encountered while reloading queue");
09824    }
09825    return 0;
09826 }

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

Definition at line 9828 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().

09829 {
09830    const char *queuename = NULL;
09831    struct ast_flags mask = {QUEUE_RESET_STATS,};
09832 
09833    queuename = astman_get_header(m, "Queue");
09834 
09835    if (!reload_handler(1, &mask, queuename)) {
09836       astman_send_ack(s, m, "Queue stats reset successfully");
09837    } else {
09838       astman_send_error(s, m, "Error encountered while resetting queue stats");
09839    }
09840    return 0;
09841 }

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

Definition at line 9424 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::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().

09425 {
09426    const char *rule = astman_get_header(m, "Rule");
09427    const char *id = astman_get_header(m, "ActionID");
09428    struct rule_list *rl_iter;
09429    struct penalty_rule *pr_iter;
09430 
09431    astman_append(s, "Response: Success\r\n");
09432    if (!ast_strlen_zero(id)) {
09433       astman_append(s, "ActionID: %s\r\n", id);
09434    }
09435 
09436    AST_LIST_LOCK(&rule_lists);
09437    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
09438       if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
09439          astman_append(s, "RuleList: %s\r\n", rl_iter->name);
09440          AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
09441             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 );
09442          }
09443          if (!ast_strlen_zero(rule)) {
09444             break;
09445          }
09446       }
09447    }
09448    AST_LIST_UNLOCK(&rule_lists);
09449 
09450    /*
09451     * Two blank lines instead of one because the Response and
09452     * ActionID headers used to not be present.
09453     */
09454    astman_append(s, "\r\n\r\n");
09455 
09456    return RESULT_SUCCESS;
09457 }

static int manager_queues_show ( struct mansession s,
const struct message m 
) [static]

Definition at line 9414 of file app_queue.c.

References __queues_show(), a, astman_append(), and RESULT_SUCCESS.

Referenced by load_module().

09415 {
09416    static const char * const a[] = { "queue", "show" };
09417 
09418    __queues_show(s, -1, 2, a);
09419    astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
09420 
09421    return RESULT_SUCCESS;
09422 }

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

Queue status info via AMI.

Definition at line 9538 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::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, call_queue::count, member::dynamic, call_queue::head, call_queue::holdtime, ast_party_connected_line::id, ast_party_caller::id, int2strat(), member::interface, member::lastcall, 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::pos, queue_t_unref, queues, RESULT_SUCCESS, S_COR, call_queue::servicelevel, queue_ent::start, 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, and call_queue::weight.

Referenced by load_module().

09539 {
09540    time_t now;
09541    int pos;
09542    int q_items = 0;
09543    const char *id = astman_get_header(m,"ActionID");
09544    const char *queuefilter = astman_get_header(m,"Queue");
09545    const char *memberfilter = astman_get_header(m,"Member");
09546    char idText[256];
09547    struct call_queue *q;
09548    struct queue_ent *qe;
09549    float sl = 0;
09550    struct member *mem;
09551    struct ao2_iterator queue_iter;
09552    struct ao2_iterator mem_iter;
09553 
09554    astman_send_listack(s, m, "Queue status will follow", "start");
09555    time(&now);
09556    idText[0] = '\0';
09557    if (!ast_strlen_zero(id)) {
09558       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
09559    }
09560 
09561    queue_iter = ao2_iterator_init(queues, 0);
09562    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
09563       ao2_lock(q);
09564 
09565       /* List queue properties */
09566       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
09567          sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
09568          astman_append(s, "Event: QueueParams\r\n"
09569             "Queue: %s\r\n"
09570             "Max: %d\r\n"
09571             "Strategy: %s\r\n"
09572             "Calls: %d\r\n"
09573             "Holdtime: %d\r\n"
09574             "TalkTime: %d\r\n"
09575             "Completed: %d\r\n"
09576             "Abandoned: %d\r\n"
09577             "ServiceLevel: %d\r\n"
09578             "ServicelevelPerf: %2.1f\r\n"
09579             "Weight: %d\r\n"
09580             "%s"
09581             "\r\n",
09582             q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
09583             q->callsabandoned, q->servicelevel, sl, q->weight, idText);
09584          ++q_items;
09585 
09586          /* List Queue Members */
09587          mem_iter = ao2_iterator_init(q->members, 0);
09588          while ((mem = ao2_iterator_next(&mem_iter))) {
09589             if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
09590                astman_append(s, "Event: QueueMember\r\n"
09591                   "Queue: %s\r\n"
09592                   "Name: %s\r\n"
09593                   "Location: %s\r\n"
09594                   "StateInterface: %s\r\n"
09595                   "Membership: %s\r\n"
09596                   "Penalty: %d\r\n"
09597                   "CallsTaken: %d\r\n"
09598                   "LastCall: %d\r\n"
09599                   "Status: %d\r\n"
09600                   "Paused: %d\r\n"
09601                   "%s"
09602                   "\r\n",
09603                   q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
09604                   mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
09605                ++q_items;
09606             }
09607             ao2_ref(mem, -1);
09608          }
09609          ao2_iterator_destroy(&mem_iter);
09610 
09611          /* List Queue Entries */
09612          pos = 1;
09613          for (qe = q->head; qe; qe = qe->next) {
09614             astman_append(s, "Event: QueueEntry\r\n"
09615                "Queue: %s\r\n"
09616                "Position: %d\r\n"
09617                "Channel: %s\r\n"
09618                "Uniqueid: %s\r\n"
09619                "CallerIDNum: %s\r\n"
09620                "CallerIDName: %s\r\n"
09621                "ConnectedLineNum: %s\r\n"
09622                "ConnectedLineName: %s\r\n"
09623                "Wait: %ld\r\n"
09624                "%s"
09625                "\r\n",
09626                q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
09627                S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, "unknown"),
09628                S_COR(ast_channel_caller(qe->chan)->id.name.valid, ast_channel_caller(qe->chan)->id.name.str, "unknown"),
09629                S_COR(ast_channel_connected(qe->chan)->id.number.valid, ast_channel_connected(qe->chan)->id.number.str, "unknown"),
09630                S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"),
09631                (long) (now - qe->start), idText);
09632             ++q_items;
09633          }
09634       }
09635       ao2_unlock(q);
09636       queue_t_unref(q, "Done with iterator");
09637    }
09638    ao2_iterator_destroy(&queue_iter);
09639 
09640    astman_send_list_complete_start(s, m, "QueueStatusComplete", q_items);
09641    astman_send_list_complete_end(s);
09642 
09643    return RESULT_SUCCESS;
09644 }

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

Summary of queue info via the AMI.

Definition at line 9460 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, queues, RESULT_SUCCESS, queue_ent::start, member::status, and call_queue::talktime.

Referenced by load_module().

09461 {
09462    time_t now;
09463    int qmemcount = 0;
09464    int qmemavail = 0;
09465    int qchancount = 0;
09466    int qlongestholdtime = 0;
09467    int qsummaries = 0;
09468    const char *id = astman_get_header(m, "ActionID");
09469    const char *queuefilter = astman_get_header(m, "Queue");
09470    char idText[256];
09471    struct call_queue *q;
09472    struct queue_ent *qe;
09473    struct member *mem;
09474    struct ao2_iterator queue_iter;
09475    struct ao2_iterator mem_iter;
09476 
09477    astman_send_listack(s, m, "Queue summary will follow", "start");
09478    time(&now);
09479    idText[0] = '\0';
09480    if (!ast_strlen_zero(id)) {
09481       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
09482    }
09483    queue_iter = ao2_iterator_init(queues, 0);
09484    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
09485       ao2_lock(q);
09486 
09487       /* List queue properties */
09488       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
09489          /* Reset the necessary local variables if no queuefilter is set*/
09490          qmemcount = 0;
09491          qmemavail = 0;
09492          qchancount = 0;
09493          qlongestholdtime = 0;
09494 
09495          /* List Queue Members */
09496          mem_iter = ao2_iterator_init(q->members, 0);
09497          while ((mem = ao2_iterator_next(&mem_iter))) {
09498             if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
09499                ++qmemcount;
09500                if (member_status_available(mem->status) && !mem->paused) {
09501                   ++qmemavail;
09502                }
09503             }
09504             ao2_ref(mem, -1);
09505          }
09506          ao2_iterator_destroy(&mem_iter);
09507          for (qe = q->head; qe; qe = qe->next) {
09508             if ((now - qe->start) > qlongestholdtime) {
09509                qlongestholdtime = now - qe->start;
09510             }
09511             ++qchancount;
09512          }
09513          astman_append(s, "Event: QueueSummary\r\n"
09514             "Queue: %s\r\n"
09515             "LoggedIn: %d\r\n"
09516             "Available: %d\r\n"
09517             "Callers: %d\r\n"
09518             "HoldTime: %d\r\n"
09519             "TalkTime: %d\r\n"
09520             "LongestHoldTime: %d\r\n"
09521             "%s"
09522             "\r\n",
09523             q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
09524          ++qsummaries;
09525       }
09526       ao2_unlock(q);
09527       queue_t_unref(q, "Done with iterator");
09528    }
09529    ao2_iterator_destroy(&queue_iter);
09530 
09531    astman_send_list_complete_start(s, m, "QueueSummaryComplete", qsummaries);
09532    astman_send_list_complete_end(s);
09533 
09534    return RESULT_SUCCESS;
09535 }

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

Definition at line 9703 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().

09704 {
09705    const char *queuename, *interface;
09706    struct member *mem = NULL;
09707 
09708    queuename = astman_get_header(m, "Queue");
09709    interface = astman_get_header(m, "Interface");
09710 
09711    if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
09712       astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
09713       return 0;
09714    }
09715 
09716    if (log_membername_as_agent) {
09717       mem = find_member_by_queuename_and_interface(queuename, interface);
09718    }
09719 
09720    switch (remove_from_queue(queuename, interface)) {
09721    case RES_OKAY:
09722       if (!mem || ast_strlen_zero(mem->membername)) {
09723          ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
09724       } else {
09725          ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
09726       }
09727       astman_send_ack(s, m, "Removed interface from queue");
09728       break;
09729    case RES_EXISTS:
09730       astman_send_error(s, m, "Unable to remove interface: Not there");
09731       break;
09732    case RES_NOSUCHQUEUE:
09733       astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
09734       break;
09735    case RES_OUTOFMEMORY:
09736       astman_send_error(s, m, "Out of memory");
09737       break;
09738    case RES_NOT_DYNAMIC:
09739       astman_send_error(s, m, "Member not dynamic");
09740       break;
09741    }
09742 
09743    if (mem) {
09744       ao2_ref(mem, -1);
09745    }
09746 
09747    return 0;
09748 }

static int mark_dead_and_unfound ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 8969 of file app_queue.c.

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

Referenced by reload_queues().

08970 {
08971    struct call_queue *q = obj;
08972    char *queuename = arg;
08973    if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
08974       q->dead = 1;
08975       q->found = 0;
08976    }
08977    return 0;
08978 }

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

Definition at line 8820 of file app_queue.c.

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

Referenced by reload_single_queue().

08821 {
08822    struct member *member = obj;
08823    if (!member->dynamic && !member->realtime) {
08824       member->delme = 1;
08825    }
08826    return 0;
08827 }

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

static void member_call_pending_clear ( struct member mem  )  [static]

Definition at line 4128 of file app_queue.c.

References ao2_lock, ao2_unlock, and member::call_pending.

Referenced by can_ring_entry(), and ring_entry().

04129 {
04130    ao2_lock(mem);
04131    mem->call_pending = 0;
04132    ao2_unlock(mem);
04133 }

static int member_call_pending_set ( struct member mem  )  [static]

Definition at line 4143 of file app_queue.c.

References ao2_lock, ao2_unlock, and member::call_pending.

Referenced by can_ring_entry().

04144 {
04145    int old_pending;
04146 
04147    ao2_lock(mem);
04148    old_pending = mem->call_pending;
04149    mem->call_pending = 1;
04150    ao2_unlock(mem);
04151 
04152    return old_pending;
04153 }

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

Definition at line 2565 of file app_queue.c.

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

Referenced by init_queue().

02566 {
02567    struct member *mem1 = obj1;
02568    struct member *mem2 = obj2;
02569    const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
02570 
02571    return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
02572 }

static int member_hash_fn ( const void *  obj,
const in