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/event.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/cel.h"#include "asterisk/data.h"
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 | member |
| struct | penalty_rule |
| struct | queue_end_bridge |
| struct | queue_ent |
| struct | queue_transfer_ds |
| struct | rule_list |
| struct | statechange |
| 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 |
| #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_t_ref(a, b) queue_ref(a) |
| #define | queue_t_unref(a, b) queue_unref(a) |
| #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 | { 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 | 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 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_queue * | alloc_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 | AST_LIST_HEAD_STATIC (rule_lists, rule_list) |
| AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,"True Call Queueing",.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_DEVSTATE_CONSUMER,.nonoptreq="res_monitor",) | |
| static int | attended_transfer_occurred (struct ast_channel *chan) |
| mechanism to tell if a queue caller was atxferred by a queue member. | |
| 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_penalty (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 member * | create_queue_member (const char *interface, const char *membername, int penalty, int paused, const char *state_interface) |
| 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 (const struct ast_event *event, void *unused) |
| 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 int | extension_state_cb (char *context, char *exten, enum ast_extension_states state, void *data) |
| static int | extensionstate2devicestate (int state) |
| Helper function which converts from extension state to device state values. | |
| static struct callattempt * | find_best (struct callattempt *outgoing) |
| find the entry with the best metric, or NULL | |
| static struct call_queue * | find_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config) |
| Reload a single queue via realtime. | |
| 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 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 int | handle_statechange (void *datap) |
| set a member's status based on device state of that member's interface | |
| static void | hangupcalls (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 member * | interface_exists (struct call_queue *q, const char *interface) |
| 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) |
| static struct call_queue * | load_realtime_queue (const char *queuename) |
| 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_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 int | ql_exec (struct ast_channel *chan, const char *data) |
| QueueLog application. | |
| 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_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 (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_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_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 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 call_queue * | queue_ref (struct call_queue *q) |
| 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 void | queue_transfer_destroy (void *data) |
| static void | queue_transfer_fixup (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) |
| Log an attended transfer when a queue caller channel is masqueraded. | |
| static struct call_queue * | queue_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 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, char *interface, char *membername, int pause) |
| 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, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface) |
| 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 struct queue_ent *qe, const char *queuename, const struct ast_channel *peer, const struct member *member, time_t callstart, char *vars, size_t vars_len, 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 (const char *queuename, const char *interface, int penalty) |
| 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 struct ast_datastore * | setup_transfer_datastore (struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl) |
| create a datastore for storing relevant info to log attended transfers in the queue_log | |
| 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, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing) |
| A large function which calls members, updates statistics, and bridges the caller and a member. | |
| 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 int | 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 char * | vars2manager (struct ast_channel *chan, char *vars, size_t len) |
| convert "\n" to "\nVariable: " ready for manager to use | |
| static int | wait_a_bit (struct queue_ent *qe) |
| static struct callattempt * | wait_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 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 int | autofill_default = 1 |
| queues.conf [general] option | |
| static struct autopause | autopausesmodes [] |
| static struct ast_cli_entry | cli_queue [] |
| static struct ast_event_sub * | device_state_sub |
| Subscription to device state change events. | |
| static struct ast_taskprocessor * | devicestate_tps |
| static int | montype_default = 0 |
| queues.conf [general] option | |
| static const char *const | pm_family = "Queue/PersistentMembers" |
| Persistent Members astdb family. | |
| static const char | qpm_cmd_usage [] |
| static const char | qsmp_cmd_usage [] |
| static struct ast_data_entry | queue_data_providers [] |
| static int | queue_persistent_members = 0 |
| queues.conf [general] option | |
| struct { | |
| enum queue_result id | |
| char * text | |
| } | queue_results [] |
| static struct ast_datastore_info | queue_transfer_info |
| a datastore used to help correctly log attended transfers of queue callers | |
| static struct ast_custom_function | queueexists_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_container * | queues |
| static struct ast_data_handler | queues_data_provider |
| static struct ast_custom_function | queuevar_function |
| static struct ast_custom_function | queuewaitingcount_function |
| static const char | qum_cmd_usage [] |
| static int | shared_lastcall = 1 |
| queues.conf [general] option | |
| static struct strategy | strategies [] |
| static int | update_cdr = 0 |
| queues.conf [general] option | |
| static int | use_weight = 0 |
| queues.conf per-queue weight option | |
True call queues with optional send URL on answer.
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.
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 ANNOUNCEHOLDTIME_ALWAYS 1 |
Definition at line 1115 of file app_queue.c.
Referenced by queue_set_param().
| #define ANNOUNCEHOLDTIME_ONCE 2 |
Definition at line 1116 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 1131 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 1130 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 1129 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 1128 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 3654 of file app_queue.c.
| #define DATA_EXPORT_CALL_QUEUE | ( | MEMBER | ) |
Definition at line 8511 of file app_queue.c.
| #define DATA_EXPORT_MEMBER | ( | MEMBER | ) |
Definition at line 8576 of file app_queue.c.
| #define DATA_EXPORT_QUEUE_ENT | ( | MEMBER | ) |
Definition at line 8590 of file app_queue.c.
| #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 |
The minimum number of seconds between position announcements \ The default value of 15 provides backwards compatibility
Definition at line 941 of file app_queue.c.
Referenced by init_queue().
| #define DEFAULT_RETRY 5 |
Definition at line 937 of file app_queue.c.
Referenced by init_queue(), and queue_set_param().
| #define DEFAULT_TIMEOUT 15 |
Definition at line 938 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 940 of file app_queue.c.
Referenced by destroy_queue(), init_queue(), and queue_set_param().
| #define MAX_QUEUE_BUCKETS 53 |
Definition at line 943 of file app_queue.c.
Referenced by load_module().
| #define QUEUE_EVENT_VARIABLES 3 |
Definition at line 1117 of file app_queue.c.
Referenced by queue_set_param(), ring_entry(), rna(), send_agent_complete(), and try_calling().
| #define queue_t_ref | ( | a, | |||
| b | ) | queue_ref(a) |
Definition at line 1378 of file app_queue.c.
Referenced by leave_queue(), and try_calling().
| #define queue_t_unref | ( | a, | |||
| b | ) | queue_unref(a) |
Definition at line 1379 of file app_queue.c.
Referenced by __queues_show(), add_to_queue(), alloc_queue(), clear_stats(), compare_weight(), complete_queue(), complete_queue_remove_member(), end_bridge_callback(), extension_state_cb(), find_queue_by_name_rt(), get_member_penalty(), handle_statechange(), join_queue(), leave_queue(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), queue_function_exists(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), reload_queue_members(), reload_single_queue(), remove_from_queue(), set_member_paused(), set_member_penalty(), unload_module(), and update_queue().
| #define queues_t_link | ( | c, | |||
| q, | |||||
| tag | ) | ao2_t_link(c,q,tag) |
Definition at line 1380 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 1381 of file app_queue.c.
Referenced by find_queue_by_name_rt(), leave_queue(), and unload_module().
| #define RECHECK 1 |
Recheck every second to see we we're at the top yet
Definition at line 939 of file app_queue.c.
Referenced by wait_our_turn().
| #define RES_EXISTS (-1) |
Entry already exists
Definition at line 946 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
| #define RES_NOSUCHQUEUE (-3) |
No such queue
Definition at line 948 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
| #define RES_NOT_DYNAMIC (-4) |
Member is not dynamic
Definition at line 949 of file app_queue.c.
Referenced by handle_queue_add_member(), handle_queue_remove_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
| #define RES_OKAY 0 |
Action completed
Definition at line 945 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
| #define RES_OUTOFMEMORY (-2) |
Out of memory
Definition at line 947 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), and reload_queue_members().
| anonymous enum |
| 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 886 of file app_queue.c.
00886 { 00887 QUEUE_STRATEGY_RINGALL = 0, 00888 QUEUE_STRATEGY_LEASTRECENT, 00889 QUEUE_STRATEGY_FEWESTCALLS, 00890 QUEUE_STRATEGY_RANDOM, 00891 QUEUE_STRATEGY_RRMEMORY, 00892 QUEUE_STRATEGY_LINEAR, 00893 QUEUE_STRATEGY_WRANDOM, 00894 QUEUE_STRATEGY_RRORDERED, 00895 };
| anonymous enum |
Definition at line 897 of file app_queue.c.
00897 { 00898 QUEUE_AUTOPAUSE_OFF = 0, 00899 QUEUE_AUTOPAUSE_ON, 00900 QUEUE_AUTOPAUSE_ALL 00901 };
Definition at line 4485 of file app_queue.c.
| enum empty_conditions |
| 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 1103 of file app_queue.c.
01103 { 01104 QUEUE_EMPTY_PENALTY = (1 << 0), 01105 QUEUE_EMPTY_PAUSED = (1 << 1), 01106 QUEUE_EMPTY_INUSE = (1 << 2), 01107 QUEUE_EMPTY_RINGING = (1 << 3), 01108 QUEUE_EMPTY_UNAVAILABLE = (1 << 4), 01109 QUEUE_EMPTY_INVALID = (1 << 5), 01110 QUEUE_EMPTY_UNKNOWN = (1 << 6), 01111 QUEUE_EMPTY_WRAPUP = (1 << 7), 01112 };
| enum queue_reload_mask |
Definition at line 903 of file app_queue.c.
00903 { 00904 QUEUE_RELOAD_PARAMETERS = (1 << 0), 00905 QUEUE_RELOAD_MEMBER = (1 << 1), 00906 QUEUE_RELOAD_RULES = (1 << 2), 00907 QUEUE_RESET_STATS = (1 << 3), 00908 };
| enum queue_result |
| QUEUE_UNKNOWN | |
| QUEUE_TIMEOUT | |
| QUEUE_JOINEMPTY | |
| QUEUE_LEAVEEMPTY | |
| QUEUE_JOINUNAVAIL | |
| QUEUE_LEAVEUNAVAIL | |
| QUEUE_FULL | |
| QUEUE_CONTINUE |
Definition at line 987 of file app_queue.c.
00987 { 00988 QUEUE_UNKNOWN = 0, 00989 QUEUE_TIMEOUT = 1, 00990 QUEUE_JOINEMPTY = 2, 00991 QUEUE_LEAVEEMPTY = 3, 00992 QUEUE_JOINUNAVAIL = 4, 00993 QUEUE_LEAVEUNAVAIL = 5, 00994 QUEUE_FULL = 6, 00995 QUEUE_CONTINUE = 7, 00996 };
Definition at line 1012 of file app_queue.c.
01012 { 01013 TIMEOUT_PRIORITY_APP, 01014 TIMEOUT_PRIORITY_CONF, 01015 };
| 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 7310 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_check_realtime(), ast_config_destroy(), ast_devstate2str(), ast_load_realtime_multientry(), ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_strlen_zero(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, CLI_SHOWUSAGE, CLI_SUCCESS, call_queue::count, do_print(), member::dynamic, call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, load_realtime_queue(), call_queue::maxlen, member::membername, call_queue::members, member::paused, member::penalty, queue_ent::pos, queue_ent::prio, queue_t_unref, queues, member::realtime, call_queue::realtime, SENTINEL, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, call_queue::talktime, and call_queue::weight.
Referenced by manager_queues_show(), and queue_show().
07311 { 07312 struct call_queue *q; 07313 struct ast_str *out = ast_str_alloca(240); 07314 int found = 0; 07315 time_t now = time(NULL); 07316 struct ao2_iterator queue_iter; 07317 struct ao2_iterator mem_iter; 07318 07319 if (argc != 2 && argc != 3) 07320 return CLI_SHOWUSAGE; 07321 07322 if (argc == 3) { /* specific queue */ 07323 if ((q = load_realtime_queue(argv[2]))) { 07324 queue_t_unref(q, "Done with temporary pointer"); 07325 } 07326 } else if (ast_check_realtime("queues")) { 07327 /* This block is to find any queues which are defined in realtime but 07328 * which have not yet been added to the in-core container 07329 */ 07330 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 07331 char *queuename; 07332 if (cfg) { 07333 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { 07334 if ((q = load_realtime_queue(queuename))) { 07335 queue_t_unref(q, "Done with temporary pointer"); 07336 } 07337 } 07338 ast_config_destroy(cfg); 07339 } 07340 } 07341 07342 ao2_lock(queues); 07343 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); 07344 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07345 float sl; 07346 struct call_queue *realtime_queue = NULL; 07347 07348 ao2_lock(q); 07349 /* This check is to make sure we don't print information for realtime 07350 * queues which have been deleted from realtime but which have not yet 07351 * been deleted from the in-core container. Only do this if we're not 07352 * looking for a specific queue. 07353 */ 07354 if (argc < 3 && q->realtime) { 07355 realtime_queue = load_realtime_queue(q->name); 07356 if (!realtime_queue) { 07357 ao2_unlock(q); 07358 queue_t_unref(q, "Done with iterator"); 07359 continue; 07360 } 07361 queue_t_unref(realtime_queue, "Queue is already in memory"); 07362 } 07363 07364 if (argc == 3 && strcasecmp(q->name, argv[2])) { 07365 ao2_unlock(q); 07366 queue_t_unref(q, "Done with iterator"); 07367 continue; 07368 } 07369 found = 1; 07370 07371 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count); 07372 if (q->maxlen) 07373 ast_str_append(&out, 0, "%d", q->maxlen); 07374 else 07375 ast_str_append(&out, 0, "unlimited"); 07376 sl = 0; 07377 if (q->callscompleted > 0) 07378 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 07379 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds", 07380 int2strat(q->strategy), q->holdtime, q->talktime, q->weight, 07381 q->callscompleted, q->callsabandoned,sl,q->servicelevel); 07382 do_print(s, fd, ast_str_buffer(out)); 07383 if (!ao2_container_count(q->members)) 07384 do_print(s, fd, " No Members"); 07385 else { 07386 struct member *mem; 07387 07388 do_print(s, fd, " Members: "); 07389 mem_iter = ao2_iterator_init(q->members, 0); 07390 while ((mem = ao2_iterator_next(&mem_iter))) { 07391 ast_str_set(&out, 0, " %s", mem->membername); 07392 if (strcasecmp(mem->membername, mem->interface)) { 07393 ast_str_append(&out, 0, " (%s)", mem->interface); 07394 } 07395 if (mem->penalty) 07396 ast_str_append(&out, 0, " with penalty %d", mem->penalty); 07397 ast_str_append(&out, 0, "%s%s%s (%s)", 07398 mem->dynamic ? " (dynamic)" : "", 07399 mem->realtime ? " (realtime)" : "", 07400 mem->paused ? " (paused)" : "", 07401 ast_devstate2str(mem->status)); 07402 if (mem->calls) 07403 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)", 07404 mem->calls, (long) (time(NULL) - mem->lastcall)); 07405 else 07406 ast_str_append(&out, 0, " has taken no calls yet"); 07407 do_print(s, fd, ast_str_buffer(out)); 07408 ao2_ref(mem, -1); 07409 } 07410 ao2_iterator_destroy(&mem_iter); 07411 } 07412 if (!q->head) 07413 do_print(s, fd, " No Callers"); 07414 else { 07415 struct queue_ent *qe; 07416 int pos = 1; 07417 07418 do_print(s, fd, " Callers: "); 07419 for (qe = q->head; qe; qe = qe->next) { 07420 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)", 07421 pos++, qe->chan->name, (long) (now - qe->start) / 60, 07422 (long) (now - qe->start) % 60, qe->prio); 07423 do_print(s, fd, ast_str_buffer(out)); 07424 } 07425 } 07426 do_print(s, fd, ""); /* blank line between entries */ 07427 ao2_unlock(q); 07428 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */ 07429 } 07430 ao2_iterator_destroy(&queue_iter); 07431 ao2_unlock(queues); 07432 if (!found) { 07433 if (argc == 3) 07434 ast_str_set(&out, 0, "No such queue: %s.", argv[2]); 07435 else 07436 ast_str_set(&out, 0, "No queues."); 07437 do_print(s, fd, ast_str_buffer(out)); 07438 } 07439 return CLI_SUCCESS; 07440 }
| 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.
| 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 |
Definition at line 5611 of file app_queue.c.
References ao2_lock, ao2_ref, ao2_unlock, member::calls, create_queue_member(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, interface_exists(), member::lastcall, load_realtime_queue(), manager_event, member_add_to_queue(), member::membername, member::paused, member::penalty, queue_t_unref, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and member::status.
Referenced by aqm_exec(), handle_queue_add_member(), manager_add_queue_member(), and reload_queue_members().
05612 { 05613 struct call_queue *q; 05614 struct member *new_member, *old_member; 05615 int res = RES_NOSUCHQUEUE; 05616 05617 /*! \note Ensure the appropriate realtime queue is loaded. Note that this 05618 * short-circuits if the queue is already in memory. */ 05619 if (!(q = load_realtime_queue(queuename))) 05620 return res; 05621 05622 ao2_lock(q); 05623 if ((old_member = interface_exists(q, interface)) == NULL) { 05624 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { 05625 new_member->dynamic = 1; 05626 member_add_to_queue(q, new_member); 05627 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 05628 "Queue: %s\r\n" 05629 "Location: %s\r\n" 05630 "MemberName: %s\r\n" 05631 "Membership: %s\r\n" 05632 "Penalty: %d\r\n" 05633 "CallsTaken: %d\r\n" 05634 "LastCall: %d\r\n" 05635 "Status: %d\r\n" 05636 "Paused: %d\r\n", 05637 q->name, new_member->interface, new_member->membername, 05638 "dynamic", 05639 new_member->penalty, new_member->calls, (int) new_member->lastcall, 05640 new_member->status, new_member->paused); 05641 05642 ao2_ref(new_member, -1); 05643 new_member = NULL; 05644 05645 if (dump) 05646 dump_queue_members(q); 05647 05648 res = RES_OKAY; 05649 } else { 05650 res = RES_OUTOFMEMORY; 05651 } 05652 } else { 05653 ao2_ref(old_member, -1); 05654 res = RES_EXISTS; 05655 } 05656 ao2_unlock(q); 05657 queue_t_unref(q, "Expiring temporary reference"); 05658 05659 return res; 05660 }
| static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static, read] |
Definition at line 2319 of file app_queue.c.
References ao2_t_alloc, ast_string_field_init, ast_string_field_set, destroy_queue(), and queue_t_unref.
Referenced by find_queue_by_name_rt(), and reload_single_queue().
02320 { 02321 struct call_queue *q; 02322 02323 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) { 02324 if (ast_string_field_init(q, 64)) { 02325 queue_t_unref(q, "String field allocation failed"); 02326 return NULL; 02327 } 02328 ast_string_field_set(q, name, queuename); 02329 } 02330 return q; 02331 }
| static int aqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
AddQueueMember application.
Definition at line 6043 of file app_queue.c.
References add_to_queue(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.
Referenced by load_module().
06044 { 06045 int res=-1; 06046 char *parse, *temppos = NULL; 06047 AST_DECLARE_APP_ARGS(args, 06048 AST_APP_ARG(queuename); 06049 AST_APP_ARG(interface); 06050 AST_APP_ARG(penalty); 06051 AST_APP_ARG(options); 06052 AST_APP_ARG(membername); 06053 AST_APP_ARG(state_interface); 06054 ); 06055 int penalty = 0; 06056 06057 if (ast_strlen_zero(data)) { 06058 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n"); 06059 return -1; 06060 } 06061 06062 parse = ast_strdupa(data); 06063 06064 AST_STANDARD_APP_ARGS(args, parse); 06065 06066 if (ast_strlen_zero(args.interface)) { 06067 args.interface = ast_strdupa(chan->name); 06068 temppos = strrchr(args.interface, '-'); 06069 if (temppos) 06070 *temppos = '\0'; 06071 } 06072 06073 if (!ast_strlen_zero(args.penalty)) { 06074 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) { 06075 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 06076 penalty = 0; 06077 } 06078 } 06079 06080 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { 06081 case RES_OKAY: 06082 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 06083 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 06084 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 06085 res = 0; 06086 break; 06087 case RES_EXISTS: 06088 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 06089 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 06090 res = 0; 06091 break; 06092 case RES_NOSUCHQUEUE: 06093 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 06094 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 06095 res = 0; 06096 break; 06097 case RES_OUTOFMEMORY: 06098 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 06099 break; 06100 } 06101 06102 return res; 06103 }
| 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 AST_LIST_HEAD_STATIC | ( | rule_lists | , | |
| rule_list | ||||
| ) | [static] |
| AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
| AST_MODFLAG_LOAD_ORDER | , | |||
| "True Call Queueing" | , | |||
| . | load = load_module, |
|||
| . | unload = unload_module, |
|||
| . | reload = reload, |
|||
| . | load_pri = AST_MODPRI_DEVSTATE_CONSUMER, |
|||
| . | nonoptreq = "res_monitor" | |||
| ) |
| static int attended_transfer_occurred | ( | struct ast_channel * | chan | ) | [static] |
mechanism to tell if a queue caller was atxferred by a queue member.
When a caller is atxferred, then the queue_transfer_info datastore is removed from the channel. If it's still there after the bridge is broken, then the caller was not atxferred.
Definition at line 4590 of file app_queue.c.
References ast_channel_datastore_find().
Referenced by try_calling().
04591 { 04592 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1; 04593 }
| static int autopause2int | ( | const char * | autopause | ) | [static] |
Definition at line 1283 of file app_queue.c.
References ARRAY_LEN, ast_strlen_zero(), ast_true(), autopausesmodes, QUEUE_AUTOPAUSE_OFF, and QUEUE_AUTOPAUSE_ON.
Referenced by queue_set_param().
01284 { 01285 int x; 01286 /*This 'double check' that default value is OFF */ 01287 if (ast_strlen_zero(autopause)) 01288 return QUEUE_AUTOPAUSE_OFF; 01289 01290 /*This 'double check' is to ensure old values works */ 01291 if(ast_true(autopause)) 01292 return QUEUE_AUTOPAUSE_ON; 01293 01294 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) { 01295 if (!strcasecmp(autopause, autopausesmodes[x].name)) 01296 return autopausesmodes[x].autopause; 01297 } 01298 01299 /*This 'double check' that default value is OFF */ 01300 return QUEUE_AUTOPAUSE_OFF; 01301 }
| 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
| -1 | if penalties are exceeded | |
| 0 | otherwise |
Definition at line 4415 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, 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().
04416 { 04417 /* disregarding penalty on too few members? */ 04418 int membercount = ao2_container_count(q->members); 04419 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1; 04420 04421 if (usepenalty) { 04422 if ((qe->max_penalty != INT_MAX && mem->penalty > qe->max_penalty) || 04423 (qe->min_penalty != INT_MAX && mem->penalty < qe->min_penalty)) { 04424 return -1; 04425 } 04426 } else { 04427 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n", 04428 membercount, q->penaltymemberslimit); 04429 } 04430 04431 switch (q->strategy) { 04432 case QUEUE_STRATEGY_RINGALL: 04433 /* Everyone equal, except for penalty */ 04434 tmp->metric = mem->penalty * 1000000 * usepenalty; 04435 break; 04436 case QUEUE_STRATEGY_LINEAR: 04437 if (pos < qe->linpos) { 04438 tmp->metric = 1000 + pos; 04439 } else { 04440 if (pos > qe->linpos) 04441 /* Indicate there is another priority */ 04442 qe->linwrapped = 1; 04443 tmp->metric = pos; 04444 } 04445 tmp->metric += mem->penalty * 1000000 * usepenalty; 04446 break; 04447 case QUEUE_STRATEGY_RRORDERED: 04448 case QUEUE_STRATEGY_RRMEMORY: 04449 pos = mem->queuepos; 04450 if (pos < q->rrpos) { 04451 tmp->metric = 1000 + pos; 04452 } else { 04453 if (pos > q->rrpos) 04454 /* Indicate there is another priority */ 04455 q->wrapped = 1; 04456 tmp->metric = pos; 04457 } 04458 tmp->metric += mem->penalty * 1000000 * usepenalty; 04459 break; 04460 case QUEUE_STRATEGY_RANDOM: 04461 tmp->metric = ast_random() % 1000; 04462 tmp->metric += mem->penalty * 1000000 * usepenalty; 04463 break; 04464 case QUEUE_STRATEGY_WRANDOM: 04465 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000); 04466 break; 04467 case QUEUE_STRATEGY_FEWESTCALLS: 04468 tmp->metric = mem->calls; 04469 tmp->metric += mem->penalty * 1000000 * usepenalty; 04470 break; 04471 case QUEUE_STRATEGY_LEASTRECENT: 04472 if (!mem->lastcall) 04473 tmp->metric = 0; 04474 else 04475 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 04476 tmp->metric += mem->penalty * 1000000 * usepenalty; 04477 break; 04478 default: 04479 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 04480 break; 04481 } 04482 return 0; 04483 }
| static void callattempt_free | ( | struct callattempt * | doomed | ) | [static] |
Definition at line 2981 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().
| static int can_ring_entry | ( | struct queue_ent * | qe, | |
| struct callattempt * | call | |||
| ) | [static] |
Definition at line 3198 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(), queue_ent::parent, member::paused, call_queue::ringinuse, member::status, and call_queue::wrapuptime.
Referenced by ring_entry().
03199 { 03200 if (call->member->paused) { 03201 ast_debug(1, "%s paused, can't receive call\n", call->interface); 03202 return 0; 03203 } 03204 03205 if (!qe->parent->ringinuse && !member_status_available(call->member->status)) { 03206 ast_debug(1, "%s not available, can't receive call\n", call->interface); 03207 return 0; 03208 } 03209 03210 if ((call->lastqueue && call->lastqueue->wrapuptime && (time(NULL) - call->lastcall < call->lastqueue->wrapuptime)) 03211 || (!call->lastqueue && qe->parent->wrapuptime && (time(NULL) - call->lastcall < qe->parent->wrapuptime))) { 03212 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 03213 (call->lastqueue ? call->lastqueue->name : qe->parent->name), 03214 call->interface); 03215 return 0; 03216 } 03217 03218 if (use_weight && compare_weight(qe->parent, call->member)) { 03219 ast_debug(1, "Priority queue delaying call to %s:%s\n", 03220 qe->parent->name, call->interface); 03221 return 0; 03222 } 03223 03224 if (!qe->parent->ringinuse) { 03225 if (member_call_pending_set(call->member)) { 03226 ast_debug(1, "%s has another call pending, can't receive call\n", 03227 call->interface); 03228 return 0; 03229 } 03230 03231 /* 03232 * The queue member is available. Get current status to be sure 03233 * because the device state and extension state callbacks may 03234 * not have updated the status yet. 03235 */ 03236 if (!member_status_available(get_queue_member_status(call->member))) { 03237 ast_debug(1, "%s actually not available, can't receive call\n", 03238 call->interface); 03239 member_call_pending_clear(call->member); 03240 return 0; 03241 } 03242 } 03243 03244 return 1; 03245 }
| static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 1848 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().
01849 { 01850 q->holdtime = 0; 01851 q->callscompleted = 0; 01852 q->callsabandoned = 0; 01853 q->callscompletedinsl = 0; 01854 q->talktime = 0; 01855 01856 if (q->members) { 01857 struct member *mem; 01858 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01859 while ((mem = ao2_iterator_next(&mem_iter))) { 01860 mem->calls = 0; 01861 mem->lastcall = 0; 01862 ao2_ref(mem, -1); 01863 } 01864 ao2_iterator_destroy(&mem_iter); 01865 } 01866 }
| 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.
| 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 |
| void |
Definition at line 7249 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(), queue_t_unref, and queues.
Referenced by reload_handler().
07250 { 07251 struct call_queue *q; 07252 struct ao2_iterator queue_iter; 07253 07254 queue_iter = ao2_iterator_init(queues, 0); 07255 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07256 ao2_lock(q); 07257 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) 07258 clear_queue(q); 07259 ao2_unlock(q); 07260 queue_t_unref(q, "Done with iterator"); 07261 } 07262 ao2_iterator_destroy(&queue_iter); 07263 return 0; 07264 }
| static int compare_weight | ( | struct call_queue * | rq, | |
| struct member * | member | |||
| ) | [static] |
Definition at line 3061 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, num_available_members(), OBJ_POINTER, queue_t_unref, queues, and call_queue::weight.
Referenced by can_ring_entry().
03062 { 03063 struct call_queue *q; 03064 struct member *mem; 03065 int found = 0; 03066 struct ao2_iterator queue_iter; 03067 03068 queue_iter = ao2_iterator_init(queues, 0); 03069 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 03070 if (q == rq) { /* don't check myself, could deadlock */ 03071 queue_t_unref(q, "Done with iterator"); 03072 continue; 03073 } 03074 ao2_lock(q); 03075 if (q->count && q->members) { 03076 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 03077 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 03078 if (q->weight > rq->weight && q->count >= num_available_members(q)) { 03079 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); 03080 found = 1; 03081 } 03082 ao2_ref(mem, -1); 03083 } 03084 } 03085 ao2_unlock(q); 03086 queue_t_unref(q, "Done with iterator"); 03087 if (found) { 03088 break; 03089 } 03090 } 03091 ao2_iterator_destroy(&queue_iter); 03092 return found; 03093 }
| 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.
| 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. |
Definition at line 7514 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_strdup, 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_penalty(), complete_queue_show(), handle_queue_reload(), and handle_queue_reset().
07515 { 07516 struct call_queue *q; 07517 char *ret = NULL; 07518 int which = 0; 07519 int wordlen = strlen(word); 07520 struct ao2_iterator queue_iter; 07521 const char *word_list = NULL; 07522 07523 /* for certain commands, already completed items should be left out of 07524 * the list */ 07525 if (word_list_offset && strlen(line) >= word_list_offset) { 07526 word_list = line + word_list_offset; 07527 } 07528 07529 queue_iter = ao2_iterator_init(queues, 0); 07530 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07531 if (!strncasecmp(word, q->name, wordlen) && ++which > state 07532 && (!word_list_offset || !word_in_list(word_list, q->name))) { 07533 ret = ast_strdup(q->name); 07534 queue_t_unref(q, "Done with iterator"); 07535 break; 07536 } 07537 queue_t_unref(q, "Done with iterator"); 07538 } 07539 ao2_iterator_destroy(&queue_iter); 07540 07541 /* Pretend "rules" is at the end of the queues list in certain 07542 * circumstances since it is an alternate command that should be 07543 * tab-completable for "queue show" */ 07544 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) { 07545 ret = ast_strdup("rules"); 07546 } 07547 07548 return ret; 07549 }
| static char* complete_queue_add_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 7976 of file app_queue.c.
References ast_malloc, ast_strdup, and complete_queue().
Referenced by handle_queue_add_member().
07977 { 07978 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 07979 switch (pos) { 07980 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 07981 return NULL; 07982 case 4: /* only one possible match, "to" */ 07983 return state == 0 ? ast_strdup("to") : NULL; 07984 case 5: /* <queue> */ 07985 return complete_queue(line, word, pos, state, 0); 07986 case 6: /* only one possible match, "penalty" */ 07987 return state == 0 ? ast_strdup("penalty") : NULL; 07988 case 7: 07989 if (state < 100) { /* 0-99 */ 07990 char *num; 07991 if ((num = ast_malloc(3))) { 07992 sprintf(num, "%d", state); 07993 } 07994 return num; 07995 } else { 07996 return NULL; 07997 } 07998 case 8: /* only one possible match, "as" */ 07999 return state == 0 ? ast_strdup("as") : NULL; 08000 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 08001 return NULL; 08002 default: 08003 return NULL; 08004 } 08005 }
| static char* complete_queue_pause_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 8198 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_pause_member().
08199 { 08200 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */ 08201 switch (pos) { 08202 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 08203 return NULL; 08204 case 4: /* only one possible match, "queue" */ 08205 return state == 0 ? ast_strdup("queue") : NULL; 08206 case 5: /* <queue> */ 08207 return complete_queue(line, word, pos, state, 0); 08208 case 6: /* "reason" */ 08209 return state == 0 ? ast_strdup("reason") : NULL; 08210 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */ 08211 return NULL; 08212 default: 08213 return NULL; 08214 } 08215 }
| static char* complete_queue_remove_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 8106 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, queue_t_unref, and queues.
Referenced by handle_queue_remove_member().
08107 { 08108 int which = 0; 08109 struct call_queue *q; 08110 struct member *m; 08111 struct ao2_iterator queue_iter; 08112 struct ao2_iterator mem_iter; 08113 int wordlen = strlen(word); 08114 08115 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 08116 if (pos > 5 || pos < 3) 08117 return NULL; 08118 if (pos == 4) /* only one possible match, 'from' */ 08119 return (state == 0 ? ast_strdup("from") : NULL); 08120 08121 if (pos == 5) { /* No need to duplicate code */ 08122 return complete_queue(line, word, pos, state, 0); 08123 } 08124 08125 /* here is the case for 3, <member> */ 08126 queue_iter = ao2_iterator_init(queues, 0); 08127 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 08128 ao2_lock(q); 08129 mem_iter = ao2_iterator_init(q->members, 0); 08130 while ((m = ao2_iterator_next(&mem_iter))) { 08131 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) { 08132 char *tmp; 08133 tmp = ast_strdup(m->interface); 08134 ao2_ref(m, -1); 08135 ao2_iterator_destroy(&mem_iter); 08136 ao2_unlock(q); 08137 queue_t_unref(q, "Done with iterator, returning interface name"); 08138 ao2_iterator_destroy(&queue_iter); 08139 return tmp; 08140 } 08141 ao2_ref(m, -1); 08142 } 08143 ao2_iterator_destroy(&mem_iter); 08144 ao2_unlock(q); 08145 queue_t_unref(q, "Done with iterator"); 08146 } 08147 ao2_iterator_destroy(&queue_iter); 08148 08149 return NULL; 08150 }
| static char* complete_queue_rule_show | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 8331 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, and rule_list::name.
Referenced by handle_queue_rule_show().
08332 { 08333 int which = 0; 08334 struct rule_list *rl_iter; 08335 int wordlen = strlen(word); 08336 char *ret = NULL; 08337 if (pos != 3) /* Wha? */ { 08338 return NULL; 08339 } 08340 08341 AST_LIST_LOCK(&rule_lists); 08342 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 08343 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) { 08344 ret = ast_strdup(rl_iter->name); 08345 break; 08346 } 08347 } 08348 AST_LIST_UNLOCK(&rule_lists); 08349 08350 return ret; 08351 }
| static char* complete_queue_set_member_penalty | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 8268 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_set_member_penalty().
08269 { 08270 /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/ 08271 switch (pos) { 08272 case 4: 08273 if (state == 0) { 08274 return ast_strdup("on"); 08275 } else { 08276 return NULL; 08277 } 08278 case 6: 08279 if (state == 0) { 08280 return ast_strdup("in"); 08281 } else { 08282 return NULL; 08283 } 08284 case 7: 08285 return complete_queue(line, word, pos, state, 0); 08286 default: 08287 return NULL; 08288 } 08289 }
| static char* complete_queue_show | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 7551 of file app_queue.c.
References complete_queue().
Referenced by queue_show().
07552 { 07553 if (pos == 2) { 07554 return complete_queue(line, word, pos, state, 0); 07555 } 07556 return NULL; 07557 }
| static int compress_char | ( | const char | c | ) | [static] |
Definition at line 1739 of file app_queue.c.
Referenced by member_hash_fn().
| static void copy_rules | ( | struct queue_ent * | qe, | |
| const char * | rulename | |||
| ) | [static] |
Copy rule from global list into specified queue.
Definition at line 6140 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(), LOG_ERROR, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, queue_ent::parent, and penalty_rule::time.
Referenced by queue_exec().
06141 { 06142 struct penalty_rule *pr_iter; 06143 struct rule_list *rl_iter; 06144 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename; 06145 AST_LIST_LOCK(&rule_lists); 06146 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 06147 if (!strcasecmp(rl_iter->name, tmp)) 06148 break; 06149 } 06150 if (rl_iter) { 06151 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 06152 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr)); 06153 if (!new_pr) { 06154 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n"); 06155 break; 06156 } 06157 new_pr->time = pr_iter->time; 06158 new_pr->max_value = pr_iter->max_value; 06159 new_pr->min_value = pr_iter->min_value; 06160 new_pr->max_relative = pr_iter->max_relative; 06161 new_pr->min_relative = pr_iter->min_relative; 06162 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list); 06163 } 06164 } 06165 AST_LIST_UNLOCK(&rule_lists); 06166 }
| static struct member* create_queue_member | ( | const char * | interface, | |
| const char * | membername, | |||
| int | penalty, | |||
| int | paused, | |||
| const char * | state_interface | |||
| ) | [static, read] |
allocate space for new queue member and set fields based on parameters passed
Definition at line 1707 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, member::paused, member::penalty, S_OR, member::state_context, member::state_exten, member::state_interface, and member::status.
Referenced by add_to_queue(), reload_single_member(), and rt_handle_member_record().
01708 { 01709 struct member *cur; 01710 01711 if ((cur = ao2_alloc(sizeof(*cur), NULL))) { 01712 cur->penalty = penalty; 01713 cur->paused = paused; 01714 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 01715 if (!ast_strlen_zero(state_interface)) 01716 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); 01717 else 01718 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface)); 01719 if (!ast_strlen_zero(membername)) 01720 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 01721 else 01722 ast_copy_string(cur->membername, interface, sizeof(cur->membername)); 01723 if (!strchr(cur->interface, '/')) 01724 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 01725 if (!strncmp(cur->state_interface, "hint:", 5)) { 01726 char *tmp = ast_strdupa(cur->state_interface), *context = tmp; 01727 char *exten = strsep(&context, "@") + 5; 01728 01729 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten)); 01730 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context)); 01731 } 01732 cur->status = get_queue_member_status(cur); 01733 } 01734 01735 return cur; 01736 }
| static void destroy_queue | ( | void * | obj | ) | [static] |
Free queue's member list then its string fields.
Definition at line 2305 of file app_queue.c.
References ao2_ref, ast_string_field_free_memory, free, free_members(), MAX_PERIODIC_ANNOUNCEMENTS, call_queue::members, and call_queue::sound_periodicannounce.
Referenced by alloc_queue().
02306 { 02307 struct call_queue *q = obj; 02308 int i; 02309 02310 free_members(q, 1); 02311 ast_string_field_free_memory(q); 02312 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 02313 if (q->sound_periodicannounce[i]) 02314 free(q->sound_periodicannounce[i]); 02315 } 02316 ao2_ref(q->members, -1); 02317 }
| static void device_state_cb | ( | const struct ast_event * | event, | |
| void * | unused | |||
| ) | [static] |
Definition at line 1605 of file app_queue.c.
References ast_calloc, ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_STATE, ast_free, ast_log(), ast_strlen_zero(), ast_taskprocessor_push(), statechange::dev, handle_statechange(), and LOG_ERROR.
Referenced by load_module().
01606 { 01607 enum ast_device_state state; 01608 const char *device; 01609 struct statechange *sc; 01610 size_t datapsize; 01611 01612 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE); 01613 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE); 01614 01615 if (ast_strlen_zero(device)) { 01616 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n"); 01617 return; 01618 } 01619 datapsize = sizeof(*sc) + strlen(device) + 1; 01620 if (!(sc = ast_calloc(1, datapsize))) { 01621 ast_log(LOG_ERROR, "failed to calloc a state change struct\n"); 01622 return; 01623 } 01624 sc->state = state; 01625 strcpy(sc->dev, device); 01626 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) { 01627 ast_free(sc); 01628 } 01629 }
| static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 3096 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry(), and wait_for_answer().
03097 { 03098 o->stillgoing = 0; 03099 ast_hangup(o->chan); 03100 o->chan = NULL; 03101 }
| 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 7296 of file app_queue.c.
References ast_cli(), and astman_append().
Referenced by __queues_show().
07297 { 07298 if (s) 07299 astman_append(s, "%s\r\n", str); 07300 else 07301 ast_cli(fd, "%s\n", str); 07302 }
| 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 5511 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, member::paused, member::penalty, member::state_interface, and value.
Referenced by add_to_queue(), remove_from_queue(), and set_member_paused().
05512 { 05513 struct member *cur_member; 05514 struct ast_str *value; 05515 struct ao2_iterator mem_iter; 05516 05517 if (!pm_queue) { 05518 return; 05519 } 05520 05521 /* 4K is a reasonable default for most applications, but we grow to 05522 * accommodate more if necessary. */ 05523 if (!(value = ast_str_create(4096))) { 05524 return; 05525 } 05526 05527 mem_iter = ao2_iterator_init(pm_queue->members, 0); 05528 while ((cur_member = ao2_iterator_next(&mem_iter))) { 05529 if (!cur_member->dynamic) { 05530 ao2_ref(cur_member, -1); 05531 continue; 05532 } 05533 05534 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s", 05535 ast_str_strlen(value) ? "|" : "", 05536 cur_member->interface, 05537 cur_member->penalty, 05538 cur_member->paused, 05539 cur_member->membername, 05540 cur_member->state_interface); 05541 05542 ao2_ref(cur_member, -1); 05543 } 05544 ao2_iterator_destroy(&mem_iter); 05545 05546 if (ast_str_strlen(value) && !cur_member) { 05547 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) 05548 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 05549 } else { 05550 /* Delete the entry if the queue is empty or there is an error */ 05551 ast_db_del(pm_family, pm_queue->name); 05552 } 05553 05554 ast_free(value); 05555 }
| static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 4638 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().
Referenced by try_calling().
04639 { 04640 struct queue_end_bridge *qeb = data; 04641 struct call_queue *q = qeb->q; 04642 struct ast_channel *chan = qeb->chan; 04643 04644 if (ao2_ref(qeb, -1) == 1) { 04645 set_queue_variables(q, chan); 04646 /* This unrefs the reference we made in try_calling when we allocated qeb */ 04647 queue_t_unref(q, "Expire bridge_config reference"); 04648 } 04649 }
| static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
| struct ast_channel * | originator, | |||
| struct ast_channel * | terminator | |||
| ) | [static] |
Definition at line 4631 of file app_queue.c.
References ao2_ref, queue_end_bridge::chan, and ast_bridge_config::end_bridge_callback_data.
Referenced by try_calling().
04632 { 04633 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data; 04634 ao2_ref(qeb, +1); 04635 qeb->chan = originator; 04636 }
| static int extension_state_cb | ( | char * | context, | |
| char * | exten, | |||
| enum ast_extension_states | state, | |||
| void * | data | |||
| ) | [static] |
Definition at line 1663 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(), extensionstate2devicestate(), call_queue::found, call_queue::members, queue_t_unref, queues, member::state_context, member::state_exten, and update_status().
Referenced by load_module(), and unload_module().
01664 { 01665 struct ao2_iterator miter, qiter; 01666 struct member *m; 01667 struct call_queue *q; 01668 int found = 0, device_state = extensionstate2devicestate(state); 01669 01670 qiter = ao2_iterator_init(queues, 0); 01671 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) { 01672 ao2_lock(q); 01673 01674 miter = ao2_iterator_init(q->members, 0); 01675 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) { 01676 if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) { 01677 update_status(q, m, device_state); 01678 ao2_ref(m, -1); 01679 found = 1; 01680 break; 01681 } 01682 } 01683 ao2_iterator_destroy(&miter); 01684 01685 ao2_unlock(q); 01686 queue_t_unref(q, "Done with iterator"); 01687 } 01688 ao2_iterator_destroy(&qiter); 01689 01690 if (found) { 01691 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state)); 01692 } else { 01693 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", 01694 exten, context, device_state, ast_devstate2str(device_state)); 01695 } 01696 01697 return 0; 01698 }
| static int extensionstate2devicestate | ( | int | state | ) | [static] |
Helper function which converts from extension state to device state values.
Definition at line 1632 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().
01633 { 01634 switch (state) { 01635 case AST_EXTENSION_NOT_INUSE: 01636 state = AST_DEVICE_NOT_INUSE; 01637 break; 01638 case AST_EXTENSION_INUSE: 01639 state = AST_DEVICE_INUSE; 01640 break; 01641 case AST_EXTENSION_BUSY: 01642 state = AST_DEVICE_BUSY; 01643 break; 01644 case AST_EXTENSION_RINGING: 01645 state = AST_DEVICE_RINGING; 01646 break; 01647 case AST_EXTENSION_ONHOLD: 01648 state = AST_DEVICE_ONHOLD; 01649 break; 01650 case AST_EXTENSION_UNAVAILABLE: 01651 state = AST_DEVICE_UNAVAILABLE; 01652 break; 01653 case AST_EXTENSION_REMOVED: 01654 case AST_EXTENSION_DEACTIVATED: 01655 default: 01656 state = AST_DEVICE_INVALID; 01657 break; 01658 } 01659 01660 return state; 01661 }
| static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static, read] |
find the entry with the best metric, or NULL
Definition at line 3419 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
Referenced by ring_one(), store_next_lin(), and store_next_rr().
03420 { 03421 struct callattempt *best = NULL, *cur; 03422 03423 for (cur = outgoing; cur; cur = cur->q_next) { 03424 if (cur->stillgoing && /* Not already done */ 03425 !cur->chan && /* Isn't already going */ 03426 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 03427 best = cur; 03428 } 03429 } 03430 03431 return best; 03432 }
| 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.
| the | queue, | |
| NULL | if it doesn't exist. |
Definition at line 2343 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_variable_retrieve(), clear_queue(), member::dead, call_queue::dead, init_queue(), member::interface, LOG_WARNING, member_remove_from_queue(), call_queue::members, ast_variable::name, ast_variable::next, 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(), S_OR, strat2int(), call_queue::strategy, and ast_variable::value.
Referenced by load_realtime_queue().
02344 { 02345 struct ast_variable *v; 02346 struct call_queue *q, tmpq = { 02347 .name = queuename, 02348 }; 02349 struct member *m; 02350 struct ao2_iterator mem_iter; 02351 char *interface = NULL; 02352 const char *tmp_name; 02353 char *tmp; 02354 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 02355 02356 /* Static queues override realtime. */ 02357 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) { 02358 ao2_lock(q); 02359 if (!q->realtime) { 02360 if (q->dead) { 02361 ao2_unlock(q); 02362 queue_t_unref(q, "Queue is dead; can't return it"); 02363 return NULL; 02364 } else { 02365 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); 02366 ao2_unlock(q); 02367 return q; 02368 } 02369 } 02370 } else if (!member_config) 02371 /* Not found in the list, and it's not realtime ... */ 02372 return NULL; 02373 02374 /* Check if queue is defined in realtime. */ 02375 if (!queue_vars) { 02376 /* Delete queue from in-core list if it has been deleted in realtime. */ 02377 if (q) { 02378 /*! \note Hmm, can't seem to distinguish a DB failure from a not 02379 found condition... So we might delete an in-core queue 02380 in case of DB failure. */ 02381 ast_debug(1, "Queue %s not found in realtime.\n", queuename); 02382 02383 q->dead = 1; 02384 /* Delete if unused (else will be deleted when last caller leaves). */ 02385 queues_t_unlink(queues, q, "Unused; removing from container"); 02386 ao2_unlock(q); 02387 queue_t_unref(q, "Queue is dead; can't return it"); 02388 } 02389 return NULL; 02390 } 02391 02392 /* Create a new queue if an in-core entry does not exist yet. */ 02393 if (!q) { 02394 struct ast_variable *tmpvar = NULL; 02395 if (!(q = alloc_queue(queuename))) 02396 return NULL; 02397 ao2_lock(q); 02398 clear_queue(q); 02399 q->realtime = 1; 02400 /*Before we initialize the queue, we need to set the strategy, so that linear strategy 02401 * will allocate the members properly 02402 */ 02403 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) { 02404 if (!strcasecmp(tmpvar->name, "strategy")) { 02405 q->strategy = strat2int(tmpvar->value); 02406 if (q->strategy < 0) { 02407 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 02408 tmpvar->value, q->name); 02409 q->strategy = QUEUE_STRATEGY_RINGALL; 02410 } 02411 break; 02412 } 02413 } 02414 /* We traversed all variables and didn't find a strategy */ 02415 if (!tmpvar) 02416 q->strategy = QUEUE_STRATEGY_RINGALL; 02417 queues_t_link(queues, q, "Add queue to container"); 02418 } 02419 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 02420 02421 memset(tmpbuf, 0, sizeof(tmpbuf)); 02422 for (v = queue_vars; v; v = v->next) { 02423 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 02424 if (strchr(v->name, '_')) { 02425 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 02426 tmp_name = tmpbuf; 02427 tmp = tmpbuf; 02428 while ((tmp = strchr(tmp, '_'))) 02429 *tmp++ = '-'; 02430 } else 02431 tmp_name = v->name; 02432 02433 /* NULL values don't get returned from realtime; blank values should 02434 * still get set. If someone doesn't want a value to be set, they 02435 * should set the realtime column to NULL, not blank. */ 02436 queue_set_param(q, tmp_name, v->value, -1, 0); 02437 } 02438 02439 /* Temporarily set realtime members dead so we can detect deleted ones. */ 02440 mem_iter = ao2_iterator_init(q->members, 0); 02441 while ((m = ao2_iterator_next(&mem_iter))) { 02442 if (m->realtime) 02443 m->dead = 1; 02444 ao2_ref(m, -1); 02445 } 02446 ao2_iterator_destroy(&mem_iter); 02447 02448 while ((interface = ast_category_browse(member_config, interface))) { 02449 rt_handle_member_record(q, interface, 02450 ast_variable_retrieve(member_config, interface, "uniqueid"), 02451 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface), 02452 ast_variable_retrieve(member_config, interface, "penalty"), 02453 ast_variable_retrieve(member_config, interface, "paused"), 02454 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface)); 02455 } 02456 02457 /* Delete all realtime members that have been deleted in DB. */ 02458 mem_iter = ao2_iterator_init(q->members, 0); 02459 while ((m = ao2_iterator_next(&mem_iter))) { 02460 if (m->dead) { 02461 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 02462 member_remove_from_queue(q, m); 02463 } 02464 ao2_ref(m, -1); 02465 } 02466 ao2_iterator_destroy(&mem_iter); 02467 02468 ao2_unlock(q); 02469 02470 return q; 02471 }
| static void free_members | ( | struct call_queue * | q, | |
| int | all | |||
| ) | [static] |
Iterate through queue's member list and delete them.
Definition at line 2289 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().
02290 { 02291 /* Free non-dynamic members */ 02292 struct member *cur; 02293 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 02294 02295 while ((cur = ao2_iterator_next(&mem_iter))) { 02296 if (all || !cur->dynamic) { 02297 member_remove_from_queue(q, cur); 02298 } 02299 ao2_ref(cur, -1); 02300 } 02301 ao2_iterator_destroy(&mem_iter); 02302 }
| static int get_member_penalty | ( | char * | queuename, | |
| char * | interface | |||
| ) | [static] |
Definition at line 5788 of file app_queue.c.
References ao2_lock, ao2_ref, ao2_t_find, ao2_unlock, ast_log(), interface_exists(), LOG_ERROR, OBJ_POINTER, member::penalty, queue_t_unref, queues, and RESULT_FAILURE.
Referenced by queue_function_memberpenalty_read().
05789 { 05790 int foundqueue = 0, penalty; 05791 struct call_queue *q, tmpq = { 05792 .name = queuename, 05793 }; 05794 struct member *mem; 05795 05796 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) { 05797 foundqueue = 1; 05798 ao2_lock(q); 05799 if ((mem = interface_exists(q, interface))) { 05800 penalty = mem->penalty; 05801 ao2_ref(mem, -1); 05802 ao2_unlock(q); 05803 queue_t_unref(q, "Search complete"); 05804 return penalty; 05805 } 05806 ao2_unlock(q); 05807 queue_t_unref(q, "Search complete"); 05808 } 05809 05810 /* some useful debuging */ 05811 if (foundqueue) 05812 ast_log (LOG_ERROR, "Invalid queuename\n"); 05813 else 05814 ast_log (LOG_ERROR, "Invalid interface\n"); 05815 05816 return RESULT_FAILURE; 05817 }
| 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 1451 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, 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().
01452 { 01453 struct member *member; 01454 struct ao2_iterator mem_iter; 01455 01456 ao2_lock(q); 01457 mem_iter = ao2_iterator_init(q->members, 0); 01458 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) { 01459 if ((max_penalty != INT_MAX && member->penalty > max_penalty) || (min_penalty != INT_MAX && member->penalty < min_penalty)) { 01460 if (conditions & QUEUE_EMPTY_PENALTY) { 01461 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty); 01462 continue; 01463 } 01464 } 01465 01466 switch (devstate ? ast_device_state(member->state_interface) : member->status) { 01467 case AST_DEVICE_INVALID: 01468 if (conditions & QUEUE_EMPTY_INVALID) { 01469 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername); 01470 break; 01471 } 01472 goto default_case; 01473 case AST_DEVICE_UNAVAILABLE: 01474 if (conditions & QUEUE_EMPTY_UNAVAILABLE) { 01475 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername); 01476 break; 01477 } 01478 goto default_case; 01479 case AST_DEVICE_INUSE: 01480 if (conditions & QUEUE_EMPTY_INUSE) { 01481 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername); 01482 break; 01483 } 01484 goto default_case; 01485 case AST_DEVICE_RINGING: 01486 if (conditions & QUEUE_EMPTY_RINGING) { 01487 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername); 01488 break; 01489 } 01490 goto default_case; 01491 case AST_DEVICE_UNKNOWN: 01492 if (conditions & QUEUE_EMPTY_UNKNOWN) { 01493 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername); 01494 break; 01495 } 01496 /* Fall-through */ 01497 default: 01498 default_case: 01499 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) { 01500 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername); 01501 break; 01502 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) { 01503 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); 01504 break; 01505 } else { 01506 ao2_ref(member, -1); 01507 ao2_iterator_destroy(&mem_iter); 01508 ao2_unlock(q); 01509 ast_debug(4, "%s is available.\n", member->membername); 01510 return 0; 01511 } 01512 break; 01513 } 01514 } 01515 ao2_iterator_destroy(&mem_iter); 01516 ao2_unlock(q); 01517 01518 if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) { 01519 /* member state still may be RINGING due to lag in event message - check again with device state */ 01520 return get_member_status(q, max_penalty, min_penalty, conditions, 1); 01521 } 01522 return -1; 01523 }
| static int get_queue_member_status | ( | struct member * | cur | ) | [static] |
Return the current state of a member.
Definition at line 1701 of file app_queue.c.
References ast_extension_state(), ast_strlen_zero(), extensionstate2devicestate(), member::state_context, member::state_exten, and member::state_interface.
Referenced by can_ring_entry(), create_queue_member(), and kill_dead_members().
01702 { 01703 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten)); 01704 }
| static char* handle_queue_add_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8032 of file app_queue.c.
References add_to_queue(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), 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, ast_cli_args::pos, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, ast_cli_entry::usage, and ast_cli_args::word.
08033 { 08034 const char *queuename, *interface, *membername = NULL, *state_interface = NULL; 08035 int penalty; 08036 08037 switch ( cmd ) { 08038 case CLI_INIT: 08039 e->command = "queue add member"; 08040 e->usage = 08041 "Usage: queue add member <dial string> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n" 08042 " 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"; 08043 return NULL; 08044 case CLI_GENERATE: 08045 return complete_queue_add_member(a->line, a->word, a->pos, a->n); 08046 } 08047 08048 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) { 08049 return CLI_SHOWUSAGE; 08050 } else if (strcmp(a->argv[4], "to")) { 08051 return CLI_SHOWUSAGE; 08052 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) { 08053 return CLI_SHOWUSAGE; 08054 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) { 08055 return CLI_SHOWUSAGE; 08056 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) { 08057 return CLI_SHOWUSAGE; 08058 } 08059 08060 queuename = a->argv[5]; 08061 interface = a->argv[3]; 08062 if (a->argc >= 8) { 08063 if (sscanf(a->argv[7], "%30d", &penalty) == 1) { 08064 if (penalty < 0) { 08065 ast_cli(a->fd, "Penalty must be >= 0\n"); 08066 penalty = 0; 08067 } 08068 } else { 08069 ast_cli(a->fd, "Penalty must be an integer >= 0\n"); 08070 penalty = 0; 08071 } 08072 } else { 08073 penalty = 0; 08074 } 08075 08076 if (a->argc >= 10) { 08077 membername = a->argv[9]; 08078 } 08079 08080 if (a->argc >= 12) { 08081 state_interface = a->argv[11]; 08082 } 08083 08084 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { 08085 case RES_OKAY: 08086 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 08087 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 08088 return CLI_SUCCESS; 08089 case RES_EXISTS: 08090 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 08091 return CLI_FAILURE; 08092 case RES_NOSUCHQUEUE: 08093 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 08094 return CLI_FAILURE; 08095 case RES_OUTOFMEMORY: 08096 ast_cli(a->fd, "Out of memory\n"); 08097 return CLI_FAILURE; 08098 case RES_NOT_DYNAMIC: 08099 ast_cli(a->fd, "Member not dynamic\n"); 08100 return CLI_FAILURE; 08101 default: 08102 return CLI_FAILURE; 08103 } 08104 }
| static char* handle_queue_pause_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8217 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_pause_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RESULT_SUCCESS, set_member_paused(), ast_cli_entry::usage, and word.
08218 { 08219 const char *queuename, *interface, *reason; 08220 int paused; 08221 08222 switch (cmd) { 08223 case CLI_INIT: 08224 e->command = "queue {pause|unpause} member"; 08225 e->usage = 08226 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n" 08227 " Pause or unpause a queue member. Not specifying a particular queue\n" 08228 " will pause or unpause a member across all queues to which the member\n" 08229 " belongs.\n"; 08230 return NULL; 08231 case CLI_GENERATE: 08232 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n); 08233 } 08234 08235 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) { 08236 return CLI_SHOWUSAGE; 08237 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) { 08238 return CLI_SHOWUSAGE; 08239 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) { 08240 return CLI_SHOWUSAGE; 08241 } 08242 08243 08244 interface = a->argv[3]; 08245 queuename = a->argc >= 6 ? a->argv[5] : NULL; 08246 reason = a->argc == 8 ? a->argv[7] : NULL; 08247 paused = !strcasecmp(a->argv[1], "pause"); 08248 08249 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) { 08250 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface); 08251 if (!ast_strlen_zero(queuename)) 08252 ast_cli(a->fd, " in queue '%s'", queuename); 08253 if (!ast_strlen_zero(reason)) 08254 ast_cli(a->fd, " for reason '%s'", reason); 08255 ast_cli(a->fd, "\n"); 08256 return CLI_SUCCESS; 08257 } else { 08258 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface); 08259 if (!ast_strlen_zero(queuename)) 08260 ast_cli(a->fd, " in queue '%s'", queuename); 08261 if (!ast_strlen_zero(reason)) 08262 ast_cli(a->fd, " for reason '%s'", reason); 08263 ast_cli(a->fd, "\n"); 08264 return CLI_FAILURE; 08265 } 08266 }
| static char* handle_queue_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8426 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, ast_cli_args::pos, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, reload_handler(), ast_cli_entry::usage, and ast_cli_args::word.
08427 { 08428 struct ast_flags mask = {0,}; 08429 int i; 08430 08431 switch (cmd) { 08432 case CLI_INIT: 08433 e->command = "queue reload {parameters|members|rules|all}"; 08434 e->usage = 08435 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n" 08436 "Reload queues. If <queuenames> are specified, only reload information pertaining\n" 08437 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n" 08438 "specified in order to know what information to reload. Below is an explanation\n" 08439 "of each of these qualifiers.\n" 08440 "\n" 08441 "\t'members' - reload queue members from queues.conf\n" 08442 "\t'parameters' - reload all queue options except for queue members\n" 08443 "\t'rules' - reload the queuerules.conf file\n" 08444 "\t'all' - reload queue rules, parameters, and members\n" 08445 "\n" 08446 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n" 08447 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n" 08448 "one queue is specified when using this command, reloading queue rules may cause\n" 08449 "other queues to be affected\n"; 08450 return NULL; 08451 case CLI_GENERATE: 08452 if (a->pos >= 3) { 08453 /* find the point at which the list of queue names starts */ 08454 const char *command_end = a->line + strlen("queue reload "); 08455 command_end = strchr(command_end, ' '); 08456 if (!command_end) { 08457 command_end = a->line + strlen(a->line); 08458 } 08459 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line); 08460 } else { 08461 return NULL; 08462 } 08463 } 08464 08465 if (a->argc < 3) 08466 return CLI_SHOWUSAGE; 08467 08468 if (!strcasecmp(a->argv[2], "rules")) { 08469 ast_set_flag(&mask, QUEUE_RELOAD_RULES); 08470 } else if (!strcasecmp(a->argv[2], "members")) { 08471 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER); 08472 } else if (!strcasecmp(a->argv[2], "parameters")) { 08473 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); 08474 } else if (!strcasecmp(a->argv[2], "all")) { 08475 ast_set_flag(&mask, AST_FLAGS_ALL); 08476 } 08477 08478 if (a->argc == 3) { 08479 reload_handler(1, &mask, NULL); 08480 return CLI_SUCCESS; 08481 } 08482 08483 for (i = 3; i < a->argc; ++i) { 08484 reload_handler(1, &mask, a->argv[i]); 08485 } 08486 08487 return CLI_SUCCESS; 08488 }
| static char* handle_queue_remove_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8152 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_remove_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, 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.
08153 { 08154 const char *queuename, *interface; 08155 08156 switch (cmd) { 08157 case CLI_INIT: 08158 e->command = "queue remove member"; 08159 e->usage = 08160 "Usage: queue remove member <channel> from <queue>\n" 08161 " Remove a specific channel from a queue.\n"; 08162 return NULL; 08163 case CLI_GENERATE: 08164 return complete_queue_remove_member(a->line, a->word, a->pos, a->n); 08165 } 08166 08167 if (a->argc != 6) { 08168 return CLI_SHOWUSAGE; 08169 } else if (strcmp(a->argv[4], "from")) { 08170 return CLI_SHOWUSAGE; 08171 } 08172 08173 queuename = a->argv[5]; 08174 interface = a->argv[3]; 08175 08176 switch (remove_from_queue(queuename, interface)) { 08177 case RES_OKAY: 08178 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 08179 ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 08180 return CLI_SUCCESS; 08181 case RES_EXISTS: 08182 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 08183 return CLI_FAILURE; 08184 case RES_NOSUCHQUEUE: 08185 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 08186 return CLI_FAILURE; 08187 case RES_OUTOFMEMORY: 08188 ast_cli(a->fd, "Out of memory\n"); 08189 return CLI_FAILURE; 08190 case RES_NOT_DYNAMIC: 08191 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename); 08192 return CLI_FAILURE; 08193 default: 08194 return CLI_FAILURE; 08195 } 08196 }
| static char* handle_queue_reset | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8387 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, ast_cli_args::pos, QUEUE_RESET_STATS, reload_handler(), ast_cli_entry::usage, and ast_cli_args::word.
08388 { 08389 struct ast_flags mask = {QUEUE_RESET_STATS,}; 08390 int i; 08391 08392 switch (cmd) { 08393 case CLI_INIT: 08394 e->command = "queue reset stats"; 08395 e->usage = 08396 "Usage: queue reset stats [<queuenames>]\n" 08397 "\n" 08398 "Issuing this command will reset statistics for\n" 08399 "<queuenames>, or for all queues if no queue is\n" 08400 "specified.\n"; 08401 return NULL; 08402 case CLI_GENERATE: 08403 if (a->pos >= 3) { 08404 return complete_queue(a->line, a->word, a->pos, a->n, 17); 08405 } else { 08406 return NULL; 08407 } 08408 } 08409 08410 if (a->argc < 3) { 08411 return CLI_SHOWUSAGE; 08412 } 08413 08414 if (a->argc == 3) { 08415 reload_handler(1, &mask, NULL); 08416 return CLI_SUCCESS; 08417 } 08418 08419 for (i = 3; i < a->argc; ++i) { 08420 reload_handler(1, &mask, a->argv[i]); 08421 } 08422 08423 return CLI_SUCCESS; 08424 }
| static char* handle_queue_rule_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8353 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, ast_cli_args::pos, penalty_rule::time, ast_cli_entry::usage, and ast_cli_args::word.
08354 { 08355 const char *rule; 08356 struct rule_list *rl_iter; 08357 struct penalty_rule *pr_iter; 08358 switch (cmd) { 08359 case CLI_INIT: 08360 e->command = "queue show rules"; 08361 e->usage = 08362 "Usage: queue show rules [rulename]\n" 08363 " Show the list of rules associated with rulename. If no\n" 08364 " rulename is specified, list all rules defined in queuerules.conf\n"; 08365 return NULL; 08366 case CLI_GENERATE: 08367 return complete_queue_rule_show(a->line, a->word, a->pos, a->n); 08368 } 08369 08370 if (a->argc != 3 && a->argc != 4) 08371 return CLI_SHOWUSAGE; 08372 08373 rule = a->argc == 4 ? a->argv[3] : ""; 08374 AST_LIST_LOCK(&rule_lists); 08375 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 08376 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) { 08377 ast_cli(a->fd, "Rule: %s\n", rl_iter->name); 08378 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 08379 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); 08380 } 08381 } 08382 } 08383 AST_LIST_UNLOCK(&rule_lists); 08384 return CLI_SUCCESS; 08385 }
| static char* handle_queue_set_member_penalty | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8291 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_penalty(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RESULT_FAILURE, RESULT_SUCCESS, set_member_penalty(), ast_cli_entry::usage, and ast_cli_args::word.
08292 { 08293 const char *queuename = NULL, *interface; 08294 int penalty = 0; 08295 08296 switch (cmd) { 08297 case CLI_INIT: 08298 e->command = "queue set penalty"; 08299 e->usage = 08300 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n" 08301 " Set a member's penalty in the queue specified. If no queue is specified\n" 08302 " then that interface's penalty is set in all queues to which that interface is a member\n"; 08303 return NULL; 08304 case CLI_GENERATE: 08305 return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n); 08306 } 08307 08308 if (a->argc != 6 && a->argc != 8) { 08309 return CLI_SHOWUSAGE; 08310 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) { 08311 return CLI_SHOWUSAGE; 08312 } 08313 08314 if (a->argc == 8) 08315 queuename = a->argv[7]; 08316 interface = a->argv[5]; 08317 penalty = atoi(a->argv[3]); 08318 08319 switch (set_member_penalty(queuename, interface, penalty)) { 08320 case RESULT_SUCCESS: 08321 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename); 08322 return CLI_SUCCESS; 08323 case RESULT_FAILURE: 08324 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename); 08325 return CLI_FAILURE; 08326 default: 08327 return CLI_FAILURE; 08328 } 08329 }
| static int handle_statechange | ( | void * | datap | ) | [static] |
set a member's status based on device state of that member's interface
Definition at line 1561 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_devstate2str(), ast_free, statechange::dev, call_queue::found, call_queue::members, queue_t_unref, queues, member::state_interface, and update_status().
Referenced by device_state_cb().
01562 { 01563 struct statechange *sc = datap; 01564 struct ao2_iterator miter, qiter; 01565 struct member *m; 01566 struct call_queue *q; 01567 char interface[80], *slash_pos; 01568 int found = 0; 01569 01570 qiter = ao2_iterator_init(queues, 0); 01571 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) { 01572 ao2_lock(q); 01573 01574 miter = ao2_iterator_init(q->members, 0); 01575 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) { 01576 ast_copy_string(interface, m->state_interface, sizeof(interface)); 01577 01578 if ((slash_pos = strchr(interface, '/'))) 01579 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) 01580 *slash_pos = '\0'; 01581 01582 if (!strcasecmp(interface, sc->dev)) { 01583 found = 1; 01584 update_status(q, m, sc->state); 01585 ao2_ref(m, -1); 01586 break; 01587 } 01588 } 01589 ao2_iterator_destroy(&miter); 01590 01591 ao2_unlock(q); 01592 queue_t_unref(q, "Done with iterator"); 01593 } 01594 ao2_iterator_destroy(&qiter); 01595 01596 if (found) 01597 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state)); 01598 else 01599 ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", sc->dev, sc->state, ast_devstate2str(sc->state)); 01600 01601 ast_free(sc); 01602 return 0; 01603 }
| static void hangupcalls | ( | struct callattempt * | outgoing, | |
| struct ast_channel * | exception, | |||
| int | cancel_answered_elsewhere | |||
| ) | [static] |
Hang up a list of outgoing calls.
Definition at line 2991 of file app_queue.c.
References callattempt::aoc_s_rate_list, ast_aoc_destroy_decoded(), AST_FLAG_ANSWERED_ELSEWHERE, ast_hangup(), ast_set_flag, callattempt_free(), callattempt::chan, and callattempt::q_next.
Referenced by try_calling().
02992 { 02993 struct callattempt *oo; 02994 02995 while (outgoing) { 02996 /* If someone else answered the call we should indicate this in the CANCEL */ 02997 /* Hangup any existing lines we have open */ 02998 if (outgoing->chan && (outgoing->chan != exception)) { 02999 if (exception || cancel_answered_elsewhere) 03000 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE); 03001 ast_hangup(outgoing->chan); 03002 } 03003 oo = outgoing; 03004 outgoing = outgoing->q_next; 03005 ast_aoc_destroy_decoded(oo->aoc_s_rate_list); 03006 callattempt_free(oo); 03007 } 03008 }
| static void init_queue | ( | struct call_queue * | q | ) | [static] |
Initialize Queue default values.
Definition at line 1771 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_free, AST_LIST_REMOVE_HEAD, ast_str_create(), ast_str_set(), ast_string_field_set, call_queue::autofill, call_queue::autopause, call_queue::dead, DEFAULT_MIN_ANNOUNCE_FREQUENCY, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::eventwhencalled, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, call_queue::maskmemberstatus, 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::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::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().
01772 { 01773 int i; 01774 struct penalty_rule *pr_iter; 01775 01776 q->dead = 0; 01777 q->retry = DEFAULT_RETRY; 01778 q->timeout = DEFAULT_TIMEOUT; 01779 q->maxlen = 0; 01780 q->announcefrequency = 0; 01781 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY; 01782 q->announceholdtime = 1; 01783 q->announcepositionlimit = 10; /* Default 10 positions */ 01784 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */ 01785 q->roundingseconds = 0; /* Default - don't announce seconds */ 01786 q->servicelevel = 0; 01787 q->ringinuse = 1; 01788 q->announce_to_first_user = 0; 01789 q->setinterfacevar = 0; 01790 q->setqueuevar = 0; 01791 q->setqueueentryvar = 0; 01792 q->autofill = autofill_default; 01793 q->montype = montype_default; 01794 q->monfmt[0] = '\0'; 01795 q->reportholdtime = 0; 01796 q->wrapuptime = 0; 01797 q->penaltymemberslimit = 0; 01798 q->joinempty = 0; 01799 q->leavewhenempty = 0; 01800 q->memberdelay = 0; 01801 q->maskmemberstatus = 0; 01802 q->eventwhencalled = 0; 01803 q->weight = 0; 01804 q->timeoutrestart = 0; 01805 q->periodicannouncefrequency = 0; 01806 q->randomperiodicannounce = 0; 01807 q->numperiodicannounce = 0; 01808 q->autopause = QUEUE_AUTOPAUSE_OFF; 01809 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 01810 if (!q->members) { 01811 if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) 01812 /* linear strategy depends on order, so we have to place all members in a single bucket */ 01813 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn); 01814 else 01815 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn); 01816 } 01817 q->found = 1; 01818 01819 ast_string_field_set(q, sound_next, "queue-youarenext"); 01820 ast_string_field_set(q, sound_thereare, "queue-thereare"); 01821 ast_string_field_set(q, sound_calls, "queue-callswaiting"); 01822 ast_string_field_set(q, queue_quantity1, "queue-quantity1"); 01823 ast_string_field_set(q, queue_quantity2, "queue-quantity2"); 01824 ast_string_field_set(q, sound_holdtime, "queue-holdtime"); 01825 ast_string_field_set(q, sound_minutes, "queue-minutes"); 01826 ast_string_field_set(q, sound_minute, "queue-minute"); 01827 ast_string_field_set(q, sound_seconds, "queue-seconds"); 01828 ast_string_field_set(q, sound_thanks, "queue-thankyou"); 01829 ast_string_field_set(q, sound_reporthold, "queue-reporthold"); 01830 01831 if (!q->sound_periodicannounce[0]) { 01832 q->sound_periodicannounce[0] = ast_str_create(32); 01833 } 01834 01835 if (q->sound_periodicannounce[0]) { 01836 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce"); 01837 } 01838 01839 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 01840 if (q->sound_periodicannounce[i]) 01841 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", ""); 01842 } 01843 01844 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) 01845 ast_free(pr_iter); 01846 }
| 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 1421 of file app_queue.c.
References call_queue::head, and queue_ref().
Referenced by join_queue().
01422 { 01423 struct queue_ent *cur; 01424 01425 if (!q || !new) 01426 return; 01427 if (prev) { 01428 cur = prev->next; 01429 prev->next = new; 01430 } else { 01431 cur = q->head; 01432 q->head = new; 01433 } 01434 new->next = cur; 01435 01436 /* every queue_ent must have a reference to it's parent call_queue, this 01437 * reference does not go away until the end of the queue_ent's life, meaning 01438 * that even when the queue_ent leaves the call_queue this ref must remain. */ 01439 queue_ref(q); 01440 new->parent = q; 01441 new->pos = ++(*pos); 01442 new->opos = *pos; 01443 }
| 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.
| -1 | on failure | |
| 0 | on success |
Definition at line 1877 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, and penalty_rule::time.
Referenced by reload_queue_rules().
01878 { 01879 char *timestr, *maxstr, *minstr, *contentdup; 01880 struct penalty_rule *rule = NULL, *rule_iter; 01881 struct rule_list *rl_iter; 01882 int penaltychangetime, inserted = 0; 01883 01884 if (!(rule = ast_calloc(1, sizeof(*rule)))) { 01885 return -1; 01886 } 01887 01888 contentdup = ast_strdupa(content); 01889 01890 if (!(maxstr = strchr(contentdup, ','))) { 01891 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum); 01892 ast_free(rule); 01893 return -1; 01894 } 01895 01896 *maxstr++ = '\0'; 01897 timestr = contentdup; 01898 01899 if ((penaltychangetime = atoi(timestr)) < 0) { 01900 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum); 01901 ast_free(rule); 01902 return -1; 01903 } 01904 01905 rule->time = penaltychangetime; 01906 01907 if ((minstr = strchr(maxstr,','))) 01908 *minstr++ = '\0'; 01909 01910 /* The last check will evaluate true if either no penalty change is indicated for a given rule 01911 * OR if a min penalty change is indicated but no max penalty change is */ 01912 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') { 01913 rule->max_relative = 1; 01914 } 01915 01916 rule->max_value = atoi(maxstr); 01917 01918 if (!ast_strlen_zero(minstr)) { 01919 if (*minstr == '+' || *minstr == '-') 01920 rule->min_relative = 1; 01921 rule->min_value = atoi(minstr); 01922 } else /*there was no minimum specified, so assume this means no change*/ 01923 rule->min_relative = 1; 01924 01925 /*We have the rule made, now we need to insert it where it belongs*/ 01926 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){ 01927 if (strcasecmp(rl_iter->name, list_name)) 01928 continue; 01929 01930 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) { 01931 if (rule->time < rule_iter->time) { 01932 AST_LIST_INSERT_BEFORE_CURRENT(rule, list); 01933 inserted = 1; 01934 break; 01935 } 01936 } 01937 AST_LIST_TRAVERSE_SAFE_END; 01938 01939 if (!inserted) { 01940 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list); 01941 inserted = 1; 01942 } 01943 01944 break; 01945 } 01946 01947 if (!inserted) { 01948 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name); 01949 ast_free(rule); 01950 return -1; 01951 } 01952 return 0; 01953 }
| static const char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 1259 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().
01260 { 01261 int x; 01262 01263 for (x = 0; x < ARRAY_LEN(strategies); x++) { 01264 if (strategy == strategies[x].strategy) 01265 return strategies[x].name; 01266 } 01267 01268 return "<unknown>"; 01269 }
| static struct member* interface_exists | ( | struct call_queue * | q, | |
| const char * | interface | |||
| ) | [static, read] |
Definition at line 5485 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, member::interface, and call_queue::members.
Referenced by add_to_queue(), get_member_penalty(), set_member_paused(), and set_member_penalty().
05486 { 05487 struct member *mem; 05488 struct ao2_iterator mem_iter; 05489 05490 if (!q) 05491 return NULL; 05492 05493 mem_iter = ao2_iterator_init(q->members, 0); 05494 while ((mem = ao2_iterator_next(&mem_iter))) { 05495 if (!strcasecmp(interface, mem->interface)) { 05496 ao2_iterator_destroy(&mem_iter); 05497 return mem; 05498 } 05499 ao2_ref(mem, -1); 05500 } 05501 ao2_iterator_destroy(&mem_iter); 05502 05503 return NULL; 05504 }
| 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.
| [in] | qe | The caller who wants to know if it is his turn |
| 0 | It is not our turn | |
| 1 | It is our turn |
Definition at line 4185 of file app_queue.c.
References ao2_lock, ao2_unlock, ast_debug, call_queue::autofill, queue_ent::chan, call_queue::head, num_available_members(), queue_ent::parent, queue_ent::pending, and queue_ent::pos.
Referenced by queue_exec(), and wait_our_turn().
04186 { 04187 struct queue_ent *ch; 04188 int res; 04189 int avl; 04190 int idx = 0; 04191 /* This needs a lock. How many members are available to be served? */ 04192 ao2_lock(qe->parent); 04193 04194 avl = num_available_members(qe->parent); 04195 04196 ch = qe->parent->head; 04197 04198 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member"); 04199 04200 while ((idx < avl) && (ch) && (ch != qe)) { 04201 if (!ch->pending) 04202 idx++; 04203 ch = ch->next; 04204 } 04205 04206 ao2_unlock(qe->parent); 04207 /* If the queue entry is within avl [the number of available members] calls from the top ... 04208 * Autofill and position check added to support autofill=no (as only calls 04209 * from the front of the queue are valid when autofill is disabled) 04210 */ 04211 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) { 04212 ast_debug(1, "It's our turn (%s).\n", qe->chan->name); 04213 res = 1; 04214 } else { 04215 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name); 04216 res = 0; 04217 } 04218 04219 return res; 04220 }
| static int join_queue | ( | char * | queuename, | |
| struct queue_ent * | qe, | |||
| enum queue_result * | reason, | |||
| int | position | |||
| ) | [static] |
Definition at line 2601 of file app_queue.c.
References queue_ent::announce, ao2_lock, ao2_unlock, ast_copy_string(), ast_debug, ast_log(), ast_manager_event, ast_channel::caller, queue_ent::chan, ast_channel::connected, queue_ent::context, call_queue::count, EVENT_FLAG_CALL, get_member_status(), call_queue::head, ast_party_connected_line::id, ast_party_caller::id, insert_entry(), call_queue::joinempty, load_realtime_queue(), LOG_NOTICE, queue_ent::max_penalty, call_queue::maxlen, queue_ent::min_penalty, queue_ent::moh, ast_party_id::name, ast_party_id::number, queue_ent::pos, queue_ent::prio, QUEUE_FULL, QUEUE_JOINEMPTY, queue_t_unref, QUEUE_UNKNOWN, S_COR, status, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.
Referenced by queue_exec().
02602 { 02603 struct call_queue *q; 02604 struct queue_ent *cur, *prev = NULL; 02605 int res = -1; 02606 int pos = 0; 02607 int inserted = 0; 02608 02609 if (!(q = load_realtime_queue(queuename))) 02610 return res; 02611 02612 ao2_lock(q); 02613 02614 /* This is our one */ 02615 if (q->joinempty) { 02616 int status = 0; 02617 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty, 0))) { 02618 *reason = QUEUE_JOINEMPTY; 02619 ao2_unlock(q); 02620 queue_t_unref(q, "Done with realtime queue"); 02621 return res; 02622 } 02623 } 02624 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) 02625 *reason = QUEUE_FULL; 02626 else if (*reason == QUEUE_UNKNOWN) { 02627 /* There's space for us, put us at the right position inside 02628 * the queue. 02629 * Take into account the priority of the calling user */ 02630 inserted = 0; 02631 prev = NULL; 02632 cur = q->head; 02633 while (cur) { 02634 /* We have higher priority than the current user, enter 02635 * before him, after all the other users with priority 02636 * higher or equal to our priority. */ 02637 if ((!inserted) && (qe->prio > cur->prio)) { 02638 insert_entry(q, prev, qe, &pos); 02639 inserted = 1; 02640 } 02641 /* <= is necessary for the position comparison because it may not be possible to enter 02642 * at our desired position since higher-priority callers may have taken the position we want 02643 */ 02644 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) { 02645 insert_entry(q, prev, qe, &pos); 02646 inserted = 1; 02647 /*pos is incremented inside insert_entry, so don't need to add 1 here*/ 02648 if (position < pos) { 02649 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos); 02650 } 02651 } 02652 cur->pos = ++pos; 02653 prev = cur; 02654 cur = cur->next; 02655 } 02656 /* No luck, join at the end of the queue */ 02657 if (!inserted) 02658 insert_entry(q, prev, qe, &pos); 02659 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 02660 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 02661 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 02662 q->count++; 02663 res = 0; 02664 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join", 02665 "Channel: %s\r\n" 02666 "CallerIDNum: %s\r\n" 02667 "CallerIDName: %s\r\n" 02668 "ConnectedLineNum: %s\r\n" 02669 "ConnectedLineName: %s\r\n" 02670 "Queue: %s\r\n" 02671 "Position: %d\r\n" 02672 "Count: %d\r\n" 02673 "Uniqueid: %s\r\n", 02674 qe->chan->name, 02675 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */ 02676 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 02677 S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */ 02678 S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), 02679 q->name, qe->pos, q->count, qe->chan->uniqueid ); 02680 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 02681 } 02682 ao2_unlock(q); 02683 queue_t_unref(q, "Done with realtime queue"); 02684 02685 return res; 02686 }
| static int kill_dead_members | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 7017 of file app_queue.c.
References CMP_MATCH, member::delme, get_queue_member_status(), and member::status.
Referenced by reload_single_queue().
| static int kill_dead_queues | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 7161 of file app_queue.c.
References ast_strlen_zero(), CMP_MATCH, and call_queue::dead.
Referenced by reload_queues().
07162 { 07163 struct call_queue *q = obj; 07164 char *queuename = arg; 07165 if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) { 07166 return CMP_MATCH; 07167 } else { 07168 return 0; 07169 } 07170 }
| 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 2913 of file app_queue.c.
References ao2_lock, ao2_unlock, ast_debug, ast_free, AST_LIST_REMOVE_HEAD, ast_load_realtime(), ast_manager_event, ast_variables_destroy(), queue_ent::chan, call_queue::count, call_queue::dead, EVENT_FLAG_CALL, call_queue::head, queue_ent::parent, pbx_builtin_setvar_helper(), queue_ent::pos, queue_t_ref, queue_t_unref, queues, queues_t_unlink, call_queue::realtime, SENTINEL, and var.
Referenced by queue_exec(), try_calling(), and wait_our_turn().
02914 { 02915 struct call_queue *q; 02916 struct queue_ent *current, *prev = NULL; 02917 struct penalty_rule *pr_iter; 02918 int pos = 0; 02919 02920 if (!(q = qe->parent)) 02921 return; 02922 queue_t_ref(q, "Copy queue pointer from queue entry"); 02923 ao2_lock(q); 02924 02925 prev = NULL; 02926 for (current = q->head; current; current = current->next) { 02927 if (current == qe) { 02928 char posstr[20]; 02929 q->count--; 02930 02931 /* Take us out of the queue */ 02932 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave", 02933 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n", 02934 qe->chan->name, q->name, q->count, qe->pos, qe->chan->uniqueid); 02935 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 02936 /* Take us out of the queue */ 02937 if (prev) 02938 prev->next = current->next; 02939 else 02940 q->head = current->next; 02941 /* Free penalty rules */ 02942 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) 02943 ast_free(pr_iter); 02944 snprintf(posstr, sizeof(posstr), "%d", qe->pos); 02945 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr); 02946 } else { 02947 /* Renumber the people after us in the queue based on a new count */ 02948 current->pos = ++pos; 02949 prev = current; 02950 } 02951 } 02952 ao2_unlock(q); 02953 02954 /*If the queue is a realtime queue, check to see if it's still defined in real time*/ 02955 if (q->realtime) { 02956 struct ast_variable *var; 02957 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) { 02958 q->dead = 1; 02959 } else { 02960 ast_variables_destroy(var); 02961 } 02962 } 02963 02964 if (q->dead) { 02965 /* It's dead and nobody is in it, so kill it */ 02966 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container"); 02967 } 02968 /* unref the explicit ref earlier in the function */ 02969 queue_t_unref(q, "Expire copied reference"); 02970 }
| static int load_module | ( | void | ) | [static] |
Definition at line 8838 of file app_queue.c.
References ao2_container_alloc, aqm_exec(), ARRAY_LEN, ast_add_extension2(), ast_cli_register_multiple(), ast_context_find_or_create(), ast_custom_function_register, ast_data_register_multiple, AST_EVENT_DEVICE_STATE, AST_EVENT_IE_END, ast_event_subscribe(), ast_extension_state_add(), AST_FLAGS_ALL, ast_free_ptr(), ast_log(), ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, ast_realtime_require_field(), ast_register_application_xml, ast_strdup, ast_taskprocessor_get(), device_state_cb(), EVENT_FLAG_AGENT, extension_state_cb(), LOG_ERROR, LOG_WARNING, manager_add_queue_member(), manager_pause_queue_member(), manager_queue_log_custom(), manager_queue_member_penalty(), manager_queue_reload(), manager_queue_reset(), manager_queue_rule_show(), manager_queues_show(), manager_queues_status(), manager_queues_summary(), manager_remove_queue_member(), MAX_QUEUE_BUCKETS, pqm_exec(), ql_exec(), queue_cmp_cb(), queue_exec(), queue_hash_cb(), queues, reload_handler(), reload_queue_members(), RQ_INTEGER1, RQ_UINTEGER2, rqm_exec(), SENTINEL, and upqm_exec().
08839 { 08840 int res; 08841 struct ast_context *con; 08842 struct ast_flags mask = {AST_FLAGS_ALL, }; 08843 08844 queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb); 08845 08846 use_weight = 0; 08847 08848 if (reload_handler(0, &mask, NULL)) 08849 return AST_MODULE_LOAD_DECLINE; 08850 08851 con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue"); 08852 if (!con) 08853 ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n"); 08854 else 08855 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue"); 08856 08857 if (queue_persistent_members) 08858 reload_queue_members(); 08859 08860 ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers)); 08861 08862 ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue)); 08863 res = ast_register_application_xml(app, queue_exec); 08864 res |= ast_register_application_xml(app_aqm, aqm_exec); 08865 res |= ast_register_application_xml(app_rqm, rqm_exec); 08866 res |= ast_register_application_xml(app_pqm, pqm_exec); 08867 res |= ast_register_application_xml(app_upqm, upqm_exec); 08868 res |= ast_register_application_xml(app_ql, ql_exec); 08869 res |= ast_manager_register_xml("Queues", 0, manager_queues_show); 08870 res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status); 08871 res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary); 08872 res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member); 08873 res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member); 08874 res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member); 08875 res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom); 08876 res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty); 08877 res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show); 08878 res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload); 08879 res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset); 08880 res |= ast_custom_function_register(&queuevar_function); 08881 res |= ast_custom_function_register(&queueexists_function); 08882 res |= ast_custom_function_register(&queuemembercount_function); 08883 res |= ast_custom_function_register(&queuemembercount_dep); 08884 res |= ast_custom_function_register(&queuememberlist_function); 08885 res |= ast_custom_function_register(&queuewaitingcount_function); 08886 res |= ast_custom_function_register(&queuememberpenalty_function); 08887 08888 if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) { 08889 ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n"); 08890 } 08891 08892 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */ 08893 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) { 08894 res = -1; 08895 } 08896 08897 ast_extension_state_add(NULL, NULL, extension_state_cb, NULL); 08898 08899 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL); 08900 08901 return res ? AST_MODULE_LOAD_DECLINE : 0; 08902 }
| static struct call_queue* load_realtime_queue | ( | const char * | queuename | ) | [static, read] |
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 2474 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(), OBJ_POINTER, queue_t_unref, queues, call_queue::realtime, SENTINEL, update_realtime_members(), and call_queue::weight.
Referenced by __queues_show(), add_to_queue(), join_queue(), queue_function_exists(), queue_function_qac(), queue_function_qac_dep(), queues_data_provider_get(), and reload_queue_members().
02475 { 02476 struct ast_variable *queue_vars; 02477 struct ast_config *member_config = NULL; 02478 struct call_queue *q = NULL, tmpq = { 02479 .name = queuename, 02480 }; 02481 int prev_weight = 0; 02482 02483 /* Find the queue in the in-core list first. */ 02484 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first"); 02485 02486 if (!q || q->realtime) { 02487 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all 02488 queue operations while waiting for the DB. 02489 02490 This will be two separate database transactions, so we might 02491 see queue parameters as they were before another process 02492 changed the queue and member list as it was after the change. 02493 Thus we might see an empty member list when a queue is 02494 deleted. In practise, this is unlikely to cause a problem. */ 02495 02496 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL); 02497 if (queue_vars) { 02498 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL); 02499 if (!member_config) { 02500 ast_debug(1, "No queue_members defined in config extconfig.conf\n"); 02501 member_config = ast_config_new(); 02502 } 02503 } 02504 if (q) { 02505 prev_weight = q->weight ? 1 : 0; 02506 queue_t_unref(q, "Need to find realtime queue"); 02507 } 02508 02509 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 02510 ast_config_destroy(member_config); 02511 ast_variables_destroy(queue_vars); 02512 02513 /* update the use_weight value if the queue's has gained or lost a weight */ 02514 if (q) { 02515 if (!q->weight && prev_weight) { 02516 ast_atomic_fetchadd_int(&use_weight, -1); 02517 } 02518 if (q->weight && !prev_weight) { 02519 ast_atomic_fetchadd_int(&use_weight, +1); 02520 } 02521 } 02522 /* Other cases will end up with the proper value for use_weight */ 02523 } else { 02524 update_realtime_members(q); 02525 } 02526 return q; 02527 }
| static int manager_add_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7799 of file app_queue.c.
References 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().
07800 { 07801 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; 07802 int paused, penalty = 0; 07803 07804 queuename = astman_get_header(m, "Queue"); 07805 interface = astman_get_header(m, "Interface"); 07806 penalty_s = astman_get_header(m, "Penalty"); 07807 paused_s = astman_get_header(m, "Paused"); 07808 membername = astman_get_header(m, "MemberName"); 07809 state_interface = astman_get_header(m, "StateInterface"); 07810 07811 if (ast_strlen_zero(queuename)) { 07812 astman_send_error(s, m, "'Queue' not specified."); 07813 return 0; 07814 } 07815 07816 if (ast_strlen_zero(interface)) { 07817 astman_send_error(s, m, "'Interface' not specified."); 07818 return 0; 07819 } 07820 07821 if (ast_strlen_zero(penalty_s)) 07822 penalty = 0; 07823 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) 07824 penalty = 0; 07825 07826 if (ast_strlen_zero(paused_s)) 07827 paused = 0; 07828 else 07829 paused = abs(ast_true(paused_s)); 07830 07831 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { 07832 case RES_OKAY: 07833 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); 07834 astman_send_ack(s, m, "Added interface to queue"); 07835 break; 07836 case RES_EXISTS: 07837 astman_send_error(s, m, "Unable to add interface: Already there"); 07838 break; 07839 case RES_NOSUCHQUEUE: 07840 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 07841 break; 07842 case RES_OUTOFMEMORY: 07843 astman_send_error(s, m, "Out of memory"); 07844 break; 07845 } 07846 07847 return 0; 07848 }
| static int manager_pause_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7884 of file app_queue.c.
References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), and set_member_paused().
Referenced by load_module().
07885 { 07886 const char *queuename, *interface, *paused_s, *reason; 07887 int paused; 07888 07889 interface = astman_get_header(m, "Interface"); 07890 paused_s = astman_get_header(m, "Paused"); 07891 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 07892 reason = astman_get_header(m, "Reason"); /* Optional - Only used for logging purposes */ 07893 07894 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 07895 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 07896 return 0; 07897 } 07898 07899 paused = abs(ast_true(paused_s)); 07900 07901 if (set_member_paused(queuename, interface, reason, paused)) 07902 astman_send_error(s, m, "Interface not found"); 07903 else 07904 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 07905 return 0; 07906 }
| static int manager_queue_log_custom | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7908 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and S_OR.
Referenced by load_module().
07909 { 07910 const char *queuename, *event, *message, *interface, *uniqueid; 07911 07912 queuename = astman_get_header(m, "Queue"); 07913 uniqueid = astman_get_header(m, "UniqueId"); 07914 interface = astman_get_header(m, "Interface"); 07915 event = astman_get_header(m, "Event"); 07916 message = astman_get_header(m, "Message"); 07917 07918 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) { 07919 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters."); 07920 return 0; 07921 } 07922 07923 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message); 07924 astman_send_ack(s, m, "Event added successfully"); 07925 07926 return 0; 07927 }
| static int manager_queue_member_penalty | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 8007 of file app_queue.c.
References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and set_member_penalty().
Referenced by load_module().
08008 { 08009 const char *queuename, *interface, *penalty_s; 08010 int penalty; 08011 08012 interface = astman_get_header(m, "Interface"); 08013 penalty_s = astman_get_header(m, "Penalty"); 08014 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */ 08015 queuename = astman_get_header(m, "Queue"); 08016 08017 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) { 08018 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters."); 08019 return 0; 08020 } 08021 08022 penalty = atoi(penalty_s); 08023 08024 if (set_member_penalty((char *)queuename, (char *)interface, penalty)) 08025 astman_send_error(s, m, "Invalid interface, queuename or penalty"); 08026 else 08027 astman_send_ack(s, m, "Interface penalty set successfully"); 08028 08029 return 0; 08030 }
| static int manager_queue_reload | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7929 of file app_queue.c.
References AST_FLAGS_ALL, ast_set_flag, astman_get_header(), astman_send_ack(), astman_send_error(), QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, reload_handler(), and S_OR.
Referenced by load_module().
07930 { 07931 struct ast_flags mask = {0,}; 07932 const char *queuename = NULL; 07933 int header_found = 0; 07934 07935 queuename = astman_get_header(m, "Queue"); 07936 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) { 07937 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER); 07938 header_found = 1; 07939 } 07940 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) { 07941 ast_set_flag(&mask, QUEUE_RELOAD_RULES); 07942 header_found = 1; 07943 } 07944 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) { 07945 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); 07946 header_found = 1; 07947 } 07948 07949 if (!header_found) { 07950 ast_set_flag(&mask, AST_FLAGS_ALL); 07951 } 07952 07953 if (!reload_handler(1, &mask, queuename)) { 07954 astman_send_ack(s, m, "Queue reloaded successfully"); 07955 } else { 07956 astman_send_error(s, m, "Error encountered while reloading queue"); 07957 } 07958 return 0; 07959 }
| static int manager_queue_reset | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7961 of file app_queue.c.
References astman_get_header(), astman_send_ack(), astman_send_error(), QUEUE_RESET_STATS, and reload_handler().
Referenced by load_module().
07962 { 07963 const char *queuename = NULL; 07964 struct ast_flags mask = {QUEUE_RESET_STATS,}; 07965 07966 queuename = astman_get_header(m, "Queue"); 07967 07968 if (!reload_handler(1, &mask, queuename)) { 07969 astman_send_ack(s, m, "Queue stats reset successfully"); 07970 } else { 07971 astman_send_error(s, m, "Error encountered while resetting queue stats"); 07972 } 07973 return 0; 07974 }
| static int manager_queue_rule_show | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7588 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, and penalty_rule::time.
Referenced by load_module().
07589 { 07590 const char *rule = astman_get_header(m, "Rule"); 07591 const char *id = astman_get_header(m, "ActionID"); 07592 struct rule_list *rl_iter; 07593 struct penalty_rule *pr_iter; 07594 07595 astman_append(s, "Response: Success\r\n"); 07596 if (!ast_strlen_zero(id)) { 07597 astman_append(s, "ActionID: %s\r\n", id); 07598 } 07599 07600 AST_LIST_LOCK(&rule_lists); 07601 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 07602 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) { 07603 astman_append(s, "RuleList: %s\r\n", rl_iter->name); 07604 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 07605 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 ); 07606 } 07607 if (!ast_strlen_zero(rule)) 07608 break; 07609 } 07610 } 07611 AST_LIST_UNLOCK(&rule_lists); 07612 07613 /* 07614 * Two blank lines instead of one because the Response and 07615 * ActionID headers used to not be present. 07616 */ 07617 astman_append(s, "\r\n\r\n"); 07618 07619 return RESULT_SUCCESS; 07620 }
| static int manager_queues_show | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7578 of file app_queue.c.
References __queues_show(), astman_append(), and RESULT_SUCCESS.
Referenced by load_module().
07579 { 07580 static const char * const a[] = { "queue", "show" }; 07581 07582 __queues_show(s, -1, 2, a); 07583 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 07584 07585 return RESULT_SUCCESS; 07586 }
| static int manager_queues_status | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Queue status info via AMI.
Definition at line 7698 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_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), ast_channel::caller, member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, ast_channel::connected, 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, 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::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().
07699 { 07700 time_t now; 07701 int pos; 07702 const char *id = astman_get_header(m,"ActionID"); 07703 const char *queuefilter = astman_get_header(m,"Queue"); 07704 const char *memberfilter = astman_get_header(m,"Member"); 07705 char idText[256] = ""; 07706 struct call_queue *q; 07707 struct queue_ent *qe; 07708 float sl = 0; 07709 struct member *mem; 07710 struct ao2_iterator queue_iter; 07711 struct ao2_iterator mem_iter; 07712 07713 astman_send_ack(s, m, "Queue status will follow"); 07714 time(&now); 07715 if (!ast_strlen_zero(id)) 07716 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 07717 07718 queue_iter = ao2_iterator_init(queues, 0); 07719 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07720 ao2_lock(q); 07721 07722 /* List queue properties */ 07723 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 07724 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 07725 astman_append(s, "Event: QueueParams\r\n" 07726 "Queue: %s\r\n" 07727 "Max: %d\r\n" 07728 "Strategy: %s\r\n" 07729 "Calls: %d\r\n" 07730 "Holdtime: %d\r\n" 07731 "TalkTime: %d\r\n" 07732 "Completed: %d\r\n" 07733 "Abandoned: %d\r\n" 07734 "ServiceLevel: %d\r\n" 07735 "ServicelevelPerf: %2.1f\r\n" 07736 "Weight: %d\r\n" 07737 "%s" 07738 "\r\n", 07739 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, 07740 q->callsabandoned, q->servicelevel, sl, q->weight, idText); 07741 /* List Queue Members */ 07742 mem_iter = ao2_iterator_init(q->members, 0); 07743 while ((mem = ao2_iterator_next(&mem_iter))) { 07744 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) { 07745 astman_append(s, "Event: QueueMember\r\n" 07746 "Queue: %s\r\n" 07747 "Name: %s\r\n" 07748 "Location: %s\r\n" 07749 "Membership: %s\r\n" 07750 "Penalty: %d\r\n" 07751 "CallsTaken: %d\r\n" 07752 "LastCall: %d\r\n" 07753 "Status: %d\r\n" 07754 "Paused: %d\r\n" 07755 "%s" 07756 "\r\n", 07757 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static", 07758 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 07759 } 07760 ao2_ref(mem, -1); 07761 } 07762 ao2_iterator_destroy(&mem_iter); 07763 /* List Queue Entries */ 07764 pos = 1; 07765 for (qe = q->head; qe; qe = qe->next) { 07766 astman_append(s, "Event: QueueEntry\r\n" 07767 "Queue: %s\r\n" 07768 "Position: %d\r\n" 07769 "Channel: %s\r\n" 07770 "Uniqueid: %s\r\n" 07771 "CallerIDNum: %s\r\n" 07772 "CallerIDName: %s\r\n" 07773 "ConnectedLineNum: %s\r\n" 07774 "ConnectedLineName: %s\r\n" 07775 "Wait: %ld\r\n" 07776 "%s" 07777 "\r\n", 07778 q->name, pos++, qe->chan->name, qe->chan->uniqueid, 07779 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"), 07780 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 07781 S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"), 07782 S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), 07783 (long) (now - qe->start), idText); 07784 } 07785 } 07786 ao2_unlock(q); 07787 queue_t_unref(q, "Done with iterator"); 07788 } 07789 ao2_iterator_destroy(&queue_iter); 07790 07791 astman_append(s, 07792 "Event: QueueStatusComplete\r\n" 07793 "%s" 07794 "\r\n",idText); 07795 07796 return RESULT_SUCCESS; 07797 }
| static int manager_queues_summary | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Summary of queue info via the AMI.
Definition at line 7623 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_ack(), call_queue::head, call_queue::holdtime, member_status_available(), call_queue::members, member::paused, queue_t_unref, queues, RESULT_SUCCESS, queue_ent::start, member::status, and call_queue::talktime.
Referenced by load_module().
07624 { 07625 time_t now; 07626 int qmemcount = 0; 07627 int qmemavail = 0; 07628 int qchancount = 0; 07629 int qlongestholdtime = 0; 07630 const char *id = astman_get_header(m, "ActionID"); 07631 const char *queuefilter = astman_get_header(m, "Queue"); 07632 char idText[256] = ""; 07633 struct call_queue *q; 07634 struct queue_ent *qe; 07635 struct member *mem; 07636 struct ao2_iterator queue_iter; 07637 struct ao2_iterator mem_iter; 07638 07639 astman_send_ack(s, m, "Queue summary will follow"); 07640 time(&now); 07641 if (!ast_strlen_zero(id)) 07642 snprintf(idText, 256, "ActionID: %s\r\n", id); 07643 queue_iter = ao2_iterator_init(queues, 0); 07644 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07645 ao2_lock(q); 07646 07647 /* List queue properties */ 07648 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 07649 /* Reset the necessary local variables if no queuefilter is set*/ 07650 qmemcount = 0; 07651 qmemavail = 0; 07652 qchancount = 0; 07653 qlongestholdtime = 0; 07654 07655 /* List Queue Members */ 07656 mem_iter = ao2_iterator_init(q->members, 0); 07657 while ((mem = ao2_iterator_next(&mem_iter))) { 07658 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) { 07659 ++qmemcount; 07660 if (member_status_available(mem->status) && !mem->paused) { 07661 ++qmemavail; 07662 } 07663 } 07664 ao2_ref(mem, -1); 07665 } 07666 ao2_iterator_destroy(&mem_iter); 07667 for (qe = q->head; qe; qe = qe->next) { 07668 if ((now - qe->start) > qlongestholdtime) { 07669 qlongestholdtime = now - qe->start; 07670 } 07671 ++qchancount; 07672 } 07673 astman_append(s, "Event: QueueSummary\r\n" 07674 "Queue: %s\r\n" 07675 "LoggedIn: %d\r\n" 07676 "Available: %d\r\n" 07677 "Callers: %d\r\n" 07678 "HoldTime: %d\r\n" 07679 "TalkTime: %d\r\n" 07680 "LongestHoldTime: %d\r\n" 07681 "%s" 07682 "\r\n", 07683 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText); 07684 } 07685 ao2_unlock(q); 07686 queue_t_unref(q, "Done with iterator"); 07687 } 07688 ao2_iterator_destroy(&queue_iter); 07689 astman_append(s, 07690 "Event: QueueSummaryComplete\r\n" 07691 "%s" 07692 "\r\n", idText); 07693 07694 return RESULT_SUCCESS; 07695 }
| static int manager_remove_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7850 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and RES_OUTOFMEMORY.
Referenced by load_module().
07851 { 07852 const char *queuename, *interface; 07853 07854 queuename = astman_get_header(m, "Queue"); 07855 interface = astman_get_header(m, "Interface"); 07856 07857 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 07858 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 07859 return 0; 07860 } 07861 07862 switch (remove_from_queue(queuename, interface)) { 07863 case RES_OKAY: 07864 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 07865 astman_send_ack(s, m, "Removed interface from queue"); 07866 break; 07867 case RES_EXISTS: 07868 astman_send_error(s, m, "Unable to remove interface: Not there"); 07869 break; 07870 case RES_NOSUCHQUEUE: 07871 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 07872 break; 07873 case RES_OUTOFMEMORY: 07874 astman_send_error(s, m, "Out of memory"); 07875 break; 07876 case RES_NOT_DYNAMIC: 07877 astman_send_error(s, m, "Member not dynamic"); 07878 break; 07879 } 07880 07881 return 0; 07882 }
| static int mark_dead_and_unfound | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 7150 of file app_queue.c.
References ast_strlen_zero(), call_queue::dead, call_queue::found, and call_queue::realtime.
Referenced by reload_queues().
07151 { 07152 struct call_queue *q = obj; 07153 char *queuename = arg; 07154 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) { 07155 q->dead = 1; 07156 q->found = 0; 07157 } 07158 return 0; 07159 }
| static int mark_member_dead | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 7008 of file app_queue.c.
References member::delme, member::dynamic, and member::realtime.
Referenced by reload_single_queue().
| static void member_add_to_queue | ( | struct call_queue * | queue, | |
| struct member * | mem | |||
| ) | [static] |
Definition at line 2201 of file app_queue.c.
References ao2_container_count(), ao2_link, ao2_lock, ao2_unlock, call_queue::members, and member::queuepos.
Referenced by add_to_queue(), reload_single_member(), and rt_handle_member_record().
02202 { 02203 ao2_lock(queue->members); 02204 mem->queuepos = ao2_container_count(queue->members); 02205 ao2_link(queue->members, mem); 02206 ao2_unlock(queue->members); 02207 }
| static void member_call_pending_clear | ( | struct member * | mem | ) | [static] |
Definition at line 3162 of file app_queue.c.
References ao2_lock, ao2_unlock, and member::call_pending.
Referenced by can_ring_entry(), and ring_entry().
03163 { 03164 ao2_lock(mem); 03165 mem->call_pending = 0; 03166 ao2_unlock(mem); 03167 }
| static int member_call_pending_set | ( | struct member * | mem | ) | [static] |
Definition at line 3177 of file app_queue.c.
References ao2_lock, ao2_unlock, and member::call_pending.
Referenced by can_ring_entry().
03178 { 03179 int old_pending; 03180 03181 ao2_lock(mem); 03182 old_pending = mem->call_pending; 03183 mem->call_pending = 1; 03184 ao2_unlock(mem); 03185 03186 return old_pending; 03187 }
| static int member_cmp_fn | ( | void * | obj1, | |
| void * | obj2, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1761 of file app_queue.c.
References CMP_MATCH, CMP_STOP, and member::interface.
Referenced by init_queue().
| static int member_hash_fn | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 1749 of file app_queue.c.
References compress_char(), and member::interface.
Referenced by init_queue().
01750 { 01751 const struct member *mem = obj; 01752 const char *chname = strchr(mem->interface, '/'); 01753 int ret = 0, i; 01754 if (!chname) 01755 chname = mem->interface; 01756 for (i = 0; i < 5 && chname[i]; i++) 01757 ret += compress_char(chname[i]) << (i * 6); 01758 return ret; 01759 }
| static void member_remove_from_queue | ( | struct call_queue * | queue, | |
| struct member * | mem | |||
| ) | [static] |
Definition at line 2215 of file app_queue.c.
References ao2_lock, ao2_unlink, ao2_unlock, call_queue::members, and queue_member_follower_removal().
Referenced by find_queue_by_name_rt(), free_members(), remove_from_queue(), and update_realtime_members().
02216 { 02217 ao2_lock(queue->members); 02218 queue_member_follower_removal(queue, mem); 02219 ao2_unlink(queue->members, mem); 02220 ao2_unlock(queue->members); 02221 }
| static int member_status_available | ( | int | status | ) | [static] |
Definition at line 3149 of file app_queue.c.
References AST_DEVICE_NOT_INUSE, and AST_DEVICE_UNKNOWN.
Referenced by can_ring_entry(), and manager_queues_summary().
03150 { 03151 return status == AST_DEVICE_NOT_INUSE || status == AST_DEVICE_UNKNOWN; 03152 }
| static int num_available_members | ( | struct call_queue * | q | ) | [static] |
Get the number of members available to accept a call.
| [in] | q | The queue for which we are couting the number of available members |
Definition at line 3018 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, call_queue::autofill, call_queue::members, member::paused, QUEUE_STRATEGY_RINGALL, call_queue::ringinuse, member::status, and call_queue::strategy.
Referenced by compare_weight(), and is_our_turn().
03019 { 03020 struct member *mem; 03021 int avl = 0; 03022 struct ao2_iterator mem_iter; 03023 03024 mem_iter = ao2_iterator_init(q->members, 0); 03025 while ((mem = ao2_iterator_next(&mem_iter))) { 03026 switch (mem->status) { 03027 case AST_DEVICE_INUSE: 03028 if (!q->ringinuse) 03029 break; 03030 /* else fall through */ 03031 case AST_DEVICE_NOT_INUSE: 03032 case AST_DEVICE_UNKNOWN: 03033 if (!mem->paused) { 03034 avl++; 03035 } 03036 break; 03037 } 03038 ao2_ref(mem, -1); 03039 03040 /* If autofill is not enabled or if the queue's strategy is ringall, then 03041 * we really don't care about the number of available members so much as we 03042 * do that there is at least one available. 03043 * 03044 * In fact, we purposely will return from this function stating that only 03045 * one member is available if either of those conditions hold. That way, 03046 * functions which determine what action to take based on the number of available 03047 * members will operate properly. The reasoning is that even if multiple 03048 * members are available, only the head caller can actually be serviced. 03049 */ 03050 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) { 03051 break; 03052 } 03053 } 03054 ao2_iterator_destroy(&mem_iter); 03055 03056 return avl; 03057 }
| static void parse_empty_options | ( | const char * | value, | |
| enum empty_conditions * | empty, | |||
| int | joinempty | |||
| ) | [static] |
Definition at line 1955 of file app_queue.c.
References ast_false(), ast_log(), ast_strdupa, ast_true(), LOG_WARNING, QUEUE_EMPTY_INUSE, QUEUE_EMPTY_INVALID, QUEUE_EMPTY_PAUSED, QUEUE_EMPTY_PENALTY, QUEUE_EMPTY_RINGING, QUEUE_EMPTY_UNAVAILABLE, QUEUE_EMPTY_UNKNOWN, and QUEUE_EMPTY_WRAPUP.
Referenced by queue_set_param().
01956 { 01957 char *value_copy = ast_strdupa(value); 01958 char *option = NULL; 01959 while ((option = strsep(&value_copy, ","))) { 01960 if (!strcasecmp(option, "paused")) { 01961 *empty |= QUEUE_EMPTY_PAUSED; 01962 } else if (!strcasecmp(option, "penalty")) { 01963 *empty |= QUEUE_EMPTY_PENALTY; 01964 } else if (!strcasecmp(option, "inuse")) { 01965 *empty |= QUEUE_EMPTY_INUSE; 01966 } else if (!strcasecmp(option, "ringing")) { 01967 *empty |= QUEUE_EMPTY_RINGING; 01968 } else if (!strcasecmp(option, "invalid")) { 01969 *empty |= QUEUE_EMPTY_INVALID; 01970 } else if (!strcasecmp(option, "wrapup")) { 01971 *empty |= QUEUE_EMPTY_WRAPUP; 01972 } else if (!strcasecmp(option, "unavailable")) { 01973 *empty |= QUEUE_EMPTY_UNAVAILABLE; 01974 } else if (!strcasecmp(option, "unknown")) { 01975 *empty |= QUEUE_EMPTY_UNKNOWN; 01976 } else if (!strcasecmp(option, "loose")) { 01977 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID); 01978 } else if (!strcasecmp(option, "strict")) { 01979 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE); 01980 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) { 01981 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED); 01982 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) { 01983 *empty = 0; 01984 } else { 01985 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty"); 01986 } 01987 } 01988 }
| static int play_file | ( | struct ast_channel * | chan, | |
| const char * | filename | |||
| ) | [static] |
Definition at line 2688 of file app_queue.c.
References AST_DIGIT_ANY, ast_fileexists(), ast_stopstream(), ast_streamfile(), ast_strlen_zero(), and ast_waitstream().
Referenced by say_periodic_announcement(), say_position(), and try_calling().
02689 { 02690 int res; 02691 02692 if (ast_strlen_zero(filename)) { 02693 return 0; 02694 } 02695 02696 if (!ast_fileexists(filename, NULL, chan->language)) { 02697 return 0; 02698 } 02699 02700 ast_stopstream(chan); 02701 02702 res = ast_streamfile(chan, filename, chan->language); 02703 if (!res) 02704 res = ast_waitstream(chan, AST_DIGIT_ANY); 02705 02706 ast_stopstream(chan); 02707 02708 return res; 02709 }
| static int pqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
PauseQueueMember application.
Definition at line 5915 of file app_queue.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, parse(), pbx_builtin_setvar_helper(), and set_member_paused().
Referenced by load_module().
05916 { 05917 char *parse; 05918 AST_DECLARE_APP_ARGS(args, 05919 AST_APP_ARG(queuename); 05920 AST_APP_ARG(interface); 05921 AST_APP_ARG(options); 05922 AST_APP_ARG(reason); 05923 ); 05924 05925 if (ast_strlen_zero(data)) { 05926 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n"); 05927 return -1; 05928 } 05929 05930 parse = ast_strdupa(data); 05931 05932 AST_STANDARD_APP_ARGS(args, parse); 05933 05934 if (ast_strlen_zero(args.interface)) { 05935 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 05936 return -1; 05937 } 05938 05939 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) { 05940 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 05941 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 05942 return 0; 05943 } 05944 05945 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 05946 05947 return 0; 05948 }
| static int ql_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
QueueLog application.
Definition at line 6106 of file app_queue.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, and parse().
Referenced by load_module().
06107 { 06108 char *parse; 06109 06110 AST_DECLARE_APP_ARGS(args, 06111 AST_APP_ARG(queuename); 06112 AST_APP_ARG(uniqueid); 06113 AST_APP_ARG(membername); 06114 AST_APP_ARG(event); 06115 AST_APP_ARG(params); 06116 ); 06117 06118 if (ast_strlen_zero(data)) { 06119 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n"); 06120 return -1; 06121 } 06122 06123 parse = ast_strdupa(data); 06124 06125 AST_STANDARD_APP_ARGS(args, parse); 06126 06127 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 06128 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 06129 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n"); 06130 return -1; 06131 } 06132 06133 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 06134 "%s", args.params ? args.params : ""); 06135 06136 return 0; 06137 }
| static int queue_cmp_cb | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1310 of file app_queue.c.
References CMP_MATCH, and CMP_STOP.
Referenced by load_module().
01311 { 01312 struct call_queue *q = obj, *q2 = arg; 01313 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0; 01314 }
| static int queue_delme_members_decrement_followers | ( | void * | obj, | |
| void * | arg, | |||
| int | flag | |||
| ) | [static] |
Definition at line 1339 of file app_queue.c.
References ao2_callback, member::delme, call_queue::members, OBJ_MULTIPLE, OBJ_NODATA, queue_member_decrement_followers(), member::queuepos, and call_queue::rrpos.
Referenced by reload_single_queue().
01340 { 01341 struct member *mem = obj; 01342 struct call_queue *queue = arg; 01343 int rrpos = mem->queuepos; 01344 01345 if (mem->delme) { 01346 ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &rrpos); 01347 } 01348 01349 return 0; 01350 }
| static int queue_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
The starting point for all queue calls.
The process involved here is to 1. Parse the options specified in the call to Queue() 2. Join the queue 3. Wait in a loop until it is our turn to try calling a queue member 4. Attempt to call a queue member 5. If 4. did not result in a bridged call, then check for between call options such as periodic announcements etc. 6. Try 4 again unless some condition (such as an expiration time) causes us to exit the queue.
Definition at line 6180 of file app_queue.c.
References call_queue::announcefrequency, ao2_container_count(), args, AST_APP_ARG, ast_assert, ast_channel_lock, ast_channel_unlock, AST_CONTROL_RINGING, ast_debug, AST_DECLARE_APP_ARGS, ast_indicate(), AST_LIST_FIRST, ast_log(), ast_moh_start(), ast_moh_stop(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::caller, queue_ent::chan, copy_rules(), queue_ent::digits, queue_ent::expire, get_member_status(), queue_ent::handled, ast_party_caller::id, is_our_turn(), join_queue(), queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::last_pos, queue_ent::last_pos_said, leave_queue(), call_queue::leavewhenempty, LOG_WARNING, queue_ent::max_penalty, call_queue::members, queue_ent::min_penalty, queue_ent::moh, ast_party_id::number, queue_ent::opos, queue_ent::parent, parse(), pbx_builtin_getvar_helper(), call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::prio, QUEUE_CONTINUE, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, QUEUE_UNKNOWN, queue_unref(), record_abandoned(), queue_ent::ring_when_ringing, S_COR, S_OR, say_periodic_announcement(), say_position(), set_queue_result(), set_queue_variables(), queue_ent::start, status, stop, ast_party_number::str, try_calling(), update_qe_rule(), update_realtime_members(), url, ast_party_number::valid, queue_ent::valid_digits, wait_a_bit(), and wait_our_turn().
Referenced by load_module().
06181 { 06182 int res=-1; 06183 int ringing=0; 06184 const char *user_priority; 06185 const char *max_penalty_str; 06186 const char *min_penalty_str; 06187 int prio; 06188 int qcontinue = 0; 06189 int max_penalty, min_penalty; 06190 enum queue_result reason = QUEUE_UNKNOWN; 06191 /* whether to exit Queue application after the timeout hits */ 06192 int tries = 0; 06193 int noption = 0; 06194 char *parse; 06195 int makeannouncement = 0; 06196 int position = 0; 06197 AST_DECLARE_APP_ARGS(args, 06198 AST_APP_ARG(queuename); 06199 AST_APP_ARG(options); 06200 AST_APP_ARG(url); 06201 AST_APP_ARG(announceoverride); 06202 AST_APP_ARG(queuetimeoutstr); 06203 AST_APP_ARG(agi); 06204 AST_APP_ARG(macro); 06205 AST_APP_ARG(gosub); 06206 AST_APP_ARG(rule); 06207 AST_APP_ARG(position); 06208 ); 06209 /* Our queue entry */ 06210 struct queue_ent qe = { 0 }; 06211 06212 if (ast_strlen_zero(data)) { 06213 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n"); 06214 return -1; 06215 } 06216 06217 parse = ast_strdupa(data); 06218 AST_STANDARD_APP_ARGS(args, parse); 06219 06220 /* Setup our queue entry */ 06221 qe.start = time(NULL); 06222 06223 /* set the expire time based on the supplied timeout; */ 06224 if (!ast_strlen_zero(args.queuetimeoutstr)) 06225 qe.expire = qe.start + atoi(args.queuetimeoutstr); 06226 else 06227 qe.expire = 0; 06228 06229 /* Get the priority from the variable ${QUEUE_PRIO} */ 06230 ast_channel_lock(chan); 06231 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 06232 if (user_priority) { 06233 if (sscanf(user_priority, "%30d", &prio) == 1) { 06234 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio); 06235 } else { 06236 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 06237 user_priority, chan->name); 06238 prio = 0; 06239 } 06240 } else { 06241 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n"); 06242 prio = 0; 06243 } 06244 06245 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 06246 06247 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 06248 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) { 06249 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty); 06250 } else { 06251 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 06252 max_penalty_str, chan->name); 06253 max_penalty = INT_MAX; 06254 } 06255 } else { 06256 max_penalty = INT_MAX; 06257 } 06258 06259 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) { 06260 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) { 06261 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty); 06262 } else { 06263 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n", 06264 min_penalty_str, chan->name); 06265 min_penalty = INT_MAX; 06266 } 06267 } else { 06268 min_penalty = INT_MAX; 06269 } 06270 ast_channel_unlock(chan); 06271 06272 if (args.options && (strchr(args.options, 'r'))) 06273 ringing = 1; 06274 06275 if (ringing != 1 && args.options && (strchr(args.options, 'R'))) { 06276 qe.ring_when_ringing = 1; 06277 } 06278 06279 if (args.options && (strchr(args.options, 'c'))) 06280 qcontinue = 1; 06281 06282 if (args.position) { 06283 position = atoi(args.position); 06284 if (position < 0) { 06285 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename); 06286 position = 0; 06287 } 06288 } 06289 06290 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 06291 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 06292 06293 qe.chan = chan; 06294 qe.prio = prio; 06295 qe.max_penalty = max_penalty; 06296 qe.min_penalty = min_penalty; 06297 qe.last_pos_said = 0; 06298 qe.last_pos = 0; 06299 qe.last_periodic_announce_time = time(NULL); 06300 qe.last_periodic_announce_sound = 0; 06301 qe.valid_digits = 0; 06302 if (join_queue(args.queuename, &qe, &reason, position)) { 06303 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 06304 set_queue_result(chan, reason); 06305 return 0; 06306 } 06307 ast_assert(qe.parent != NULL); 06308 06309 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d", 06310 S_OR(args.url, ""), 06311 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""), 06312 qe.opos); 06313 copy_rules(&qe, args.rule); 06314 qe.pr = AST_LIST_FIRST(&qe.qe_rules); 06315 check_turns: 06316 if (ringing) { 06317 ast_indicate(chan, AST_CONTROL_RINGING); 06318 } else { 06319 ast_moh_start(chan, qe.moh, NULL); 06320 } 06321 06322 /* This is the wait loop for callers 2 through maxlen */ 06323 res = wait_our_turn(&qe, ringing, &reason); 06324 if (res) { 06325 goto stop; 06326 } 06327 06328 makeannouncement = 0; 06329 06330 for (;;) { 06331 /* This is the wait loop for the head caller*/ 06332 /* To exit, they may get their call answered; */ 06333 /* they may dial a digit from the queue context; */ 06334 /* or, they may timeout. */ 06335 06336 /* Leave if we have exceeded our queuetimeout */ 06337 if (qe.expire && (time(NULL) >= qe.expire)) { 06338 record_abandoned(&qe); 06339 reason = QUEUE_TIMEOUT; 06340 res = 0; 06341 ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 06342 qe.pos, qe.opos, (long) time(NULL) - qe.start); 06343 break; 06344 } 06345 06346 if (makeannouncement) { 06347 /* Make a position announcement, if enabled */ 06348 if (qe.parent->announcefrequency) 06349 if ((res = say_position(&qe,ringing))) 06350 goto stop; 06351 } 06352 makeannouncement = 1; 06353 06354 /* Make a periodic announcement, if enabled */ 06355 if (qe.parent->periodicannouncefrequency) 06356 if ((res = say_periodic_announcement(&qe,ringing))) 06357 goto stop; 06358 06359 /* Leave if we have exceeded our queuetimeout */ 06360 if (qe.expire && (time(NULL) >= qe.expire)) { 06361 record_abandoned(&qe); 06362 reason = QUEUE_TIMEOUT; 06363 res = 0; 06364 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 06365 break; 06366 } 06367 06368 /* see if we need to move to the next penalty level for this queue */ 06369 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) { 06370 update_qe_rule(&qe); 06371 } 06372 06373 /* Try calling all queue members for 'timeout' seconds */ 06374 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing); 06375 if (res) { 06376 goto stop; 06377 } 06378 06379 if (qe.parent->leavewhenempty) { 06380 int status = 0; 06381 if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty, 0))) { 06382 record_abandoned(&qe); 06383 reason = QUEUE_LEAVEEMPTY; 06384 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 06385 res = 0; 06386 break; 06387 } 06388 } 06389 06390 /* exit after 'timeout' cycle if 'n' option enabled */ 06391 if (noption && tries >= ao2_container_count(qe.parent->members)) { 06392 ast_verb(3, "Exiting on time-out cycle\n"); 06393 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 06394 record_abandoned(&qe); 06395 reason = QUEUE_TIMEOUT; 06396 res = 0; 06397 break; 06398 } 06399 06400 06401 /* Leave if we have exceeded our queuetimeout */ 06402 if (qe.expire && (time(NULL) >= qe.expire)) { 06403 record_abandoned(&qe); 06404 reason = QUEUE_TIMEOUT; 06405 res = 0; 06406 ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start); 06407 break; 06408 } 06409 06410 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 06411 update_realtime_members(qe.parent); 06412 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 06413 res = wait_a_bit(&qe); 06414 if (res) 06415 goto stop; 06416 06417 /* Since this is a priority queue and 06418 * it is not sure that we are still at the head 06419 * of the queue, go and check for our turn again. 06420 */ 06421 if (!is_our_turn(&qe)) { 06422 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name); 06423 goto check_turns; 06424 } 06425 } 06426 06427 stop: 06428 if (res) { 06429 if (res < 0) { 06430 if (!qe.handled) { 06431 record_abandoned(&qe); 06432 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 06433 "%d|%d|%ld", qe.pos, qe.opos, 06434 (long) time(NULL) - qe.start); 06435 res = -1; 06436 } else if (qcontinue) { 06437 reason = QUEUE_CONTINUE; 06438 res = 0; 06439 } 06440 } else if (qe.valid_digits) { 06441 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 06442 "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) time(NULL) - qe.start); 06443 } 06444 } 06445 06446 /* Don't allow return code > 0 */ 06447 if (res >= 0) { 06448 res = 0; 06449 if (ringing) { 06450 ast_indicate(chan, -1); 06451 } else { 06452 ast_moh_stop(chan); 06453 } 06454 ast_stopstream(chan); 06455 } 06456 06457 set_queue_variables(qe.parent, qe.chan); 06458 06459 leave_queue(&qe); 06460 if (reason != QUEUE_UNKNOWN) 06461 set_queue_result(chan, reason); 06462 06463 /* 06464 * every queue_ent is given a reference to it's parent 06465 * call_queue when it joins the queue. This ref must be taken 06466 * away right before the queue_ent is destroyed. In this case 06467 * the queue_ent is about to be returned on the stack 06468 */ 06469 qe.parent = queue_unref(qe.parent); 06470 06471 return res; 06472 }
| static int queue_function_exists | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Check if a given queue exists.
Definition at line 6526 of file app_queue.c.
References ast_log(), ast_strlen_zero(), load_realtime_queue(), LOG_ERROR, and queue_t_unref.
06527 { 06528 struct call_queue *q; 06529 06530 buf[0] = '\0'; 06531 06532 if (ast_strlen_zero(data)) { 06533 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06534 return -1; 06535 } 06536 q = load_realtime_queue(data); 06537 snprintf(buf, len, "%d", q != NULL? 1 : 0); 06538 if (q) { 06539 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()"); 06540 } 06541 06542 return 0; 06543 }
| static int queue_function_memberpenalty_read | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.
Definition at line 6745 of file app_queue.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), get_member_penalty(), and LOG_ERROR.
06746 { 06747 int penalty; 06748 AST_DECLARE_APP_ARGS(args, 06749 AST_APP_ARG(queuename); 06750 AST_APP_ARG(interface); 06751 ); 06752 /* Make sure the returned value on error is NULL. */ 06753 buf[0] = '\0'; 06754 06755 if (ast_strlen_zero(data)) { 06756 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06757 return -1; 06758 } 06759 06760 AST_STANDARD_APP_ARGS(args, data); 06761 06762 if (args.argc < 2) { 06763 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06764 return -1; 06765 } 06766 06767 penalty = get_member_penalty (args.queuename, args.interface); 06768 06769 if (penalty >= 0) /* remember that buf is already '\0' */ 06770 snprintf (buf, len, "%d", penalty); 06771 06772 return 0; 06773 }
| static int queue_function_memberpenalty_write | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| const char * | value | |||
| ) | [static] |
Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.
Definition at line 6776 of file app_queue.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), LOG_ERROR, and set_member_penalty().
06777 { 06778 int penalty; 06779 AST_DECLARE_APP_ARGS(args, 06780 AST_APP_ARG(queuename); 06781 AST_APP_ARG(interface); 06782 ); 06783 06784 if (ast_strlen_zero(data)) { 06785 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06786 return -1; 06787 } 06788 06789 AST_STANDARD_APP_ARGS(args, data); 06790 06791 if (args.argc < 2) { 06792 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06793 return -1; 06794 } 06795 06796 penalty = atoi(value); 06797 06798 if (ast_strlen_zero(args.interface)) { 06799 ast_log (LOG_ERROR, "<interface> parameter can't be null\n"); 06800 return -1; 06801 } 06802 06803 /* if queuename = NULL then penalty will be set for interface in all the queues. */ 06804 if (set_member_penalty(args.queuename, args.interface, penalty)) { 06805 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); 06806 return -1; 06807 } 06808 06809 return 0; 06810 }
| static int queue_function_qac | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Get number either busy / free / ready or total members of a specific queue.
| number | of members (busy / free / ready / total) | |
| -1 | on error |
Definition at line 6550 of file app_queue.c.
References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_log(), ast_strlen_zero(), call_queue::count, member::lastcall, load_realtime_queue(), LOG_ERROR, LOG_WARNING, call_queue::members, member::paused, queue_t_unref, member::status, and call_queue::wrapuptime.
06551 { 06552 int count = 0; 06553 struct member *m; 06554 struct ao2_iterator mem_iter; 06555 struct call_queue *q; 06556 char *option; 06557 06558 if (ast_strlen_zero(data)) { 06559 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06560 return -1; 06561 } 06562 06563 if ((option = strchr(data, ','))) 06564 *option++ = '\0'; 06565 else 06566 option = "logged"; 06567 if ((q = load_realtime_queue(data))) { 06568 ao2_lock(q); 06569 if (!strcasecmp(option, "logged")) { 06570 mem_iter = ao2_iterator_init(q->members, 0); 06571 while ((m = ao2_iterator_next(&mem_iter))) { 06572 /* Count the agents who are logged in and presently answering calls */ 06573 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 06574 count++; 06575 } 06576 ao2_ref(m, -1); 06577 } 06578 ao2_iterator_destroy(&mem_iter); 06579 } else if (!strcasecmp(option, "free")) { 06580 mem_iter = ao2_iterator_init(q->members, 0); 06581 while ((m = ao2_iterator_next(&mem_iter))) { 06582 /* Count the agents who are logged in and presently answering calls */ 06583 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) { 06584 count++; 06585 } 06586 ao2_ref(m, -1); 06587 } 06588 ao2_iterator_destroy(&mem_iter); 06589 } else if (!strcasecmp(option, "ready")) { 06590 time_t now; 06591 time(&now); 06592 mem_iter = ao2_iterator_init(q->members, 0); 06593 while ((m = ao2_iterator_next(&mem_iter))) { 06594 /* Count the agents who are logged in, not paused and not wrapping up */ 06595 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) && 06596 !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) { 06597 count++; 06598 } 06599 ao2_ref(m, -1); 06600 } 06601 ao2_iterator_destroy(&mem_iter); 06602 } else /* must be "count" */ 06603 count = ao2_container_count(q->members); 06604 ao2_unlock(q); 06605 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()"); 06606 } else 06607 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06608 06609 snprintf(buf, len, "%d", count); 06610 06611 return 0; 06612 }
| static int queue_function_qac_dep | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Get the total number of members in a specific queue (Deprecated).
| number | of members | |
| -1 | on error |
Definition at line 6619 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, ast_log(), ast_strlen_zero(), call_queue::count, load_realtime_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, call_queue::members, queue_t_unref, and member::status.
06620 { 06621 int count = 0; 06622 struct member *m; 06623 struct call_queue *q; 06624 struct ao2_iterator mem_iter; 06625 static int depflag = 1; 06626 06627 if (depflag) { 06628 depflag = 0; 06629 ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n"); 06630 } 06631 06632 if (ast_strlen_zero(data)) { 06633 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06634 return -1; 06635 } 06636 06637 if ((q = load_realtime_queue(data))) { 06638 ao2_lock(q); 06639 mem_iter = ao2_iterator_init(q->members, 0); 06640 while ((m = ao2_iterator_next(&mem_iter))) { 06641 /* Count the agents who are logged in and presently answering calls */ 06642 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 06643 count++; 06644 } 06645 ao2_ref(m, -1); 06646 } 06647 ao2_iterator_destroy(&mem_iter); 06648 ao2_unlock(q); 06649 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT"); 06650 } else 06651 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06652 06653 snprintf(buf, len, "%d", count); 06654 06655 return 0; 06656 }
| static int queue_function_queuememberlist | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue.
Definition at line 6695 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_find, ao2_unlock, ast_log(), ast_strlen_zero(), member::interface, LOG_ERROR, LOG_WARNING, call_queue::members, OBJ_POINTER, queue_t_unref, and queues.
06696 { 06697 struct call_queue *q, tmpq = { 06698 .name = data, 06699 }; 06700 struct member *m; 06701 06702 /* Ensure an otherwise empty list doesn't return garbage */ 06703 buf[0] = '\0'; 06704 06705 if (ast_strlen_zero(data)) { 06706 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 06707 return -1; 06708 } 06709 06710 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) { 06711 int buflen = 0, count = 0; 06712 struct ao2_iterator mem_iter; 06713 06714 ao2_lock(q); 06715 mem_iter = ao2_iterator_init(q->members, 0); 06716 while ((m = ao2_iterator_next(&mem_iter))) { 06717 /* strcat() is always faster than printf() */ 06718 if (count++) { 06719 strncat(buf + buflen, ",", len - buflen - 1); 06720 buflen++; 06721 } 06722 strncat(buf + buflen, m->interface, len - buflen - 1); 06723 buflen += strlen(m->interface); 06724 /* Safeguard against overflow (negative length) */ 06725 if (buflen >= len - 2) { 06726 ao2_ref(m, -1); 06727 ast_log(LOG_WARNING, "Truncating list\n"); 06728 break; 06729 } 06730 ao2_ref(m, -1); 06731 } 06732 ao2_iterator_destroy(&mem_iter); 06733 ao2_unlock(q); 06734 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()"); 06735 } else 06736 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06737 06738 /* We should already be terminated, but let's make sure. */ 06739 buf[len - 1] = '\0'; 06740 06741 return 0; 06742 }
| static int queue_function_queuewaitingcount | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue.
Definition at line 6659 of file app_queue.c.
References ao2_lock, ao2_t_find, ao2_unlock, ast_load_realtime(), ast_log(), ast_strlen_zero(), ast_variables_destroy(), call_queue::count, LOG_ERROR, LOG_WARNING, OBJ_POINTER, queue_t_unref, queues, SENTINEL, and var.
06660 { 06661 int count = 0; 06662 struct call_queue *q, tmpq = { 06663 .name = data, 06664 }; 06665 struct ast_variable *var = NULL; 06666 06667 buf[0] = '\0'; 06668 06669 if (ast_strlen_zero(data)) { 06670 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n"); 06671 return -1; 06672 } 06673 06674 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) { 06675 ao2_lock(q); 06676 count = q->count; 06677 ao2_unlock(q); 06678 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()"); 06679 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) { 06680 /* if the queue is realtime but was not found in memory, this 06681 * means that the queue had been deleted from memory since it was 06682 * "dead." This means it has a 0 waiting count 06683 */ 06684 count = 0; 06685 ast_variables_destroy(var); 06686 } else 06687 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06688 06689 snprintf(buf, len, "%d", count); 06690 06691 return 0; 06692 }
| static int queue_function_var | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
create interface var with all queue details.
| 0 | on success | |
| -1 | on error |
Definition at line 6479 of file app_queue.c.
References ao2_lock, ao2_t_find, ao2_unlock, ast_log(), ast_strlen_zero(), call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::count, call_queue::holdtime, int2strat(), LOG_ERROR, LOG_WARNING, call_queue::maxlen, OBJ_POINTER, pbx_builtin_setvar_multiple(), queue_t_unref, queues, call_queue::servicelevel, call_queue::setqueuevar, call_queue::strategy, and call_queue::talktime.
06480 { 06481 int res = -1; 06482 struct call_queue *q, tmpq = { 06483 .name = data, 06484 }; 06485 06486 char interfacevar[256] = ""; 06487 float sl = 0; 06488 06489 if (ast_strlen_zero(data)) { 06490 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06491 return -1; 06492 } 06493 06494 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) { 06495 ao2_lock(q); 06496 if (q->setqueuevar) { 06497 sl = 0; 06498 res = 0; 06499 06500 if (q->callscompleted > 0) { 06501 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 06502 } 06503 06504 snprintf(interfacevar, sizeof(interfacevar), 06505 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 06506 q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 06507 06508 pbx_builtin_setvar_multiple(chan, interfacevar); 06509 } 06510 06511 ao2_unlock(q); 06512 queue_t_unref(q, "Done with QUEUE() function"); 06513 } else { 06514 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06515 } 06516 06517 snprintf(buf, len, "%d", res); 06518 06519 return 0; 06520 }
| static int queue_hash_cb | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 1303 of file app_queue.c.
References ast_str_case_hash().
Referenced by load_module().
01304 { 01305 const struct call_queue *q = obj; 01306 01307 return ast_str_case_hash(q->name); 01308 }
| static int queue_member_decrement_followers | ( | void * | obj, | |
| void * | arg, | |||
| int | flag | |||
| ) | [static] |
Definition at line 1321 of file app_queue.c.
References member::queuepos.
Referenced by queue_delme_members_decrement_followers(), and queue_member_follower_removal().
| static void queue_member_follower_removal | ( | struct call_queue * | queue, | |
| struct member * | mem | |||
| ) | [static] |
Definition at line 1357 of file app_queue.c.
References ao2_callback, call_queue::members, OBJ_MULTIPLE, OBJ_NODATA, queue_ent::pos, queue_member_decrement_followers(), member::queuepos, and call_queue::rrpos.
Referenced by member_remove_from_queue().
01358 { 01359 int pos = mem->queuepos; 01360 01361 /* If the position being removed is less than the current place in the queue, reduce the queue position by one so that we don't skip the member 01362 * who would have been next otherwise. */ 01363 if (pos < queue->rrpos) { 01364 queue->rrpos--; 01365 } 01366 01367 ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &pos); 01368 }
| static struct call_queue* queue_ref | ( | struct call_queue * | q | ) | [static, read] |
Definition at line 1382 of file app_queue.c.
References ao2_ref.
Referenced by insert_entry().
01383 { 01384 ao2_ref(q, 1); 01385 return q; 01386 }
| static void queue_set_global_params | ( | struct ast_config * | cfg | ) | [static] |
Set the global queue parameters as defined in the "general" section of queues.conf
Definition at line 6903 of file app_queue.c.
References ast_true(), and ast_variable_retrieve().
Referenced by reload_queues().
06904 { 06905 const char *general_val = NULL; 06906 queue_persistent_members = 0; 06907 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 06908 queue_persistent_members = ast_true(general_val); 06909 autofill_default = 0; 06910 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 06911 autofill_default = ast_true(general_val); 06912 montype_default = 0; 06913 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) { 06914 if (!strcasecmp(general_val, "mixmonitor")) 06915 montype_default = 1; 06916 } 06917 update_cdr = 0; 06918 if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr"))) 06919 update_cdr = ast_true(general_val); 06920 shared_lastcall = 0; 06921 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) 06922 shared_lastcall = ast_true(general_val); 06923 }
| static void queue_set_param | ( | struct call_queue * | q, | |
| const char * | param, | |||
| const char * | val, | |||
| int | linenum, | |||
| int | failunknown | |||
| ) | [static] |
Configure a queue parameter.
The failunknown flag is set for config files (and static realtime) to show errors for unknown parameters. It is cleared for dynamic realtime to allow extra fields in the tables.
Definition at line 1998 of file app_queue.c.
References queue_ent::announce, call_queue::announce_to_first_user, call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_NO, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, ast_copy_string(), ast_debug, ast_log(), ast_str_create(), ast_str_set(), ast_strdupa, ast_string_field_set, ast_true(), call_queue::autofill, call_queue::autopause, autopause2int(), queue_ent::context, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::eventwhencalled, call_queue::joinempty, call_queue::leavewhenempty, LOG_WARNING, call_queue::maskmemberstatus, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, call_queue::memberdelay, call_queue::minannouncefrequency, queue_ent::moh, call_queue::monfmt, call_queue::montype, call_queue::numperiodicannounce, parse_empty_options(), call_queue::penaltymemberslimit, call_queue::periodicannouncefrequency, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RINGALL, call_queue::randomperiodicannounce, call_queue::relativeperiodicannounce, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::roundingseconds, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::setqueueentryvar, call_queue::setqueuevar, call_queue::sound_periodicannounce, strat2int(), call_queue::strategy, call_queue::timeout, TIMEOUT_PRIORITY_APP, TIMEOUT_PRIORITY_CONF, call_queue::timeoutpriority, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_single_queue().
01999 { 02000 if (!strcasecmp(param, "musicclass") || 02001 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 02002 ast_string_field_set(q, moh, val); 02003 } else if (!strcasecmp(param, "announce")) { 02004 ast_string_field_set(q, announce, val); 02005 } else if (!strcasecmp(param, "context")) { 02006 ast_string_field_set(q, context, val); 02007 } else if (!strcasecmp(param, "timeout")) { 02008 q->timeout = atoi(val); 02009 if (q->timeout < 0) 02010 q->timeout = DEFAULT_TIMEOUT; 02011 } else if (!strcasecmp(param, "ringinuse")) { 02012 q->ringinuse = ast_true(val); 02013 } else if (!strcasecmp(param, "setinterfacevar")) { 02014 q->setinterfacevar = ast_true(val); 02015 } else if (!strcasecmp(param, "setqueuevar")) { 02016 q->setqueuevar = ast_true(val); 02017 } else if (!strcasecmp(param, "setqueueentryvar")) { 02018 q->setqueueentryvar = ast_true(val); 02019 } else if (!strcasecmp(param, "monitor-format")) { 02020 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 02021 } else if (!strcasecmp(param, "membermacro")) { 02022 ast_string_field_set(q, membermacro, val); 02023 } else if (!strcasecmp(param, "membergosub")) { 02024 ast_string_field_set(q, membergosub, val); 02025 } else if (!strcasecmp(param, "queue-youarenext")) { 02026 ast_string_field_set(q, sound_next, val); 02027 } else if (!strcasecmp(param, "queue-thereare")) { 02028 ast_string_field_set(q, sound_thereare, val); 02029 } else if (!strcasecmp(param, "queue-callswaiting")) { 02030 ast_string_field_set(q, sound_calls, val); 02031 } else if (!strcasecmp(param, "queue-quantity1")) { 02032 ast_string_field_set(q, queue_quantity1, val); 02033 } else if (!strcasecmp(param, "queue-quantity2")) { 02034 ast_string_field_set(q, queue_quantity2, val); 02035 } else if (!strcasecmp(param, "queue-holdtime")) { 02036 ast_string_field_set(q, sound_holdtime, val); 02037 } else if (!strcasecmp(param, "queue-minutes")) { 02038 ast_string_field_set(q, sound_minutes, val); 02039 } else if (!strcasecmp(param, "queue-minute")) { 02040 ast_string_field_set(q, sound_minute, val); 02041 } else if (!strcasecmp(param, "queue-seconds")) { 02042 ast_string_field_set(q, sound_seconds, val); 02043 } else if (!strcasecmp(param, "queue-thankyou")) { 02044 ast_string_field_set(q, sound_thanks, val); 02045 } else if (!strcasecmp(param, "queue-callerannounce")) { 02046 ast_string_field_set(q, sound_callerannounce, val); 02047 } else if (!strcasecmp(param, "queue-reporthold")) { 02048 ast_string_field_set(q, sound_reporthold, val); 02049 } else if (!strcasecmp(param, "announce-frequency")) { 02050 q->announcefrequency = atoi(val); 02051 } else if (!strcasecmp(param, "announce-to-first-user")) { 02052 q->announce_to_first_user = ast_true(val); 02053 } else if (!strcasecmp(param, "min-announce-frequency")) { 02054 q->minannouncefrequency = atoi(val); 02055 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name); 02056 } else if (!strcasecmp(param, "announce-round-seconds")) { 02057 q->roundingseconds = atoi(val); 02058 /* Rounding to any other values just doesn't make sense... */ 02059 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10 02060 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) { 02061 if (linenum >= 0) { 02062 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 02063 "using 0 instead for queue '%s' at line %d of queues.conf\n", 02064 val, param, q->name, linenum); 02065 } else { 02066 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 02067 "using 0 instead for queue '%s'\n", val, param, q->name); 02068 } 02069 q->roundingseconds=0; 02070 } 02071 } else if (!strcasecmp(param, "announce-holdtime")) { 02072 if (!strcasecmp(val, "once")) 02073 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 02074 else if (ast_true(val)) 02075 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 02076 else 02077 q->announceholdtime = 0; 02078 } else if (!strcasecmp(param, "announce-position")) { 02079 if (!strcasecmp(val, "limit")) 02080 q->announceposition = ANNOUNCEPOSITION_LIMIT; 02081 else if (!strcasecmp(val, "more")) 02082 q->announceposition = ANNOUNCEPOSITION_MORE_THAN; 02083 else if (ast_true(val)) 02084 q->announceposition = ANNOUNCEPOSITION_YES; 02085 else 02086 q->announceposition = ANNOUNCEPOSITION_NO; 02087 } else if (!strcasecmp(param, "announce-position-limit")) { 02088 q->announcepositionlimit = atoi(val); 02089 } else if (!strcasecmp(param, "periodic-announce")) { 02090 if (strchr(val, ',')) { 02091 char *s, *buf = ast_strdupa(val); 02092 unsigned int i = 0; 02093 02094 while ((s = strsep(&buf, ",|"))) { 02095 if (!q->sound_periodicannounce[i]) 02096 q->sound_periodicannounce[i] = ast_str_create(16); 02097 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s); 02098 i++; 02099 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 02100 break; 02101 } 02102 q->numperiodicannounce = i; 02103 } else { 02104 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val); 02105 q->numperiodicannounce = 1; 02106 } 02107 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 02108 q->periodicannouncefrequency = atoi(val); 02109 } else if (!strcasecmp(param, "relative-periodic-announce")) { 02110 q->relativeperiodicannounce = ast_true(val); 02111 } else if (!strcasecmp(param, "random-periodic-announce")) { 02112 q->randomperiodicannounce = ast_true(val); 02113 } else if (!strcasecmp(param, "retry")) { 02114 q->retry = atoi(val); 02115 if (q->retry <= 0) 02116 q->retry = DEFAULT_RETRY; 02117 } else if (!strcasecmp(param, "wrapuptime")) { 02118 q->wrapuptime = atoi(val); 02119 } else if (!strcasecmp(param, "penaltymemberslimit")) { 02120 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) { 02121 q->penaltymemberslimit = 0; 02122 } 02123 } else if (!strcasecmp(param, "autofill")) { 02124 q->autofill = ast_true(val); 02125 } else if (!strcasecmp(param, "monitor-type")) { 02126 if (!strcasecmp(val, "mixmonitor")) 02127 q->montype = 1; 02128 } else if (!strcasecmp(param, "autopause")) { 02129 q->autopause = autopause2int(val); 02130 } else if (!strcasecmp(param, "maxlen")) { 02131 q->maxlen = atoi(val); 02132 if (q->maxlen < 0) 02133 q->maxlen = 0; 02134 } else if (!strcasecmp(param, "servicelevel")) { 02135 q->servicelevel= atoi(val); 02136 } else if (!strcasecmp(param, "strategy")) { 02137 int strategy; 02138 02139 /* We are a static queue and already have set this, no need to do it again */ 02140 if (failunknown) { 02141 return; 02142 } 02143 strategy = strat2int(val); 02144 if (strategy < 0) { 02145 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 02146 val, q->name); 02147 q->strategy = QUEUE_STRATEGY_RINGALL; 02148 } 02149 if (strategy == q->strategy) { 02150 return; 02151 } 02152 if (strategy == QUEUE_STRATEGY_LINEAR) { 02153 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n"); 02154 return; 02155 } 02156 q->strategy = strategy; 02157 } else if (!strcasecmp(param, "joinempty")) { 02158 parse_empty_options(val, &q->joinempty, 1); 02159 } else if (!strcasecmp(param, "leavewhenempty")) { 02160 parse_empty_options(val, &q->leavewhenempty, 0); 02161 } else if (!strcasecmp(param, "eventmemberstatus")) { 02162 q->maskmemberstatus = !ast_true(val); 02163 } else if (!strcasecmp(param, "eventwhencalled")) { 02164 if (!strcasecmp(val, "vars")) { 02165 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 02166 } else { 02167 q->eventwhencalled = ast_true(val) ? 1 : 0; 02168 } 02169 } else if (!strcasecmp(param, "reportholdtime")) { 02170 q->reportholdtime = ast_true(val); 02171 } else if (!strcasecmp(param, "memberdelay")) { 02172 q->memberdelay = atoi(val); 02173 } else if (!strcasecmp(param, "weight")) { 02174 q->weight = atoi(val); 02175 } else if (!strcasecmp(param, "timeoutrestart")) { 02176 q->timeoutrestart = ast_true(val); 02177 } else if (!strcasecmp(param, "defaultrule")) { 02178 ast_string_field_set(q, defaultrule, val); 02179 } else if (!strcasecmp(param, "timeoutpriority")) { 02180 if (!strcasecmp(val, "conf")) { 02181 q->timeoutpriority = TIMEOUT_PRIORITY_CONF; 02182 } else { 02183 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 02184 } 02185 } else if (failunknown) { 02186 if (linenum >= 0) { 02187 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 02188 q->name, param, linenum); 02189 } else { 02190 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 02191 } 02192 } 02193 }
| static char* queue_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7559 of file app_queue.c.
References __queues_show(), ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, ast_cli_entry::command, complete_queue_show(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.
07560 { 07561 switch ( cmd ) { 07562 case CLI_INIT: 07563 e->command = "queue show"; 07564 e->usage = 07565 "Usage: queue show\n" 07566 " Provides summary information on a specified queue.\n"; 07567 return NULL; 07568 case CLI_GENERATE: 07569 return complete_queue_show(a->line, a->word, a->pos, a->n); 07570 } 07571 07572 return __queues_show(NULL, a->fd, a->argc, a->argv); 07573 }
| static void queue_transfer_destroy | ( | void * | data | ) | [static] |
Definition at line 4535 of file app_queue.c.
References ast_free.
04536 { 04537 struct queue_transfer_ds *qtds = data; 04538 ast_free(qtds); 04539 }
| static void queue_transfer_fixup | ( | void * | data, | |
| struct ast_channel * | old_chan, | |||
| struct ast_channel * | new_chan | |||
| ) | [static] |
Log an attended transfer when a queue caller channel is masqueraded.
When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when the actual transfer occurs. This happens during the masquerade after datastores are moved from old_chan to new_chan. This is why new_chan is referenced for exten, context, and datastore information.
At the end of this, we want to remove the datastore so that this fixup function is not called on any future masquerades of the caller during the current call.
Definition at line 4558 of file app_queue.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_log(), ast_queue_log(), queue_transfer_ds::callcompletedinsl, queue_ent::chan, ast_channel::context, ast_channel::exten, LOG_WARNING, queue_transfer_ds::member, member::membername, queue_ent::opos, queue_ent::parent, queue_transfer_ds::qe, queue_ent::start, queue_transfer_ds::starttime, and update_queue().
04559 { 04560 struct queue_transfer_ds *qtds = data; 04561 struct queue_ent *qe = qtds->qe; 04562 struct member *member = qtds->member; 04563 time_t callstart = qtds->starttime; 04564 int callcompletedinsl = qtds->callcompletedinsl; 04565 struct ast_datastore *datastore; 04566 04567 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 04568 new_chan->exten, new_chan->context, (long) (callstart - qe->start), 04569 (long) (time(NULL) - callstart), qe->opos); 04570 04571 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart)); 04572 04573 /* No need to lock the channels because they are already locked in ast_do_masquerade */ 04574 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) { 04575 ast_channel_datastore_remove(old_chan, datastore); 04576 /* Datastore is freed in try_calling() */ 04577 } else { 04578 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n"); 04579 } 04580 }
| static struct call_queue* queue_unref | ( | struct call_queue * | q | ) | [static, read] |
Definition at line 1388 of file app_queue.c.
References ao2_ref.
Referenced by queue_exec(), and queues_data_provider_get().
01389 { 01390 ao2_ref(q, -1); 01391 return NULL; 01392 }
| static int queues_data_provider_get | ( | const struct ast_data_search * | search, | |
| struct ast_data * | data_root | |||
| ) | [static] |
Definition at line 8728 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, ast_category_browse(), ast_config_destroy(), ast_load_realtime_multientry(), ast_strlen_zero(), load_realtime_queue(), queue_unref(), queues, queues_data_provider_get_helper(), call_queue::realtime, and SENTINEL.
08730 { 08731 struct ao2_iterator i; 08732 struct call_queue *queue, *queue_realtime = NULL; 08733 struct ast_config *cfg; 08734 char *queuename; 08735 08736 /* load realtime queues. */ 08737 cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 08738 if (cfg) { 08739 for (queuename = ast_category_browse(cfg, NULL); 08740 !ast_strlen_zero(queuename); 08741 queuename = ast_category_browse(cfg, queuename)) { 08742 if ((queue = load_realtime_queue(queuename))) { 08743 queue_unref(queue); 08744 } 08745 } 08746 ast_config_destroy(cfg); 08747 } 08748 08749 /* static queues. */ 08750 i = ao2_iterator_init(queues, 0); 08751 while ((queue = ao2_iterator_next(&i))) { 08752 ao2_lock(queue); 08753 if (queue->realtime) { 08754 queue_realtime = load_realtime_queue(queue->name); 08755 if (!queue_realtime) { 08756 ao2_unlock(queue); 08757 queue_unref(queue); 08758 continue; 08759 } 08760 queue_unref(queue_realtime); 08761 } 08762 08763 queues_data_provider_get_helper(search, data_root, queue); 08764 ao2_unlock(queue); 08765 queue_unref(queue); 08766 } 08767 ao2_iterator_destroy(&i); 08768 08769 return 0; 08770 }
| static void queues_data_provider_get_helper | ( | const struct ast_data_search * | search, | |
| struct ast_data * | data_root, | |||
| struct call_queue * | queue | |||
| ) | [static] |
Definition at line 8622 of file app_queue.c.
References call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_NO, ANNOUNCEPOSITION_YES, ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_data_add_structure(), ast_data_add_int(), ast_data_add_node(), ast_data_add_str(), ast_data_add_structure, ast_data_remove_node(), ast_data_search_match(), queue_ent::chan, call_queue::head, int2strat(), call_queue::members, and call_queue::strategy.
Referenced by queues_data_provider_get().
08624 { 08625 struct ao2_iterator im; 08626 struct member *member; 08627 struct queue_ent *qe; 08628 struct ast_data *data_queue, *data_members = NULL, *enum_node; 08629 struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel; 08630 08631 data_queue = ast_data_add_node(data_root, "queue"); 08632 if (!data_queue) { 08633 return; 08634 } 08635 08636 ast_data_add_structure(call_queue, data_queue, queue); 08637 08638 ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy)); 08639 ast_data_add_int(data_queue, "membercount", ao2_container_count(queue->members)); 08640 08641 /* announce position */ 08642 enum_node = ast_data_add_node(data_queue, "announceposition"); 08643 if (!enum_node) { 08644 return; 08645 } 08646 switch (queue->announceposition) { 08647 case ANNOUNCEPOSITION_LIMIT: 08648 ast_data_add_str(enum_node, "text", "limit"); 08649 break; 08650 case ANNOUNCEPOSITION_MORE_THAN: 08651 ast_data_add_str(enum_node, "text", "more"); 08652 break; 08653 case ANNOUNCEPOSITION_YES: 08654 ast_data_add_str(enum_node, "text", "yes"); 08655 break; 08656 case ANNOUNCEPOSITION_NO: 08657 ast_data_add_str(enum_node, "text", "no"); 08658 break; 08659 default: 08660 ast_data_add_str(enum_node, "text", "unknown"); 08661 break; 08662 } 08663 ast_data_add_int(enum_node, "value", queue->announceposition); 08664 08665 /* add queue members */ 08666 im = ao2_iterator_init(queue->members, 0); 08667 while ((member = ao2_iterator_next(&im))) { 08668 if (!data_members) { 08669 data_members = ast_data_add_node(data_queue, "members"); 08670 if (!data_members) { 08671 ao2_ref(member, -1); 08672 continue; 08673 } 08674 } 08675 08676 data_member = ast_data_add_node(data_members, "member"); 08677 if (!data_member) { 08678 ao2_ref(member, -1); 08679 continue; 08680 } 08681 08682 ast_data_add_structure(member, data_member, member); 08683 08684 ao2_ref(member, -1); 08685 } 08686 ao2_iterator_destroy(&im); 08687 08688 /* include the callers inside the result. */ 08689 if (queue->head) { 08690 for (qe = queue->head; qe; qe = qe->next) { 08691 if (!data_callers) { 08692 data_callers = ast_data_add_node(data_queue, "callers"); 08693 if (!data_callers) { 08694 continue; 08695 } 08696 } 08697 08698 data_caller = ast_data_add_node(data_callers, "caller"); 08699 if (!data_caller) { 08700 continue; 08701 } 08702 08703 ast_data_add_structure(queue_ent, data_caller, qe); 08704 08705 /* add the caller channel. */ 08706 data_caller_channel = ast_data_add_node(data_caller, "channel"); 08707 if (!data_caller_channel) { 08708 continue; 08709 } 08710 08711 ast_channel_data_add_structure(data_caller_channel, qe->chan, 1); 08712 } 08713 } 08714 08715 /* if this queue doesn't match remove the added queue. */ 08716 if (!ast_data_search_match(search, data_queue)) { 08717 ast_data_remove_node(data_root, data_queue); 08718 } 08719 }
| static void recalc_holdtime | ( | struct queue_ent * | qe, | |
| int | newholdtime | |||
| ) | [static] |
Definition at line 2894 of file app_queue.c.
References ao2_lock, ao2_unlock, call_queue::holdtime, and queue_ent::parent.
Referenced by try_calling().
02895 { 02896 int oldvalue; 02897 02898 /* Calculate holdtime using an exponential average */ 02899 /* Thanks to SRT for this contribution */ 02900 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 02901 02902 ao2_lock(qe->parent); 02903 oldvalue = qe->parent->holdtime; 02904 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 02905 ao2_unlock(qe->parent); 02906 }
| static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Record that a caller gave up on waiting in queue.
Definition at line 3585 of file app_queue.c.
References ao2_lock, ao2_unlock, call_queue::callsabandoned, queue_ent::chan, EVENT_FLAG_AGENT, manager_event, queue_ent::opos, queue_ent::parent, queue_ent::pos, set_queue_variables(), and queue_ent::start.
Referenced by queue_exec(), and try_calling().
03586 { 03587 set_queue_variables(qe->parent, qe->chan); 03588 ao2_lock(qe->parent); 03589 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 03590 "Queue: %s\r\n" 03591 "Uniqueid: %s\r\n" 03592 "Position: %d\r\n" 03593 "OriginalPosition: %d\r\n" 03594 "HoldTime: %d\r\n", 03595 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 03596 03597 qe->parent->callsabandoned++; 03598 ao2_unlock(qe->parent); 03599 }
| static int reload | ( | void | ) | [static] |
Definition at line 8904 of file app_queue.c.
References AST_FLAGS_ALL, ast_unload_realtime(), QUEUE_RESET_STATS, and reload_handler().
08905 { 08906 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,}; 08907 ast_unload_realtime("queue_members"); 08908 reload_handler(1, &mask, NULL); 08909 return 0; 08910 }
| static int reload_handler | ( | int | reload, | |
| struct ast_flags * | mask, | |||
| const char * | queuename | |||
| ) | [static] |
The command center for all reload operations.
Whenever any piece of queue information is to be reloaded, this function is called. It interprets the flags set in the mask parameter and acts based on how they are set.
| reload | True if we are reloading information, false if we are loading information for the first time. | |
| mask | A bitmask which tells the handler what actions to take | |
| queuename | The name of the queue on which we wish to take action |
| 0 | All reloads were successful | |
| non-zero | There was a failure |
Definition at line 7279 of file app_queue.c.
References ast_test_flag, clear_stats(), QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, QUEUE_RESET_STATS, reload_queue_rules(), and reload_queues().
Referenced by handle_queue_reload(), handle_queue_reset(), load_module(), manager_queue_reload(), manager_queue_reset(), and reload().
07280 { 07281 int res = 0; 07282 07283 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) { 07284 res |= reload_queue_rules(reload); 07285 } 07286 if (ast_test_flag(mask, QUEUE_RESET_STATS)) { 07287 res |= clear_stats(queuename); 07288 } 07289 if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) { 07290 res |= reload_queues(reload, mask, queuename); 07291 } 07292 return res; 07293 }
| static void reload_queue_members | ( | void | ) | [static] |
Reload dynamic queue members persisted into the astdb.
Definition at line 5820 of file app_queue.c.
References add_to_queue(), ao2_t_find, ast_db_del(), ast_db_freetree(), ast_db_get_allocated(), ast_db_gettree(), ast_debug, ast_free, ast_log(), ast_strlen_zero(), errno, member::interface, ast_db_entry::key, load_realtime_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, member::membername, ast_db_entry::next, OBJ_POINTER, member::paused, member::penalty, queue_t_unref, queues, RES_OUTOFMEMORY, and member::state_interface.
Referenced by load_module().
05821 { 05822 char *cur_ptr; 05823 const char *queue_name; 05824 char *member; 05825 char *interface; 05826 char *membername = NULL; 05827 char *state_interface; 05828 char *penalty_tok; 05829 int penalty = 0; 05830 char *paused_tok; 05831 int paused = 0; 05832 struct ast_db_entry *db_tree; 05833 struct ast_db_entry *entry; 05834 struct call_queue *cur_queue; 05835 char *queue_data; 05836 05837 /* Each key in 'pm_family' is the name of a queue */ 05838 db_tree = ast_db_gettree(pm_family, NULL); 05839 for (entry = db_tree; entry; entry = entry->next) { 05840 05841 queue_name = entry->key + strlen(pm_family) + 2; 05842 05843 { 05844 struct call_queue tmpq = { 05845 .name = queue_name, 05846 }; 05847 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members"); 05848 } 05849 05850 if (!cur_queue) 05851 cur_queue = load_realtime_queue(queue_name); 05852 05853 if (!cur_queue) { 05854 /* If the queue no longer exists, remove it from the 05855 * database */ 05856 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 05857 ast_db_del(pm_family, queue_name); 05858 continue; 05859 } 05860 05861 if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) { 05862 queue_t_unref(cur_queue, "Expire reload reference"); 05863 continue; 05864 } 05865 05866 cur_ptr = queue_data; 05867 while ((member = strsep(&cur_ptr, ",|"))) { 05868 if (ast_strlen_zero(member)) 05869 continue; 05870 05871 interface = strsep(&member, ";"); 05872 penalty_tok = strsep(&member, ";"); 05873 paused_tok = strsep(&member, ";"); 05874 membername = strsep(&member, ";"); 05875 state_interface = strsep(&member, ";"); 05876 05877 if (!penalty_tok) { 05878 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 05879 break; 05880 } 05881 penalty = strtol(penalty_tok, NULL, 10); 05882 if (errno == ERANGE) { 05883 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 05884 break; 05885 } 05886 05887 if (!paused_tok) { 05888 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 05889 break; 05890 } 05891 paused = strtol(paused_tok, NULL, 10); 05892 if ((errno == ERANGE) || paused < 0 || paused > 1) { 05893 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 05894 break; 05895 } 05896 05897 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 05898 05899 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { 05900 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 05901 break; 05902 } 05903 } 05904 queue_t_unref(cur_queue, "Expire reload reference"); 05905 ast_free(queue_data); 05906 } 05907 05908 if (db_tree) { 05909 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 05910 ast_db_freetree(db_tree); 05911 } 05912 }
| static int reload_queue_rules | ( | int | reload | ) | [static] |
Reload the rules defined in queuerules.conf.
| reload | If 1, then only process queuerules.conf if the file has changed since the last time we inspected it. |
Definition at line 6854 of file app_queue.c.
References ast_calloc, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, insert_penaltychange(), ast_variable::lineno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_variable::name, rule_list::name, ast_variable::next, and ast_variable::value.
Referenced by reload_handler().
06855 { 06856 struct ast_config *cfg; 06857 struct rule_list *rl_iter, *new_rl; 06858 struct penalty_rule *pr_iter; 06859 char *rulecat = NULL; 06860 struct ast_variable *rulevar = NULL; 06861 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06862 06863 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) { 06864 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n"); 06865 return AST_MODULE_LOAD_SUCCESS; 06866 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06867 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n"); 06868 return AST_MODULE_LOAD_SUCCESS; 06869 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 06870 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n"); 06871 return AST_MODULE_LOAD_SUCCESS; 06872 } 06873 06874 AST_LIST_LOCK(&rule_lists); 06875 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) { 06876 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list))) 06877 ast_free(pr_iter); 06878 ast_free(rl_iter); 06879 } 06880 while ((rulecat = ast_category_browse(cfg, rulecat))) { 06881 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) { 06882 AST_LIST_UNLOCK(&rule_lists); 06883 ast_config_destroy(cfg); 06884 return AST_MODULE_LOAD_FAILURE; 06885 } else { 06886 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name)); 06887 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list); 06888 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next) 06889 if(!strcasecmp(rulevar->name, "penaltychange")) 06890 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno); 06891 else 06892 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno); 06893 } 06894 } 06895 AST_LIST_UNLOCK(&rule_lists); 06896 06897 ast_config_destroy(cfg); 06898 06899 return AST_MODULE_LOAD_SUCCESS; 06900 }
| static int reload_queues | ( | int | reload, | |
| struct ast_flags * | mask, | |||
| const char * | queuename | |||
| ) | [static] |
reload the queues.conf file
This function reloads the information in the general section of the queues.conf file and potentially more, depending on the value of mask.
| reload | 0 if we are calling this the first time, 1 every other time | |
| mask | Gives flags telling us what information to actually reload | |
| queuename | If set to a non-zero string, then only reload information from that particular queue. Otherwise inspect all queues |
| -1 | Failure occurred | |
| 0 | All clear! |
Definition at line 7184 of file app_queue.c.
References ao2_callback, ao2_lock, ao2_unlock, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_log(), ast_strlen_zero(), ast_test_flag, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, kill_dead_queues(), LOG_ERROR, LOG_NOTICE, mark_dead_and_unfound(), OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, queue_set_global_params(), queues, reload_single_queue(), and remove_members_and_mark_unfound().
Referenced by reload_handler().
07185 { 07186 struct ast_config *cfg; 07187 char *cat; 07188 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 07189 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); 07190 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER); 07191 07192 if (!(cfg = ast_config_load("queues.conf", config_flags))) { 07193 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 07194 return -1; 07195 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 07196 return 0; 07197 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 07198 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n"); 07199 return -1; 07200 } 07201 07202 /* We've made it here, so it looks like we're doing operations on all queues. */ 07203 ao2_lock(queues); 07204 07205 /* Mark all queues as dead for the moment if we're reloading queues. 07206 * For clarity, we could just be reloading members, in which case we don't want to mess 07207 * with the other queue parameters at all*/ 07208 if (queue_reload) { 07209 ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename); 07210 } 07211 07212 if (member_reload) { 07213 ao2_callback(queues, OBJ_NODATA, remove_members_and_mark_unfound, (char *) queuename); 07214 } 07215 07216 /* Chug through config file */ 07217 cat = NULL; 07218 while ((cat = ast_category_browse(cfg, cat)) ) { 07219 if (!strcasecmp(cat, "general") && queue_reload) { 07220 queue_set_global_params(cfg); 07221 continue; 07222 } 07223 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename)) 07224 reload_single_queue(cfg, mask, cat); 07225 } 07226 07227 ast_config_destroy(cfg); 07228 /* Unref all the dead queues if we were reloading queues */ 07229 if (queue_reload) { 07230 ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename); 07231 } 07232 ao2_unlock(queues); 07233 return 0; 07234 }
| static void reload_single_member | ( | const char * | memberdata, | |
| struct call_queue * | q | |||
| ) | [static] |
reload information pertaining to a single member
This function is called when a member = line is encountered in queues.conf.
| memberdata | The part after member = in the config file | |
| q | The queue to which this member belongs |
Definition at line 6933 of file app_queue.c.
References ao2_find, ao2_link, ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, args, AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strip(), ast_strlen_zero(), create_queue_member(), member::interface, LOG_WARNING, member_add_to_queue(), call_queue::members, OBJ_POINTER, parse(), member::paused, member::penalty, and member::queuepos.
Referenced by reload_single_queue().
06934 { 06935 char *membername, *interface, *state_interface, *tmp; 06936 char *parse; 06937 struct member *cur, *newm; 06938 struct member tmpmem; 06939 int penalty; 06940 AST_DECLARE_APP_ARGS(args, 06941 AST_APP_ARG(interface); 06942 AST_APP_ARG(penalty); 06943 AST_APP_ARG(membername); 06944 AST_APP_ARG(state_interface); 06945 ); 06946 06947 if (ast_strlen_zero(memberdata)) { 06948 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n"); 06949 return; 06950 } 06951 06952 /* Add a new member */ 06953 parse = ast_strdupa(memberdata); 06954 06955 AST_STANDARD_APP_ARGS(args, parse); 06956 06957 interface = args.interface; 06958 if (!ast_strlen_zero(args.penalty)) { 06959 tmp = args.penalty; 06960 ast_strip(tmp); 06961 penalty = atoi(tmp); 06962 if (penalty < 0) { 06963 penalty = 0; 06964 } 06965 } else { 06966 penalty = 0; 06967 } 06968 06969 if (!ast_strlen_zero(args.membername)) { 06970 membername = args.membername; 06971 ast_strip(membername); 06972 } else { 06973 membername = interface; 06974 } 06975 06976 if (!ast_strlen_zero(args.state_interface)) { 06977 state_interface = args.state_interface; 06978 ast_strip(state_interface); 06979 } else { 06980 state_interface = interface; 06981 } 06982 06983 /* Find the old position in the list */ 06984 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 06985 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER); 06986 06987 if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) { 06988 if (cur) { 06989 /* Round Robin Queue Position must be copied if this is replacing an existing member */ 06990 ao2_lock(q->members); 06991 newm->queuepos = cur->queuepos; 06992 ao2_link(q->members, newm); 06993 ao2_unlink(q->members, cur); 06994 ao2_unlock(q->members); 06995 } else { 06996 /* Otherwise we need to add using the function that will apply a round robin queue position manually. */ 06997 member_add_to_queue(q, newm); 06998 } 06999 ao2_ref(newm, -1); 07000 } 07001 newm = NULL; 07002 07003 if (cur) { 07004 ao2_ref(cur, -1); 07005 } 07006 }
| static void reload_single_queue | ( | struct ast_config * | cfg, | |
| struct ast_flags * | mask, | |||
| const char * | queuename | |||
| ) | [static] |
Reload information pertaining to a particular queue.
Once we have isolated a queue within reload_queues, we call this. This will either reload information for the queue or if we're just reloading member information, we'll just reload that without touching other settings within the queue
| cfg | The configuration which we are reading | |
| mask | Tells us what information we need to reload | |
| queuename | The name of the queue we are reloading information from |
| void |
Definition at line 7040 of file app_queue.c.
References alloc_queue(), ao2_callback, ao2_lock, ao2_t_find, ao2_unlock, ast_atomic_fetchadd_int(), ast_log(), ast_test_flag, ast_variable_browse(), ast_variable_retrieve(), call_queue::found, init_queue(), kill_dead_members(), ast_variable::lineno, LOG_WARNING, mark_member_dead(), call_queue::members, ast_variable::name, ast_variable::next, OBJ_MULTIPLE, OBJ_NODATA, OBJ_POINTER, OBJ_UNLINK, queue_delme_members_decrement_followers(), QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_t_unref, queues, queues_t_link, reload_single_member(), strat2int(), call_queue::strategy, ast_variable::value, var, and call_queue::weight.
Referenced by reload_queues().
07041 { 07042 int new; 07043 struct call_queue *q = NULL; 07044 /*We're defining a queue*/ 07045 struct call_queue tmpq = { 07046 .name = queuename, 07047 }; 07048 const char *tmpvar; 07049 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); 07050 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER); 07051 int prev_weight = 0; 07052 struct ast_variable *var; 07053 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) { 07054 if (queue_reload) { 07055 /* Make one then */ 07056 if (!(q = alloc_queue(queuename))) { 07057 return; 07058 } 07059 } else { 07060 /* Since we're not reloading queues, this means that we found a queue 07061 * in the configuration file which we don't know about yet. Just return. 07062 */ 07063 return; 07064 } 07065 new = 1; 07066 } else { 07067 new = 0; 07068 } 07069 07070 if (!new) { 07071 ao2_lock(q); 07072 prev_weight = q->weight ? 1 : 0; 07073 } 07074 /* Check if we already found a queue with this name in the config file */ 07075 if (q->found) { 07076 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename); 07077 if (!new) { 07078 /* It should be impossible to *not* hit this case*/ 07079 ao2_unlock(q); 07080 } 07081 queue_t_unref(q, "We exist! Expiring temporary pointer"); 07082 return; 07083 } 07084 /* Due to the fact that the "linear" strategy will have a different allocation 07085 * scheme for queue members, we must devise the queue's strategy before other initializations. 07086 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2 07087 * container used will have only a single bucket instead of the typical number. 07088 */ 07089 if (queue_reload) { 07090 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) { 07091 q->strategy = strat2int(tmpvar); 07092 if (q->strategy < 0) { 07093 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 07094 tmpvar, q->name); 07095 q->strategy = QUEUE_STRATEGY_RINGALL; 07096 } 07097 } else { 07098 q->strategy = QUEUE_STRATEGY_RINGALL; 07099 } 07100 init_queue(q); 07101 } 07102 if (member_reload) { 07103 ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL); 07104 q->found = 1; 07105 } 07106 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) { 07107 if (member_reload && !strcasecmp(var->name, "member")) { 07108 reload_single_member(var->value, q); 07109 } else if (queue_reload) { 07110 queue_set_param(q, var->name, var->value, var->lineno, 1); 07111 } 07112 } 07113 /* At this point, we've determined if the queue has a weight, so update use_weight 07114 * as appropriate 07115 */ 07116 if (!q->weight && prev_weight) { 07117 ast_atomic_fetchadd_int(&use_weight, -1); 07118 } 07119 else if (q->weight && !prev_weight) { 07120 ast_atomic_fetchadd_int(&use_weight, +1); 07121 } 07122 07123 /* Free remaining members marked as delme */ 07124 if (member_reload) { 07125 ao2_lock(q->members); 07126 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE, queue_delme_members_decrement_followers, q); 07127 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q); 07128 ao2_unlock(q->members); 07129 } 07130 07131 if (new) { 07132 queues_t_link(queues, q, "Add queue to container"); 07133 } else { 07134 ao2_unlock(q); 07135 } 07136 queue_t_unref(q, "Expiring creation reference"); 07137 }
| static int remove_from_queue | ( | const char * | queuename, | |
| const char * | interface | |||
| ) | [static] |
Remove member from queue.
| RES_NOT_DYNAMIC | when they aren't a RT member | |
| RES_NOSUCHQUEUE | queue does not exist | |
| RES_OKAY | removed member from queue | |
| RES_EXISTS | queue exists but no members |
Definition at line 5563 of file app_queue.c.
References ao2_find, ao2_lock, ao2_ref, ao2_t_find, ao2_unlock, ast_copy_string(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, manager_event, member_remove_from_queue(), member::membername, call_queue::members, OBJ_POINTER, queue_t_unref, queues, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, and RES_OKAY.
Referenced by handle_queue_remove_member(), manager_remove_queue_member(), and rqm_exec().
05564 { 05565 struct call_queue *q, tmpq = { 05566 .name = queuename, 05567 }; 05568 struct member *mem, tmpmem; 05569 int res = RES_NOSUCHQUEUE; 05570 05571 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 05572 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) { 05573 ao2_lock(q); 05574 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 05575 /* XXX future changes should beware of this assumption!! */ 05576 if (!mem->dynamic) { 05577 ao2_ref(mem, -1); 05578 ao2_unlock(q); 05579 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference"); 05580 return RES_NOT_DYNAMIC; 05581 } 05582 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 05583 "Queue: %s\r\n" 05584 "Location: %s\r\n" 05585 "MemberName: %s\r\n", 05586 q->name, mem->interface, mem->membername); 05587 member_remove_from_queue(q, mem); 05588 ao2_ref(mem, -1); 05589 05590 if (queue_persistent_members) 05591 dump_queue_members(q); 05592 05593 res = RES_OKAY; 05594 } else { 05595 res = RES_EXISTS; 05596 } 05597 ao2_unlock(q); 05598 queue_t_unref(q, "Expiring temporary reference"); 05599 } 05600 05601 return res; 05602 }
| static int remove_members_and_mark_unfound | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 7139 of file app_queue.c.
References ast_strlen_zero(), call_queue::found, and call_queue::realtime.
Referenced by reload_queues().
07140 { 07141 struct call_queue *q = obj; 07142 char *queuename = arg; 07143 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) { 07144 q->found = 0; 07145 07146 } 07147 return 0; 07148 }
| static int ring_entry | ( | struct queue_ent * | qe, | |
| struct callattempt * | tmp, | |||
| int * | busies | |||
| ) | [static] |
Part 2 of ring_one.
Does error checking before attempting to request a channel and call a member. This function is only called from ring_one(). Failure can occur if:
| 1 | on success to reach a free agent | |
| 0 | on failure to get agent. |
Definition at line 3261 of file app_queue.c.
References ast_cdr::accountcode, ast_channel::adsicpe, ast_cdr::amaflags, ast_party_connected_line::ani, ast_party_caller::ani, ao2_lock, ao2_unlock, ast_channel::appl, ast_assert, ast_call(), ast_cdr_busy(), ast_cdr_isset_unanswered(), ast_cdr_setdestchan(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_lock_both, ast_channel_set_caller_event(), ast_channel_unlock, ast_connected_line_copy_from_caller(), ast_copy_string(), AST_FLAG_ANSWERED_ELSEWHERE, ast_party_caller_set_init(), ast_party_redirecting_copy(), ast_request(), ast_set_callerid(), ast_set_flag, ast_string_field_set, ast_strlen_zero(), ast_verb, member::call_pending, ast_channel::caller, can_ring_entry(), queue_ent::cancel_answered_elsewhere, ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_cdr::channel, ast_cdr::clid, ast_channel::connected, ast_channel::context, ast_channel::data, ast_cdr::dcontext, callattempt::dial_callerid_absent, dialcontext, ast_channel::dialed, do_hang(), ast_cdr::dst, EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, ast_party_connected_line::id, ast_party_caller::id, callattempt::interface, ast_cdr::lastapp, ast_cdr::lastdata, queue_ent::linpos, ast_channel::macroexten, manager_event, callattempt::member, member_call_pending_clear(), member::membername, ast_party_id::name, ast_channel::nativeformats, ast_party_dialed::number, ast_party_id::number, queue_ent::parent, pbx_builtin_getvar_helper(), ast_channel::priority, QUEUE_EVENT_VARIABLES, ast_channel::redirecting, call_queue::ringinuse, call_queue::rrpos, S_COR, S_OR, ast_cdr::src, status, callattempt::stillgoing, ast_party_name::str, ast_party_number::str, ast_party_dialed::str, ast_party_dialed::transit_network_select, ast_cdr::userfield, ast_party_name::valid, ast_party_number::valid, vars2manager(), and ast_channel::whentohangup.
Referenced by ring_one().
03262 { 03263 int res; 03264 int status; 03265 char tech[256]; 03266 char *location; 03267 const char *macrocontext, *macroexten; 03268 03269 /* on entry here, we know that tmp->chan == NULL */ 03270 if (!can_ring_entry(qe, tmp)) { 03271 if (qe->chan->cdr) { 03272 ast_cdr_busy(qe->chan->cdr); 03273 } 03274 tmp->stillgoing = 0; 03275 ++*busies; 03276 return 0; 03277 } 03278 ast_assert(qe->parent->ringinuse || tmp->member->call_pending); 03279 03280 ast_copy_string(tech, tmp->interface, sizeof(tech)); 03281 if ((location = strchr(tech, '/'))) 03282 *location++ = '\0'; 03283 else 03284 location = ""; 03285 03286 /* Request the peer */ 03287 tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status); 03288 if (!tmp->chan) { /* If we can't, just go on to the next call */ 03289 ao2_lock(qe->parent); 03290 qe->parent->rrpos++; 03291 qe->linpos++; 03292 ao2_unlock(qe->parent); 03293 03294 member_call_pending_clear(tmp->member); 03295 03296 if (qe->chan->cdr) { 03297 ast_cdr_busy(qe->chan->cdr); 03298 } 03299 tmp->stillgoing = 0; 03300 ++*busies; 03301 return 0; 03302 } 03303 03304 ast_channel_lock_both(tmp->chan, qe->chan); 03305 03306 if (qe->cancel_answered_elsewhere) { 03307 ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE); 03308 } 03309 tmp->chan->appl = "AppQueue"; 03310 tmp->chan->data = "(Outgoing Line)"; 03311 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup)); 03312 03313 /* If the new channel has no callerid, try to guess what it should be */ 03314 if (!tmp->chan->caller.id.number.valid) { 03315 if (qe->chan->connected.id.number.valid) { 03316 struct ast_party_caller caller; 03317 03318 ast_party_caller_set_init(&caller, &tmp->chan->caller); 03319 caller.id = qe->chan->connected.id; 03320 caller.ani = qe->chan->connected.ani; 03321 ast_channel_set_caller_event(tmp->chan, &caller, NULL); 03322 } else if (!ast_strlen_zero(qe->chan->dialed.number.str)) { 03323 ast_set_callerid(tmp->chan, qe->chan->dialed.number.str, NULL, NULL); 03324 } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) { 03325 ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL); 03326 } 03327 tmp->dial_callerid_absent = 1; 03328 } 03329 03330 ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting); 03331 03332 tmp->chan->dialed.transit_network_select = qe->chan->dialed.transit_network_select; 03333 03334 ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->caller); 03335 03336 /* Inherit specially named variables from parent channel */ 03337 ast_channel_inherit_variables(qe->chan, tmp->chan); 03338 ast_channel_datastore_inherit(qe->chan, tmp->chan); 03339 03340 /* Presense of ADSI CPE on outgoing channel follows ours */ 03341 tmp->chan->adsicpe = qe->chan->adsicpe; 03342 03343 /* Inherit context and extension */ 03344 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 03345 ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext); 03346 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 03347 if (!ast_strlen_zero(macroexten)) 03348 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 03349 else 03350 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 03351 if (ast_cdr_isset_unanswered()) { 03352 /* they want to see the unanswered dial attempts! */ 03353 /* set up the CDR fields on all the CDRs to give sensical information */ 03354 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name); 03355 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid); 03356 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel); 03357 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src); 03358 strcpy(tmp->chan->cdr->dst, qe->chan->exten); 03359 strcpy(tmp->chan->cdr->dcontext, qe->chan->context); 03360 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp); 03361 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata); 03362 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags; 03363 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode); 03364 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); 03365 } 03366 03367 ast_channel_unlock(tmp->chan); 03368 ast_channel_unlock(qe->chan); 03369 03370 /* Place the call, but don't wait on the answer */ 03371 if ((res = ast_call(tmp->chan, location, 0))) { 03372 /* Again, keep going even if there's an error */ 03373 ast_verb(3, "Couldn't call %s\n", tmp->interface); 03374 do_hang(tmp); 03375 member_call_pending_clear(tmp->member); 03376 ++*busies; 03377 return 0; 03378 } 03379 03380 if (qe->parent->eventwhencalled) { 03381 char vars[2048]; 03382 03383 ast_channel_lock_both(tmp->chan, qe->chan); 03384 03385 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 03386 "Queue: %s\r\n" 03387 "AgentCalled: %s\r\n" 03388 "AgentName: %s\r\n" 03389 "ChannelCalling: %s\r\n" 03390 "DestinationChannel: %s\r\n" 03391 "CallerIDNum: %s\r\n" 03392 "CallerIDName: %s\r\n" 03393 "ConnectedLineNum: %s\r\n" 03394 "ConnectedLineName: %s\r\n" 03395 "Context: %s\r\n" 03396 "Extension: %s\r\n" 03397 "Priority: %d\r\n" 03398 "Uniqueid: %s\r\n" 03399 "%s", 03400 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name, 03401 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"), 03402 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 03403 S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"), 03404 S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), 03405 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid, 03406 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03407 03408 ast_channel_unlock(tmp->chan); 03409 ast_channel_unlock(qe->chan); 03410 03411 ast_verb(3, "Called %s\n", tmp->interface); 03412 } 03413 03414 member_call_pending_clear(tmp->member); 03415 return 1; 03416 }
| static int ring_one | ( | struct queue_ent * | qe, | |
| struct callattempt * | outgoing, | |||
| int * | busies | |||
| ) | [static] |
Place a call to a queue member.
Once metrics have been calculated for each member, this function is used to place a call to the appropriate member (or members). The low-level channel-handling and error detection is handled in ring_entry
| 1 | if a member was called successfully | |
| 0 | otherwise |
Definition at line 3444 of file app_queue.c.
References ast_debug, callattempt::chan, queue_ent::expire, find_best(), callattempt::interface, callattempt::metric, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_entry(), callattempt::stillgoing, and call_queue::strategy.
Referenced by try_calling(), and wait_for_answer().
03445 { 03446 int ret = 0; 03447 03448 while (ret == 0) { 03449 struct callattempt *best = find_best(outgoing); 03450 if (!best) { 03451 ast_debug(1, "Nobody left to try ringing in queue\n"); 03452 break; 03453 } 03454 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 03455 struct callattempt *cur; 03456 /* Ring everyone who shares this best metric (for ringall) */ 03457 for (cur = outgoing; cur; cur = cur->q_next) { 03458 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 03459 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 03460 ret |= ring_entry(qe, cur, busies); 03461 } 03462 } 03463 } else { 03464 /* Ring just the best channel */ 03465 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric); 03466 ret = ring_entry(qe, best, busies); 03467 } 03468 03469 /* If we have timed out, break out */ 03470 if (qe->expire && (time(NULL) >= qe->expire)) { 03471 ast_debug(1, "Queue timed out while ringing members.\n"); 03472 ret = 0; 03473 break; 03474 } 03475 } 03476 03477 return ret; 03478 }
| static void rna | ( | int | rnatime, | |
| struct queue_ent * | qe, | |||
| char * | interface, | |||
| char * | membername, | |||
| int | pause | |||
| ) | [static] |
RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.
Definition at line 3602 of file app_queue.c.
References ast_indicate(), ast_moh_start(), ast_queue_log(), ast_verb, call_queue::autopause, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, manager_event, queue_ent::moh, queue_ent::parent, QUEUE_AUTOPAUSE_OFF, QUEUE_AUTOPAUSE_ON, QUEUE_EVENT_VARIABLES, queue_ent::ring_when_ringing, set_member_paused(), and vars2manager().
Referenced by wait_for_answer().
03603 { 03604 ast_verb(3, "Nobody picked up in %d ms\n", rnatime); 03605 03606 /* Stop ringing, and resume MOH if specified */ 03607 if (qe->ring_when_ringing) { 03608 ast_indicate(qe->chan, -1); 03609 ast_moh_start(qe->chan, qe->moh, NULL); 03610 } 03611 03612 if (qe->parent->eventwhencalled) { 03613 char vars[2048]; 03614 03615 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer", 03616 "Queue: %s\r\n" 03617 "Uniqueid: %s\r\n" 03618 "Channel: %s\r\n" 03619 "Member: %s\r\n" 03620 "MemberName: %s\r\n" 03621 "Ringtime: %d\r\n" 03622 "%s", 03623 qe->parent->name, 03624 qe->chan->uniqueid, 03625 qe->chan->name, 03626 interface, 03627 membername, 03628 rnatime, 03629 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03630 } 03631 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 03632 if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) { 03633 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) { 03634 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) { 03635 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", 03636 interface, qe->parent->name); 03637 } else { 03638 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 03639 } 03640 } else { 03641 /* If queue autopause is mode all, just don't send any queue to stop. 03642 * the function will stop in all queues */ 03643 if (!set_member_paused("", interface, "Auto-Pause", 1)) { 03644 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n", 03645 interface, qe->parent->name); 03646 } else { 03647 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface); 03648 } 03649 } 03650 } 03651 return; 03652 }
| static int rqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
RemoveQueueMember application.
Definition at line 5987 of file app_queue.c.
References args, AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_NOTICE, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, and RES_OKAY.
Referenced by load_module().
05988 { 05989 int res=-1; 05990 char *parse, *temppos = NULL; 05991 AST_DECLARE_APP_ARGS(args, 05992 AST_APP_ARG(queuename); 05993 AST_APP_ARG(interface); 05994 ); 05995 05996 05997 if (ast_strlen_zero(data)) { 05998 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n"); 05999 return -1; 06000 } 06001 06002 parse = ast_strdupa(data); 06003 06004 AST_STANDARD_APP_ARGS(args, parse); 06005 06006 if (ast_strlen_zero(args.interface)) { 06007 args.interface = ast_strdupa(chan->name); 06008 temppos = strrchr(args.interface, '-'); 06009 if (temppos) 06010 *temppos = '\0'; 06011 } 06012 06013 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface); 06014 06015 switch (remove_from_queue(args.queuename, args.interface)) { 06016 case RES_OKAY: 06017 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 06018 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 06019 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 06020 res = 0; 06021 break; 06022 case RES_EXISTS: 06023 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 06024 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 06025 res = 0; 06026 break; 06027 case RES_NOSUCHQUEUE: 06028 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 06029 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 06030 res = 0; 06031 break; 06032 case RES_NOT_DYNAMIC: 06033 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 06034 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 06035 res = 0; 06036 break; 06037 } 06038 06039 return res; 06040 }
| static void rt_handle_member_record | ( | struct call_queue * | q, | |
| char * | interface, | |||
| const char * | rt_uniqueid, | |||
| const char * | membername, | |||
| const char * | penalty_str, | |||
| const char * | paused_str, | |||
| const char * | state_interface | |||
| ) | [static] |
Find rt member record to update otherwise create one.
Search for member in queue, if found update penalty/paused state, if no member exists create one flag it as a RT member and add to queue member list.
Definition at line 2229 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_copy_string(), ast_log(), ast_queue_log(), ast_strlen_zero(), create_queue_member(), member::dead, member::interface, LOG_WARNING, member_add_to_queue(), call_queue::members, member::paused, member::penalty, member::realtime, member::rt_uniqueid, S_OR, and member::state_interface.
Referenced by find_queue_by_name_rt(), and update_realtime_members().
02230 { 02231 struct member *m; 02232 struct ao2_iterator mem_iter; 02233 int penalty = 0; 02234 int paused = 0; 02235 int found = 0; 02236 02237 if (ast_strlen_zero(rt_uniqueid)) { 02238 ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL")); 02239 return; 02240 } 02241 02242 if (penalty_str) { 02243 penalty = atoi(penalty_str); 02244 if (penalty < 0) 02245 penalty = 0; 02246 } 02247 02248 if (paused_str) { 02249 paused = atoi(paused_str); 02250 if (paused < 0) 02251 paused = 0; 02252 } 02253 02254 /* Find member by realtime uniqueid and update */ 02255 mem_iter = ao2_iterator_init(q->members, 0); 02256 while ((m = ao2_iterator_next(&mem_iter))) { 02257 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) { 02258 m->dead = 0; /* Do not delete this one. */ 02259 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 02260 if (paused_str) 02261 m->paused = paused; 02262 if (strcasecmp(state_interface, m->state_interface)) { 02263 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); 02264 } 02265 m->penalty = penalty; 02266 found = 1; 02267 ao2_ref(m, -1); 02268 break; 02269 } 02270 ao2_ref(m, -1); 02271 } 02272 ao2_iterator_destroy(&mem_iter); 02273 02274 /* Create a new member */ 02275 if (!found) { 02276 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { 02277 m->dead = 0; 02278 m->realtime = 1; 02279 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 02280 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); 02281 member_add_to_queue(q, m); 02282 ao2_ref(m, -1); 02283 m = NULL; 02284 } 02285 } 02286 }
| static int say_periodic_announcement | ( | struct queue_ent * | qe, | |
| int | ringing | |||
| ) | [static] |
Playback announcement to queued members if period has elapsed.
Definition at line 3529 of file app_queue.c.
References AST_CONTROL_RINGING, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_random(), ast_str_buffer(), ast_str_strlen(), ast_verb, queue_ent::chan, queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::moh, call_queue::numperiodicannounce, queue_ent::parent, call_queue::periodicannouncefrequency, play_file(), call_queue::randomperiodicannounce, call_queue::relativeperiodicannounce, call_queue::sound_periodicannounce, and valid_exit().
Referenced by queue_exec(), wait_for_answer(), and wait_our_turn().
03530 { 03531 int res = 0; 03532 time_t now; 03533 03534 /* Get the current time */ 03535 time(&now); 03536 03537 /* Check to see if it is time to announce */ 03538 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 03539 return 0; 03540 03541 /* Stop the music on hold so we can play our own file */ 03542 if (ringing) 03543 ast_indicate(qe->chan,-1); 03544 else 03545 ast_moh_stop(qe->chan); 03546 03547 ast_verb(3, "Playing periodic announcement\n"); 03548 03549 if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) { 03550 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce; 03551 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce || 03552 ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) { 03553 qe->last_periodic_announce_sound = 0; 03554 } 03555 03556 /* play the announcement */ 03557 res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])); 03558 03559 if (res > 0 && !valid_exit(qe, res)) 03560 res = 0; 03561 03562 /* Resume Music on Hold if the caller is going to stay in the queue */ 03563 if (!res) { 03564 if (ringing) 03565 ast_indicate(qe->chan, AST_CONTROL_RINGING); 03566 else 03567 ast_moh_start(qe->chan, qe->moh, NULL); 03568 } 03569 03570 /* update last_periodic_announce_time */ 03571 if (qe->parent->relativeperiodicannounce) 03572 time(&qe->last_periodic_announce_time); 03573 else 03574 qe->last_periodic_announce_time = now; 03575 03576 /* Update the current periodic announcement to the next announcement */ 03577 if (!qe->parent->randomperiodicannounce) { 03578 qe->last_periodic_announce_sound++; 03579 } 03580 03581 return res; 03582 }
| static int say_position | ( | struct queue_ent * | qe, | |
| int | ringing | |||
| ) | [static] |
Definition at line 2750 of file app_queue.c.
References call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, AST_CONTROL_RINGING, AST_DIGIT_ANY, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_say_number(), ast_verb, queue_ent::chan, call_queue::holdtime, queue_ent::last_pos, queue_ent::last_pos_said, call_queue::minannouncefrequency, queue_ent::moh, queue_ent::parent, play_file(), queue_ent::pos, call_queue::roundingseconds, queue_ent::start, and valid_exit().
Referenced by queue_exec(), wait_for_answer(), and wait_our_turn().
02751 { 02752 int res = 0, avgholdmins, avgholdsecs, announceposition = 0; 02753 int say_thanks = 1; 02754 time_t now; 02755 02756 /* Let minannouncefrequency seconds pass between the start of each position announcement */ 02757 time(&now); 02758 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) 02759 return 0; 02760 02761 /* If either our position has changed, or we are over the freq timer, say position */ 02762 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 02763 return 0; 02764 02765 if (ringing) { 02766 ast_indicate(qe->chan,-1); 02767 } else { 02768 ast_moh_stop(qe->chan); 02769 } 02770 02771 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES || 02772 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN || 02773 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT && 02774 qe->pos <= qe->parent->announcepositionlimit)) 02775 announceposition = 1; 02776 02777 02778 if (announceposition == 1) { 02779 /* Say we're next, if we are */ 02780 if (qe->pos == 1) { 02781 res = play_file(qe->chan, qe->parent->sound_next); 02782 if (res) 02783 goto playout; 02784 else 02785 goto posout; 02786 } else { 02787 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 02788 /* More than Case*/ 02789 res = play_file(qe->chan, qe->parent->queue_quantity1); 02790 if (res) 02791 goto playout; 02792 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 02793 if (res) 02794 goto playout; 02795 } else { 02796 /* Normal Case */ 02797 res = play_file(qe->chan, qe->parent->sound_thereare); 02798 if (res) 02799 goto playout; 02800 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 02801 if (res) 02802 goto playout; 02803 } 02804 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 02805 /* More than Case*/ 02806 res = play_file(qe->chan, qe->parent->queue_quantity2); 02807 if (res) 02808 goto playout; 02809 } else { 02810 res = play_file(qe->chan, qe->parent->sound_calls); 02811 if (res) 02812 goto playout; 02813 } 02814 } 02815 } 02816 /* Round hold time to nearest minute */ 02817 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 02818 02819 /* If they have specified a rounding then round the seconds as well */ 02820 if (qe->parent->roundingseconds) { 02821 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 02822 avgholdsecs *= qe->parent->roundingseconds; 02823 } else { 02824 avgholdsecs = 0; 02825 } 02826 02827 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 02828 02829 /* If the hold time is >1 min, if it's enabled, and if it's not 02830 supposed to be only once and we have already said it, say it */ 02831 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime && 02832 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) || 02833 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) { 02834 res = play_file(qe->chan, qe->parent->sound_holdtime); 02835 if (res) 02836 goto playout; 02837 02838 if (avgholdmins >= 1) { 02839 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL); 02840 if (res) 02841 goto playout; 02842 02843 if (avgholdmins == 1) { 02844 res = play_file(qe->chan, qe->parent->sound_minute); 02845 if (res) 02846 goto playout; 02847 } else { 02848 res = play_file(qe->chan, qe->parent->sound_minutes); 02849 if (res) 02850 goto playout; 02851 } 02852 } 02853 if (avgholdsecs >= 1) { 02854 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL); 02855 if (res) 02856 goto playout; 02857 02858 res = play_file(qe->chan, qe->parent->sound_seconds); 02859 if (res) 02860 goto playout; 02861 } 02862 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) { 02863 say_thanks = 0; 02864 } 02865 02866 posout: 02867 if (qe->parent->announceposition) { 02868 ast_verb(3, "Told %s in %s their queue position (which was %d)\n", 02869 qe->chan->name, qe->parent->name, qe->pos); 02870 } 02871 if (say_thanks) { 02872 res = play_file(qe->chan, qe->parent->sound_thanks); 02873 } 02874 playout: 02875 02876 if ((res > 0 && !valid_exit(qe, res))) 02877 res = 0; 02878 02879 /* Set our last_pos indicators */ 02880 qe->last_pos = now; 02881 qe->last_pos_said = qe->pos; 02882 02883 /* Don't restart music on hold if we're about to exit the caller from the queue */ 02884 if (!res) { 02885 if (ringing) { 02886 ast_indicate(qe->chan, AST_CONTROL_RINGING); 02887 } else { 02888 ast_moh_start(qe->chan, qe->moh, NULL); 02889 } 02890 } 02891 return res; 02892 }
| static void send_agent_complete | ( | const struct queue_ent * | qe, | |
| const char * | queuename, | |||
| const struct ast_channel * | peer, | |||
| const struct member * | member, | |||
| time_t | callstart, | |||
| char * | vars, | |||
| size_t | vars_len, | |||
| enum agent_complete_reason | rsn | |||
| ) | [static] |
Send out AMI message with member call completion status information.
Definition at line 4492 of file app_queue.c.
References AGENT, CALLER, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, member::interface, manager_event, member::membername, queue_ent::parent, QUEUE_EVENT_VARIABLES, queue_ent::start, TRANSFER, and vars2manager().
Referenced by try_calling().
04495 { 04496 const char *reason = NULL; /* silence dumb compilers */ 04497 04498 if (!qe->parent->eventwhencalled) 04499 return; 04500 04501 switch (rsn) { 04502 case CALLER: 04503 reason = "caller"; 04504 break; 04505 case AGENT: 04506 reason = "agent"; 04507 break; 04508 case TRANSFER: 04509 reason = "transfer"; 04510 break; 04511 } 04512 04513 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 04514 "Queue: %s\r\n" 04515 "Uniqueid: %s\r\n" 04516 "Channel: %s\r\n" 04517 "Member: %s\r\n" 04518 "MemberName: %s\r\n" 04519 "HoldTime: %ld\r\n" 04520 "TalkTime: %ld\r\n" 04521 "Reason: %s\r\n" 04522 "%s", 04523 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 04524 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason, 04525 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : ""); 04526 }
| static int set_member_paused | ( | const char * | queuename, | |
| const char * | interface, | |||
| const char * | reason, | |||
| int | paused | |||
| ) | [static] |
Definition at line 5662 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_debug, ast_log(), ast_queue_log(), ast_strlen_zero(), dump_queue_members(), EVENT_FLAG_AGENT, member::interface, interface_exists(), LOG_WARNING, manager_event, member::membername, member::paused, queue_t_unref, queues, member::realtime, RESULT_FAILURE, RESULT_SUCCESS, S_OR, and update_realtime_member_field().
Referenced by handle_queue_pause_member(), manager_pause_queue_member(), pqm_exec(), rna(), and upqm_exec().
05663 { 05664 int found = 0; 05665 struct call_queue *q; 05666 struct member *mem; 05667 struct ao2_iterator queue_iter; 05668 int failed; 05669 05670 /* Special event for when all queues are paused - individual events still generated */ 05671 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 05672 if (ast_strlen_zero(queuename)) 05673 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 05674 05675 queue_iter = ao2_iterator_init(queues, 0); 05676 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) { 05677 ao2_lock(q); 05678 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 05679 if ((mem = interface_exists(q, interface))) { 05680 if (mem->paused == paused) { 05681 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 05682 } 05683 05684 failed = 0; 05685 if (mem->realtime) { 05686 failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); 05687 } 05688 05689 if (failed) { 05690 ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface); 05691 ao2_ref(mem, -1); 05692 ao2_unlock(q); 05693 queue_t_unref(q, "Done with iterator"); 05694 continue; 05695 } 05696 found++; 05697 mem->paused = paused; 05698 05699 if (queue_persistent_members) 05700 dump_queue_members(q); 05701 05702 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, "")); 05703 05704 if (!ast_strlen_zero(reason)) { 05705 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 05706 "Queue: %s\r\n" 05707 "Location: %s\r\n" 05708 "MemberName: %s\r\n" 05709 "Paused: %d\r\n" 05710 "Reason: %s\r\n", 05711 q->name, mem->interface, mem->membername, paused, reason); 05712 } else { 05713 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 05714 "Queue: %s\r\n" 05715 "Location: %s\r\n" 05716 "MemberName: %s\r\n" 05717 "Paused: %d\r\n", 05718 q->name, mem->interface, mem->membername, paused); 05719 } 05720 ao2_ref(mem, -1); 05721 } 05722 } 05723 05724 if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) { 05725 ao2_unlock(q); 05726 queue_t_unref(q, "Done with iterator"); 05727 break; 05728 } 05729 05730 ao2_unlock(q); 05731 queue_t_unref(q, "Done with iterator"); 05732 } 05733 ao2_iterator_destroy(&queue_iter); 05734 05735 return found ? RESULT_SUCCESS : RESULT_FAILURE; 05736 }
| static int set_member_penalty | ( | const char * | queuename, | |
| const char * | interface, | |||
| int | penalty | |||
| ) | [static] |
Definition at line 5739 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_log(), ast_queue_log(), ast_strlen_zero(), EVENT_FLAG_AGENT, member::interface, interface_exists(), LOG_ERROR, manager_event, member::penalty, queue_t_unref, queues, RESULT_FAILURE, and RESULT_SUCCESS.
Referenced by handle_queue_set_member_penalty(), manager_queue_member_penalty(), and queue_function_memberpenalty_write().
05740 { 05741 int foundinterface = 0, foundqueue = 0; 05742 struct call_queue *q; 05743 struct member *mem; 05744 struct ao2_iterator queue_iter; 05745 05746 if (penalty < 0) { 05747 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty); 05748 return RESULT_FAILURE; 05749 } 05750 05751 queue_iter = ao2_iterator_init(queues, 0); 05752 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 05753 ao2_lock(q); 05754 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 05755 foundqueue++; 05756 if ((mem = interface_exists(q, interface))) { 05757 foundinterface++; 05758 mem->penalty = penalty; 05759 05760 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty); 05761 manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty", 05762 "Queue: %s\r\n" 05763 "Location: %s\r\n" 05764 "Penalty: %d\r\n", 05765 q->name, mem->interface, penalty); 05766 ao2_ref(mem, -1); 05767 } 05768 } 05769 ao2_unlock(q); 05770 queue_t_unref(q, "Done with iterator"); 05771 } 05772 ao2_iterator_destroy(&queue_iter); 05773 05774 if (foundinterface) { 05775 return RESULT_SUCCESS; 05776 } else if (!foundqueue) { 05777 ast_log (LOG_ERROR, "Invalid queuename\n"); 05778 } else { 05779 ast_log (LOG_ERROR, "Invalid interface\n"); 05780 } 05781 05782 return RESULT_FAILURE; 05783 }
| static void set_queue_result | ( | struct ast_channel * | chan, | |
| enum queue_result | res | |||
| ) | [static] |
sets the QUEUESTATUS channel variable
Definition at line 1247 of file app_queue.c.
References ARRAY_LEN, pbx_builtin_setvar_helper(), queue_results, and text.
Referenced by queue_exec().
01248 { 01249 int i; 01250 01251 for (i = 0; i < ARRAY_LEN(queue_results); i++) { 01252 if (queue_results[i].id == res) { 01253 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 01254 return; 01255 } 01256 } 01257 }
| static void set_queue_variables | ( | struct call_queue * | q, | |
| struct ast_channel * | chan | |||
| ) | [static] |
Set variables of queue.
Definition at line 1396 of file app_queue.c.
References ao2_lock, ao2_unlock, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::count, call_queue::holdtime, int2strat(), call_queue::maxlen, pbx_builtin_setvar_multiple(), call_queue::servicelevel, call_queue::setqueuevar, call_queue::strategy, and call_queue::talktime.
Referenced by end_bridge_callback(), queue_exec(), record_abandoned(), and try_calling().
01397 { 01398 char interfacevar[256]=""; 01399 float sl = 0; 01400 01401 ao2_lock(q); 01402 01403 if (q->setqueuevar) { 01404 sl = 0; 01405 if (q->callscompleted > 0) 01406 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 01407 01408 snprintf(interfacevar, sizeof(interfacevar), 01409 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 01410 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 01411 01412 ao2_unlock(q); 01413 01414 pbx_builtin_setvar_multiple(chan, interfacevar); 01415 } else { 01416 ao2_unlock(q); 01417 } 01418 }
| static struct ast_datastore* setup_transfer_datastore | ( | struct queue_ent * | qe, | |
| struct member * | member, | |||
| time_t | starttime, | |||
| int | callcompletedinsl | |||
| ) | [static, read] |
create a datastore for storing relevant info to log attended transfers in the queue_log
Definition at line 4597 of file app_queue.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_free, ast_log(), queue_transfer_ds::callcompletedinsl, queue_ent::chan, ast_datastore::data, LOG_WARNING, queue_transfer_ds::member, queue_transfer_ds::qe, and queue_transfer_ds::starttime.
Referenced by try_calling().
04598 { 04599 struct ast_datastore *ds; 04600 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds)); 04601 04602 if (!qtds) { 04603 ast_log(LOG_WARNING, "Memory allocation error!\n"); 04604 return NULL; 04605 } 04606 04607 ast_channel_lock(qe->chan); 04608 if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) { 04609 ast_channel_unlock(qe->chan); 04610 ast_free(qtds); 04611 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n"); 04612 return NULL; 04613 } 04614 04615 qtds->qe = qe; 04616 /* This member is refcounted in try_calling, so no need to add it here, too */ 04617 qtds->member = member; 04618 qtds->starttime = starttime; 04619 qtds->callcompletedinsl = callcompletedinsl; 04620 ds->data = qtds; 04621 ast_channel_datastore_add(qe->chan, ds); 04622 ast_channel_unlock(qe->chan); 04623 return ds; 04624 }
| static int store_next_lin | ( | struct queue_ent * | qe, | |
| struct callattempt * | outgoing | |||
| ) | [static] |
Search for best metric and add to Linear queue.
Definition at line 3505 of file app_queue.c.
References ast_debug, find_best(), callattempt::interface, queue_ent::linpos, queue_ent::linwrapped, and callattempt::metric.
Referenced by try_calling().
03506 { 03507 struct callattempt *best = find_best(outgoing); 03508 03509 if (best) { 03510 /* Ring just the best channel */ 03511 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 03512 qe->linpos = best->metric % 1000; 03513 } else { 03514 /* Just increment rrpos */ 03515 if (qe->linwrapped) { 03516 /* No more channels, start over */ 03517 qe->linpos = 0; 03518 } else { 03519 /* Prioritize next entry */ 03520 qe->linpos++; 03521 } 03522 } 03523 qe->linwrapped = 0; 03524 03525 return 0; 03526 }
| static int store_next_rr | ( | struct queue_ent * | qe, | |
| struct callattempt * | outgoing | |||
| ) | [static] |
Search for best metric and add to Round Robbin queue.
Definition at line 3481 of file app_queue.c.
References ast_debug, find_best(), callattempt::interface, callattempt::metric, queue_ent::parent, call_queue::rrpos, and call_queue::wrapped.
Referenced by try_calling().
03482 { 03483 struct callattempt *best = find_best(outgoing); 03484 03485 if (best) { 03486 /* Ring just the best channel */ 03487 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 03488 qe->parent->rrpos = best->metric % 1000; 03489 } else { 03490 /* Just increment rrpos */ 03491 if (qe->parent->wrapped) { 03492 /* No more channels, start over */ 03493 qe->parent->rrpos = 0; 03494 } else { 03495 /* Prioritize next entry */ 03496 qe->parent->rrpos++; 03497 } 03498 } 03499 qe->parent->wrapped = 0; 03500 03501 return 0; 03502 }
| static int strat2int | ( | const char * | strategy | ) | [static] |
Definition at line 1271 of file app_queue.c.
References ARRAY_LEN, and strategies.
Referenced by find_queue_by_name_rt(), queue_set_param(), and reload_single_queue().
01272 { 01273 int x; 01274 01275 for (x = 0; x < ARRAY_LEN(strategies); x++) { 01276 if (!strcasecmp(strategy, strategies[x].name)) 01277 return strategies[x].strategy; 01278 } 01279 01280 return -1; 01281 }
| static int try_calling | ( | struct queue_ent * | qe, | |
| const char * | options, | |||
| char * | announceoverride, | |||
| const char * | url, | |||
| int * | tries, | |||
| int * | noption, | |||
| const char * | agi, | |||
| const char * | macro, | |||
| const char * | gosub, | |||
| int | ringing | |||
| ) | [static] |
A large function which calls members, updates statistics, and bridges the caller and a member.
Here is the process of this function 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue() 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also during each iteration, we call calc_metric to determine which members should be rung when. 3. Call ring_one to place a call to the appropriate member(s) 4. Call wait_for_answer to wait for an answer. If no one answers, return. 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered. 6. Start the monitor or mixmonitor if the option is set 7. Remove the caller from the queue to allow other callers to advance 8. Bridge the call. 9. Do any post processing after the call has disconnected.
| [in] | qe | the queue_ent structure which corresponds to the caller attempting to reach members |
| [in] | options | the options passed as the third parameter to the Queue() application |
| [in] | announceoverride | filename to play to user when waiting |
| [in] | url | the url passed as the fourth parameter to the Queue() application |
| [in,out] | tries | the number of times we have tried calling queue members |
| [out] | noption | set if the call to Queue() has the 'n' option set. |
| [in] | agi | the agi passed as the fifth parameter to the Queue() application |
| [in] | macro | the macro passed as the sixth parameter to the Queue() application |
| [in] | gosub | the gosub passed as the seventh parameter to the Queue() application |
| [in] | ringing | 1 if the 'r' option is set, otherwise 0 |
Definition at line 4678 of file app_queue.c.
References ast_channel::_softhangup, ast_channel::_state, AGENT, queue_ent::announce, ao2_alloc, ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_asprintf, ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_calloc, ast_cdr_append(), ast_cdr_dup(), ast_cdr_failed(), AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POST_DISABLED, ast_cdr_init(), ast_cdr_isset_unanswered(), ast_cdr_reset(), ast_cdr_setdestchan(), ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_sendurl(), ast_channel_setoption(), ast_channel_supports_html(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, ast_copy_string(), ast_datastore_alloc, ast_datastore_free(), ast_debug, AST_DIGIT_ANY, ast_exists_extension(), AST_FEATURE_AUTOMIXMON, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAG_ANSWERED_ELSEWHERE, ast_free, ast_hangup(), ast_indicate(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_moh_stop(), ast_monitor_setjoinfiles(), ast_monitor_start(), AST_OPTION_TONE_VERIFY, ast_party_connected_line_copy(), ast_pbx_run_args(), ast_queue_log(), ast_random(), ast_safe_sleep(), ast_say_number(), ast_set_flag, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, attended_transfer_occurred(), callattempt::block_connected_update, calc_metric(), callattempt_free(), CALLER, ast_channel::caller, member::calls, queue_ent::cancel_answered_elsewhere, ast_channel::cdr, queue_end_bridge::chan, callattempt::chan, queue_ent::chan, ast_channel::connected, callattempt::connected, ast_channel::context, ast_datastore::data, DATASTORE_INHERIT_FOREVER, di, dialed_interface_info, ast_cdr::dstchannel, member::dynamic, end_bridge_callback(), ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, end_bridge_callback_data_fixup(), ast_bridge_config::end_bridge_callback_data_fixup, EVENT_FLAG_AGENT, call_queue::eventwhencalled, queue_ent::expire, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, queue_ent::handled, hangupcalls(), ast_party_caller::id, ast_datastore::inheritance, callattempt::interface, ast_dialed_interface::interface, member::interface, member::lastcall, callattempt::lastcall, member::lastqueue, callattempt::lastqueue, leave_queue(), ast_cdr::linkedid, LOG_ERROR, LOG_NOTICE, LOG_WARNING, manager_event, callattempt::member, call_queue::memberdelay, member::membername, call_queue::members, call_queue::monfmt, call_queue::montype, ast_cdr::next, ast_pbx_args::no_hangup_chan, ast_party_id::number, queue_ent::opos, queue_ent::parent, pbx_builtin_getvar_helper(), pbx_builtin_setvar_multiple(), pbx_exec(), pbx_findapp(), pbx_substitute_variables_helper(), member::penalty, queue_ent::pending, play_file(), queue_ent::pos, ast_channel::priority, queue_end_bridge::q, callattempt::q_next, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, queue_t_ref, member::realtime, recalc_holdtime(), record_abandoned(), call_queue::reportholdtime, ring_one(), S_COR, send_agent_complete(), call_queue::servicelevel, set_queue_variables(), call_queue::setinterfacevar, call_queue::setqueueentryvar, setup_transfer_datastore(), queue_ent::start, callattempt::stillgoing, store_next_lin(), store_next_rr(), ast_party_number::str, call_queue::strategy, ast_channel::tech, call_queue::timeout, TIMEOUT_PRIORITY_APP, call_queue::timeoutpriority, TRANSFER, ast_channel_tech::type, ast_cdr::uniqueid, update_queue(), ast_party_number::valid, vars2manager(), wait_for_answer(), X_REC_IN, and X_REC_OUT.
Referenced by queue_exec().
04679 { 04680 struct member *cur; 04681 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 04682 int to, orig; 04683 char oldexten[AST_MAX_EXTENSION]=""; 04684 char oldcontext[AST_MAX_CONTEXT]=""; 04685 char queuename[256]=""; 04686 char interfacevar[256]=""; 04687 struct ast_channel *peer; 04688 struct ast_channel *which; 04689 struct callattempt *lpeer; 04690 struct member *member; 04691 struct ast_app *application; 04692 int res = 0, bridge = 0; 04693 int numbusies = 0; 04694 int x=0; 04695 char *announce = NULL; 04696 char digit = 0; 04697 time_t callstart; 04698 time_t now = time(NULL); 04699 struct ast_bridge_config bridge_config; 04700 char nondataquality = 1; 04701 char *agiexec = NULL; 04702 char *macroexec = NULL; 04703 char *gosubexec = NULL; 04704 const char *monitorfilename; 04705 const char *monitor_exec; 04706 const char *monitor_options; 04707 char tmpid[256], tmpid2[256]; 04708 char meid[1024], meid2[1024]; 04709 char mixmonargs[1512]; 04710 struct ast_app *mixmonapp = NULL; 04711 char *p; 04712 char vars[2048]; 04713 int forwardsallowed = 1; 04714 int block_connected_line = 0; 04715 int callcompletedinsl; 04716 struct ao2_iterator memi; 04717 struct ast_datastore *datastore, *transfer_ds; 04718 struct queue_end_bridge *queue_end_bridge = NULL; 04719 04720 ast_channel_lock(qe->chan); 04721 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL); 04722 ast_channel_unlock(qe->chan); 04723 04724 memset(&bridge_config, 0, sizeof(bridge_config)); 04725 tmpid[0] = 0; 04726 meid[0] = 0; 04727 time(&now); 04728 04729 /* If we've already exceeded our timeout, then just stop 04730 * This should be extremely rare. queue_exec will take care 04731 * of removing the caller and reporting the timeout as the reason. 04732 */ 04733 if (qe->expire && now >= qe->expire) { 04734 res = 0; 04735 goto out; 04736 } 04737 04738 for (; options && *options; options++) 04739 switch (*options) { 04740 case 't': 04741 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 04742 break; 04743 case 'T': 04744 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 04745 break; 04746 case 'w': 04747 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 04748 break; 04749 case 'W': 04750 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 04751 break; 04752 case 'c': 04753 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN); 04754 break; 04755 case 'd': 04756 nondataquality = 0; 04757 break; 04758 case 'h': 04759 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 04760 break; 04761 case 'H': 04762 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 04763 break; 04764 case 'k': 04765 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL); 04766 break; 04767 case 'K': 04768 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL); 04769 break; 04770 case 'n': 04771 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) 04772 (*tries)++; 04773 else 04774 *tries = ao2_container_count(qe->parent->members); 04775 *noption = 1; 04776 break; 04777 case 'i': 04778 forwardsallowed = 0; 04779 break; 04780 case 'I': 04781 block_connected_line = 1; 04782 break; 04783 case 'x': 04784 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON); 04785 break; 04786 case 'X': 04787 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON); 04788 break; 04789 case 'C': 04790 qe->cancel_answered_elsewhere = 1; 04791 break; 04792 } 04793 04794 /* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited. 04795 (this is mainly to support chan_local) 04796 */ 04797 if (ast_test_flag(qe->chan, AST_FLAG_ANSWERED_ELSEWHERE)) { 04798 qe->cancel_answered_elsewhere = 1; 04799 } 04800 04801 ao2_lock(qe->parent); 04802 ast_debug(1, "%s is trying to call a queue member.\n", 04803 qe->chan->name); 04804 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 04805 if (!ast_strlen_zero(qe->announce)) 04806 announce = qe->announce; 04807 if (!ast_strlen_zero(announceoverride)) 04808 announce = announceoverride; 04809 04810 memi = ao2_iterator_init(qe->parent->members, 0); 04811 while ((cur = ao2_iterator_next(&memi))) { 04812 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 04813 struct ast_dialed_interface *di; 04814 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 04815 if (!tmp) { 04816 ao2_ref(cur, -1); 04817 ao2_iterator_destroy(&memi); 04818 ao2_unlock(qe->parent); 04819 goto out; 04820 } 04821 if (!datastore) { 04822 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) { 04823 callattempt_free(tmp); 04824 ao2_ref(cur, -1); 04825 ao2_iterator_destroy(&memi); 04826 ao2_unlock(qe->parent); 04827 goto out; 04828 } 04829 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 04830 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 04831 callattempt_free(tmp); 04832 ao2_ref(cur, -1); 04833 ao2_iterator_destroy(&memi); 04834 ao2_unlock(qe->parent); 04835 goto out; 04836 } 04837 datastore->data = dialed_interfaces; 04838 AST_LIST_HEAD_INIT(dialed_interfaces); 04839 04840 ast_channel_lock(qe->chan); 04841 ast_channel_datastore_add(qe->chan, datastore); 04842 ast_channel_unlock(qe->chan); 04843 } else 04844 dialed_interfaces = datastore->data; 04845 04846 AST_LIST_LOCK(dialed_interfaces); 04847 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 04848 if (!strcasecmp(cur->interface, di->interface)) { 04849 ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n", 04850 di->interface); 04851 break; 04852 } 04853 } 04854 AST_LIST_UNLOCK(dialed_interfaces); 04855 04856 if (di) { 04857 callattempt_free(tmp); 04858 ao2_ref(cur, -1); 04859 continue; 04860 } 04861 04862 /* It is always ok to dial a Local interface. We only keep track of 04863 * which "real" interfaces have been dialed. The Local channel will 04864 * inherit this list so that if it ends up dialing a real interface, 04865 * it won't call one that has already been called. */ 04866 if (strncasecmp(cur->interface, "Local/", 6)) { 04867 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) { 04868 callattempt_free(tmp); 04869 ao2_ref(cur, -1); 04870 ao2_iterator_destroy(&memi); 04871 ao2_unlock(qe->parent); 04872 goto out; 04873 } 04874 strcpy(di->interface, cur->interface); 04875 04876 AST_LIST_LOCK(dialed_interfaces); 04877 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 04878 AST_LIST_UNLOCK(dialed_interfaces); 04879 } 04880 04881 /* 04882 * Seed the callattempt's connected line information with previously 04883 * acquired connected line info from the queued channel. The 04884 * previously acquired connected line info could have been set 04885 * through the CONNECTED_LINE dialplan function. 04886 */ 04887 ast_channel_lock(qe->chan); 04888 ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected); 04889 ast_channel_unlock(qe->chan); 04890 04891 tmp->block_connected_update = block_connected_line; 04892 tmp->stillgoing = 1; 04893 tmp->member = cur;/* Place the reference for cur into callattempt. */ 04894 tmp->lastcall = cur->lastcall; 04895 tmp->lastqueue = cur->lastqueue; 04896 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 04897 /* Special case: If we ring everyone, go ahead and ring them, otherwise 04898 just calculate their metric for the appropriate strategy */ 04899 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 04900 /* Put them in the list of outgoing thingies... We're ready now. 04901 XXX If we're forcibly removed, these outgoing calls won't get 04902 hung up XXX */ 04903 tmp->q_next = outgoing; 04904 outgoing = tmp; 04905 /* If this line is up, don't try anybody else */ 04906 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 04907 break; 04908 } else { 04909 callattempt_free(tmp); 04910 } 04911 } 04912 ao2_iterator_destroy(&memi); 04913 04914 if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) { 04915 /* Application arguments have higher timeout priority (behaviour for <=1.6) */ 04916 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 04917 to = (qe->expire - now) * 1000; 04918 else 04919 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 04920 } else { 04921 /* Config timeout is higher priority thatn application timeout */ 04922 if (qe->expire && qe->expire<=now) { 04923 to = 0; 04924 } else if (qe->parent->timeout) { 04925 to = qe->parent->timeout * 1000; 04926 } else { 04927 to = -1; 04928 } 04929 } 04930 orig = to; 04931 ++qe->pending; 04932 ao2_unlock(qe->parent); 04933 ring_one(qe, outgoing, &numbusies); 04934 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, 04935 ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), 04936 forwardsallowed, ringing); 04937 /* The ast_channel_datastore_remove() function could fail here if the 04938 * datastore was moved to another channel during a masquerade. If this is 04939 * the case, don't free the datastore here because later, when the channel 04940 * to which the datastore was moved hangs up, it will attempt to free this 04941 * datastore again, causing a crash 04942 */ 04943 ast_channel_lock(qe->chan); 04944 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) { 04945 ast_datastore_free(datastore); 04946 } 04947 ast_channel_unlock(qe->chan); 04948 ao2_lock(qe->parent); 04949 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) { 04950 store_next_rr(qe, outgoing); 04951 04952 } 04953 if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) { 04954 store_next_lin(qe, outgoing); 04955 } 04956 ao2_unlock(qe->parent); 04957 peer = lpeer ? lpeer->chan : NULL; 04958 if (!peer) { 04959 qe->pending = 0; 04960 if (to) { 04961 /* Must gotten hung up */ 04962 res = -1; 04963 } else { 04964 /* User exited by pressing a digit */ 04965 res = digit; 04966 } 04967 if (res == -1) 04968 ast_debug(1, "%s: Nobody answered.\n", qe->chan->name); 04969 if (ast_cdr_isset_unanswered()) { 04970 /* channel contains the name of one of the outgoing channels 04971 in its CDR; zero out this CDR to avoid a dual-posting */ 04972 struct callattempt *o; 04973 for (o = outgoing; o; o = o->q_next) { 04974 if (!o->chan) { 04975 continue; 04976 } 04977 if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) { 04978 ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED); 04979 break; 04980 } 04981 } 04982 } 04983 } else { /* peer is valid */ 04984 /* Ah ha! Someone answered within the desired timeframe. Of course after this 04985 we will always return with -1 so that it is hung up properly after the 04986 conversation. */ 04987 if (!strcmp(qe->chan->tech->type, "DAHDI")) 04988 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 04989 if (!strcmp(peer->tech->type, "DAHDI")) 04990 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 04991 /* Update parameters for the queue */ 04992 time(&now); 04993 recalc_holdtime(qe, (now - qe->start)); 04994 ao2_lock(qe->parent); 04995 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 04996 ao2_unlock(qe->parent); 04997 member = lpeer->member; 04998 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ 04999 ao2_ref(member, 1); 05000 hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere); 05001 outgoing = NULL; 05002 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 05003 int res2; 05004 05005 res2 = ast_autoservice_start(qe->chan); 05006 if (!res2) { 05007 if (qe->parent->memberdelay) { 05008 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 05009 res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 05010 } 05011 if (!res2 && announce) { 05012 if (play_file(peer, announce) < 0) { 05013 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", announce, peer->name); 05014 } 05015 } 05016 if (!res2 && qe->parent->reportholdtime) { 05017 if (!play_file(peer, qe->parent->sound_reporthold)) { 05018 int holdtime, holdtimesecs; 05019 05020 time(&now); 05021 holdtime = abs((now - qe->start) / 60); 05022 holdtimesecs = abs((now - qe->start) % 60); 05023 if (holdtime > 0) { 05024 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 05025 if (play_file(peer, qe->parent->sound_minutes) < 0) { 05026 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, peer->name); 05027 } 05028 } 05029 if (holdtimesecs > 1) { 05030 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL); 05031 if (play_file(peer, qe->parent->sound_seconds) < 0) { 05032 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, peer->name); 05033 } 05034 } 05035 } 05036 } 05037 ast_autoservice_stop(qe->chan); 05038 } 05039 if (ast_check_hangup(peer)) { 05040 /* Agent must have hung up */ 05041 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name); 05042 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", ""); 05043 if (qe->parent->eventwhencalled) 05044 manager_event(EVENT_FLAG_AGENT, "AgentDump", 05045 "Queue: %s\r\n" 05046 "Uniqueid: %s\r\n" 05047 "Channel: %s\r\n" 05048 "Member: %s\r\n" 05049 "MemberName: %s\r\n" 05050 "%s", 05051 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 05052 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 05053 ast_hangup(peer); 05054 ao2_ref(member, -1); 05055 goto out; 05056 } else if (ast_check_hangup(qe->chan)) { 05057 /* Caller must have hung up just before being connected */ 05058 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 05059 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 05060 record_abandoned(qe); 05061 ast_hangup(peer); 05062 ao2_ref(member, -1); 05063 return -1; 05064 } 05065 } 05066 /* Stop music on hold */ 05067 if (ringing) 05068 ast_indicate(qe->chan,-1); 05069 else 05070 ast_moh_stop(qe->chan); 05071 /* If appropriate, log that we have a destination channel */ 05072 if (qe->chan->cdr) 05073 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 05074 /* Make sure channels are compatible */ 05075 res = ast_channel_make_compatible(qe->chan, peer); 05076 if (res < 0) { 05077 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", ""); 05078 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 05079 record_abandoned(qe); 05080 ast_cdr_failed(qe->chan->cdr); 05081 ast_hangup(peer); 05082 ao2_ref(member, -1); 05083 return -1; 05084 } 05085 05086 /* Play announcement to the caller telling it's his turn if defined */ 05087 if (!ast_strlen_zero(qe->parent->sound_callerannounce)) { 05088 if (play_file(qe->chan, qe->parent->sound_callerannounce)) 05089 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce); 05090 } 05091 05092 ao2_lock(qe->parent); 05093 /* if setinterfacevar is defined, make member variables available to the channel */ 05094 /* use pbx_builtin_setvar to set a load of variables with one call */ 05095 if (qe->parent->setinterfacevar) { 05096 snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d", 05097 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime); 05098 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 05099 pbx_builtin_setvar_multiple(peer, interfacevar); 05100 } 05101 05102 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */ 05103 /* use pbx_builtin_setvar to set a load of variables with one call */ 05104 if (qe->parent->setqueueentryvar) { 05105 snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d", 05106 (long) time(NULL) - qe->start, qe->opos); 05107 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 05108 pbx_builtin_setvar_multiple(peer, interfacevar); 05109 } 05110 05111 ao2_unlock(qe->parent); 05112 05113 /* try to set queue variables if configured to do so*/ 05114 set_queue_variables(qe->parent, qe->chan); 05115 set_queue_variables(qe->parent, peer); 05116 05117 ast_channel_lock(qe->chan); 05118 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) { 05119 monitorfilename = ast_strdupa(monitorfilename); 05120 } 05121 ast_channel_unlock(qe->chan); 05122 /* Begin Monitoring */ 05123 if (qe->parent->monfmt && *qe->parent->monfmt) { 05124 if (!qe->parent->montype) { 05125 const char *monexec; 05126 ast_debug(1, "Starting Monitor as requested.\n"); 05127 ast_channel_lock(qe->chan); 05128 if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) { 05129 which = qe->chan; 05130 monexec = monexec ? ast_strdupa(monexec) : NULL; 05131 } 05132 else 05133 which = peer; 05134 ast_channel_unlock(qe->chan); 05135 if (monitorfilename) { 05136 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT); 05137 } else if (qe->chan->cdr) { 05138 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT); 05139 } else { 05140 /* Last ditch effort -- no CDR, make up something */ 05141 snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random()); 05142 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT); 05143 } 05144 if (!ast_strlen_zero(monexec)) { 05145 ast_monitor_setjoinfiles(which, 1); 05146 } 05147 } else { 05148 mixmonapp = pbx_findapp("MixMonitor"); 05149 05150 if (mixmonapp) { 05151 ast_debug(1, "Starting MixMonitor as requested.\n"); 05152 if (!monitorfilename) { 05153 if (qe->chan->cdr) 05154 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)); 05155 else 05156 snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random()); 05157 } else { 05158 const char *m = monitorfilename; 05159 for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) { 05160 switch (*m) { 05161 case '^': 05162 if (*(m + 1) == '{') 05163 *p = '$'; 05164 break; 05165 case ',': 05166 *p++ = '\\'; 05167 /* Fall through */ 05168 default: 05169 *p = *m; 05170 } 05171 if (*m == '\0') 05172 break; 05173 } 05174 if (p == tmpid2 + sizeof(tmpid2)) 05175 tmpid2[sizeof(tmpid2) - 1] = '\0'; 05176 05177 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 05178 } 05179 05180 ast_channel_lock(qe->chan); 05181 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) { 05182 monitor_exec = ast_strdupa(monitor_exec); 05183 } 05184 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) { 05185 monitor_options = ast_strdupa(monitor_options); 05186 } else { 05187 monitor_options = ""; 05188 } 05189 ast_channel_unlock(qe->chan); 05190 05191 if (monitor_exec) { 05192 const char *m = monitor_exec; 05193 for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) { 05194 switch (*m) { 05195 case '^': 05196 if (*(m + 1) == '{') 05197 *p = '$'; 05198 break; 05199 case ',': 05200 *p++ = '\\'; 05201 /* Fall through */ 05202 default: 05203 *p = *m; 05204 } 05205 if (*m == '\0') 05206 break; 05207 } 05208 if (p == meid2 + sizeof(meid2)) 05209 meid2[sizeof(meid2) - 1] = '\0'; 05210 05211 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 05212 } 05213 05214 snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt); 05215 05216 if (!ast_strlen_zero(monitor_exec)) 05217 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec); 05218 else 05219 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options); 05220 05221 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 05222 /* We purposely lock the CDR so that pbx_exec does not update the application data */ 05223 if (qe->chan->cdr) 05224 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 05225 pbx_exec(qe->chan, mixmonapp, mixmonargs); 05226 if (qe->chan->cdr) 05227 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 05228 05229 } else { 05230 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 05231 } 05232 } 05233 } 05234 /* Drop out of the queue at this point, to prepare for next caller */ 05235 leave_queue(qe); 05236 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 05237 ast_debug(1, "app_queue: sendurl=%s.\n", url); 05238 ast_channel_sendurl(peer, url); 05239 } 05240 05241 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */ 05242 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */ 05243 if (!ast_strlen_zero(macro)) { 05244 macroexec = ast_strdupa(macro); 05245 } else { 05246 if (qe->parent->membermacro) 05247 macroexec = ast_strdupa(qe->parent->membermacro); 05248 } 05249 05250 if (!ast_strlen_zero(macroexec)) { 05251 ast_debug(1, "app_queue: macro=%s.\n", macroexec); 05252 05253 res = ast_autoservice_start(qe->chan); 05254 if (res) { 05255 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 05256 res = -1; 05257 } 05258 05259 application = pbx_findapp("Macro"); 05260 05261 if (application) { 05262 res = pbx_exec(peer, application, macroexec); 05263 ast_debug(1, "Macro exited with status %d\n", res); 05264 res = 0; 05265 } else { 05266 ast_log(LOG_ERROR, "Could not find application Macro\n"); 05267 res = -1; 05268 } 05269 05270 if (ast_autoservice_stop(qe->chan) < 0) { 05271 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 05272 res = -1; 05273 } 05274 } 05275 05276 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */ 05277 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */ 05278 if (!ast_strlen_zero(gosub)) { 05279 gosubexec = ast_strdupa(gosub); 05280 } else { 05281 if (qe->parent->membergosub) 05282 gosubexec = ast_strdupa(qe->parent->membergosub); 05283 } 05284 05285 if (!ast_strlen_zero(gosubexec)) { 05286 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec); 05287 05288 res = ast_autoservice_start(qe->chan); 05289 if (res) { 05290 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 05291 res = -1; 05292 } 05293 05294 application = pbx_findapp("Gosub"); 05295 05296 if (application) { 05297 char *gosub_args, *gosub_argstart; 05298 05299 /* Set where we came from */ 05300 ast_copy_string(peer->context, "app_queue_gosub_virtual_context", sizeof(peer->context)); 05301 ast_copy_string(peer->exten, "s", sizeof(peer->exten)); 05302 peer->priority = 0; 05303 05304 gosub_argstart = strchr(gosubexec, ','); 05305 if (gosub_argstart) { 05306 const char *what_is_s = "s"; 05307 *gosub_argstart = 0; 05308 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) && 05309 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) { 05310 what_is_s = "~~s~~"; 05311 } 05312 if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) { 05313 gosub_args = NULL; 05314 } 05315 *gosub_argstart = ','; 05316 } else { 05317 const char *what_is_s = "s"; 05318 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) && 05319 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) { 05320 what_is_s = "~~s~~"; 05321 } 05322 if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) { 05323 gosub_args = NULL; 05324 } 05325 } 05326 if (gosub_args) { 05327 res = pbx_exec(peer, application, gosub_args); 05328 if (!res) { 05329 struct ast_pbx_args args; 05330 memset(&args, 0, sizeof(args)); 05331 args.no_hangup_chan = 1; 05332 ast_pbx_run_args(peer, &args); 05333 } 05334 ast_free(gosub_args); 05335 ast_debug(1, "Gosub exited with status %d\n", res); 05336 } else { 05337 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n"); 05338 } 05339 } else { 05340 ast_log(LOG_ERROR, "Could not find application Gosub\n"); 05341 res = -1; 05342 } 05343 05344 if (ast_autoservice_stop(qe->chan) < 0) { 05345 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 05346 res = -1; 05347 } 05348 } 05349 05350 if (!ast_strlen_zero(agi)) { 05351 ast_debug(1, "app_queue: agi=%s.\n", agi); 05352 application = pbx_findapp("agi"); 05353 if (application) { 05354 agiexec = ast_strdupa(agi); 05355 pbx_exec(qe->chan, application, agiexec); 05356 } else 05357 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 05358 } 05359 qe->handled++; 05360 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid, 05361 (long)(orig - to > 0 ? (orig - to) / 1000 : 0)); 05362 05363 if (qe->chan->cdr) { 05364 struct ast_cdr *cdr; 05365 struct ast_cdr *newcdr; 05366 05367 /* Only work with the last CDR in the stack*/ 05368 cdr = qe->chan->cdr; 05369 while (cdr->next) { 05370 cdr = cdr->next; 05371 } 05372 05373 /* If this CDR is not related to us add new one*/ 05374 if ((strcasecmp(cdr->uniqueid, qe->chan->uniqueid)) && 05375 (strcasecmp(cdr->linkedid, qe->chan->uniqueid)) && 05376 (newcdr = ast_cdr_dup(cdr))) { 05377 ast_channel_lock(qe->chan); 05378 ast_cdr_init(newcdr, qe->chan); 05379 ast_cdr_reset(newcdr, 0); 05380 cdr = ast_cdr_append(cdr, newcdr); 05381 cdr = cdr->next; 05382 ast_channel_unlock(qe->chan); 05383 } 05384 05385 if (update_cdr) { 05386 ast_copy_string(cdr->dstchannel, member->membername, sizeof(cdr->dstchannel)); 05387 } 05388 } 05389 05390 if (qe->parent->eventwhencalled) 05391 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 05392 "Queue: %s\r\n" 05393 "Uniqueid: %s\r\n" 05394 "Channel: %s\r\n" 05395 "Member: %s\r\n" 05396 "MemberName: %s\r\n" 05397 "Holdtime: %ld\r\n" 05398 "BridgedChannel: %s\r\n" 05399 "Ringtime: %ld\r\n" 05400 "%s", 05401 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 05402 (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0), 05403 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 05404 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 05405 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 05406 05407 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) { 05408 queue_end_bridge->q = qe->parent; 05409 queue_end_bridge->chan = qe->chan; 05410 bridge_config.end_bridge_callback = end_bridge_callback; 05411 bridge_config.end_bridge_callback_data = queue_end_bridge; 05412 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 05413 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need 05414 * to make sure to increase the refcount of this queue so it cannot be freed until we 05415 * are done with it. We remove this reference in end_bridge_callback. 05416 */ 05417 queue_t_ref(qe->parent, "For bridge_config reference"); 05418 } 05419 05420 time(&callstart); 05421 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl); 05422 bridge = ast_bridge_call(qe->chan, peer, &bridge_config); 05423 05424 /* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log 05425 * when the masquerade occurred. These other "ending" queue_log messages are unnecessary, except for 05426 * the AgentComplete manager event 05427 */ 05428 ast_channel_lock(qe->chan); 05429 if (!attended_transfer_occurred(qe->chan)) { 05430 struct ast_datastore *tds; 05431 05432 /* detect a blind transfer */ 05433 if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) { 05434 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 05435 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 05436 (long) (time(NULL) - callstart), qe->opos); 05437 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER); 05438 } else if (ast_check_hangup(qe->chan) && !ast_check_hangup(peer)) { 05439 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d", 05440 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 05441 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER); 05442 } else { 05443 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 05444 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 05445 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT); 05446 } 05447 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) { 05448 ast_channel_datastore_remove(qe->chan, tds); 05449 /* tds was added by setup_transfer_datastore() and is freed below. */ 05450 } 05451 ast_channel_unlock(qe->chan); 05452 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart)); 05453 } else { 05454 ast_channel_unlock(qe->chan); 05455 05456 /* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */ 05457 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER); 05458 } 05459 05460 if (transfer_ds) { 05461 ast_datastore_free(transfer_ds); 05462 } 05463 ast_hangup(peer); 05464 res = bridge ? bridge : 1; 05465 ao2_ref(member, -1); 05466 } 05467 out: 05468 hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere); 05469 05470 return res; 05471 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 8781 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_ref, ao2_t_iterator_next, ARRAY_LEN, ast_cli_unregister_multiple(), ast_context_destroy(), ast_context_find(), ast_context_remove_extension2(), ast_custom_function_unregister(), ast_data_unregister, ast_event_unsubscribe(), ast_extension_state_del(), ast_manager_unregister(), ast_taskprocessor_unreference(), ast_unload_realtime(), ast_unregister_application(), extension_state_cb(), queue_t_unref, queues, and queues_t_unlink.
08782 { 08783 int res; 08784 struct ast_context *con; 08785 struct ao2_iterator q_iter; 08786 struct call_queue *q = NULL; 08787 08788 ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue)); 08789 res = ast_manager_unregister("QueueStatus"); 08790 res |= ast_manager_unregister("Queues"); 08791 res |= ast_manager_unregister("QueueRule"); 08792 res |= ast_manager_unregister("QueueSummary"); 08793 res |= ast_manager_unregister("QueueAdd"); 08794 res |= ast_manager_unregister("QueueRemove"); 08795 res |= ast_manager_unregister("QueuePause"); 08796 res |= ast_manager_unregister("QueueLog"); 08797 res |= ast_manager_unregister("QueuePenalty"); 08798 res |= ast_manager_unregister("QueueReload"); 08799 res |= ast_manager_unregister("QueueReset"); 08800 res |= ast_unregister_application(app_aqm); 08801 res |= ast_unregister_application(app_rqm); 08802 res |= ast_unregister_application(app_pqm); 08803 res |= ast_unregister_application(app_upqm); 08804 res |= ast_unregister_application(app_ql); 08805 res |= ast_unregister_application(app); 08806 res |= ast_custom_function_unregister(&queueexists_function); 08807 res |= ast_custom_function_unregister(&queuevar_function); 08808 res |= ast_custom_function_unregister(&queuemembercount_function); 08809 res |= ast_custom_function_unregister(&queuemembercount_dep); 08810 res |= ast_custom_function_unregister(&queuememberlist_function); 08811 res |= ast_custom_function_unregister(&queuewaitingcount_function); 08812 res |= ast_custom_function_unregister(&queuememberpenalty_function); 08813 08814 res |= ast_data_unregister(NULL); 08815 08816 if (device_state_sub) 08817 ast_event_unsubscribe(device_state_sub); 08818 08819 ast_extension_state_del(0, extension_state_cb); 08820 08821 if ((con = ast_context_find("app_queue_gosub_virtual_context"))) { 08822 ast_context_remove_extension2(con, "s", 1, NULL, 0); 08823 ast_context_destroy(con, "app_queue"); /* leave no trace */ 08824 } 08825 08826 q_iter = ao2_iterator_init(queues, 0); 08827 while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) { 08828 queues_t_unlink(queues, q, "Remove queue from container due to unload"); 08829 queue_t_unref(q, "Done with iterator"); 08830 } 08831 ao2_iterator_destroy(&q_iter); 08832 devicestate_tps = ast_taskprocessor_unreference(devicestate_tps); 08833 ao2_ref(queues, -1); 08834 ast_unload_realtime("queue_members"); 08835 return res; 08836 }
| static void update_qe_rule | ( | struct queue_ent * | qe | ) | [static] |
update rules for queues
Calculate min/max penalties making sure if relative they stay within bounds. Update queues penalty and set dialplan vars, goto next list entry.
Definition at line 4228 of file app_queue.c.
References ast_debug, AST_LIST_NEXT, queue_ent::chan, queue_ent::max_penalty, queue_ent::min_penalty, and pbx_builtin_setvar_helper().
Referenced by queue_exec(), and wait_our_turn().
04229 { 04230 int max_penalty = INT_MAX; 04231 04232 if (qe->max_penalty != INT_MAX) { 04233 char max_penalty_str[20]; 04234 04235 if (qe->pr->max_relative) { 04236 max_penalty = qe->max_penalty + qe->pr->max_value; 04237 } else { 04238 max_penalty = qe->pr->max_value; 04239 } 04240 04241 /* a relative change to the penalty could put it below 0 */ 04242 if (max_penalty < 0) { 04243 max_penalty = 0; 04244 } 04245 04246 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty); 04247 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str); 04248 qe->max_penalty = max_penalty; 04249 ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n", 04250 qe->max_penalty, qe->chan->name, qe->pr->time); 04251 } 04252 04253 if (qe->min_penalty != INT_MAX) { 04254 char min_penalty_str[20]; 04255 int min_penalty; 04256 04257 if (qe->pr->min_relative) { 04258 min_penalty = qe->min_penalty + qe->pr->min_value; 04259 } else { 04260 min_penalty = qe->pr->min_value; 04261 } 04262 04263 if (min_penalty < 0) { 04264 min_penalty = 0; 04265 } 04266 04267 if (max_penalty != INT_MAX && min_penalty > max_penalty) { 04268 min_penalty = max_penalty; 04269 } 04270 04271 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty); 04272 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str); 04273 qe->min_penalty = min_penalty; 04274 ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n", 04275 qe->min_penalty, qe->chan->name, qe->pr->time); 04276 } 04277 04278 qe->pr = AST_LIST_NEXT(qe->pr, list); 04279 }
| static int update_queue | ( | struct call_queue * | q, | |
| struct member * | member, | |||
| int | callcompletedinsl, | |||
| int | newtalktime | |||
| ) | [static] |
update the queue status
| Always | 0 |
Definition at line 4367 of file app_queue.c.
References ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, member::calls, call_queue::callscompleted, call_queue::callscompletedinsl, member::lastcall, member::lastqueue, call_queue::members, OBJ_POINTER, queue_t_unref, queues, and call_queue::talktime.
Referenced by queue_transfer_fixup(), and try_calling().
04368 { 04369 int oldtalktime; 04370 04371 struct member *mem; 04372 struct call_queue *qtmp; 04373 struct ao2_iterator queue_iter; 04374 04375 if (shared_lastcall) { 04376 queue_iter = ao2_iterator_init(queues, 0); 04377 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 04378 ao2_lock(qtmp); 04379 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) { 04380 time(&mem->lastcall); 04381 mem->calls++; 04382 mem->lastqueue = q; 04383 ao2_ref(mem, -1); 04384 } 04385 ao2_unlock(qtmp); 04386 queue_t_unref(qtmp, "Done with iterator"); 04387 } 04388 ao2_iterator_destroy(&queue_iter); 04389 } else { 04390 ao2_lock(q); 04391 time(&member->lastcall); 04392 member->calls++; 04393 member->lastqueue = q; 04394 ao2_unlock(q); 04395 } 04396 ao2_lock(q); 04397 q->callscompleted++; 04398 if (callcompletedinsl) 04399 q->callscompletedinsl++; 04400 /* Calculate talktime using the same exponential average as holdtime code*/ 04401 oldtalktime = q->talktime; 04402 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2; 04403 ao2_unlock(q); 04404 return 0; 04405 }
| static int update_realtime_member_field | ( | struct member * | mem, | |
| const char * | queue_name, | |||
| const char * | field, | |||
| const char * | value | |||
| ) | [static] |
Definition at line 2529 of file app_queue.c.
References ast_strlen_zero(), ast_update_realtime(), member::rt_uniqueid, and SENTINEL.
Referenced by set_member_paused().
02530 { 02531 int ret = -1; 02532 02533 if (ast_strlen_zero(mem->rt_uniqueid)) 02534 return ret; 02535 02536 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0) 02537 ret = 0; 02538 02539 return ret; 02540 }
| static void update_realtime_members | ( | struct call_queue * | q | ) | [static] |
Definition at line 2543 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_category_browse(), ast_config_destroy(), ast_debug, ast_load_realtime_multientry(), ast_queue_log(), ast_variable_retrieve(), member::dead, member::interface, member_remove_from_queue(), call_queue::members, member::realtime, rt_handle_member_record(), S_OR, and SENTINEL.
Referenced by load_realtime_queue(), and queue_exec().
02544 { 02545 struct ast_config *member_config = NULL; 02546 struct member *m; 02547 char *interface = NULL; 02548 struct ao2_iterator mem_iter; 02549 02550 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) { 02551 /* This queue doesn't have realtime members. If the queue still has any realtime 02552 * members in memory, they need to be removed. 02553 */ 02554 ao2_lock(q); 02555 mem_iter = ao2_iterator_init(q->members, 0); 02556 while ((m = ao2_iterator_next(&mem_iter))) { 02557 if (m->realtime) { 02558 member_remove_from_queue(q, m); 02559 } 02560 ao2_ref(m, -1); 02561 } 02562 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name); 02563 ao2_unlock(q); 02564 return; 02565 } 02566 02567 ao2_lock(q); 02568 02569 /* Temporarily set realtime members dead so we can detect deleted ones.*/ 02570 mem_iter = ao2_iterator_init(q->members, 0); 02571 while ((m = ao2_iterator_next(&mem_iter))) { 02572 if (m->realtime) 02573 m->dead = 1; 02574 ao2_ref(m, -1); 02575 } 02576 ao2_iterator_destroy(&mem_iter); 02577 02578 while ((interface = ast_category_browse(member_config, interface))) { 02579 rt_handle_member_record(q, interface, 02580 ast_variable_retrieve(member_config, interface, "uniqueid"), 02581 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), 02582 ast_variable_retrieve(member_config, interface, "penalty"), 02583 ast_variable_retrieve(member_config, interface, "paused"), 02584 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface)); 02585 } 02586 02587 /* Delete all realtime members that have been deleted in DB. */ 02588 mem_iter = ao2_iterator_init(q->members, 0); 02589 while ((m = ao2_iterator_next(&mem_iter))) { 02590 if (m->dead) { 02591 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 02592 member_remove_from_queue(q, m); 02593 } 02594 ao2_ref(m, -1); 02595 } 02596 ao2_iterator_destroy(&mem_iter); 02597 ao2_unlock(q); 02598 ast_config_destroy(member_config); 02599 }
| static int update_status | ( | struct call_queue * | q, | |
| struct member * | m, | |||
| const int | status | |||
| ) | [static] |
set a member's status based on device state of that member's state_interface.
Lock interface list find sc, iterate through each queues queue_member list for member to update state inside queues
Definition at line 1536 of file app_queue.c.
References member::calls, member::dynamic, EVENT_FLAG_AGENT, member::interface, member::lastcall, manager_event, call_queue::maskmemberstatus, member::membername, member::paused, member::penalty, member::realtime, and member::status.
Referenced by extension_state_cb(), and handle_statechange().
01537 { 01538 m->status = status; 01539 01540 if (q->maskmemberstatus) 01541 return 0; 01542 01543 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 01544 "Queue: %s\r\n" 01545 "Location: %s\r\n" 01546 "MemberName: %s\r\n" 01547 "Membership: %s\r\n" 01548 "Penalty: %d\r\n" 01549 "CallsTaken: %d\r\n" 01550 "LastCall: %d\r\n" 01551 "Status: %d\r\n" 01552 "Paused: %d\r\n", 01553 q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static", 01554 m->penalty, m->calls, (int)m->lastcall, m->status, m->paused 01555 ); 01556 01557 return 0; 01558 }
| static int upqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
UnPauseQueueMember application.
Definition at line 5951 of file app_queue.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, parse(), pbx_builtin_setvar_helper(), and set_member_paused().
Referenced by load_module().
05952 { 05953 char *parse; 05954 AST_DECLARE_APP_ARGS(args, 05955 AST_APP_ARG(queuename); 05956 AST_APP_ARG(interface); 05957 AST_APP_ARG(options); 05958 AST_APP_ARG(reason); 05959 ); 05960 05961 if (ast_strlen_zero(data)) { 05962 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n"); 05963 return -1; 05964 } 05965 05966 parse = ast_strdupa(data); 05967 05968 AST_STANDARD_APP_ARGS(args, parse); 05969 05970 if (ast_strlen_zero(args.interface)) { 05971 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 05972 return -1; 05973 } 05974 05975 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) { 05976 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 05977 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 05978 return 0; 05979 } 05980 05981 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 05982 05983 return 0; 05984 }
| static int valid_exit | ( | struct queue_ent * | qe, | |
| char | digit | |||
| ) | [static] |
Check for valid exit from queue via goto.
| 0 | if failure | |
| 1 | if successful |
Definition at line 2716 of file app_queue.c.
References ast_canmatch_extension(), ast_goto_if_exists(), ast_strlen_zero(), ast_channel::caller, queue_ent::chan, queue_ent::context, queue_ent::digits, ast_party_caller::id, ast_party_id::number, S_COR, ast_party_number::str, ast_party_number::valid, and queue_ent::valid_digits.
Referenced by say_periodic_announcement(), say_position(), wait_a_bit(), wait_for_answer(), and wait_our_turn().
02717 { 02718 int digitlen = strlen(qe->digits); 02719 02720 /* Prevent possible buffer overflow */ 02721 if (digitlen < sizeof(qe->digits) - 2) { 02722 qe->digits[digitlen] = digit; 02723 qe->digits[digitlen + 1] = '\0'; 02724 } else { 02725 qe->digits[0] = '\0'; 02726 return 0; 02727 } 02728 02729 /* If there's no context to goto, short-circuit */ 02730 if (ast_strlen_zero(qe->context)) 02731 return 0; 02732 02733 /* If the extension is bad, then reset the digits to blank */ 02734 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, 02735 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, NULL))) { 02736 qe->digits[0] = '\0'; 02737 return 0; 02738 } 02739 02740 /* We have an exact match */ 02741 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 02742 qe->valid_digits = 1; 02743 /* Return 1 on a successful goto */ 02744 return 1; 02745 } 02746 02747 return 0; 02748 }
| static char* vars2manager | ( | struct ast_channel * | chan, | |
| char * | vars, | |||
| size_t | len | |||
| ) | [static] |
convert "\n" to "\nVariable: " ready for manager to use
Definition at line 3104 of file app_queue.c.
References ast_copy_string(), ast_str_buffer(), ast_str_thread_get(), and pbx_builtin_serialize_variables().
Referenced by ring_entry(), rna(), send_agent_complete(), and try_calling().
03105 { 03106 struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1); 03107 const char *tmp; 03108 03109 if (pbx_builtin_serialize_variables(chan, &buf)) { 03110 int i, j; 03111 03112 /* convert "\n" to "\nVariable: " */ 03113 strcpy(vars, "Variable: "); 03114 tmp = ast_str_buffer(buf); 03115 03116 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 03117 vars[j] = tmp[i]; 03118 03119 if (tmp[i + 1] == '\0') 03120 break; 03121 if (tmp[i] == '\n') { 03122 vars[j++] = '\r'; 03123 vars[j++] = '\n'; 03124 03125 ast_copy_string(&(vars[j]), "Variable: ", len - j); 03126 j += 9; 03127 } 03128 } 03129 if (j > len - 3) 03130 j = len - 3; 03131 vars[j++] = '\r'; 03132 vars[j++] = '\n'; 03133 vars[j] = '\0'; 03134 } else { 03135 /* there are no channel variables; leave it blank */ 03136 *vars = '\0'; 03137 } 03138 return vars; 03139 }
| static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 5473 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
05474 { 05475 /* Don't need to hold the lock while we setup the outgoing calls */ 05476 int retrywait = qe->parent->retry * 1000; 05477 05478 int res = ast_waitfordigit(qe->chan, retrywait); 05479 if (res > 0 && !valid_exit(qe, res)) 05480 res = 0; 05481 05482 return res; 05483 }
| static struct callattempt* wait_for_answer | ( | struct queue_ent * | qe, | |
| struct callattempt * | outgoing, | |||
| int * | to, | |||
| char * | digit, | |||
| int | prebusies, | |||
| int | caller_disconnect, | |||
| int | forwardsallowed, | |||
| int | ringing | |||
| ) | [static, read] |
Wait for a member to answer the call.
| [in] | qe | the queue_ent corresponding to the caller in the queue |
| [in] | outgoing | the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero |
| [in] | to | the amount of time (in milliseconds) to wait for a response |
| [out] | digit | if a user presses a digit to exit the queue, this is the digit the caller pressed |
| [in] | prebusies | number of busy members calculated prior to calling wait_for_answer |
| [in] | caller_disconnect | if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call |
| [in] | forwardsallowed | used to detect if we should allow call forwarding, based on the 'i' option to Queue() |
Definition at line 3668 of file app_queue.c.
References ast_channel::_state, accountcode, call_queue::announce_to_first_user, call_queue::announcefrequency, callattempt::aoc_s_rate_list, ast_aoc_decode(), ast_aoc_destroy_decoded(), ast_aoc_destroy_encoded(), ast_aoc_encode(), ast_aoc_get_msg_type(), AST_AOC_S, ast_call(), ast_cdr_busy(), AST_CEL_FORWARD, ast_cel_report_event(), ast_channel_connected_line_macro(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_lock_both, AST_CHANNEL_NAME, ast_channel_redirecting_macro(), ast_channel_unlock, ast_channel_update_connected_line(), ast_channel_update_redirecting(), ast_connected_line_copy_from_caller(), ast_connected_line_parse_data(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, AST_CONTROL_AOC, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_HANGUP, AST_CONTROL_OFFHOOK, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, ast_copy_string(), ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_WATCHERS, ast_moh_stop(), ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_party_connected_line_set(), ast_party_connected_line_set_init(), ast_party_number_free(), ast_party_number_init(), ast_party_redirecting_copy(), ast_party_redirecting_free(), ast_party_redirecting_init(), ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), ast_remaining_ms(), ast_request(), AST_STATE_UP, ast_strdup, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_tvnow(), ast_verb, ast_waitfor_n(), callattempt::block_connected_update, callattempt::call_next, ast_channel::caller, ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_channel::connected, callattempt::connected, ast_channel::context, ast_frame::data, ast_frame::datalen, callattempt::dial_callerid_absent, ast_channel::dialed, do_hang(), ast_channel::exten, f, ast_frame::frametype, ast_party_redirecting::from, ast_channel::hangupcause, ast_party_caller::id, ast_frame_subclass::integer, callattempt::interface, member::interface, LOG_NOTICE, ast_channel::macroexten, callattempt::member, member::membername, ast_channel::nativeformats, ast_party_id::number, queue_ent::parent, callattempt::pending_connected_update, call_queue::periodicannouncefrequency, queue_ent::pos, ast_frame::ptr, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ast_channel::redirecting, ring_one(), queue_ent::ring_when_ringing, rna(), S_OR, say_periodic_announcement(), say_position(), ast_party_connected_line::source, queue_ent::start, status, callattempt::stillgoing, ast_party_number::str, call_queue::strategy, ast_frame::subclass, ast_channel::tech, call_queue::timeoutrestart, ast_party_dialed::transit_network_select, ast_frame::uint32, ast_party_number::valid, and valid_exit().
Referenced by try_calling().
03669 { 03670 const char *queue = qe->parent->name; 03671 struct callattempt *o, *start = NULL, *prev = NULL; 03672 int status; 03673 int numbusies = prebusies; 03674 int numnochan = 0; 03675 int stillgoing = 0; 03676 int orig = *to; 03677 struct ast_frame *f; 03678 struct callattempt *peer = NULL; 03679 struct ast_channel *winner; 03680 struct ast_channel *in = qe->chan; 03681 char on[80] = ""; 03682 char membername[80] = ""; 03683 long starttime = 0; 03684 long endtime = 0; 03685 #ifdef HAVE_EPOLL 03686 struct callattempt *epollo; 03687 #endif 03688 struct ast_party_connected_line connected_caller; 03689 char *inchan_name; 03690 struct timeval start_time_tv = ast_tvnow(); 03691 03692 ast_party_connected_line_init(&connected_caller); 03693 03694 ast_channel_lock(qe->chan); 03695 inchan_name = ast_strdupa(qe->chan->name); 03696 ast_channel_unlock(qe->chan); 03697 03698 starttime = (long) time(NULL); 03699 #ifdef HAVE_EPOLL 03700 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 03701 if (epollo->chan) 03702 ast_poll_channel_add(in, epollo->chan); 03703 } 03704 #endif 03705 03706 while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) { 03707 int numlines, retry, pos = 1; 03708 struct ast_channel *watchers[AST_MAX_WATCHERS]; 03709 watchers[0] = in; 03710 start = NULL; 03711 03712 for (retry = 0; retry < 2; retry++) { 03713 numlines = 0; 03714 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 03715 if (o->stillgoing) { /* Keep track of important channels */ 03716 stillgoing = 1; 03717 if (o->chan) { 03718 if (pos < AST_MAX_WATCHERS) { 03719 watchers[pos++] = o->chan; 03720 } 03721 if (!start) 03722 start = o; 03723 else 03724 prev->call_next = o; 03725 prev = o; 03726 } 03727 } 03728 numlines++; 03729 } 03730 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 03731 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 03732 break; 03733 /* On "ringall" strategy we only move to the next penalty level 03734 when *all* ringing phones are done in the current penalty level */ 03735 ring_one(qe, outgoing, &numbusies); 03736 /* and retry... */ 03737 } 03738 if (pos == 1 /* not found */) { 03739 if (numlines == (numbusies + numnochan)) { 03740 ast_debug(1, "Everyone is busy at this time\n"); 03741 } else { 03742 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan); 03743 } 03744 *to = 0; 03745 return NULL; 03746 } 03747 03748 /* Poll for events from both the incoming channel as well as any outgoing channels */ 03749 winner = ast_waitfor_n(watchers, pos, to); 03750 03751 /* Service all of the outgoing channels */ 03752 for (o = start; o; o = o->call_next) { 03753 /* We go with a fixed buffer here instead of using ast_strdupa. Using 03754 * ast_strdupa in a loop like this one can cause a stack overflow 03755 */ 03756 char ochan_name[AST_CHANNEL_NAME]; 03757 03758 if (o->chan) { 03759 ast_channel_lock(o->chan); 03760 ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name)); 03761 ast_channel_unlock(o->chan); 03762 } 03763 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 03764 if (!peer) { 03765 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); 03766 if (!o->block_connected_update) { 03767 if (o->pending_connected_update) { 03768 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { 03769 ast_channel_update_connected_line(in, &o->connected, NULL); 03770 } 03771 } else if (!o->dial_callerid_absent) { 03772 ast_channel_lock(o->chan); 03773 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller); 03774 ast_channel_unlock(o->chan); 03775 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 03776 if (ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) { 03777 ast_channel_update_connected_line(in, &connected_caller, NULL); 03778 } 03779 ast_party_connected_line_free(&connected_caller); 03780 } 03781 } 03782 if (o->aoc_s_rate_list) { 03783 size_t encoded_size; 03784 struct ast_aoc_encoded *encoded; 03785 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) { 03786 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size); 03787 ast_aoc_destroy_encoded(encoded); 03788 } 03789 } 03790 peer = o; 03791 } 03792 } else if (o->chan && (o->chan == winner)) { 03793 03794 ast_copy_string(on, o->member->interface, sizeof(on)); 03795 ast_copy_string(membername, o->member->membername, sizeof(membername)); 03796 03797 /* Before processing channel, go ahead and check for forwarding */ 03798 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { 03799 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward); 03800 numnochan++; 03801 do_hang(o); 03802 winner = NULL; 03803 continue; 03804 } else if (!ast_strlen_zero(o->chan->call_forward)) { 03805 struct ast_channel *original = o->chan; 03806 char tmpchan[256]; 03807 char *stuff; 03808 char *tech; 03809 03810 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 03811 if ((stuff = strchr(tmpchan, '/'))) { 03812 *stuff++ = '\0'; 03813 tech = tmpchan; 03814 } else { 03815 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 03816 stuff = tmpchan; 03817 tech = "Local"; 03818 } 03819 if (!strcasecmp(tech, "Local")) { 03820 /* 03821 * Drop the connected line update block for local channels since 03822 * this is going to run dialplan and the user can change his 03823 * mind about what connected line information he wants to send. 03824 */ 03825 o->block_connected_update = 0; 03826 } 03827 03828 ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL); 03829 03830 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name); 03831 /* Setup parameters */ 03832 o->chan = ast_request(tech, in->nativeformats, in, stuff, &status); 03833 if (!o->chan) { 03834 ast_log(LOG_NOTICE, 03835 "Forwarding failed to create channel to dial '%s/%s'\n", 03836 tech, stuff); 03837 o->stillgoing = 0; 03838 numnochan++; 03839 } else { 03840 ast_channel_lock_both(o->chan, original); 03841 ast_party_redirecting_copy(&o->chan->redirecting, &original->redirecting); 03842 ast_channel_unlock(o->chan); 03843 ast_channel_unlock(original); 03844 03845 ast_channel_lock_both(o->chan, in); 03846 ast_channel_inherit_variables(in, o->chan); 03847 ast_channel_datastore_inherit(in, o->chan); 03848 03849 if (o->pending_connected_update) { 03850 /* 03851 * Re-seed the callattempt's connected line information with 03852 * previously acquired connected line info from the queued 03853 * channel. The previously acquired connected line info could 03854 * have been set through the CONNECTED_LINE dialplan function. 03855 */ 03856 o->pending_connected_update = 0; 03857 ast_party_connected_line_copy(&o->connected, &in->connected); 03858 } 03859 03860 ast_string_field_set(o->chan, accountcode, in->accountcode); 03861 03862 if (!o->chan->redirecting.from.number.valid 03863 || ast_strlen_zero(o->chan->redirecting.from.number.str)) { 03864 /* 03865 * The call was not previously redirected so it is 03866 * now redirected from this number. 03867 */ 03868 ast_party_number_free(&o->chan->redirecting.from.number); 03869 ast_party_number_init(&o->chan->redirecting.from.number); 03870 o->chan->redirecting.from.number.valid = 1; 03871 o->chan->redirecting.from.number.str = 03872 ast_strdup(S_OR(in->macroexten, in->exten)); 03873 } 03874 03875 o->chan->dialed.transit_network_select = in->dialed.transit_network_select; 03876 03877 o->dial_callerid_absent = !o->chan->caller.id.number.valid 03878 || ast_strlen_zero(o->chan->caller.id.number.str); 03879 ast_connected_line_copy_from_caller(&o->chan->connected, &in->caller); 03880 03881 ast_channel_unlock(in); 03882 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL 03883 && !o->block_connected_update) { 03884 struct ast_party_redirecting redirecting; 03885 03886 /* 03887 * Redirecting updates to the caller make sense only on single 03888 * call at a time strategies. 03889 * 03890 * We must unlock o->chan before calling 03891 * ast_channel_redirecting_macro, because we put o->chan into 03892 * autoservice there. That is pretty much a guaranteed 03893 * deadlock. This is why the handling of o->chan's lock may 03894 * seem a bit unusual here. 03895 */ 03896 ast_party_redirecting_init(&redirecting); 03897 ast_party_redirecting_copy(&redirecting, &o->chan->redirecting); 03898 ast_channel_unlock(o->chan); 03899 if (ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0)) { 03900 ast_channel_update_redirecting(in, &redirecting, NULL); 03901 } 03902 ast_party_redirecting_free(&redirecting); 03903 } else { 03904 ast_channel_unlock(o->chan); 03905 } 03906 03907 if (ast_call(o->chan, stuff, 0)) { 03908 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n", 03909 tech, stuff); 03910 do_hang(o); 03911 numnochan++; 03912 } 03913 } 03914 /* Hangup the original channel now, in case we needed it */ 03915 ast_hangup(winner); 03916 continue; 03917 } 03918 f = ast_read(winner); 03919 if (f) { 03920 if (f->frametype == AST_FRAME_CONTROL) { 03921 switch (f->subclass.integer) { 03922 case AST_CONTROL_ANSWER: 03923 /* This is our guy if someone answered. */ 03924 if (!peer) { 03925 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); 03926 if (!o->block_connected_update) { 03927 if (o->pending_connected_update) { 03928 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { 03929 ast_channel_update_connected_line(in, &o->connected, NULL); 03930 } 03931 } else if (!o->dial_callerid_absent) { 03932 ast_channel_lock(o->chan); 03933 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller); 03934 ast_channel_unlock(o->chan); 03935 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 03936 if (ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) { 03937 ast_channel_update_connected_line(in, &connected_caller, NULL); 03938 } 03939 ast_party_connected_line_free(&connected_caller); 03940 } 03941 } 03942 if (o->aoc_s_rate_list) { 03943 size_t encoded_size; 03944 struct ast_aoc_encoded *encoded; 03945 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) { 03946 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size); 03947 ast_aoc_destroy_encoded(encoded); 03948 } 03949 } 03950 peer = o; 03951 } 03952 break; 03953 case AST_CONTROL_BUSY: 03954 ast_verb(3, "%s is busy\n", ochan_name); 03955 if (in->cdr) 03956 ast_cdr_busy(in->cdr); 03957 do_hang(o); 03958 endtime = (long) time(NULL); 03959 endtime -= starttime; 03960 rna(endtime * 1000, qe, on, membername, 0); 03961 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03962 if (qe->parent->timeoutrestart) { 03963 start_time_tv = ast_tvnow(); 03964 } 03965 /* Have enough time for a queue member to answer? */ 03966 if (ast_remaining_ms(start_time_tv, orig) > 500) { 03967 ring_one(qe, outgoing, &numbusies); 03968 starttime = (long) time(NULL); 03969 } 03970 } 03971 numbusies++; 03972 break; 03973 case AST_CONTROL_CONGESTION: 03974 ast_verb(3, "%s is circuit-busy\n", ochan_name); 03975 if (in->cdr) 03976 ast_cdr_busy(in->cdr); 03977 endtime = (long) time(NULL); 03978 endtime -= starttime; 03979 rna(endtime * 1000, qe, on, membername, 0); 03980 do_hang(o); 03981 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03982 if (qe->parent->timeoutrestart) { 03983 start_time_tv = ast_tvnow(); 03984 } 03985 if (ast_remaining_ms(start_time_tv, orig) > 500) { 03986 ring_one(qe, outgoing, &numbusies); 03987 starttime = (long) time(NULL); 03988 } 03989 } 03990 numbusies++; 03991 break; 03992 case AST_CONTROL_RINGING: 03993 ast_verb(3, "%s is ringing\n", ochan_name); 03994 03995 /* Start ring indication when the channel is ringing, if specified */ 03996 if (qe->ring_when_ringing) { 03997 ast_moh_stop(qe->chan); 03998 ast_indicate(qe->chan, AST_CONTROL_RINGING); 03999 } 04000 break; 04001 case AST_CONTROL_OFFHOOK: 04002 /* Ignore going off hook */ 04003 break; 04004 case AST_CONTROL_CONNECTED_LINE: 04005 if (o->block_connected_update) { 04006 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name); 04007 break; 04008 } 04009 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 04010 struct ast_party_connected_line connected; 04011 04012 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name); 04013 ast_party_connected_line_set_init(&connected, &o->connected); 04014 ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected); 04015 ast_party_connected_line_set(&o->connected, &connected, NULL); 04016 ast_party_connected_line_free(&connected); 04017 o->pending_connected_update = 1; 04018 break; 04019 } 04020 04021 /* 04022 * Prevent using the CallerID from the outgoing channel since we 04023 * got a connected line update from it. 04024 */ 04025 o->dial_callerid_absent = 1; 04026 04027 if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) { 04028 ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); 04029 } 04030 break; 04031 case AST_CONTROL_AOC: 04032 { 04033 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan); 04034 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) { 04035 ast_aoc_destroy_decoded(o->aoc_s_rate_list); 04036 o->aoc_s_rate_list = decoded; 04037 } else { 04038 ast_aoc_destroy_decoded(decoded); 04039 } 04040 } 04041 break; 04042 case AST_CONTROL_REDIRECTING: 04043 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 04044 /* 04045 * Redirecting updates to the caller make sense only on single 04046 * call at a time strategies. 04047 */ 04048 break; 04049 } 04050 if (o->block_connected_update) { 04051 ast_verb(3, "Redirecting update to %s prevented\n", 04052 inchan_name); 04053 break; 04054 } 04055 ast_verb(3, "%s redirecting info has changed, passing it to %s\n", 04056 ochan_name, inchan_name); 04057 if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) { 04058 ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); 04059 } 04060 break; 04061 default: 04062 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer); 04063 break; 04064 } 04065 } 04066 ast_frfree(f); 04067 } else { /* ast_read() returned NULL */ 04068 endtime = (long) time(NULL) - starttime; 04069 rna(endtime * 1000, qe, on, membername, 1); 04070 do_hang(o); 04071 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 04072 if (qe->parent->timeoutrestart) { 04073 start_time_tv = ast_tvnow(); 04074 } 04075 if (ast_remaining_ms(start_time_tv, orig) > 500) { 04076 ring_one(qe, outgoing, &numbusies); 04077 starttime = (long) time(NULL); 04078 } 04079 } 04080 } 04081 } 04082 } 04083 04084 /* If we received an event from the caller, deal with it. */ 04085 if (winner == in) { 04086 f = ast_read(in); 04087 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) { 04088 /* Got hung up */ 04089 *to = -1; 04090 if (f) { 04091 if (f->data.uint32) { 04092 in->hangupcause = f->data.uint32; 04093 } 04094 ast_frfree(f); 04095 } 04096 return NULL; 04097 } 04098 04099 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) { 04100 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer); 04101 *to = 0; 04102 ast_frfree(f); 04103 return NULL; 04104 } 04105 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) { 04106 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer); 04107 *to = 0; 04108 *digit = f->subclass.integer; 04109 ast_frfree(f); 04110 return NULL; 04111 } 04112 04113 /* Send the frame from the in channel to all outgoing channels. */ 04114 for (o = start; o; o = o->call_next) { 04115 if (!o->stillgoing || !o->chan) { 04116 /* This outgoing channel has died so don't send the frame to it. */ 04117 continue; 04118 } 04119 switch (f->frametype) { 04120 case AST_FRAME_CONTROL: 04121 switch (f->subclass.integer) { 04122 case AST_CONTROL_CONNECTED_LINE: 04123 if (ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) { 04124 ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen); 04125 } 04126 break; 04127 case AST_CONTROL_REDIRECTING: 04128 if (ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) { 04129 ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen); 04130 } 04131 break; 04132 default: 04133 /* We are not going to do anything with this frame. */ 04134 goto skip_frame; 04135 } 04136 break; 04137 default: 04138 /* We are not going to do anything with this frame. */ 04139 goto skip_frame; 04140 } 04141 } 04142 skip_frame:; 04143 04144 ast_frfree(f); 04145 } 04146 } 04147 04148 /* Make a position announcement, if enabled */ 04149 if (qe->parent->announcefrequency && qe->parent->announce_to_first_user) { 04150 say_position(qe, ringing); 04151 } 04152 04153 /* Make a periodic announcement, if enabled */ 04154 if (qe->parent->periodicannouncefrequency && qe->parent->announce_to_first_user) { 04155 say_periodic_announcement(qe, ringing); 04156 } 04157 04158 if (!*to) { 04159 for (o = start; o; o = o->call_next) { 04160 rna(orig, qe, o->interface, o->member->membername, 1); 04161 } 04162 } 04163 04164 #ifdef HAVE_EPOLL 04165 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 04166 if (epollo->chan) 04167 ast_poll_channel_del(in, epollo->chan); 04168 } 04169 #endif 04170 04171 return peer; 04172 }
| static int wait_our_turn | ( | struct queue_ent * | qe, | |
| int | ringing, | |||
| enum queue_result * | reason | |||
| ) | [static] |
The waiting areas for callers who are not actively calling members.
This function is one large loop. This function will return if a caller either exits the queue or it becomes that caller's turn to attempt calling queue members. Inside the loop, we service the caller with periodic announcements, holdtime announcements, etc. as configured in queues.conf
| 0 | if the caller's turn has arrived | |
| -1 | if the caller should exit the queue. |
Definition at line 4291 of file app_queue.c.
References call_queue::announcefrequency, ast_queue_log(), ast_waitfordigit(), queue_ent::chan, queue_ent::expire, get_member_status(), is_our_turn(), leave_queue(), call_queue::leavewhenempty, queue_ent::max_penalty, queue_ent::min_penalty, queue_ent::opos, queue_ent::parent, call_queue::periodicannouncefrequency, queue_ent::pos, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, RECHECK, say_periodic_announcement(), say_position(), queue_ent::start, status, update_qe_rule(), and valid_exit().
Referenced by queue_exec().
04292 { 04293 int res = 0; 04294 04295 /* This is the holding pen for callers 2 through maxlen */ 04296 for (;;) { 04297 04298 if (is_our_turn(qe)) 04299 break; 04300 04301 /* If we have timed out, break out */ 04302 if (qe->expire && (time(NULL) >= qe->expire)) { 04303 *reason = QUEUE_TIMEOUT; 04304 break; 04305 } 04306 04307 if (qe->parent->leavewhenempty) { 04308 int status = 0; 04309 04310 if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty, 0))) { 04311 *reason = QUEUE_LEAVEEMPTY; 04312 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 04313 leave_queue(qe); 04314 break; 04315 } 04316 } 04317 04318 /* Make a position announcement, if enabled */ 04319 if (qe->parent->announcefrequency && 04320 (res = say_position(qe,ringing))) 04321 break; 04322 04323 /* If we have timed out, break out */ 04324 if (qe->expire && (time(NULL) >= qe->expire)) { 04325 *reason = QUEUE_TIMEOUT; 04326 break; 04327 } 04328 04329 /* Make a periodic announcement, if enabled */ 04330 if (qe->parent->periodicannouncefrequency && 04331 (res = say_periodic_announcement(qe,ringing))) 04332 break; 04333 04334 /* see if we need to move to the next penalty level for this queue */ 04335 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) { 04336 update_qe_rule(qe); 04337 } 04338 04339 /* If we have timed out, break out */ 04340 if (qe->expire && (time(NULL) >= qe->expire)) { 04341 *reason = QUEUE_TIMEOUT; 04342 break; 04343 } 04344 04345 /* Wait a second before checking again */ 04346 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 04347 if (res > 0 && !valid_exit(qe, res)) 04348 res = 0; 04349 else 04350 break; 04351 } 04352 04353 /* If we have timed out, break out */ 04354 if (qe->expire && (time(NULL) >= qe->expire)) { 04355 *reason = QUEUE_TIMEOUT; 04356 break; 04357 } 04358 } 04359 04360 return res; 04361 }
| static int word_in_list | ( | const char * | list, | |
| const char * | word | |||
| ) | [static] |
Check if a given word is in a space-delimited list.
| list | Space delimited list of words | |
| word | The word used to search the list |
Definition at line 7455 of file app_queue.c.
Referenced by complete_queue().
07455 { 07456 int list_len, word_len = strlen(word); 07457 const char *find, *end_find, *end_list; 07458 07459 /* strip whitespace from front */ 07460 while (isspace(*list)) { 07461 list++; 07462 } 07463 07464 while ((find = strstr(list, word))) { 07465 /* beginning of find starts inside another word? */ 07466 if (find != list && *(find - 1) != ' ') { 07467 list = find; 07468 /* strip word from front */ 07469 while (!isspace(*list) && *list != '\0') { 07470 list++; 07471 } 07472 /* strip whitespace from front */ 07473 while (isspace(*list)) { 07474 list++; 07475 } 07476 continue; 07477 } 07478 07479 /* end of find ends inside another word or at very end of list? */ 07480 list_len = strlen(list); 07481 end_find = find + word_len; 07482 end_list = list + list_len; 07483 if (end_find == end_list || *end_find != ' ') { 07484 list = find; 07485 /* strip word from front */ 07486 while (!isspace(*list) && *list != '\0') { 07487 list++; 07488 } 07489 /* strip whitespace from front */ 07490 while (isspace(*list)) { 07491 list++; 07492 } 07493 continue; 07494 } 07495 07496 /* terminating conditions satisfied, word at beginning or separated by ' ' */ 07497 return 1; 07498 } 07499 07500 return 0; 07501 }
char* app = "Queue" [static] |
Definition at line 951 of file app_queue.c.
char* app_aqm = "AddQueueMember" [static] |
Definition at line 953 of file app_queue.c.
char* app_pqm = "PauseQueueMember" [static] |
Definition at line 957 of file app_queue.c.
char* app_ql = "QueueLog" [static] |
Definition at line 961 of file app_queue.c.
char* app_rqm = "RemoveQueueMember" [static] |
Definition at line 955 of file app_queue.c.
char* app_upqm = "UnpauseQueueMember" [static] |
Definition at line 959 of file app_queue.c.
int autofill_default = 1 [static] |
queues.conf [general] option
Definition at line 973 of file app_queue.c.
struct autopause autopausesmodes[] [static] |
Referenced by autopause2int().
struct ast_cli_entry cli_queue[] [static] |
Definition at line 8499 of file app_queue.c.
struct ast_event_sub* device_state_sub [static] |
Subscription to device state change events.
Definition at line 982 of file app_queue.c.
struct ast_taskprocessor* devicestate_tps [static] |
Definition at line 935 of file app_queue.c.
| enum queue_result id |
Definition at line 999 of file app_queue.c.
Referenced by _sip_show_peers(), _skinny_show_devices(), _skinny_show_lines(), ast_cc_extension_monitor_add_dialstring(), frame_trace_helper(), and idemodulator().
int montype_default = 0 [static] |
queues.conf [general] option
Definition at line 976 of file app_queue.c.
const char* const pm_family = "Queue/PersistentMembers" [static] |
Persistent Members astdb family.
Definition at line 964 of file app_queue.c.
const char qpm_cmd_usage[] [static] |
"Usage: queue pause member <channel> in <queue> reason <reason>\n"
Definition at line 8490 of file app_queue.c.
const char qsmp_cmd_usage[] [static] |
"Usage: queue set member penalty <channel> from <queue> <penalty>\n"
Definition at line 8496 of file app_queue.c.
struct ast_data_entry queue_data_providers[] [static] |
{
AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider),
}
Definition at line 8777 of file app_queue.c.
int queue_persistent_members = 0 [static] |
queues.conf [general] option
Definition at line 967 of file app_queue.c.
struct { ... } queue_results[] [static] |
Referenced by set_queue_result().
struct ast_datastore_info queue_transfer_info [static] |
{
.type = "queue_transfer",
.chan_fixup = queue_transfer_fixup,
.destroy = queue_transfer_destroy,
}
a datastore used to help correctly log attended transfers of queue callers
Definition at line 4543 of file app_queue.c.
struct ast_custom_function queueexists_function [static] |
{
.name = "QUEUE_EXISTS",
.read = queue_function_exists,
}
Definition at line 6812 of file app_queue.c.
struct ast_custom_function queuemembercount_dep [static] |
{
.name = "QUEUE_MEMBER_COUNT",
.read = queue_function_qac_dep,
}
Definition at line 6827 of file app_queue.c.
struct ast_custom_function queuemembercount_function [static] |
{
.name = "QUEUE_MEMBER",
.read = queue_function_qac,
}
Definition at line 6822 of file app_queue.c.
struct ast_custom_function queuememberlist_function [static] |
{
.name = "QUEUE_MEMBER_LIST",
.read = queue_function_queuememberlist,
}
Definition at line 6837 of file app_queue.c.
struct ast_custom_function queuememberpenalty_function [static] |
{
.name = "QUEUE_MEMBER_PENALTY",
.read = queue_function_memberpenalty_read,
.write = queue_function_memberpenalty_write,
}
Definition at line 6842 of file app_queue.c.
struct ao2_container* queues [static] |
Definition at line 1240 of file app_queue.c.
Referenced by __queues_show(), clear_stats(), compare_weight(), complete_queue(), complete_queue_remove_member(), extension_state_cb(), find_queue_by_name_rt(), get_member_penalty(), handle_statechange(), leave_queue(), load_module(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), queues_data_provider_get(), reload_queue_members(), reload_queues(), reload_single_queue(), remove_from_queue(), set_member_paused(), set_member_penalty(), unload_module(), and update_queue().
struct ast_data_handler queues_data_provider [static] |
{
.version = AST_DATA_HANDLER_VERSION,
.get = queues_data_provider_get
}
Definition at line 8772 of file app_queue.c.
struct ast_custom_function queuevar_function [static] |
{
.name = "QUEUE_VARIABLES",
.read = queue_function_var,
}
Definition at line 6817 of file app_queue.c.
struct ast_custom_function queuewaitingcount_function [static] |
{
.name = "QUEUE_WAITING_COUNT",
.read = queue_function_queuewaitingcount,
}
Definition at line 6832 of file app_queue.c.
const char qum_cmd_usage[] [static] |
"Usage: queue unpause member <channel> in <queue> reason <reason>\n"
Definition at line 8493 of file app_queue.c.
int shared_lastcall = 1 [static] |
queues.conf [general] option
Definition at line 979 of file app_queue.c.
struct strategy strategies[] [static] |
Referenced by int2strat(), and strat2int().
| char* text |
Definition at line 1000 of file app_queue.c.
Referenced by _sip_show_peer(), add_required_respheader(), build_reply_digest(), check_auth(), festival_exec(), handle_response(), handle_response_info(), handle_response_message(), iconv_read(), method_match(), parse_sip_options(), peers_data_provider_get(), process_sdp(), reqprep(), set_queue_result(), and sip_new().
int update_cdr = 0 [static] |
queues.conf [general] option
Definition at line 985 of file app_queue.c.
Referenced by login_exec().
int use_weight = 0 [static] |
queues.conf per-queue weight option
Definition at line 970 of file app_queue.c.
1.6.1