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) |
| 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 1065 of file app_queue.c.
Referenced by queue_set_param().
| #define ANNOUNCEHOLDTIME_ONCE 2 |
Definition at line 1066 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 1081 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 1080 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 1079 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 1078 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 3600 of file app_queue.c.
| #define DATA_EXPORT_CALL_QUEUE | ( | MEMBER | ) |
Definition at line 8455 of file app_queue.c.
| #define DATA_EXPORT_MEMBER | ( | MEMBER | ) |
Definition at line 8520 of file app_queue.c.
| #define DATA_EXPORT_QUEUE_ENT | ( | MEMBER | ) |
Definition at line 8534 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 891 of file app_queue.c.
Referenced by init_queue().
| #define DEFAULT_RETRY 5 |
Definition at line 887 of file app_queue.c.
Referenced by init_queue(), and queue_set_param().
| #define DEFAULT_TIMEOUT 15 |
Definition at line 888 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 890 of file app_queue.c.
Referenced by destroy_queue(), init_queue(), and queue_set_param().
| #define MAX_QUEUE_BUCKETS 53 |
Definition at line 893 of file app_queue.c.
Referenced by load_module().
| #define QUEUE_EVENT_VARIABLES 3 |
Definition at line 1067 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 1328 of file app_queue.c.
Referenced by leave_queue(), and try_calling().
| #define queue_t_unref | ( | a, | |||
| b | ) | queue_unref(a) |
Definition at line 1329 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 1330 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 1331 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 889 of file app_queue.c.
Referenced by wait_our_turn().
| #define RES_EXISTS (-1) |
Entry already exists
Definition at line 896 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 898 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 899 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 895 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 897 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 836 of file app_queue.c.
00836 { 00837 QUEUE_STRATEGY_RINGALL = 0, 00838 QUEUE_STRATEGY_LEASTRECENT, 00839 QUEUE_STRATEGY_FEWESTCALLS, 00840 QUEUE_STRATEGY_RANDOM, 00841 QUEUE_STRATEGY_RRMEMORY, 00842 QUEUE_STRATEGY_LINEAR, 00843 QUEUE_STRATEGY_WRANDOM, 00844 QUEUE_STRATEGY_RRORDERED, 00845 };
| anonymous enum |
Definition at line 847 of file app_queue.c.
00847 { 00848 QUEUE_AUTOPAUSE_OFF = 0, 00849 QUEUE_AUTOPAUSE_ON, 00850 QUEUE_AUTOPAUSE_ALL 00851 };
Definition at line 4431 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 1053 of file app_queue.c.
01053 { 01054 QUEUE_EMPTY_PENALTY = (1 << 0), 01055 QUEUE_EMPTY_PAUSED = (1 << 1), 01056 QUEUE_EMPTY_INUSE = (1 << 2), 01057 QUEUE_EMPTY_RINGING = (1 << 3), 01058 QUEUE_EMPTY_UNAVAILABLE = (1 << 4), 01059 QUEUE_EMPTY_INVALID = (1 << 5), 01060 QUEUE_EMPTY_UNKNOWN = (1 << 6), 01061 QUEUE_EMPTY_WRAPUP = (1 << 7), 01062 };
| enum queue_reload_mask |
Definition at line 853 of file app_queue.c.
00853 { 00854 QUEUE_RELOAD_PARAMETERS = (1 << 0), 00855 QUEUE_RELOAD_MEMBER = (1 << 1), 00856 QUEUE_RELOAD_RULES = (1 << 2), 00857 QUEUE_RESET_STATS = (1 << 3), 00858 };
| enum queue_result |
| QUEUE_UNKNOWN | |
| QUEUE_TIMEOUT | |
| QUEUE_JOINEMPTY | |
| QUEUE_LEAVEEMPTY | |
| QUEUE_JOINUNAVAIL | |
| QUEUE_LEAVEUNAVAIL | |
| QUEUE_FULL | |
| QUEUE_CONTINUE |
Definition at line 937 of file app_queue.c.
00937 { 00938 QUEUE_UNKNOWN = 0, 00939 QUEUE_TIMEOUT = 1, 00940 QUEUE_JOINEMPTY = 2, 00941 QUEUE_LEAVEEMPTY = 3, 00942 QUEUE_JOINUNAVAIL = 4, 00943 QUEUE_LEAVEUNAVAIL = 5, 00944 QUEUE_FULL = 6, 00945 QUEUE_CONTINUE = 7, 00946 };
Definition at line 962 of file app_queue.c.
00962 { 00963 TIMEOUT_PRIORITY_APP, 00964 TIMEOUT_PRIORITY_CONF, 00965 };
| 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 7254 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().
07255 { 07256 struct call_queue *q; 07257 struct ast_str *out = ast_str_alloca(240); 07258 int found = 0; 07259 time_t now = time(NULL); 07260 struct ao2_iterator queue_iter; 07261 struct ao2_iterator mem_iter; 07262 07263 if (argc != 2 && argc != 3) 07264 return CLI_SHOWUSAGE; 07265 07266 if (argc == 3) { /* specific queue */ 07267 if ((q = load_realtime_queue(argv[2]))) { 07268 queue_t_unref(q, "Done with temporary pointer"); 07269 } 07270 } else if (ast_check_realtime("queues")) { 07271 /* This block is to find any queues which are defined in realtime but 07272 * which have not yet been added to the in-core container 07273 */ 07274 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 07275 char *queuename; 07276 if (cfg) { 07277 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { 07278 if ((q = load_realtime_queue(queuename))) { 07279 queue_t_unref(q, "Done with temporary pointer"); 07280 } 07281 } 07282 ast_config_destroy(cfg); 07283 } 07284 } 07285 07286 ao2_lock(queues); 07287 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); 07288 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07289 float sl; 07290 struct call_queue *realtime_queue = NULL; 07291 07292 ao2_lock(q); 07293 /* This check is to make sure we don't print information for realtime 07294 * queues which have been deleted from realtime but which have not yet 07295 * been deleted from the in-core container. Only do this if we're not 07296 * looking for a specific queue. 07297 */ 07298 if (argc < 3 && q->realtime) { 07299 realtime_queue = load_realtime_queue(q->name); 07300 if (!realtime_queue) { 07301 ao2_unlock(q); 07302 queue_t_unref(q, "Done with iterator"); 07303 continue; 07304 } 07305 queue_t_unref(realtime_queue, "Queue is already in memory"); 07306 } 07307 07308 if (argc == 3 && strcasecmp(q->name, argv[2])) { 07309 ao2_unlock(q); 07310 queue_t_unref(q, "Done with iterator"); 07311 continue; 07312 } 07313 found = 1; 07314 07315 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count); 07316 if (q->maxlen) 07317 ast_str_append(&out, 0, "%d", q->maxlen); 07318 else 07319 ast_str_append(&out, 0, "unlimited"); 07320 sl = 0; 07321 if (q->callscompleted > 0) 07322 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 07323 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds", 07324 int2strat(q->strategy), q->holdtime, q->talktime, q->weight, 07325 q->callscompleted, q->callsabandoned,sl,q->servicelevel); 07326 do_print(s, fd, ast_str_buffer(out)); 07327 if (!ao2_container_count(q->members)) 07328 do_print(s, fd, " No Members"); 07329 else { 07330 struct member *mem; 07331 07332 do_print(s, fd, " Members: "); 07333 mem_iter = ao2_iterator_init(q->members, 0); 07334 while ((mem = ao2_iterator_next(&mem_iter))) { 07335 ast_str_set(&out, 0, " %s", mem->membername); 07336 if (strcasecmp(mem->membername, mem->interface)) { 07337 ast_str_append(&out, 0, " (%s)", mem->interface); 07338 } 07339 if (mem->penalty) 07340 ast_str_append(&out, 0, " with penalty %d", mem->penalty); 07341 ast_str_append(&out, 0, "%s%s%s (%s)", 07342 mem->dynamic ? " (dynamic)" : "", 07343 mem->realtime ? " (realtime)" : "", 07344 mem->paused ? " (paused)" : "", 07345 ast_devstate2str(mem->status)); 07346 if (mem->calls) 07347 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)", 07348 mem->calls, (long) (time(NULL) - mem->lastcall)); 07349 else 07350 ast_str_append(&out, 0, " has taken no calls yet"); 07351 do_print(s, fd, ast_str_buffer(out)); 07352 ao2_ref(mem, -1); 07353 } 07354 ao2_iterator_destroy(&mem_iter); 07355 } 07356 if (!q->head) 07357 do_print(s, fd, " No Callers"); 07358 else { 07359 struct queue_ent *qe; 07360 int pos = 1; 07361 07362 do_print(s, fd, " Callers: "); 07363 for (qe = q->head; qe; qe = qe->next) { 07364 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)", 07365 pos++, qe->chan->name, (long) (now - qe->start) / 60, 07366 (long) (now - qe->start) % 60, qe->prio); 07367 do_print(s, fd, ast_str_buffer(out)); 07368 } 07369 } 07370 do_print(s, fd, ""); /* blank line between entries */ 07371 ao2_unlock(q); 07372 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */ 07373 } 07374 ao2_iterator_destroy(&queue_iter); 07375 ao2_unlock(queues); 07376 if (!found) { 07377 if (argc == 3) 07378 ast_str_set(&out, 0, "No such queue: %s.", argv[2]); 07379 else 07380 ast_str_set(&out, 0, "No queues."); 07381 do_print(s, fd, ast_str_buffer(out)); 07382 } 07383 return CLI_SUCCESS; 07384 }
| 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 5555 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().
05556 { 05557 struct call_queue *q; 05558 struct member *new_member, *old_member; 05559 int res = RES_NOSUCHQUEUE; 05560 05561 /*! \note Ensure the appropriate realtime queue is loaded. Note that this 05562 * short-circuits if the queue is already in memory. */ 05563 if (!(q = load_realtime_queue(queuename))) 05564 return res; 05565 05566 ao2_lock(q); 05567 if ((old_member = interface_exists(q, interface)) == NULL) { 05568 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { 05569 new_member->dynamic = 1; 05570 member_add_to_queue(q, new_member); 05571 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 05572 "Queue: %s\r\n" 05573 "Location: %s\r\n" 05574 "MemberName: %s\r\n" 05575 "Membership: %s\r\n" 05576 "Penalty: %d\r\n" 05577 "CallsTaken: %d\r\n" 05578 "LastCall: %d\r\n" 05579 "Status: %d\r\n" 05580 "Paused: %d\r\n", 05581 q->name, new_member->interface, new_member->membername, 05582 "dynamic", 05583 new_member->penalty, new_member->calls, (int) new_member->lastcall, 05584 new_member->status, new_member->paused); 05585 05586 ao2_ref(new_member, -1); 05587 new_member = NULL; 05588 05589 if (dump) 05590 dump_queue_members(q); 05591 05592 res = RES_OKAY; 05593 } else { 05594 res = RES_OUTOFMEMORY; 05595 } 05596 } else { 05597 ao2_ref(old_member, -1); 05598 res = RES_EXISTS; 05599 } 05600 ao2_unlock(q); 05601 queue_t_unref(q, "Expiring temporary reference"); 05602 05603 return res; 05604 }
| static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static, read] |
Definition at line 2265 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().
02266 { 02267 struct call_queue *q; 02268 02269 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) { 02270 if (ast_string_field_init(q, 64)) { 02271 queue_t_unref(q, "String field allocation failed"); 02272 return NULL; 02273 } 02274 ast_string_field_set(q, name, queuename); 02275 } 02276 return q; 02277 }
| static int aqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
AddQueueMember application.
Definition at line 5987 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().
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 AST_APP_ARG(penalty); 05995 AST_APP_ARG(options); 05996 AST_APP_ARG(membername); 05997 AST_APP_ARG(state_interface); 05998 ); 05999 int penalty = 0; 06000 06001 if (ast_strlen_zero(data)) { 06002 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n"); 06003 return -1; 06004 } 06005 06006 parse = ast_strdupa(data); 06007 06008 AST_STANDARD_APP_ARGS(args, parse); 06009 06010 if (ast_strlen_zero(args.interface)) { 06011 args.interface = ast_strdupa(chan->name); 06012 temppos = strrchr(args.interface, '-'); 06013 if (temppos) 06014 *temppos = '\0'; 06015 } 06016 06017 if (!ast_strlen_zero(args.penalty)) { 06018 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) { 06019 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 06020 penalty = 0; 06021 } 06022 } 06023 06024 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { 06025 case RES_OKAY: 06026 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 06027 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 06028 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 06029 res = 0; 06030 break; 06031 case RES_EXISTS: 06032 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 06033 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 06034 res = 0; 06035 break; 06036 case RES_NOSUCHQUEUE: 06037 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 06038 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 06039 res = 0; 06040 break; 06041 case RES_OUTOFMEMORY: 06042 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 06043 break; 06044 } 06045 06046 return res; 06047 }
| 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 4535 of file app_queue.c.
References ast_channel_datastore_find().
Referenced by try_calling().
04536 { 04537 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1; 04538 }
| static int autopause2int | ( | const char * | autopause | ) | [static] |
Definition at line 1233 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().
01234 { 01235 int x; 01236 /*This 'double check' that default value is OFF */ 01237 if (ast_strlen_zero(autopause)) 01238 return QUEUE_AUTOPAUSE_OFF; 01239 01240 /*This 'double check' is to ensure old values works */ 01241 if(ast_true(autopause)) 01242 return QUEUE_AUTOPAUSE_ON; 01243 01244 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) { 01245 if (!strcasecmp(autopause, autopausesmodes[x].name)) 01246 return autopausesmodes[x].autopause; 01247 } 01248 01249 /*This 'double check' that default value is OFF */ 01250 return QUEUE_AUTOPAUSE_OFF; 01251 }
| 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 4361 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().
04362 { 04363 /* disregarding penalty on too few members? */ 04364 int membercount = ao2_container_count(q->members); 04365 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1; 04366 04367 if (usepenalty) { 04368 if ((qe->max_penalty != INT_MAX && mem->penalty > qe->max_penalty) || 04369 (qe->min_penalty != INT_MAX && mem->penalty < qe->min_penalty)) { 04370 return -1; 04371 } 04372 } else { 04373 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n", 04374 membercount, q->penaltymemberslimit); 04375 } 04376 04377 switch (q->strategy) { 04378 case QUEUE_STRATEGY_RINGALL: 04379 /* Everyone equal, except for penalty */ 04380 tmp->metric = mem->penalty * 1000000 * usepenalty; 04381 break; 04382 case QUEUE_STRATEGY_LINEAR: 04383 if (pos < qe->linpos) { 04384 tmp->metric = 1000 + pos; 04385 } else { 04386 if (pos > qe->linpos) 04387 /* Indicate there is another priority */ 04388 qe->linwrapped = 1; 04389 tmp->metric = pos; 04390 } 04391 tmp->metric += mem->penalty * 1000000 * usepenalty; 04392 break; 04393 case QUEUE_STRATEGY_RRORDERED: 04394 case QUEUE_STRATEGY_RRMEMORY: 04395 pos = mem->queuepos; 04396 if (pos < q->rrpos) { 04397 tmp->metric = 1000 + pos; 04398 } else { 04399 if (pos > q->rrpos) 04400 /* Indicate there is another priority */ 04401 q->wrapped = 1; 04402 tmp->metric = pos; 04403 } 04404 tmp->metric += mem->penalty * 1000000 * usepenalty; 04405 break; 04406 case QUEUE_STRATEGY_RANDOM: 04407 tmp->metric = ast_random() % 1000; 04408 tmp->metric += mem->penalty * 1000000 * usepenalty; 04409 break; 04410 case QUEUE_STRATEGY_WRANDOM: 04411 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000); 04412 break; 04413 case QUEUE_STRATEGY_FEWESTCALLS: 04414 tmp->metric = mem->calls; 04415 tmp->metric += mem->penalty * 1000000 * usepenalty; 04416 break; 04417 case QUEUE_STRATEGY_LEASTRECENT: 04418 if (!mem->lastcall) 04419 tmp->metric = 0; 04420 else 04421 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 04422 tmp->metric += mem->penalty * 1000000 * usepenalty; 04423 break; 04424 default: 04425 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 04426 break; 04427 } 04428 return 0; 04429 }
| static void callattempt_free | ( | struct callattempt * | doomed | ) | [static] |
Definition at line 2927 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 3144 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().
03145 { 03146 if (call->member->paused) { 03147 ast_debug(1, "%s paused, can't receive call\n", call->interface); 03148 return 0; 03149 } 03150 03151 if (!qe->parent->ringinuse && !member_status_available(call->member->status)) { 03152 ast_debug(1, "%s not available, can't receive call\n", call->interface); 03153 return 0; 03154 } 03155 03156 if ((call->lastqueue && call->lastqueue->wrapuptime && (time(NULL) - call->lastcall < call->lastqueue->wrapuptime)) 03157 || (!call->lastqueue && qe->parent->wrapuptime && (time(NULL) - call->lastcall < qe->parent->wrapuptime))) { 03158 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 03159 (call->lastqueue ? call->lastqueue->name : qe->parent->name), 03160 call->interface); 03161 return 0; 03162 } 03163 03164 if (use_weight && compare_weight(qe->parent, call->member)) { 03165 ast_debug(1, "Priority queue delaying call to %s:%s\n", 03166 qe->parent->name, call->interface); 03167 return 0; 03168 } 03169 03170 if (!qe->parent->ringinuse) { 03171 if (member_call_pending_set(call->member)) { 03172 ast_debug(1, "%s has another call pending, can't receive call\n", 03173 call->interface); 03174 return 0; 03175 } 03176 03177 /* 03178 * The queue member is available. Get current status to be sure 03179 * because the device state and extension state callbacks may 03180 * not have updated the status yet. 03181 */ 03182 if (!member_status_available(get_queue_member_status(call->member))) { 03183 ast_debug(1, "%s actually not available, can't receive call\n", 03184 call->interface); 03185 member_call_pending_clear(call->member); 03186 return 0; 03187 } 03188 } 03189 03190 return 1; 03191 }
| static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 1794 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().
01795 { 01796 q->holdtime = 0; 01797 q->callscompleted = 0; 01798 q->callsabandoned = 0; 01799 q->callscompletedinsl = 0; 01800 q->talktime = 0; 01801 01802 if (q->members) { 01803 struct member *mem; 01804 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01805 while ((mem = ao2_iterator_next(&mem_iter))) { 01806 mem->calls = 0; 01807 mem->lastcall = 0; 01808 ao2_ref(mem, -1); 01809 } 01810 ao2_iterator_destroy(&mem_iter); 01811 } 01812 }
| 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 7193 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().
07194 { 07195 struct call_queue *q; 07196 struct ao2_iterator queue_iter; 07197 07198 queue_iter = ao2_iterator_init(queues, 0); 07199 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07200 ao2_lock(q); 07201 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) 07202 clear_queue(q); 07203 ao2_unlock(q); 07204 queue_t_unref(q, "Done with iterator"); 07205 } 07206 ao2_iterator_destroy(&queue_iter); 07207 return 0; 07208 }
| static int compare_weight | ( | struct call_queue * | rq, | |
| struct member * | member | |||
| ) | [static] |
Definition at line 3007 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().
03008 { 03009 struct call_queue *q; 03010 struct member *mem; 03011 int found = 0; 03012 struct ao2_iterator queue_iter; 03013 03014 queue_iter = ao2_iterator_init(queues, 0); 03015 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 03016 if (q == rq) { /* don't check myself, could deadlock */ 03017 queue_t_unref(q, "Done with iterator"); 03018 continue; 03019 } 03020 ao2_lock(q); 03021 if (q->count && q->members) { 03022 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 03023 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 03024 if (q->weight > rq->weight && q->count >= num_available_members(q)) { 03025 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); 03026 found = 1; 03027 } 03028 ao2_ref(mem, -1); 03029 } 03030 } 03031 ao2_unlock(q); 03032 queue_t_unref(q, "Done with iterator"); 03033 if (found) { 03034 break; 03035 } 03036 } 03037 ao2_iterator_destroy(&queue_iter); 03038 return found; 03039 }
| 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 7458 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().
07459 { 07460 struct call_queue *q; 07461 char *ret = NULL; 07462 int which = 0; 07463 int wordlen = strlen(word); 07464 struct ao2_iterator queue_iter; 07465 const char *word_list = NULL; 07466 07467 /* for certain commands, already completed items should be left out of 07468 * the list */ 07469 if (word_list_offset && strlen(line) >= word_list_offset) { 07470 word_list = line + word_list_offset; 07471 } 07472 07473 queue_iter = ao2_iterator_init(queues, 0); 07474 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07475 if (!strncasecmp(word, q->name, wordlen) && ++which > state 07476 && (!word_list_offset || !word_in_list(word_list, q->name))) { 07477 ret = ast_strdup(q->name); 07478 queue_t_unref(q, "Done with iterator"); 07479 break; 07480 } 07481 queue_t_unref(q, "Done with iterator"); 07482 } 07483 ao2_iterator_destroy(&queue_iter); 07484 07485 /* Pretend "rules" is at the end of the queues list in certain 07486 * circumstances since it is an alternate command that should be 07487 * tab-completable for "queue show" */ 07488 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) { 07489 ret = ast_strdup("rules"); 07490 } 07491 07492 return ret; 07493 }
| static char* complete_queue_add_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 7920 of file app_queue.c.
References ast_malloc, ast_strdup, and complete_queue().
Referenced by handle_queue_add_member().
07921 { 07922 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 07923 switch (pos) { 07924 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 07925 return NULL; 07926 case 4: /* only one possible match, "to" */ 07927 return state == 0 ? ast_strdup("to") : NULL; 07928 case 5: /* <queue> */ 07929 return complete_queue(line, word, pos, state, 0); 07930 case 6: /* only one possible match, "penalty" */ 07931 return state == 0 ? ast_strdup("penalty") : NULL; 07932 case 7: 07933 if (state < 100) { /* 0-99 */ 07934 char *num; 07935 if ((num = ast_malloc(3))) { 07936 sprintf(num, "%d", state); 07937 } 07938 return num; 07939 } else { 07940 return NULL; 07941 } 07942 case 8: /* only one possible match, "as" */ 07943 return state == 0 ? ast_strdup("as") : NULL; 07944 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 07945 return NULL; 07946 default: 07947 return NULL; 07948 } 07949 }
| static char* complete_queue_pause_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 8142 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_pause_member().
08143 { 08144 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */ 08145 switch (pos) { 08146 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 08147 return NULL; 08148 case 4: /* only one possible match, "queue" */ 08149 return state == 0 ? ast_strdup("queue") : NULL; 08150 case 5: /* <queue> */ 08151 return complete_queue(line, word, pos, state, 0); 08152 case 6: /* "reason" */ 08153 return state == 0 ? ast_strdup("reason") : NULL; 08154 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */ 08155 return NULL; 08156 default: 08157 return NULL; 08158 } 08159 }
| static char* complete_queue_remove_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 8050 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().
08051 { 08052 int which = 0; 08053 struct call_queue *q; 08054 struct member *m; 08055 struct ao2_iterator queue_iter; 08056 struct ao2_iterator mem_iter; 08057 int wordlen = strlen(word); 08058 08059 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 08060 if (pos > 5 || pos < 3) 08061 return NULL; 08062 if (pos == 4) /* only one possible match, 'from' */ 08063 return (state == 0 ? ast_strdup("from") : NULL); 08064 08065 if (pos == 5) { /* No need to duplicate code */ 08066 return complete_queue(line, word, pos, state, 0); 08067 } 08068 08069 /* here is the case for 3, <member> */ 08070 queue_iter = ao2_iterator_init(queues, 0); 08071 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 08072 ao2_lock(q); 08073 mem_iter = ao2_iterator_init(q->members, 0); 08074 while ((m = ao2_iterator_next(&mem_iter))) { 08075 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) { 08076 char *tmp; 08077 tmp = ast_strdup(m->interface); 08078 ao2_ref(m, -1); 08079 ao2_iterator_destroy(&mem_iter); 08080 ao2_unlock(q); 08081 queue_t_unref(q, "Done with iterator, returning interface name"); 08082 ao2_iterator_destroy(&queue_iter); 08083 return tmp; 08084 } 08085 ao2_ref(m, -1); 08086 } 08087 ao2_iterator_destroy(&mem_iter); 08088 ao2_unlock(q); 08089 queue_t_unref(q, "Done with iterator"); 08090 } 08091 ao2_iterator_destroy(&queue_iter); 08092 08093 return NULL; 08094 }
| static char* complete_queue_rule_show | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 8275 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().
08276 { 08277 int which = 0; 08278 struct rule_list *rl_iter; 08279 int wordlen = strlen(word); 08280 char *ret = NULL; 08281 if (pos != 3) /* Wha? */ { 08282 return NULL; 08283 } 08284 08285 AST_LIST_LOCK(&rule_lists); 08286 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 08287 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) { 08288 ret = ast_strdup(rl_iter->name); 08289 break; 08290 } 08291 } 08292 AST_LIST_UNLOCK(&rule_lists); 08293 08294 return ret; 08295 }
| static char* complete_queue_set_member_penalty | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 8212 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_set_member_penalty().
08213 { 08214 /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/ 08215 switch (pos) { 08216 case 4: 08217 if (state == 0) { 08218 return ast_strdup("on"); 08219 } else { 08220 return NULL; 08221 } 08222 case 6: 08223 if (state == 0) { 08224 return ast_strdup("in"); 08225 } else { 08226 return NULL; 08227 } 08228 case 7: 08229 return complete_queue(line, word, pos, state, 0); 08230 default: 08231 return NULL; 08232 } 08233 }
| static char* complete_queue_show | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 7495 of file app_queue.c.
References complete_queue().
Referenced by queue_show().
07496 { 07497 if (pos == 2) { 07498 return complete_queue(line, word, pos, state, 0); 07499 } 07500 return NULL; 07501 }
| static int compress_char | ( | const char | c | ) | [static] |
Definition at line 1685 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 6084 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().
06085 { 06086 struct penalty_rule *pr_iter; 06087 struct rule_list *rl_iter; 06088 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename; 06089 AST_LIST_LOCK(&rule_lists); 06090 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 06091 if (!strcasecmp(rl_iter->name, tmp)) 06092 break; 06093 } 06094 if (rl_iter) { 06095 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 06096 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr)); 06097 if (!new_pr) { 06098 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n"); 06099 break; 06100 } 06101 new_pr->time = pr_iter->time; 06102 new_pr->max_value = pr_iter->max_value; 06103 new_pr->min_value = pr_iter->min_value; 06104 new_pr->max_relative = pr_iter->max_relative; 06105 new_pr->min_relative = pr_iter->min_relative; 06106 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list); 06107 } 06108 } 06109 AST_LIST_UNLOCK(&rule_lists); 06110 }
| 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 1653 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().
01654 { 01655 struct member *cur; 01656 01657 if ((cur = ao2_alloc(sizeof(*cur), NULL))) { 01658 cur->penalty = penalty; 01659 cur->paused = paused; 01660 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 01661 if (!ast_strlen_zero(state_interface)) 01662 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); 01663 else 01664 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface)); 01665 if (!ast_strlen_zero(membername)) 01666 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 01667 else 01668 ast_copy_string(cur->membername, interface, sizeof(cur->membername)); 01669 if (!strchr(cur->interface, '/')) 01670 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 01671 if (!strncmp(cur->state_interface, "hint:", 5)) { 01672 char *tmp = ast_strdupa(cur->state_interface), *context = tmp; 01673 char *exten = strsep(&context, "@") + 5; 01674 01675 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten)); 01676 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context)); 01677 } 01678 cur->status = get_queue_member_status(cur); 01679 } 01680 01681 return cur; 01682 }
| static void destroy_queue | ( | void * | obj | ) | [static] |
Free queue's member list then its string fields.
Definition at line 2251 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().
02252 { 02253 struct call_queue *q = obj; 02254 int i; 02255 02256 free_members(q, 1); 02257 ast_string_field_free_memory(q); 02258 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 02259 if (q->sound_periodicannounce[i]) 02260 free(q->sound_periodicannounce[i]); 02261 } 02262 ao2_ref(q->members, -1); 02263 }
| static void device_state_cb | ( | const struct ast_event * | event, | |
| void * | unused | |||
| ) | [static] |
Definition at line 1551 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().
01552 { 01553 enum ast_device_state state; 01554 const char *device; 01555 struct statechange *sc; 01556 size_t datapsize; 01557 01558 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE); 01559 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE); 01560 01561 if (ast_strlen_zero(device)) { 01562 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n"); 01563 return; 01564 } 01565 datapsize = sizeof(*sc) + strlen(device) + 1; 01566 if (!(sc = ast_calloc(1, datapsize))) { 01567 ast_log(LOG_ERROR, "failed to calloc a state change struct\n"); 01568 return; 01569 } 01570 sc->state = state; 01571 strcpy(sc->dev, device); 01572 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) { 01573 ast_free(sc); 01574 } 01575 }
| static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 3042 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry(), and wait_for_answer().
03043 { 03044 o->stillgoing = 0; 03045 ast_hangup(o->chan); 03046 o->chan = NULL; 03047 }
| 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 7240 of file app_queue.c.
References ast_cli(), and astman_append().
Referenced by __queues_show().
07241 { 07242 if (s) 07243 astman_append(s, "%s\r\n", str); 07244 else 07245 ast_cli(fd, "%s\n", str); 07246 }
| 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 5455 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().
05456 { 05457 struct member *cur_member; 05458 struct ast_str *value; 05459 struct ao2_iterator mem_iter; 05460 05461 if (!pm_queue) { 05462 return; 05463 } 05464 05465 /* 4K is a reasonable default for most applications, but we grow to 05466 * accommodate more if necessary. */ 05467 if (!(value = ast_str_create(4096))) { 05468 return; 05469 } 05470 05471 mem_iter = ao2_iterator_init(pm_queue->members, 0); 05472 while ((cur_member = ao2_iterator_next(&mem_iter))) { 05473 if (!cur_member->dynamic) { 05474 ao2_ref(cur_member, -1); 05475 continue; 05476 } 05477 05478 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s", 05479 ast_str_strlen(value) ? "|" : "", 05480 cur_member->interface, 05481 cur_member->penalty, 05482 cur_member->paused, 05483 cur_member->membername, 05484 cur_member->state_interface); 05485 05486 ao2_ref(cur_member, -1); 05487 } 05488 ao2_iterator_destroy(&mem_iter); 05489 05490 if (ast_str_strlen(value) && !cur_member) { 05491 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) 05492 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 05493 } else { 05494 /* Delete the entry if the queue is empty or there is an error */ 05495 ast_db_del(pm_family, pm_queue->name); 05496 } 05497 05498 ast_free(value); 05499 }
| static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 4583 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().
04584 { 04585 struct queue_end_bridge *qeb = data; 04586 struct call_queue *q = qeb->q; 04587 struct ast_channel *chan = qeb->chan; 04588 04589 if (ao2_ref(qeb, -1) == 1) { 04590 set_queue_variables(q, chan); 04591 /* This unrefs the reference we made in try_calling when we allocated qeb */ 04592 queue_t_unref(q, "Expire bridge_config reference"); 04593 } 04594 }
| static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
| struct ast_channel * | originator, | |||
| struct ast_channel * | terminator | |||
| ) | [static] |
Definition at line 4576 of file app_queue.c.
References ao2_ref, queue_end_bridge::chan, and ast_bridge_config::end_bridge_callback_data.
Referenced by try_calling().
04577 { 04578 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data; 04579 ao2_ref(qeb, +1); 04580 qeb->chan = originator; 04581 }
| static int extension_state_cb | ( | char * | context, | |
| char * | exten, | |||
| enum ast_extension_states | state, | |||
| void * | data | |||
| ) | [static] |
Definition at line 1609 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().
01610 { 01611 struct ao2_iterator miter, qiter; 01612 struct member *m; 01613 struct call_queue *q; 01614 int found = 0, device_state = extensionstate2devicestate(state); 01615 01616 qiter = ao2_iterator_init(queues, 0); 01617 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) { 01618 ao2_lock(q); 01619 01620 miter = ao2_iterator_init(q->members, 0); 01621 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) { 01622 if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) { 01623 update_status(q, m, device_state); 01624 ao2_ref(m, -1); 01625 found = 1; 01626 break; 01627 } 01628 } 01629 ao2_iterator_destroy(&miter); 01630 01631 ao2_unlock(q); 01632 queue_t_unref(q, "Done with iterator"); 01633 } 01634 ao2_iterator_destroy(&qiter); 01635 01636 if (found) { 01637 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state)); 01638 } else { 01639 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", 01640 exten, context, device_state, ast_devstate2str(device_state)); 01641 } 01642 01643 return 0; 01644 }
| static int extensionstate2devicestate | ( | int | state | ) | [static] |
Helper function which converts from extension state to device state values.
Definition at line 1578 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().
01579 { 01580 switch (state) { 01581 case AST_EXTENSION_NOT_INUSE: 01582 state = AST_DEVICE_NOT_INUSE; 01583 break; 01584 case AST_EXTENSION_INUSE: 01585 state = AST_DEVICE_INUSE; 01586 break; 01587 case AST_EXTENSION_BUSY: 01588 state = AST_DEVICE_BUSY; 01589 break; 01590 case AST_EXTENSION_RINGING: 01591 state = AST_DEVICE_RINGING; 01592 break; 01593 case AST_EXTENSION_ONHOLD: 01594 state = AST_DEVICE_ONHOLD; 01595 break; 01596 case AST_EXTENSION_UNAVAILABLE: 01597 state = AST_DEVICE_UNAVAILABLE; 01598 break; 01599 case AST_EXTENSION_REMOVED: 01600 case AST_EXTENSION_DEACTIVATED: 01601 default: 01602 state = AST_DEVICE_INVALID; 01603 break; 01604 } 01605 01606 return state; 01607 }
| static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static, read] |
find the entry with the best metric, or NULL
Definition at line 3365 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
Referenced by ring_one(), store_next_lin(), and store_next_rr().
03366 { 03367 struct callattempt *best = NULL, *cur; 03368 03369 for (cur = outgoing; cur; cur = cur->q_next) { 03370 if (cur->stillgoing && /* Not already done */ 03371 !cur->chan && /* Isn't already going */ 03372 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 03373 best = cur; 03374 } 03375 } 03376 03377 return best; 03378 }
| 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 2289 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().
02290 { 02291 struct ast_variable *v; 02292 struct call_queue *q, tmpq = { 02293 .name = queuename, 02294 }; 02295 struct member *m; 02296 struct ao2_iterator mem_iter; 02297 char *interface = NULL; 02298 const char *tmp_name; 02299 char *tmp; 02300 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 02301 02302 /* Static queues override realtime. */ 02303 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) { 02304 ao2_lock(q); 02305 if (!q->realtime) { 02306 if (q->dead) { 02307 ao2_unlock(q); 02308 queue_t_unref(q, "Queue is dead; can't return it"); 02309 return NULL; 02310 } else { 02311 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); 02312 ao2_unlock(q); 02313 return q; 02314 } 02315 } 02316 } else if (!member_config) 02317 /* Not found in the list, and it's not realtime ... */ 02318 return NULL; 02319 02320 /* Check if queue is defined in realtime. */ 02321 if (!queue_vars) { 02322 /* Delete queue from in-core list if it has been deleted in realtime. */ 02323 if (q) { 02324 /*! \note Hmm, can't seem to distinguish a DB failure from a not 02325 found condition... So we might delete an in-core queue 02326 in case of DB failure. */ 02327 ast_debug(1, "Queue %s not found in realtime.\n", queuename); 02328 02329 q->dead = 1; 02330 /* Delete if unused (else will be deleted when last caller leaves). */ 02331 queues_t_unlink(queues, q, "Unused; removing from container"); 02332 ao2_unlock(q); 02333 queue_t_unref(q, "Queue is dead; can't return it"); 02334 } 02335 return NULL; 02336 } 02337 02338 /* Create a new queue if an in-core entry does not exist yet. */ 02339 if (!q) { 02340 struct ast_variable *tmpvar = NULL; 02341 if (!(q = alloc_queue(queuename))) 02342 return NULL; 02343 ao2_lock(q); 02344 clear_queue(q); 02345 q->realtime = 1; 02346 /*Before we initialize the queue, we need to set the strategy, so that linear strategy 02347 * will allocate the members properly 02348 */ 02349 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) { 02350 if (!strcasecmp(tmpvar->name, "strategy")) { 02351 q->strategy = strat2int(tmpvar->value); 02352 if (q->strategy < 0) { 02353 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 02354 tmpvar->value, q->name); 02355 q->strategy = QUEUE_STRATEGY_RINGALL; 02356 } 02357 break; 02358 } 02359 } 02360 /* We traversed all variables and didn't find a strategy */ 02361 if (!tmpvar) 02362 q->strategy = QUEUE_STRATEGY_RINGALL; 02363 queues_t_link(queues, q, "Add queue to container"); 02364 } 02365 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 02366 02367 memset(tmpbuf, 0, sizeof(tmpbuf)); 02368 for (v = queue_vars; v; v = v->next) { 02369 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 02370 if (strchr(v->name, '_')) { 02371 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 02372 tmp_name = tmpbuf; 02373 tmp = tmpbuf; 02374 while ((tmp = strchr(tmp, '_'))) 02375 *tmp++ = '-'; 02376 } else 02377 tmp_name = v->name; 02378 02379 /* NULL values don't get returned from realtime; blank values should 02380 * still get set. If someone doesn't want a value to be set, they 02381 * should set the realtime column to NULL, not blank. */ 02382 queue_set_param(q, tmp_name, v->value, -1, 0); 02383 } 02384 02385 /* Temporarily set realtime members dead so we can detect deleted ones. */ 02386 mem_iter = ao2_iterator_init(q->members, 0); 02387 while ((m = ao2_iterator_next(&mem_iter))) { 02388 if (m->realtime) 02389 m->dead = 1; 02390 ao2_ref(m, -1); 02391 } 02392 ao2_iterator_destroy(&mem_iter); 02393 02394 while ((interface = ast_category_browse(member_config, interface))) { 02395 rt_handle_member_record(q, interface, 02396 ast_variable_retrieve(member_config, interface, "uniqueid"), 02397 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface), 02398 ast_variable_retrieve(member_config, interface, "penalty"), 02399 ast_variable_retrieve(member_config, interface, "paused"), 02400 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface)); 02401 } 02402 02403 /* Delete all realtime members that have been deleted in DB. */ 02404 mem_iter = ao2_iterator_init(q->members, 0); 02405 while ((m = ao2_iterator_next(&mem_iter))) { 02406 if (m->dead) { 02407 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 02408 member_remove_from_queue(q, m); 02409 } 02410 ao2_ref(m, -1); 02411 } 02412 ao2_iterator_destroy(&mem_iter); 02413 02414 ao2_unlock(q); 02415 02416 return q; 02417 }
| static void free_members | ( | struct call_queue * | q, | |
| int | all | |||
| ) | [static] |
Iterate through queue's member list and delete them.
Definition at line 2235 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().
02236 { 02237 /* Free non-dynamic members */ 02238 struct member *cur; 02239 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 02240 02241 while ((cur = ao2_iterator_next(&mem_iter))) { 02242 if (all || !cur->dynamic) { 02243 member_remove_from_queue(q, cur); 02244 } 02245 ao2_ref(cur, -1); 02246 } 02247 ao2_iterator_destroy(&mem_iter); 02248 }
| static int get_member_penalty | ( | char * | queuename, | |
| char * | interface | |||
| ) | [static] |
Definition at line 5732 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().
05733 { 05734 int foundqueue = 0, penalty; 05735 struct call_queue *q, tmpq = { 05736 .name = queuename, 05737 }; 05738 struct member *mem; 05739 05740 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) { 05741 foundqueue = 1; 05742 ao2_lock(q); 05743 if ((mem = interface_exists(q, interface))) { 05744 penalty = mem->penalty; 05745 ao2_ref(mem, -1); 05746 ao2_unlock(q); 05747 queue_t_unref(q, "Search complete"); 05748 return penalty; 05749 } 05750 ao2_unlock(q); 05751 queue_t_unref(q, "Search complete"); 05752 } 05753 05754 /* some useful debuging */ 05755 if (foundqueue) 05756 ast_log (LOG_ERROR, "Invalid queuename\n"); 05757 else 05758 ast_log (LOG_ERROR, "Invalid interface\n"); 05759 05760 return RESULT_FAILURE; 05761 }
| static int get_member_status | ( | struct call_queue * | q, | |
| int | max_penalty, | |||
| int | min_penalty, | |||
| enum empty_conditions | conditions | |||
| ) | [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 1401 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::status, and call_queue::wrapuptime.
Referenced by join_queue(), queue_exec(), and wait_our_turn().
01402 { 01403 struct member *member; 01404 struct ao2_iterator mem_iter; 01405 01406 ao2_lock(q); 01407 mem_iter = ao2_iterator_init(q->members, 0); 01408 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) { 01409 if ((max_penalty != INT_MAX && member->penalty > max_penalty) || (min_penalty != INT_MAX && member->penalty < min_penalty)) { 01410 if (conditions & QUEUE_EMPTY_PENALTY) { 01411 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty); 01412 continue; 01413 } 01414 } 01415 01416 switch (member->status) { 01417 case AST_DEVICE_INVALID: 01418 if (conditions & QUEUE_EMPTY_INVALID) { 01419 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername); 01420 break; 01421 } 01422 goto default_case; 01423 case AST_DEVICE_UNAVAILABLE: 01424 if (conditions & QUEUE_EMPTY_UNAVAILABLE) { 01425 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername); 01426 break; 01427 } 01428 goto default_case; 01429 case AST_DEVICE_INUSE: 01430 if (conditions & QUEUE_EMPTY_INUSE) { 01431 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername); 01432 break; 01433 } 01434 goto default_case; 01435 case AST_DEVICE_RINGING: 01436 if (conditions & QUEUE_EMPTY_RINGING) { 01437 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername); 01438 break; 01439 } 01440 goto default_case; 01441 case AST_DEVICE_UNKNOWN: 01442 if (conditions & QUEUE_EMPTY_UNKNOWN) { 01443 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername); 01444 break; 01445 } 01446 /* Fall-through */ 01447 default: 01448 default_case: 01449 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) { 01450 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername); 01451 break; 01452 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) { 01453 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); 01454 break; 01455 } else { 01456 ao2_ref(member, -1); 01457 ao2_iterator_destroy(&mem_iter); 01458 ao2_unlock(q); 01459 ast_debug(4, "%s is available.\n", member->membername); 01460 return 0; 01461 } 01462 break; 01463 } 01464 } 01465 ao2_iterator_destroy(&mem_iter); 01466 01467 ao2_unlock(q); 01468 return -1; 01469 }
| static int get_queue_member_status | ( | struct member * | cur | ) | [static] |
Return the current state of a member.
Definition at line 1647 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().
01648 { 01649 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten)); 01650 }
| static char* handle_queue_add_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7976 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.
07977 { 07978 const char *queuename, *interface, *membername = NULL, *state_interface = NULL; 07979 int penalty; 07980 07981 switch ( cmd ) { 07982 case CLI_INIT: 07983 e->command = "queue add member"; 07984 e->usage = 07985 "Usage: queue add member <dial string> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n" 07986 " 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"; 07987 return NULL; 07988 case CLI_GENERATE: 07989 return complete_queue_add_member(a->line, a->word, a->pos, a->n); 07990 } 07991 07992 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) { 07993 return CLI_SHOWUSAGE; 07994 } else if (strcmp(a->argv[4], "to")) { 07995 return CLI_SHOWUSAGE; 07996 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) { 07997 return CLI_SHOWUSAGE; 07998 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) { 07999 return CLI_SHOWUSAGE; 08000 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) { 08001 return CLI_SHOWUSAGE; 08002 } 08003 08004 queuename = a->argv[5]; 08005 interface = a->argv[3]; 08006 if (a->argc >= 8) { 08007 if (sscanf(a->argv[7], "%30d", &penalty) == 1) { 08008 if (penalty < 0) { 08009 ast_cli(a->fd, "Penalty must be >= 0\n"); 08010 penalty = 0; 08011 } 08012 } else { 08013 ast_cli(a->fd, "Penalty must be an integer >= 0\n"); 08014 penalty = 0; 08015 } 08016 } else { 08017 penalty = 0; 08018 } 08019 08020 if (a->argc >= 10) { 08021 membername = a->argv[9]; 08022 } 08023 08024 if (a->argc >= 12) { 08025 state_interface = a->argv[11]; 08026 } 08027 08028 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { 08029 case RES_OKAY: 08030 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 08031 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 08032 return CLI_SUCCESS; 08033 case RES_EXISTS: 08034 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 08035 return CLI_FAILURE; 08036 case RES_NOSUCHQUEUE: 08037 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 08038 return CLI_FAILURE; 08039 case RES_OUTOFMEMORY: 08040 ast_cli(a->fd, "Out of memory\n"); 08041 return CLI_FAILURE; 08042 case RES_NOT_DYNAMIC: 08043 ast_cli(a->fd, "Member not dynamic\n"); 08044 return CLI_FAILURE; 08045 default: 08046 return CLI_FAILURE; 08047 } 08048 }
| static char* handle_queue_pause_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8161 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.
08162 { 08163 const char *queuename, *interface, *reason; 08164 int paused; 08165 08166 switch (cmd) { 08167 case CLI_INIT: 08168 e->command = "queue {pause|unpause} member"; 08169 e->usage = 08170 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n" 08171 " Pause or unpause a queue member. Not specifying a particular queue\n" 08172 " will pause or unpause a member across all queues to which the member\n" 08173 " belongs.\n"; 08174 return NULL; 08175 case CLI_GENERATE: 08176 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n); 08177 } 08178 08179 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) { 08180 return CLI_SHOWUSAGE; 08181 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) { 08182 return CLI_SHOWUSAGE; 08183 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) { 08184 return CLI_SHOWUSAGE; 08185 } 08186 08187 08188 interface = a->argv[3]; 08189 queuename = a->argc >= 6 ? a->argv[5] : NULL; 08190 reason = a->argc == 8 ? a->argv[7] : NULL; 08191 paused = !strcasecmp(a->argv[1], "pause"); 08192 08193 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) { 08194 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface); 08195 if (!ast_strlen_zero(queuename)) 08196 ast_cli(a->fd, " in queue '%s'", queuename); 08197 if (!ast_strlen_zero(reason)) 08198 ast_cli(a->fd, " for reason '%s'", reason); 08199 ast_cli(a->fd, "\n"); 08200 return CLI_SUCCESS; 08201 } else { 08202 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface); 08203 if (!ast_strlen_zero(queuename)) 08204 ast_cli(a->fd, " in queue '%s'", queuename); 08205 if (!ast_strlen_zero(reason)) 08206 ast_cli(a->fd, " for reason '%s'", reason); 08207 ast_cli(a->fd, "\n"); 08208 return CLI_FAILURE; 08209 } 08210 }
| static char* handle_queue_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8370 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.
08371 { 08372 struct ast_flags mask = {0,}; 08373 int i; 08374 08375 switch (cmd) { 08376 case CLI_INIT: 08377 e->command = "queue reload {parameters|members|rules|all}"; 08378 e->usage = 08379 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n" 08380 "Reload queues. If <queuenames> are specified, only reload information pertaining\n" 08381 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n" 08382 "specified in order to know what information to reload. Below is an explanation\n" 08383 "of each of these qualifiers.\n" 08384 "\n" 08385 "\t'members' - reload queue members from queues.conf\n" 08386 "\t'parameters' - reload all queue options except for queue members\n" 08387 "\t'rules' - reload the queuerules.conf file\n" 08388 "\t'all' - reload queue rules, parameters, and members\n" 08389 "\n" 08390 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n" 08391 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n" 08392 "one queue is specified when using this command, reloading queue rules may cause\n" 08393 "other queues to be affected\n"; 08394 return NULL; 08395 case CLI_GENERATE: 08396 if (a->pos >= 3) { 08397 /* find the point at which the list of queue names starts */ 08398 const char *command_end = a->line + strlen("queue reload "); 08399 command_end = strchr(command_end, ' '); 08400 if (!command_end) { 08401 command_end = a->line + strlen(a->line); 08402 } 08403 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line); 08404 } else { 08405 return NULL; 08406 } 08407 } 08408 08409 if (a->argc < 3) 08410 return CLI_SHOWUSAGE; 08411 08412 if (!strcasecmp(a->argv[2], "rules")) { 08413 ast_set_flag(&mask, QUEUE_RELOAD_RULES); 08414 } else if (!strcasecmp(a->argv[2], "members")) { 08415 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER); 08416 } else if (!strcasecmp(a->argv[2], "parameters")) { 08417 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); 08418 } else if (!strcasecmp(a->argv[2], "all")) { 08419 ast_set_flag(&mask, AST_FLAGS_ALL); 08420 } 08421 08422 if (a->argc == 3) { 08423 reload_handler(1, &mask, NULL); 08424 return CLI_SUCCESS; 08425 } 08426 08427 for (i = 3; i < a->argc; ++i) { 08428 reload_handler(1, &mask, a->argv[i]); 08429 } 08430 08431 return CLI_SUCCESS; 08432 }
| static char* handle_queue_remove_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8096 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.
08097 { 08098 const char *queuename, *interface; 08099 08100 switch (cmd) { 08101 case CLI_INIT: 08102 e->command = "queue remove member"; 08103 e->usage = 08104 "Usage: queue remove member <channel> from <queue>\n" 08105 " Remove a specific channel from a queue.\n"; 08106 return NULL; 08107 case CLI_GENERATE: 08108 return complete_queue_remove_member(a->line, a->word, a->pos, a->n); 08109 } 08110 08111 if (a->argc != 6) { 08112 return CLI_SHOWUSAGE; 08113 } else if (strcmp(a->argv[4], "from")) { 08114 return CLI_SHOWUSAGE; 08115 } 08116 08117 queuename = a->argv[5]; 08118 interface = a->argv[3]; 08119 08120 switch (remove_from_queue(queuename, interface)) { 08121 case RES_OKAY: 08122 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 08123 ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 08124 return CLI_SUCCESS; 08125 case RES_EXISTS: 08126 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 08127 return CLI_FAILURE; 08128 case RES_NOSUCHQUEUE: 08129 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 08130 return CLI_FAILURE; 08131 case RES_OUTOFMEMORY: 08132 ast_cli(a->fd, "Out of memory\n"); 08133 return CLI_FAILURE; 08134 case RES_NOT_DYNAMIC: 08135 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename); 08136 return CLI_FAILURE; 08137 default: 08138 return CLI_FAILURE; 08139 } 08140 }
| static char* handle_queue_reset | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8331 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.
08332 { 08333 struct ast_flags mask = {QUEUE_RESET_STATS,}; 08334 int i; 08335 08336 switch (cmd) { 08337 case CLI_INIT: 08338 e->command = "queue reset stats"; 08339 e->usage = 08340 "Usage: queue reset stats [<queuenames>]\n" 08341 "\n" 08342 "Issuing this command will reset statistics for\n" 08343 "<queuenames>, or for all queues if no queue is\n" 08344 "specified.\n"; 08345 return NULL; 08346 case CLI_GENERATE: 08347 if (a->pos >= 3) { 08348 return complete_queue(a->line, a->word, a->pos, a->n, 17); 08349 } else { 08350 return NULL; 08351 } 08352 } 08353 08354 if (a->argc < 3) { 08355 return CLI_SHOWUSAGE; 08356 } 08357 08358 if (a->argc == 3) { 08359 reload_handler(1, &mask, NULL); 08360 return CLI_SUCCESS; 08361 } 08362 08363 for (i = 3; i < a->argc; ++i) { 08364 reload_handler(1, &mask, a->argv[i]); 08365 } 08366 08367 return CLI_SUCCESS; 08368 }
| static char* handle_queue_rule_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8297 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.
08298 { 08299 const char *rule; 08300 struct rule_list *rl_iter; 08301 struct penalty_rule *pr_iter; 08302 switch (cmd) { 08303 case CLI_INIT: 08304 e->command = "queue show rules"; 08305 e->usage = 08306 "Usage: queue show rules [rulename]\n" 08307 " Show the list of rules associated with rulename. If no\n" 08308 " rulename is specified, list all rules defined in queuerules.conf\n"; 08309 return NULL; 08310 case CLI_GENERATE: 08311 return complete_queue_rule_show(a->line, a->word, a->pos, a->n); 08312 } 08313 08314 if (a->argc != 3 && a->argc != 4) 08315 return CLI_SHOWUSAGE; 08316 08317 rule = a->argc == 4 ? a->argv[3] : ""; 08318 AST_LIST_LOCK(&rule_lists); 08319 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 08320 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) { 08321 ast_cli(a->fd, "Rule: %s\n", rl_iter->name); 08322 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 08323 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); 08324 } 08325 } 08326 } 08327 AST_LIST_UNLOCK(&rule_lists); 08328 return CLI_SUCCESS; 08329 }
| static char* handle_queue_set_member_penalty | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8235 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.
08236 { 08237 const char *queuename = NULL, *interface; 08238 int penalty = 0; 08239 08240 switch (cmd) { 08241 case CLI_INIT: 08242 e->command = "queue set penalty"; 08243 e->usage = 08244 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n" 08245 " Set a member's penalty in the queue specified. If no queue is specified\n" 08246 " then that interface's penalty is set in all queues to which that interface is a member\n"; 08247 return NULL; 08248 case CLI_GENERATE: 08249 return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n); 08250 } 08251 08252 if (a->argc != 6 && a->argc != 8) { 08253 return CLI_SHOWUSAGE; 08254 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) { 08255 return CLI_SHOWUSAGE; 08256 } 08257 08258 if (a->argc == 8) 08259 queuename = a->argv[7]; 08260 interface = a->argv[5]; 08261 penalty = atoi(a->argv[3]); 08262 08263 switch (set_member_penalty(queuename, interface, penalty)) { 08264 case RESULT_SUCCESS: 08265 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename); 08266 return CLI_SUCCESS; 08267 case RESULT_FAILURE: 08268 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename); 08269 return CLI_FAILURE; 08270 default: 08271 return CLI_FAILURE; 08272 } 08273 }
| static int handle_statechange | ( | void * | datap | ) | [static] |
set a member's status based on device state of that member's interface
Definition at line 1507 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().
01508 { 01509 struct statechange *sc = datap; 01510 struct ao2_iterator miter, qiter; 01511 struct member *m; 01512 struct call_queue *q; 01513 char interface[80], *slash_pos; 01514 int found = 0; 01515 01516 qiter = ao2_iterator_init(queues, 0); 01517 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) { 01518 ao2_lock(q); 01519 01520 miter = ao2_iterator_init(q->members, 0); 01521 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) { 01522 ast_copy_string(interface, m->state_interface, sizeof(interface)); 01523 01524 if ((slash_pos = strchr(interface, '/'))) 01525 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) 01526 *slash_pos = '\0'; 01527 01528 if (!strcasecmp(interface, sc->dev)) { 01529 found = 1; 01530 update_status(q, m, sc->state); 01531 ao2_ref(m, -1); 01532 break; 01533 } 01534 } 01535 ao2_iterator_destroy(&miter); 01536 01537 ao2_unlock(q); 01538 queue_t_unref(q, "Done with iterator"); 01539 } 01540 ao2_iterator_destroy(&qiter); 01541 01542 if (found) 01543 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state)); 01544 else 01545 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)); 01546 01547 ast_free(sc); 01548 return 0; 01549 }
| 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 2937 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().
02938 { 02939 struct callattempt *oo; 02940 02941 while (outgoing) { 02942 /* If someone else answered the call we should indicate this in the CANCEL */ 02943 /* Hangup any existing lines we have open */ 02944 if (outgoing->chan && (outgoing->chan != exception)) { 02945 if (exception || cancel_answered_elsewhere) 02946 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE); 02947 ast_hangup(outgoing->chan); 02948 } 02949 oo = outgoing; 02950 outgoing = outgoing->q_next; 02951 ast_aoc_destroy_decoded(oo->aoc_s_rate_list); 02952 callattempt_free(oo); 02953 } 02954 }
| static void init_queue | ( | struct call_queue * | q | ) | [static] |
Initialize Queue default values.
Definition at line 1717 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().
01718 { 01719 int i; 01720 struct penalty_rule *pr_iter; 01721 01722 q->dead = 0; 01723 q->retry = DEFAULT_RETRY; 01724 q->timeout = DEFAULT_TIMEOUT; 01725 q->maxlen = 0; 01726 q->announcefrequency = 0; 01727 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY; 01728 q->announceholdtime = 1; 01729 q->announcepositionlimit = 10; /* Default 10 positions */ 01730 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */ 01731 q->roundingseconds = 0; /* Default - don't announce seconds */ 01732 q->servicelevel = 0; 01733 q->ringinuse = 1; 01734 q->announce_to_first_user = 0; 01735 q->setinterfacevar = 0; 01736 q->setqueuevar = 0; 01737 q->setqueueentryvar = 0; 01738 q->autofill = autofill_default; 01739 q->montype = montype_default; 01740 q->monfmt[0] = '\0'; 01741 q->reportholdtime = 0; 01742 q->wrapuptime = 0; 01743 q->penaltymemberslimit = 0; 01744 q->joinempty = 0; 01745 q->leavewhenempty = 0; 01746 q->memberdelay = 0; 01747 q->maskmemberstatus = 0; 01748 q->eventwhencalled = 0; 01749 q->weight = 0; 01750 q->timeoutrestart = 0; 01751 q->periodicannouncefrequency = 0; 01752 q->randomperiodicannounce = 0; 01753 q->numperiodicannounce = 0; 01754 q->autopause = QUEUE_AUTOPAUSE_OFF; 01755 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 01756 if (!q->members) { 01757 if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) 01758 /* linear strategy depends on order, so we have to place all members in a single bucket */ 01759 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn); 01760 else 01761 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn); 01762 } 01763 q->found = 1; 01764 01765 ast_string_field_set(q, sound_next, "queue-youarenext"); 01766 ast_string_field_set(q, sound_thereare, "queue-thereare"); 01767 ast_string_field_set(q, sound_calls, "queue-callswaiting"); 01768 ast_string_field_set(q, queue_quantity1, "queue-quantity1"); 01769 ast_string_field_set(q, queue_quantity2, "queue-quantity2"); 01770 ast_string_field_set(q, sound_holdtime, "queue-holdtime"); 01771 ast_string_field_set(q, sound_minutes, "queue-minutes"); 01772 ast_string_field_set(q, sound_minute, "queue-minute"); 01773 ast_string_field_set(q, sound_seconds, "queue-seconds"); 01774 ast_string_field_set(q, sound_thanks, "queue-thankyou"); 01775 ast_string_field_set(q, sound_reporthold, "queue-reporthold"); 01776 01777 if (!q->sound_periodicannounce[0]) { 01778 q->sound_periodicannounce[0] = ast_str_create(32); 01779 } 01780 01781 if (q->sound_periodicannounce[0]) { 01782 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce"); 01783 } 01784 01785 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 01786 if (q->sound_periodicannounce[i]) 01787 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", ""); 01788 } 01789 01790 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) 01791 ast_free(pr_iter); 01792 }
| 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 1371 of file app_queue.c.
References call_queue::head, and queue_ref().
Referenced by join_queue().
01372 { 01373 struct queue_ent *cur; 01374 01375 if (!q || !new) 01376 return; 01377 if (prev) { 01378 cur = prev->next; 01379 prev->next = new; 01380 } else { 01381 cur = q->head; 01382 q->head = new; 01383 } 01384 new->next = cur; 01385 01386 /* every queue_ent must have a reference to it's parent call_queue, this 01387 * reference does not go away until the end of the queue_ent's life, meaning 01388 * that even when the queue_ent leaves the call_queue this ref must remain. */ 01389 queue_ref(q); 01390 new->parent = q; 01391 new->pos = ++(*pos); 01392 new->opos = *pos; 01393 }
| 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 1823 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().
01824 { 01825 char *timestr, *maxstr, *minstr, *contentdup; 01826 struct penalty_rule *rule = NULL, *rule_iter; 01827 struct rule_list *rl_iter; 01828 int penaltychangetime, inserted = 0; 01829 01830 if (!(rule = ast_calloc(1, sizeof(*rule)))) { 01831 return -1; 01832 } 01833 01834 contentdup = ast_strdupa(content); 01835 01836 if (!(maxstr = strchr(contentdup, ','))) { 01837 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum); 01838 ast_free(rule); 01839 return -1; 01840 } 01841 01842 *maxstr++ = '\0'; 01843 timestr = contentdup; 01844 01845 if ((penaltychangetime = atoi(timestr)) < 0) { 01846 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum); 01847 ast_free(rule); 01848 return -1; 01849 } 01850 01851 rule->time = penaltychangetime; 01852 01853 if ((minstr = strchr(maxstr,','))) 01854 *minstr++ = '\0'; 01855 01856 /* The last check will evaluate true if either no penalty change is indicated for a given rule 01857 * OR if a min penalty change is indicated but no max penalty change is */ 01858 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') { 01859 rule->max_relative = 1; 01860 } 01861 01862 rule->max_value = atoi(maxstr); 01863 01864 if (!ast_strlen_zero(minstr)) { 01865 if (*minstr == '+' || *minstr == '-') 01866 rule->min_relative = 1; 01867 rule->min_value = atoi(minstr); 01868 } else /*there was no minimum specified, so assume this means no change*/ 01869 rule->min_relative = 1; 01870 01871 /*We have the rule made, now we need to insert it where it belongs*/ 01872 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){ 01873 if (strcasecmp(rl_iter->name, list_name)) 01874 continue; 01875 01876 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) { 01877 if (rule->time < rule_iter->time) { 01878 AST_LIST_INSERT_BEFORE_CURRENT(rule, list); 01879 inserted = 1; 01880 break; 01881 } 01882 } 01883 AST_LIST_TRAVERSE_SAFE_END; 01884 01885 if (!inserted) { 01886 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list); 01887 inserted = 1; 01888 } 01889 01890 break; 01891 } 01892 01893 if (!inserted) { 01894 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name); 01895 ast_free(rule); 01896 return -1; 01897 } 01898 return 0; 01899 }
| static const char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 1209 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().
01210 { 01211 int x; 01212 01213 for (x = 0; x < ARRAY_LEN(strategies); x++) { 01214 if (strategy == strategies[x].strategy) 01215 return strategies[x].name; 01216 } 01217 01218 return "<unknown>"; 01219 }
| static struct member* interface_exists | ( | struct call_queue * | q, | |
| const char * | interface | |||
| ) | [static, read] |
Definition at line 5429 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().
05430 { 05431 struct member *mem; 05432 struct ao2_iterator mem_iter; 05433 05434 if (!q) 05435 return NULL; 05436 05437 mem_iter = ao2_iterator_init(q->members, 0); 05438 while ((mem = ao2_iterator_next(&mem_iter))) { 05439 if (!strcasecmp(interface, mem->interface)) { 05440 ao2_iterator_destroy(&mem_iter); 05441 return mem; 05442 } 05443 ao2_ref(mem, -1); 05444 } 05445 ao2_iterator_destroy(&mem_iter); 05446 05447 return NULL; 05448 }
| 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 4131 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().
04132 { 04133 struct queue_ent *ch; 04134 int res; 04135 int avl; 04136 int idx = 0; 04137 /* This needs a lock. How many members are available to be served? */ 04138 ao2_lock(qe->parent); 04139 04140 avl = num_available_members(qe->parent); 04141 04142 ch = qe->parent->head; 04143 04144 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member"); 04145 04146 while ((idx < avl) && (ch) && (ch != qe)) { 04147 if (!ch->pending) 04148 idx++; 04149 ch = ch->next; 04150 } 04151 04152 ao2_unlock(qe->parent); 04153 /* If the queue entry is within avl [the number of available members] calls from the top ... 04154 * Autofill and position check added to support autofill=no (as only calls 04155 * from the front of the queue are valid when autofill is disabled) 04156 */ 04157 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) { 04158 ast_debug(1, "It's our turn (%s).\n", qe->chan->name); 04159 res = 1; 04160 } else { 04161 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name); 04162 res = 0; 04163 } 04164 04165 return res; 04166 }
| static int join_queue | ( | char * | queuename, | |
| struct queue_ent * | qe, | |||
| enum queue_result * | reason, | |||
| int | position | |||
| ) | [static] |
Definition at line 2547 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().
02548 { 02549 struct call_queue *q; 02550 struct queue_ent *cur, *prev = NULL; 02551 int res = -1; 02552 int pos = 0; 02553 int inserted = 0; 02554 02555 if (!(q = load_realtime_queue(queuename))) 02556 return res; 02557 02558 ao2_lock(q); 02559 02560 /* This is our one */ 02561 if (q->joinempty) { 02562 int status = 0; 02563 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) { 02564 *reason = QUEUE_JOINEMPTY; 02565 ao2_unlock(q); 02566 queue_t_unref(q, "Done with realtime queue"); 02567 return res; 02568 } 02569 } 02570 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) 02571 *reason = QUEUE_FULL; 02572 else if (*reason == QUEUE_UNKNOWN) { 02573 /* There's space for us, put us at the right position inside 02574 * the queue. 02575 * Take into account the priority of the calling user */ 02576 inserted = 0; 02577 prev = NULL; 02578 cur = q->head; 02579 while (cur) { 02580 /* We have higher priority than the current user, enter 02581 * before him, after all the other users with priority 02582 * higher or equal to our priority. */ 02583 if ((!inserted) && (qe->prio > cur->prio)) { 02584 insert_entry(q, prev, qe, &pos); 02585 inserted = 1; 02586 } 02587 /* <= is necessary for the position comparison because it may not be possible to enter 02588 * at our desired position since higher-priority callers may have taken the position we want 02589 */ 02590 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) { 02591 insert_entry(q, prev, qe, &pos); 02592 inserted = 1; 02593 /*pos is incremented inside insert_entry, so don't need to add 1 here*/ 02594 if (position < pos) { 02595 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos); 02596 } 02597 } 02598 cur->pos = ++pos; 02599 prev = cur; 02600 cur = cur->next; 02601 } 02602 /* No luck, join at the end of the queue */ 02603 if (!inserted) 02604 insert_entry(q, prev, qe, &pos); 02605 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 02606 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 02607 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 02608 q->count++; 02609 res = 0; 02610 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join", 02611 "Channel: %s\r\n" 02612 "CallerIDNum: %s\r\n" 02613 "CallerIDName: %s\r\n" 02614 "ConnectedLineNum: %s\r\n" 02615 "ConnectedLineName: %s\r\n" 02616 "Queue: %s\r\n" 02617 "Position: %d\r\n" 02618 "Count: %d\r\n" 02619 "Uniqueid: %s\r\n", 02620 qe->chan->name, 02621 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */ 02622 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 02623 S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */ 02624 S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), 02625 q->name, qe->pos, q->count, qe->chan->uniqueid ); 02626 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 02627 } 02628 ao2_unlock(q); 02629 queue_t_unref(q, "Done with realtime queue"); 02630 02631 return res; 02632 }
| static int kill_dead_members | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 6961 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 7105 of file app_queue.c.
References ast_strlen_zero(), CMP_MATCH, and call_queue::dead.
Referenced by reload_queues().
07106 { 07107 struct call_queue *q = obj; 07108 char *queuename = arg; 07109 if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) { 07110 return CMP_MATCH; 07111 } else { 07112 return 0; 07113 } 07114 }
| 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 2859 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().
02860 { 02861 struct call_queue *q; 02862 struct queue_ent *current, *prev = NULL; 02863 struct penalty_rule *pr_iter; 02864 int pos = 0; 02865 02866 if (!(q = qe->parent)) 02867 return; 02868 queue_t_ref(q, "Copy queue pointer from queue entry"); 02869 ao2_lock(q); 02870 02871 prev = NULL; 02872 for (current = q->head; current; current = current->next) { 02873 if (current == qe) { 02874 char posstr[20]; 02875 q->count--; 02876 02877 /* Take us out of the queue */ 02878 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave", 02879 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n", 02880 qe->chan->name, q->name, q->count, qe->pos, qe->chan->uniqueid); 02881 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 02882 /* Take us out of the queue */ 02883 if (prev) 02884 prev->next = current->next; 02885 else 02886 q->head = current->next; 02887 /* Free penalty rules */ 02888 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) 02889 ast_free(pr_iter); 02890 snprintf(posstr, sizeof(posstr), "%d", qe->pos); 02891 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr); 02892 } else { 02893 /* Renumber the people after us in the queue based on a new count */ 02894 current->pos = ++pos; 02895 prev = current; 02896 } 02897 } 02898 ao2_unlock(q); 02899 02900 /*If the queue is a realtime queue, check to see if it's still defined in real time*/ 02901 if (q->realtime) { 02902 struct ast_variable *var; 02903 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) { 02904 q->dead = 1; 02905 } else { 02906 ast_variables_destroy(var); 02907 } 02908 } 02909 02910 if (q->dead) { 02911 /* It's dead and nobody is in it, so kill it */ 02912 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container"); 02913 } 02914 /* unref the explicit ref earlier in the function */ 02915 queue_t_unref(q, "Expire copied reference"); 02916 }
| static int load_module | ( | void | ) | [static] |
Definition at line 8782 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().
08783 { 08784 int res; 08785 struct ast_context *con; 08786 struct ast_flags mask = {AST_FLAGS_ALL, }; 08787 08788 queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb); 08789 08790 use_weight = 0; 08791 08792 if (reload_handler(0, &mask, NULL)) 08793 return AST_MODULE_LOAD_DECLINE; 08794 08795 con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue"); 08796 if (!con) 08797 ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n"); 08798 else 08799 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue"); 08800 08801 if (queue_persistent_members) 08802 reload_queue_members(); 08803 08804 ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers)); 08805 08806 ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue)); 08807 res = ast_register_application_xml(app, queue_exec); 08808 res |= ast_register_application_xml(app_aqm, aqm_exec); 08809 res |= ast_register_application_xml(app_rqm, rqm_exec); 08810 res |= ast_register_application_xml(app_pqm, pqm_exec); 08811 res |= ast_register_application_xml(app_upqm, upqm_exec); 08812 res |= ast_register_application_xml(app_ql, ql_exec); 08813 res |= ast_manager_register_xml("Queues", 0, manager_queues_show); 08814 res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status); 08815 res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary); 08816 res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member); 08817 res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member); 08818 res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member); 08819 res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom); 08820 res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty); 08821 res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show); 08822 res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload); 08823 res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset); 08824 res |= ast_custom_function_register(&queuevar_function); 08825 res |= ast_custom_function_register(&queueexists_function); 08826 res |= ast_custom_function_register(&queuemembercount_function); 08827 res |= ast_custom_function_register(&queuemembercount_dep); 08828 res |= ast_custom_function_register(&queuememberlist_function); 08829 res |= ast_custom_function_register(&queuewaitingcount_function); 08830 res |= ast_custom_function_register(&queuememberpenalty_function); 08831 08832 if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) { 08833 ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n"); 08834 } 08835 08836 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */ 08837 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) { 08838 res = -1; 08839 } 08840 08841 ast_extension_state_add(NULL, NULL, extension_state_cb, NULL); 08842 08843 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL); 08844 08845 return res ? AST_MODULE_LOAD_DECLINE : 0; 08846 }
| 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 2420 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().
02421 { 02422 struct ast_variable *queue_vars; 02423 struct ast_config *member_config = NULL; 02424 struct call_queue *q = NULL, tmpq = { 02425 .name = queuename, 02426 }; 02427 int prev_weight = 0; 02428 02429 /* Find the queue in the in-core list first. */ 02430 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first"); 02431 02432 if (!q || q->realtime) { 02433 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all 02434 queue operations while waiting for the DB. 02435 02436 This will be two separate database transactions, so we might 02437 see queue parameters as they were before another process 02438 changed the queue and member list as it was after the change. 02439 Thus we might see an empty member list when a queue is 02440 deleted. In practise, this is unlikely to cause a problem. */ 02441 02442 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL); 02443 if (queue_vars) { 02444 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL); 02445 if (!member_config) { 02446 ast_debug(1, "No queue_members defined in config extconfig.conf\n"); 02447 member_config = ast_config_new(); 02448 } 02449 } 02450 if (q) { 02451 prev_weight = q->weight ? 1 : 0; 02452 queue_t_unref(q, "Need to find realtime queue"); 02453 } 02454 02455 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 02456 ast_config_destroy(member_config); 02457 ast_variables_destroy(queue_vars); 02458 02459 /* update the use_weight value if the queue's has gained or lost a weight */ 02460 if (q) { 02461 if (!q->weight && prev_weight) { 02462 ast_atomic_fetchadd_int(&use_weight, -1); 02463 } 02464 if (q->weight && !prev_weight) { 02465 ast_atomic_fetchadd_int(&use_weight, +1); 02466 } 02467 } 02468 /* Other cases will end up with the proper value for use_weight */ 02469 } else { 02470 update_realtime_members(q); 02471 } 02472 return q; 02473 }
| static int manager_add_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7743 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().
07744 { 07745 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; 07746 int paused, penalty = 0; 07747 07748 queuename = astman_get_header(m, "Queue"); 07749 interface = astman_get_header(m, "Interface"); 07750 penalty_s = astman_get_header(m, "Penalty"); 07751 paused_s = astman_get_header(m, "Paused"); 07752 membername = astman_get_header(m, "MemberName"); 07753 state_interface = astman_get_header(m, "StateInterface"); 07754 07755 if (ast_strlen_zero(queuename)) { 07756 astman_send_error(s, m, "'Queue' not specified."); 07757 return 0; 07758 } 07759 07760 if (ast_strlen_zero(interface)) { 07761 astman_send_error(s, m, "'Interface' not specified."); 07762 return 0; 07763 } 07764 07765 if (ast_strlen_zero(penalty_s)) 07766 penalty = 0; 07767 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) 07768 penalty = 0; 07769 07770 if (ast_strlen_zero(paused_s)) 07771 paused = 0; 07772 else 07773 paused = abs(ast_true(paused_s)); 07774 07775 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { 07776 case RES_OKAY: 07777 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); 07778 astman_send_ack(s, m, "Added interface to queue"); 07779 break; 07780 case RES_EXISTS: 07781 astman_send_error(s, m, "Unable to add interface: Already there"); 07782 break; 07783 case RES_NOSUCHQUEUE: 07784 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 07785 break; 07786 case RES_OUTOFMEMORY: 07787 astman_send_error(s, m, "Out of memory"); 07788 break; 07789 } 07790 07791 return 0; 07792 }
| static int manager_pause_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7828 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().
07829 { 07830 const char *queuename, *interface, *paused_s, *reason; 07831 int paused; 07832 07833 interface = astman_get_header(m, "Interface"); 07834 paused_s = astman_get_header(m, "Paused"); 07835 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 07836 reason = astman_get_header(m, "Reason"); /* Optional - Only used for logging purposes */ 07837 07838 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 07839 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 07840 return 0; 07841 } 07842 07843 paused = abs(ast_true(paused_s)); 07844 07845 if (set_member_paused(queuename, interface, reason, paused)) 07846 astman_send_error(s, m, "Interface not found"); 07847 else 07848 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 07849 return 0; 07850 }
| static int manager_queue_log_custom | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7852 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().
07853 { 07854 const char *queuename, *event, *message, *interface, *uniqueid; 07855 07856 queuename = astman_get_header(m, "Queue"); 07857 uniqueid = astman_get_header(m, "UniqueId"); 07858 interface = astman_get_header(m, "Interface"); 07859 event = astman_get_header(m, "Event"); 07860 message = astman_get_header(m, "Message"); 07861 07862 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) { 07863 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters."); 07864 return 0; 07865 } 07866 07867 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message); 07868 astman_send_ack(s, m, "Event added successfully"); 07869 07870 return 0; 07871 }
| static int manager_queue_member_penalty | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7951 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().
07952 { 07953 const char *queuename, *interface, *penalty_s; 07954 int penalty; 07955 07956 interface = astman_get_header(m, "Interface"); 07957 penalty_s = astman_get_header(m, "Penalty"); 07958 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */ 07959 queuename = astman_get_header(m, "Queue"); 07960 07961 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) { 07962 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters."); 07963 return 0; 07964 } 07965 07966 penalty = atoi(penalty_s); 07967 07968 if (set_member_penalty((char *)queuename, (char *)interface, penalty)) 07969 astman_send_error(s, m, "Invalid interface, queuename or penalty"); 07970 else 07971 astman_send_ack(s, m, "Interface penalty set successfully"); 07972 07973 return 0; 07974 }
| static int manager_queue_reload | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7873 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().
07874 { 07875 struct ast_flags mask = {0,}; 07876 const char *queuename = NULL; 07877 int header_found = 0; 07878 07879 queuename = astman_get_header(m, "Queue"); 07880 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) { 07881 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER); 07882 header_found = 1; 07883 } 07884 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) { 07885 ast_set_flag(&mask, QUEUE_RELOAD_RULES); 07886 header_found = 1; 07887 } 07888 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) { 07889 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); 07890 header_found = 1; 07891 } 07892 07893 if (!header_found) { 07894 ast_set_flag(&mask, AST_FLAGS_ALL); 07895 } 07896 07897 if (!reload_handler(1, &mask, queuename)) { 07898 astman_send_ack(s, m, "Queue reloaded successfully"); 07899 } else { 07900 astman_send_error(s, m, "Error encountered while reloading queue"); 07901 } 07902 return 0; 07903 }
| static int manager_queue_reset | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7905 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().
07906 { 07907 const char *queuename = NULL; 07908 struct ast_flags mask = {QUEUE_RESET_STATS,}; 07909 07910 queuename = astman_get_header(m, "Queue"); 07911 07912 if (!reload_handler(1, &mask, queuename)) { 07913 astman_send_ack(s, m, "Queue stats reset successfully"); 07914 } else { 07915 astman_send_error(s, m, "Error encountered while resetting queue stats"); 07916 } 07917 return 0; 07918 }
| static int manager_queue_rule_show | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7532 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().
07533 { 07534 const char *rule = astman_get_header(m, "Rule"); 07535 const char *id = astman_get_header(m, "ActionID"); 07536 struct rule_list *rl_iter; 07537 struct penalty_rule *pr_iter; 07538 07539 astman_append(s, "Response: Success\r\n"); 07540 if (!ast_strlen_zero(id)) { 07541 astman_append(s, "ActionID: %s\r\n", id); 07542 } 07543 07544 AST_LIST_LOCK(&rule_lists); 07545 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 07546 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) { 07547 astman_append(s, "RuleList: %s\r\n", rl_iter->name); 07548 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 07549 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 ); 07550 } 07551 if (!ast_strlen_zero(rule)) 07552 break; 07553 } 07554 } 07555 AST_LIST_UNLOCK(&rule_lists); 07556 07557 /* 07558 * Two blank lines instead of one because the Response and 07559 * ActionID headers used to not be present. 07560 */ 07561 astman_append(s, "\r\n\r\n"); 07562 07563 return RESULT_SUCCESS; 07564 }
| static int manager_queues_show | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7522 of file app_queue.c.
References __queues_show(), astman_append(), and RESULT_SUCCESS.
Referenced by load_module().
07523 { 07524 static const char * const a[] = { "queue", "show" }; 07525 07526 __queues_show(s, -1, 2, a); 07527 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 07528 07529 return RESULT_SUCCESS; 07530 }
| static int manager_queues_status | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Queue status info via AMI.
Definition at line 7642 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().
07643 { 07644 time_t now; 07645 int pos; 07646 const char *id = astman_get_header(m,"ActionID"); 07647 const char *queuefilter = astman_get_header(m,"Queue"); 07648 const char *memberfilter = astman_get_header(m,"Member"); 07649 char idText[256] = ""; 07650 struct call_queue *q; 07651 struct queue_ent *qe; 07652 float sl = 0; 07653 struct member *mem; 07654 struct ao2_iterator queue_iter; 07655 struct ao2_iterator mem_iter; 07656 07657 astman_send_ack(s, m, "Queue status will follow"); 07658 time(&now); 07659 if (!ast_strlen_zero(id)) 07660 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 07661 07662 queue_iter = ao2_iterator_init(queues, 0); 07663 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07664 ao2_lock(q); 07665 07666 /* List queue properties */ 07667 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 07668 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 07669 astman_append(s, "Event: QueueParams\r\n" 07670 "Queue: %s\r\n" 07671 "Max: %d\r\n" 07672 "Strategy: %s\r\n" 07673 "Calls: %d\r\n" 07674 "Holdtime: %d\r\n" 07675 "TalkTime: %d\r\n" 07676 "Completed: %d\r\n" 07677 "Abandoned: %d\r\n" 07678 "ServiceLevel: %d\r\n" 07679 "ServicelevelPerf: %2.1f\r\n" 07680 "Weight: %d\r\n" 07681 "%s" 07682 "\r\n", 07683 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, 07684 q->callsabandoned, q->servicelevel, sl, q->weight, idText); 07685 /* List Queue Members */ 07686 mem_iter = ao2_iterator_init(q->members, 0); 07687 while ((mem = ao2_iterator_next(&mem_iter))) { 07688 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) { 07689 astman_append(s, "Event: QueueMember\r\n" 07690 "Queue: %s\r\n" 07691 "Name: %s\r\n" 07692 "Location: %s\r\n" 07693 "Membership: %s\r\n" 07694 "Penalty: %d\r\n" 07695 "CallsTaken: %d\r\n" 07696 "LastCall: %d\r\n" 07697 "Status: %d\r\n" 07698 "Paused: %d\r\n" 07699 "%s" 07700 "\r\n", 07701 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static", 07702 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 07703 } 07704 ao2_ref(mem, -1); 07705 } 07706 ao2_iterator_destroy(&mem_iter); 07707 /* List Queue Entries */ 07708 pos = 1; 07709 for (qe = q->head; qe; qe = qe->next) { 07710 astman_append(s, "Event: QueueEntry\r\n" 07711 "Queue: %s\r\n" 07712 "Position: %d\r\n" 07713 "Channel: %s\r\n" 07714 "Uniqueid: %s\r\n" 07715 "CallerIDNum: %s\r\n" 07716 "CallerIDName: %s\r\n" 07717 "ConnectedLineNum: %s\r\n" 07718 "ConnectedLineName: %s\r\n" 07719 "Wait: %ld\r\n" 07720 "%s" 07721 "\r\n", 07722 q->name, pos++, qe->chan->name, qe->chan->uniqueid, 07723 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"), 07724 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 07725 S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"), 07726 S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), 07727 (long) (now - qe->start), idText); 07728 } 07729 } 07730 ao2_unlock(q); 07731 queue_t_unref(q, "Done with iterator"); 07732 } 07733 ao2_iterator_destroy(&queue_iter); 07734 07735 astman_append(s, 07736 "Event: QueueStatusComplete\r\n" 07737 "%s" 07738 "\r\n",idText); 07739 07740 return RESULT_SUCCESS; 07741 }
| static int manager_queues_summary | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Summary of queue info via the AMI.
Definition at line 7567 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().
07568 { 07569 time_t now; 07570 int qmemcount = 0; 07571 int qmemavail = 0; 07572 int qchancount = 0; 07573 int qlongestholdtime = 0; 07574 const char *id = astman_get_header(m, "ActionID"); 07575 const char *queuefilter = astman_get_header(m, "Queue"); 07576 char idText[256] = ""; 07577 struct call_queue *q; 07578 struct queue_ent *qe; 07579 struct member *mem; 07580 struct ao2_iterator queue_iter; 07581 struct ao2_iterator mem_iter; 07582 07583 astman_send_ack(s, m, "Queue summary will follow"); 07584 time(&now); 07585 if (!ast_strlen_zero(id)) 07586 snprintf(idText, 256, "ActionID: %s\r\n", id); 07587 queue_iter = ao2_iterator_init(queues, 0); 07588 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07589 ao2_lock(q); 07590 07591 /* List queue properties */ 07592 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 07593 /* Reset the necessary local variables if no queuefilter is set*/ 07594 qmemcount = 0; 07595 qmemavail = 0; 07596 qchancount = 0; 07597 qlongestholdtime = 0; 07598 07599 /* List Queue Members */ 07600 mem_iter = ao2_iterator_init(q->members, 0); 07601 while ((mem = ao2_iterator_next(&mem_iter))) { 07602 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) { 07603 ++qmemcount; 07604 if (member_status_available(mem->status) && !mem->paused) { 07605 ++qmemavail; 07606 } 07607 } 07608 ao2_ref(mem, -1); 07609 } 07610 ao2_iterator_destroy(&mem_iter); 07611 for (qe = q->head; qe; qe = qe->next) { 07612 if ((now - qe->start) > qlongestholdtime) { 07613 qlongestholdtime = now - qe->start; 07614 } 07615 ++qchancount; 07616 } 07617 astman_append(s, "Event: QueueSummary\r\n" 07618 "Queue: %s\r\n" 07619 "LoggedIn: %d\r\n" 07620 "Available: %d\r\n" 07621 "Callers: %d\r\n" 07622 "HoldTime: %d\r\n" 07623 "TalkTime: %d\r\n" 07624 "LongestHoldTime: %d\r\n" 07625 "%s" 07626 "\r\n", 07627 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText); 07628 } 07629 ao2_unlock(q); 07630 queue_t_unref(q, "Done with iterator"); 07631 } 07632 ao2_iterator_destroy(&queue_iter); 07633 astman_append(s, 07634 "Event: QueueSummaryComplete\r\n" 07635 "%s" 07636 "\r\n", idText); 07637 07638 return RESULT_SUCCESS; 07639 }
| static int manager_remove_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7794 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().
07795 { 07796 const char *queuename, *interface; 07797 07798 queuename = astman_get_header(m, "Queue"); 07799 interface = astman_get_header(m, "Interface"); 07800 07801 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 07802 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 07803 return 0; 07804 } 07805 07806 switch (remove_from_queue(queuename, interface)) { 07807 case RES_OKAY: 07808 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 07809 astman_send_ack(s, m, "Removed interface from queue"); 07810 break; 07811 case RES_EXISTS: 07812 astman_send_error(s, m, "Unable to remove interface: Not there"); 07813 break; 07814 case RES_NOSUCHQUEUE: 07815 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 07816 break; 07817 case RES_OUTOFMEMORY: 07818 astman_send_error(s, m, "Out of memory"); 07819 break; 07820 case RES_NOT_DYNAMIC: 07821 astman_send_error(s, m, "Member not dynamic"); 07822 break; 07823 } 07824 07825 return 0; 07826 }
| static int mark_dead_and_unfound | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 7094 of file app_queue.c.
References ast_strlen_zero(), call_queue::dead, call_queue::found, and call_queue::realtime.
Referenced by reload_queues().
07095 { 07096 struct call_queue *q = obj; 07097 char *queuename = arg; 07098 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) { 07099 q->dead = 1; 07100 q->found = 0; 07101 } 07102 return 0; 07103 }
| static int mark_member_dead | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 6952 of file app_queue.c.
References member::delme, and member::dynamic.
Referenced by reload_single_queue().
| static void member_add_to_queue | ( | struct call_queue * | queue, | |
| struct member * | mem | |||
| ) | [static] |
Definition at line 2147 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().
02148 { 02149 ao2_lock(queue->members); 02150 mem->queuepos = ao2_container_count(queue->members); 02151 ao2_link(queue->members, mem); 02152 ao2_unlock(queue->members); 02153 }
| static void member_call_pending_clear | ( | struct member * | mem | ) | [static] |
Definition at line 3108 of file app_queue.c.
References ao2_lock, ao2_unlock, and member::call_pending.
Referenced by can_ring_entry(), and ring_entry().
03109 { 03110 ao2_lock(mem); 03111 mem->call_pending = 0; 03112 ao2_unlock(mem); 03113 }
| static int member_call_pending_set | ( | struct member * | mem | ) | [static] |
Definition at line 3123 of file app_queue.c.
References ao2_lock, ao2_unlock, and member::call_pending.
Referenced by can_ring_entry().
03124 { 03125 int old_pending; 03126 03127 ao2_lock(mem); 03128 old_pending = mem->call_pending; 03129 mem->call_pending = 1; 03130 ao2_unlock(mem); 03131 03132 return old_pending; 03133 }
| static int member_cmp_fn | ( | void * | obj1, | |
| void * | obj2, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1707 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 1695 of file app_queue.c.
References compress_char(), and member::interface.
Referenced by init_queue().
01696 { 01697 const struct member *mem = obj; 01698 const char *chname = strchr(mem->interface, '/'); 01699 int ret = 0, i; 01700 if (!chname) 01701 chname = mem->interface; 01702 for (i = 0; i < 5 && chname[i]; i++) 01703 ret += compress_char(chname[i]) << (i * 6); 01704 return ret; 01705 }
| static void member_remove_from_queue | ( | struct call_queue * | queue, | |
| struct member * | mem | |||
| ) | [static] |
Definition at line 2161 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().
02162 { 02163 ao2_lock(queue->members); 02164 queue_member_follower_removal(queue, mem); 02165 ao2_unlink(queue->members, mem); 02166 ao2_unlock(queue->members); 02167 }
| static int member_status_available | ( | int | status | ) | [static] |
Definition at line 3095 of file app_queue.c.
References AST_DEVICE_NOT_INUSE, and AST_DEVICE_UNKNOWN.
Referenced by can_ring_entry(), and manager_queues_summary().
03096 { 03097 return status == AST_DEVICE_NOT_INUSE || status == AST_DEVICE_UNKNOWN; 03098 }
| 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 2964 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().
02965 { 02966 struct member *mem; 02967 int avl = 0; 02968 struct ao2_iterator mem_iter; 02969 02970 mem_iter = ao2_iterator_init(q->members, 0); 02971 while ((mem = ao2_iterator_next(&mem_iter))) { 02972 switch (mem->status) { 02973 case AST_DEVICE_INUSE: 02974 if (!q->ringinuse) 02975 break; 02976 /* else fall through */ 02977 case AST_DEVICE_NOT_INUSE: 02978 case AST_DEVICE_UNKNOWN: 02979 if (!mem->paused) { 02980 avl++; 02981 } 02982 break; 02983 } 02984 ao2_ref(mem, -1); 02985 02986 /* If autofill is not enabled or if the queue's strategy is ringall, then 02987 * we really don't care about the number of available members so much as we 02988 * do that there is at least one available. 02989 * 02990 * In fact, we purposely will return from this function stating that only 02991 * one member is available if either of those conditions hold. That way, 02992 * functions which determine what action to take based on the number of available 02993 * members will operate properly. The reasoning is that even if multiple 02994 * members are available, only the head caller can actually be serviced. 02995 */ 02996 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) { 02997 break; 02998 } 02999 } 03000 ao2_iterator_destroy(&mem_iter); 03001 03002 return avl; 03003 }
| static void parse_empty_options | ( | const char * | value, | |
| enum empty_conditions * | empty, | |||
| int | joinempty | |||
| ) | [static] |
Definition at line 1901 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().
01902 { 01903 char *value_copy = ast_strdupa(value); 01904 char *option = NULL; 01905 while ((option = strsep(&value_copy, ","))) { 01906 if (!strcasecmp(option, "paused")) { 01907 *empty |= QUEUE_EMPTY_PAUSED; 01908 } else if (!strcasecmp(option, "penalty")) { 01909 *empty |= QUEUE_EMPTY_PENALTY; 01910 } else if (!strcasecmp(option, "inuse")) { 01911 *empty |= QUEUE_EMPTY_INUSE; 01912 } else if (!strcasecmp(option, "ringing")) { 01913 *empty |= QUEUE_EMPTY_RINGING; 01914 } else if (!strcasecmp(option, "invalid")) { 01915 *empty |= QUEUE_EMPTY_INVALID; 01916 } else if (!strcasecmp(option, "wrapup")) { 01917 *empty |= QUEUE_EMPTY_WRAPUP; 01918 } else if (!strcasecmp(option, "unavailable")) { 01919 *empty |= QUEUE_EMPTY_UNAVAILABLE; 01920 } else if (!strcasecmp(option, "unknown")) { 01921 *empty |= QUEUE_EMPTY_UNKNOWN; 01922 } else if (!strcasecmp(option, "loose")) { 01923 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID); 01924 } else if (!strcasecmp(option, "strict")) { 01925 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE); 01926 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) { 01927 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED); 01928 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) { 01929 *empty = 0; 01930 } else { 01931 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty"); 01932 } 01933 } 01934 }
| static int play_file | ( | struct ast_channel * | chan, | |
| const char * | filename | |||
| ) | [static] |
Definition at line 2634 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().
02635 { 02636 int res; 02637 02638 if (ast_strlen_zero(filename)) { 02639 return 0; 02640 } 02641 02642 if (!ast_fileexists(filename, NULL, chan->language)) { 02643 return 0; 02644 } 02645 02646 ast_stopstream(chan); 02647 02648 res = ast_streamfile(chan, filename, chan->language); 02649 if (!res) 02650 res = ast_waitstream(chan, AST_DIGIT_ANY); 02651 02652 ast_stopstream(chan); 02653 02654 return res; 02655 }
| static int pqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
PauseQueueMember application.
Definition at line 5859 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().
05860 { 05861 char *parse; 05862 AST_DECLARE_APP_ARGS(args, 05863 AST_APP_ARG(queuename); 05864 AST_APP_ARG(interface); 05865 AST_APP_ARG(options); 05866 AST_APP_ARG(reason); 05867 ); 05868 05869 if (ast_strlen_zero(data)) { 05870 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n"); 05871 return -1; 05872 } 05873 05874 parse = ast_strdupa(data); 05875 05876 AST_STANDARD_APP_ARGS(args, parse); 05877 05878 if (ast_strlen_zero(args.interface)) { 05879 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 05880 return -1; 05881 } 05882 05883 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) { 05884 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 05885 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 05886 return 0; 05887 } 05888 05889 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 05890 05891 return 0; 05892 }
| static int ql_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
QueueLog application.
Definition at line 6050 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().
06051 { 06052 char *parse; 06053 06054 AST_DECLARE_APP_ARGS(args, 06055 AST_APP_ARG(queuename); 06056 AST_APP_ARG(uniqueid); 06057 AST_APP_ARG(membername); 06058 AST_APP_ARG(event); 06059 AST_APP_ARG(params); 06060 ); 06061 06062 if (ast_strlen_zero(data)) { 06063 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n"); 06064 return -1; 06065 } 06066 06067 parse = ast_strdupa(data); 06068 06069 AST_STANDARD_APP_ARGS(args, parse); 06070 06071 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 06072 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 06073 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n"); 06074 return -1; 06075 } 06076 06077 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 06078 "%s", args.params ? args.params : ""); 06079 06080 return 0; 06081 }
| static int queue_cmp_cb | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1260 of file app_queue.c.
References CMP_MATCH, and CMP_STOP.
Referenced by load_module().
01261 { 01262 struct call_queue *q = obj, *q2 = arg; 01263 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0; 01264 }
| static int queue_delme_members_decrement_followers | ( | void * | obj, | |
| void * | arg, | |||
| int | flag | |||
| ) | [static] |
Definition at line 1289 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().
01290 { 01291 struct member *mem = obj; 01292 struct call_queue *queue = arg; 01293 int rrpos = mem->queuepos; 01294 01295 if (mem->delme) { 01296 ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &rrpos); 01297 } 01298 01299 return 0; 01300 }
| 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 6124 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().
06125 { 06126 int res=-1; 06127 int ringing=0; 06128 const char *user_priority; 06129 const char *max_penalty_str; 06130 const char *min_penalty_str; 06131 int prio; 06132 int qcontinue = 0; 06133 int max_penalty, min_penalty; 06134 enum queue_result reason = QUEUE_UNKNOWN; 06135 /* whether to exit Queue application after the timeout hits */ 06136 int tries = 0; 06137 int noption = 0; 06138 char *parse; 06139 int makeannouncement = 0; 06140 int position = 0; 06141 AST_DECLARE_APP_ARGS(args, 06142 AST_APP_ARG(queuename); 06143 AST_APP_ARG(options); 06144 AST_APP_ARG(url); 06145 AST_APP_ARG(announceoverride); 06146 AST_APP_ARG(queuetimeoutstr); 06147 AST_APP_ARG(agi); 06148 AST_APP_ARG(macro); 06149 AST_APP_ARG(gosub); 06150 AST_APP_ARG(rule); 06151 AST_APP_ARG(position); 06152 ); 06153 /* Our queue entry */ 06154 struct queue_ent qe = { 0 }; 06155 06156 if (ast_strlen_zero(data)) { 06157 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n"); 06158 return -1; 06159 } 06160 06161 parse = ast_strdupa(data); 06162 AST_STANDARD_APP_ARGS(args, parse); 06163 06164 /* Setup our queue entry */ 06165 qe.start = time(NULL); 06166 06167 /* set the expire time based on the supplied timeout; */ 06168 if (!ast_strlen_zero(args.queuetimeoutstr)) 06169 qe.expire = qe.start + atoi(args.queuetimeoutstr); 06170 else 06171 qe.expire = 0; 06172 06173 /* Get the priority from the variable ${QUEUE_PRIO} */ 06174 ast_channel_lock(chan); 06175 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 06176 if (user_priority) { 06177 if (sscanf(user_priority, "%30d", &prio) == 1) { 06178 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio); 06179 } else { 06180 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 06181 user_priority, chan->name); 06182 prio = 0; 06183 } 06184 } else { 06185 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n"); 06186 prio = 0; 06187 } 06188 06189 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 06190 06191 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 06192 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) { 06193 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty); 06194 } else { 06195 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 06196 max_penalty_str, chan->name); 06197 max_penalty = INT_MAX; 06198 } 06199 } else { 06200 max_penalty = INT_MAX; 06201 } 06202 06203 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) { 06204 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) { 06205 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty); 06206 } else { 06207 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n", 06208 min_penalty_str, chan->name); 06209 min_penalty = INT_MAX; 06210 } 06211 } else { 06212 min_penalty = INT_MAX; 06213 } 06214 ast_channel_unlock(chan); 06215 06216 if (args.options && (strchr(args.options, 'r'))) 06217 ringing = 1; 06218 06219 if (ringing != 1 && args.options && (strchr(args.options, 'R'))) { 06220 qe.ring_when_ringing = 1; 06221 } 06222 06223 if (args.options && (strchr(args.options, 'c'))) 06224 qcontinue = 1; 06225 06226 if (args.position) { 06227 position = atoi(args.position); 06228 if (position < 0) { 06229 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename); 06230 position = 0; 06231 } 06232 } 06233 06234 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 06235 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 06236 06237 qe.chan = chan; 06238 qe.prio = prio; 06239 qe.max_penalty = max_penalty; 06240 qe.min_penalty = min_penalty; 06241 qe.last_pos_said = 0; 06242 qe.last_pos = 0; 06243 qe.last_periodic_announce_time = time(NULL); 06244 qe.last_periodic_announce_sound = 0; 06245 qe.valid_digits = 0; 06246 if (join_queue(args.queuename, &qe, &reason, position)) { 06247 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 06248 set_queue_result(chan, reason); 06249 return 0; 06250 } 06251 ast_assert(qe.parent != NULL); 06252 06253 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d", 06254 S_OR(args.url, ""), 06255 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""), 06256 qe.opos); 06257 copy_rules(&qe, args.rule); 06258 qe.pr = AST_LIST_FIRST(&qe.qe_rules); 06259 check_turns: 06260 if (ringing) { 06261 ast_indicate(chan, AST_CONTROL_RINGING); 06262 } else { 06263 ast_moh_start(chan, qe.moh, NULL); 06264 } 06265 06266 /* This is the wait loop for callers 2 through maxlen */ 06267 res = wait_our_turn(&qe, ringing, &reason); 06268 if (res) { 06269 goto stop; 06270 } 06271 06272 makeannouncement = 0; 06273 06274 for (;;) { 06275 /* This is the wait loop for the head caller*/ 06276 /* To exit, they may get their call answered; */ 06277 /* they may dial a digit from the queue context; */ 06278 /* or, they may timeout. */ 06279 06280 /* Leave if we have exceeded our queuetimeout */ 06281 if (qe.expire && (time(NULL) >= qe.expire)) { 06282 record_abandoned(&qe); 06283 reason = QUEUE_TIMEOUT; 06284 res = 0; 06285 ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 06286 qe.pos, qe.opos, (long) time(NULL) - qe.start); 06287 break; 06288 } 06289 06290 if (makeannouncement) { 06291 /* Make a position announcement, if enabled */ 06292 if (qe.parent->announcefrequency) 06293 if ((res = say_position(&qe,ringing))) 06294 goto stop; 06295 } 06296 makeannouncement = 1; 06297 06298 /* Make a periodic announcement, if enabled */ 06299 if (qe.parent->periodicannouncefrequency) 06300 if ((res = say_periodic_announcement(&qe,ringing))) 06301 goto stop; 06302 06303 /* Leave if we have exceeded our queuetimeout */ 06304 if (qe.expire && (time(NULL) >= qe.expire)) { 06305 record_abandoned(&qe); 06306 reason = QUEUE_TIMEOUT; 06307 res = 0; 06308 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 06309 break; 06310 } 06311 06312 /* see if we need to move to the next penalty level for this queue */ 06313 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) { 06314 update_qe_rule(&qe); 06315 } 06316 06317 /* Try calling all queue members for 'timeout' seconds */ 06318 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing); 06319 if (res) { 06320 goto stop; 06321 } 06322 06323 if (qe.parent->leavewhenempty) { 06324 int status = 0; 06325 if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty))) { 06326 record_abandoned(&qe); 06327 reason = QUEUE_LEAVEEMPTY; 06328 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 06329 res = 0; 06330 break; 06331 } 06332 } 06333 06334 /* exit after 'timeout' cycle if 'n' option enabled */ 06335 if (noption && tries >= ao2_container_count(qe.parent->members)) { 06336 ast_verb(3, "Exiting on time-out cycle\n"); 06337 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 06338 record_abandoned(&qe); 06339 reason = QUEUE_TIMEOUT; 06340 res = 0; 06341 break; 06342 } 06343 06344 06345 /* Leave if we have exceeded our queuetimeout */ 06346 if (qe.expire && (time(NULL) >= qe.expire)) { 06347 record_abandoned(&qe); 06348 reason = QUEUE_TIMEOUT; 06349 res = 0; 06350 ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start); 06351 break; 06352 } 06353 06354 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 06355 update_realtime_members(qe.parent); 06356 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 06357 res = wait_a_bit(&qe); 06358 if (res) 06359 goto stop; 06360 06361 /* Since this is a priority queue and 06362 * it is not sure that we are still at the head 06363 * of the queue, go and check for our turn again. 06364 */ 06365 if (!is_our_turn(&qe)) { 06366 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name); 06367 goto check_turns; 06368 } 06369 } 06370 06371 stop: 06372 if (res) { 06373 if (res < 0) { 06374 if (!qe.handled) { 06375 record_abandoned(&qe); 06376 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 06377 "%d|%d|%ld", qe.pos, qe.opos, 06378 (long) time(NULL) - qe.start); 06379 res = -1; 06380 } else if (qcontinue) { 06381 reason = QUEUE_CONTINUE; 06382 res = 0; 06383 } 06384 } else if (qe.valid_digits) { 06385 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 06386 "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) time(NULL) - qe.start); 06387 } 06388 } 06389 06390 /* Don't allow return code > 0 */ 06391 if (res >= 0) { 06392 res = 0; 06393 if (ringing) { 06394 ast_indicate(chan, -1); 06395 } else { 06396 ast_moh_stop(chan); 06397 } 06398 ast_stopstream(chan); 06399 } 06400 06401 set_queue_variables(qe.parent, qe.chan); 06402 06403 leave_queue(&qe); 06404 if (reason != QUEUE_UNKNOWN) 06405 set_queue_result(chan, reason); 06406 06407 /* 06408 * every queue_ent is given a reference to it's parent 06409 * call_queue when it joins the queue. This ref must be taken 06410 * away right before the queue_ent is destroyed. In this case 06411 * the queue_ent is about to be returned on the stack 06412 */ 06413 qe.parent = queue_unref(qe.parent); 06414 06415 return res; 06416 }
| 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 6470 of file app_queue.c.
References ast_log(), ast_strlen_zero(), load_realtime_queue(), LOG_ERROR, and queue_t_unref.
06471 { 06472 struct call_queue *q; 06473 06474 buf[0] = '\0'; 06475 06476 if (ast_strlen_zero(data)) { 06477 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06478 return -1; 06479 } 06480 q = load_realtime_queue(data); 06481 snprintf(buf, len, "%d", q != NULL? 1 : 0); 06482 if (q) { 06483 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()"); 06484 } 06485 06486 return 0; 06487 }
| 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 6689 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.
06690 { 06691 int penalty; 06692 AST_DECLARE_APP_ARGS(args, 06693 AST_APP_ARG(queuename); 06694 AST_APP_ARG(interface); 06695 ); 06696 /* Make sure the returned value on error is NULL. */ 06697 buf[0] = '\0'; 06698 06699 if (ast_strlen_zero(data)) { 06700 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06701 return -1; 06702 } 06703 06704 AST_STANDARD_APP_ARGS(args, data); 06705 06706 if (args.argc < 2) { 06707 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06708 return -1; 06709 } 06710 06711 penalty = get_member_penalty (args.queuename, args.interface); 06712 06713 if (penalty >= 0) /* remember that buf is already '\0' */ 06714 snprintf (buf, len, "%d", penalty); 06715 06716 return 0; 06717 }
| 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 6720 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().
06721 { 06722 int penalty; 06723 AST_DECLARE_APP_ARGS(args, 06724 AST_APP_ARG(queuename); 06725 AST_APP_ARG(interface); 06726 ); 06727 06728 if (ast_strlen_zero(data)) { 06729 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06730 return -1; 06731 } 06732 06733 AST_STANDARD_APP_ARGS(args, data); 06734 06735 if (args.argc < 2) { 06736 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06737 return -1; 06738 } 06739 06740 penalty = atoi(value); 06741 06742 if (ast_strlen_zero(args.interface)) { 06743 ast_log (LOG_ERROR, "<interface> parameter can't be null\n"); 06744 return -1; 06745 } 06746 06747 /* if queuename = NULL then penalty will be set for interface in all the queues. */ 06748 if (set_member_penalty(args.queuename, args.interface, penalty)) { 06749 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); 06750 return -1; 06751 } 06752 06753 return 0; 06754 }
| 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 6494 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.
06495 { 06496 int count = 0; 06497 struct member *m; 06498 struct ao2_iterator mem_iter; 06499 struct call_queue *q; 06500 char *option; 06501 06502 if (ast_strlen_zero(data)) { 06503 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06504 return -1; 06505 } 06506 06507 if ((option = strchr(data, ','))) 06508 *option++ = '\0'; 06509 else 06510 option = "logged"; 06511 if ((q = load_realtime_queue(data))) { 06512 ao2_lock(q); 06513 if (!strcasecmp(option, "logged")) { 06514 mem_iter = ao2_iterator_init(q->members, 0); 06515 while ((m = ao2_iterator_next(&mem_iter))) { 06516 /* Count the agents who are logged in and presently answering calls */ 06517 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 06518 count++; 06519 } 06520 ao2_ref(m, -1); 06521 } 06522 ao2_iterator_destroy(&mem_iter); 06523 } else if (!strcasecmp(option, "free")) { 06524 mem_iter = ao2_iterator_init(q->members, 0); 06525 while ((m = ao2_iterator_next(&mem_iter))) { 06526 /* Count the agents who are logged in and presently answering calls */ 06527 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) { 06528 count++; 06529 } 06530 ao2_ref(m, -1); 06531 } 06532 ao2_iterator_destroy(&mem_iter); 06533 } else if (!strcasecmp(option, "ready")) { 06534 time_t now; 06535 time(&now); 06536 mem_iter = ao2_iterator_init(q->members, 0); 06537 while ((m = ao2_iterator_next(&mem_iter))) { 06538 /* Count the agents who are logged in, not paused and not wrapping up */ 06539 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) && 06540 !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) { 06541 count++; 06542 } 06543 ao2_ref(m, -1); 06544 } 06545 ao2_iterator_destroy(&mem_iter); 06546 } else /* must be "count" */ 06547 count = ao2_container_count(q->members); 06548 ao2_unlock(q); 06549 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()"); 06550 } else 06551 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06552 06553 snprintf(buf, len, "%d", count); 06554 06555 return 0; 06556 }
| 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 6563 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.
06564 { 06565 int count = 0; 06566 struct member *m; 06567 struct call_queue *q; 06568 struct ao2_iterator mem_iter; 06569 static int depflag = 1; 06570 06571 if (depflag) { 06572 depflag = 0; 06573 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"); 06574 } 06575 06576 if (ast_strlen_zero(data)) { 06577 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06578 return -1; 06579 } 06580 06581 if ((q = load_realtime_queue(data))) { 06582 ao2_lock(q); 06583 mem_iter = ao2_iterator_init(q->members, 0); 06584 while ((m = ao2_iterator_next(&mem_iter))) { 06585 /* Count the agents who are logged in and presently answering calls */ 06586 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 06587 count++; 06588 } 06589 ao2_ref(m, -1); 06590 } 06591 ao2_iterator_destroy(&mem_iter); 06592 ao2_unlock(q); 06593 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT"); 06594 } else 06595 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06596 06597 snprintf(buf, len, "%d", count); 06598 06599 return 0; 06600 }
| 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 6639 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.
06640 { 06641 struct call_queue *q, tmpq = { 06642 .name = data, 06643 }; 06644 struct member *m; 06645 06646 /* Ensure an otherwise empty list doesn't return garbage */ 06647 buf[0] = '\0'; 06648 06649 if (ast_strlen_zero(data)) { 06650 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 06651 return -1; 06652 } 06653 06654 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) { 06655 int buflen = 0, count = 0; 06656 struct ao2_iterator mem_iter; 06657 06658 ao2_lock(q); 06659 mem_iter = ao2_iterator_init(q->members, 0); 06660 while ((m = ao2_iterator_next(&mem_iter))) { 06661 /* strcat() is always faster than printf() */ 06662 if (count++) { 06663 strncat(buf + buflen, ",", len - buflen - 1); 06664 buflen++; 06665 } 06666 strncat(buf + buflen, m->interface, len - buflen - 1); 06667 buflen += strlen(m->interface); 06668 /* Safeguard against overflow (negative length) */ 06669 if (buflen >= len - 2) { 06670 ao2_ref(m, -1); 06671 ast_log(LOG_WARNING, "Truncating list\n"); 06672 break; 06673 } 06674 ao2_ref(m, -1); 06675 } 06676 ao2_iterator_destroy(&mem_iter); 06677 ao2_unlock(q); 06678 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()"); 06679 } else 06680 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06681 06682 /* We should already be terminated, but let's make sure. */ 06683 buf[len - 1] = '\0'; 06684 06685 return 0; 06686 }
| 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 6603 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.
06604 { 06605 int count = 0; 06606 struct call_queue *q, tmpq = { 06607 .name = data, 06608 }; 06609 struct ast_variable *var = NULL; 06610 06611 buf[0] = '\0'; 06612 06613 if (ast_strlen_zero(data)) { 06614 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n"); 06615 return -1; 06616 } 06617 06618 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) { 06619 ao2_lock(q); 06620 count = q->count; 06621 ao2_unlock(q); 06622 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()"); 06623 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) { 06624 /* if the queue is realtime but was not found in memory, this 06625 * means that the queue had been deleted from memory since it was 06626 * "dead." This means it has a 0 waiting count 06627 */ 06628 count = 0; 06629 ast_variables_destroy(var); 06630 } else 06631 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06632 06633 snprintf(buf, len, "%d", count); 06634 06635 return 0; 06636 }
| 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 6423 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.
06424 { 06425 int res = -1; 06426 struct call_queue *q, tmpq = { 06427 .name = data, 06428 }; 06429 06430 char interfacevar[256] = ""; 06431 float sl = 0; 06432 06433 if (ast_strlen_zero(data)) { 06434 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06435 return -1; 06436 } 06437 06438 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) { 06439 ao2_lock(q); 06440 if (q->setqueuevar) { 06441 sl = 0; 06442 res = 0; 06443 06444 if (q->callscompleted > 0) { 06445 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 06446 } 06447 06448 snprintf(interfacevar, sizeof(interfacevar), 06449 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 06450 q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 06451 06452 pbx_builtin_setvar_multiple(chan, interfacevar); 06453 } 06454 06455 ao2_unlock(q); 06456 queue_t_unref(q, "Done with QUEUE() function"); 06457 } else { 06458 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06459 } 06460 06461 snprintf(buf, len, "%d", res); 06462 06463 return 0; 06464 }
| static int queue_hash_cb | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 1253 of file app_queue.c.
References ast_str_case_hash().
Referenced by load_module().
01254 { 01255 const struct call_queue *q = obj; 01256 01257 return ast_str_case_hash(q->name); 01258 }
| static int queue_member_decrement_followers | ( | void * | obj, | |
| void * | arg, | |||
| int | flag | |||
| ) | [static] |
Definition at line 1271 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 1307 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().
01308 { 01309 int pos = mem->queuepos; 01310 01311 /* 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 01312 * who would have been next otherwise. */ 01313 if (pos < queue->rrpos) { 01314 queue->rrpos--; 01315 } 01316 01317 ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &pos); 01318 }
| static struct call_queue* queue_ref | ( | struct call_queue * | q | ) | [static, read] |
Definition at line 1332 of file app_queue.c.
References ao2_ref.
Referenced by insert_entry().
01333 { 01334 ao2_ref(q, 1); 01335 return q; 01336 }
| 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 6847 of file app_queue.c.
References ast_true(), and ast_variable_retrieve().
Referenced by reload_queues().
06848 { 06849 const char *general_val = NULL; 06850 queue_persistent_members = 0; 06851 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 06852 queue_persistent_members = ast_true(general_val); 06853 autofill_default = 0; 06854 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 06855 autofill_default = ast_true(general_val); 06856 montype_default = 0; 06857 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) { 06858 if (!strcasecmp(general_val, "mixmonitor")) 06859 montype_default = 1; 06860 } 06861 update_cdr = 0; 06862 if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr"))) 06863 update_cdr = ast_true(general_val); 06864 shared_lastcall = 0; 06865 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) 06866 shared_lastcall = ast_true(general_val); 06867 }
| 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 1944 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().
01945 { 01946 if (!strcasecmp(param, "musicclass") || 01947 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 01948 ast_string_field_set(q, moh, val); 01949 } else if (!strcasecmp(param, "announce")) { 01950 ast_string_field_set(q, announce, val); 01951 } else if (!strcasecmp(param, "context")) { 01952 ast_string_field_set(q, context, val); 01953 } else if (!strcasecmp(param, "timeout")) { 01954 q->timeout = atoi(val); 01955 if (q->timeout < 0) 01956 q->timeout = DEFAULT_TIMEOUT; 01957 } else if (!strcasecmp(param, "ringinuse")) { 01958 q->ringinuse = ast_true(val); 01959 } else if (!strcasecmp(param, "setinterfacevar")) { 01960 q->setinterfacevar = ast_true(val); 01961 } else if (!strcasecmp(param, "setqueuevar")) { 01962 q->setqueuevar = ast_true(val); 01963 } else if (!strcasecmp(param, "setqueueentryvar")) { 01964 q->setqueueentryvar = ast_true(val); 01965 } else if (!strcasecmp(param, "monitor-format")) { 01966 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 01967 } else if (!strcasecmp(param, "membermacro")) { 01968 ast_string_field_set(q, membermacro, val); 01969 } else if (!strcasecmp(param, "membergosub")) { 01970 ast_string_field_set(q, membergosub, val); 01971 } else if (!strcasecmp(param, "queue-youarenext")) { 01972 ast_string_field_set(q, sound_next, val); 01973 } else if (!strcasecmp(param, "queue-thereare")) { 01974 ast_string_field_set(q, sound_thereare, val); 01975 } else if (!strcasecmp(param, "queue-callswaiting")) { 01976 ast_string_field_set(q, sound_calls, val); 01977 } else if (!strcasecmp(param, "queue-quantity1")) { 01978 ast_string_field_set(q, queue_quantity1, val); 01979 } else if (!strcasecmp(param, "queue-quantity2")) { 01980 ast_string_field_set(q, queue_quantity2, val); 01981 } else if (!strcasecmp(param, "queue-holdtime")) { 01982 ast_string_field_set(q, sound_holdtime, val); 01983 } else if (!strcasecmp(param, "queue-minutes")) { 01984 ast_string_field_set(q, sound_minutes, val); 01985 } else if (!strcasecmp(param, "queue-minute")) { 01986 ast_string_field_set(q, sound_minute, val); 01987 } else if (!strcasecmp(param, "queue-seconds")) { 01988 ast_string_field_set(q, sound_seconds, val); 01989 } else if (!strcasecmp(param, "queue-thankyou")) { 01990 ast_string_field_set(q, sound_thanks, val); 01991 } else if (!strcasecmp(param, "queue-callerannounce")) { 01992 ast_string_field_set(q, sound_callerannounce, val); 01993 } else if (!strcasecmp(param, "queue-reporthold")) { 01994 ast_string_field_set(q, sound_reporthold, val); 01995 } else if (!strcasecmp(param, "announce-frequency")) { 01996 q->announcefrequency = atoi(val); 01997 } else if (!strcasecmp(param, "announce-to-first-user")) { 01998 q->announce_to_first_user = ast_true(val); 01999 } else if (!strcasecmp(param, "min-announce-frequency")) { 02000 q->minannouncefrequency = atoi(val); 02001 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name); 02002 } else if (!strcasecmp(param, "announce-round-seconds")) { 02003 q->roundingseconds = atoi(val); 02004 /* Rounding to any other values just doesn't make sense... */ 02005 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10 02006 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) { 02007 if (linenum >= 0) { 02008 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 02009 "using 0 instead for queue '%s' at line %d of queues.conf\n", 02010 val, param, q->name, linenum); 02011 } else { 02012 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 02013 "using 0 instead for queue '%s'\n", val, param, q->name); 02014 } 02015 q->roundingseconds=0; 02016 } 02017 } else if (!strcasecmp(param, "announce-holdtime")) { 02018 if (!strcasecmp(val, "once")) 02019 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 02020 else if (ast_true(val)) 02021 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 02022 else 02023 q->announceholdtime = 0; 02024 } else if (!strcasecmp(param, "announce-position")) { 02025 if (!strcasecmp(val, "limit")) 02026 q->announceposition = ANNOUNCEPOSITION_LIMIT; 02027 else if (!strcasecmp(val, "more")) 02028 q->announceposition = ANNOUNCEPOSITION_MORE_THAN; 02029 else if (ast_true(val)) 02030 q->announceposition = ANNOUNCEPOSITION_YES; 02031 else 02032 q->announceposition = ANNOUNCEPOSITION_NO; 02033 } else if (!strcasecmp(param, "announce-position-limit")) { 02034 q->announcepositionlimit = atoi(val); 02035 } else if (!strcasecmp(param, "periodic-announce")) { 02036 if (strchr(val, ',')) { 02037 char *s, *buf = ast_strdupa(val); 02038 unsigned int i = 0; 02039 02040 while ((s = strsep(&buf, ",|"))) { 02041 if (!q->sound_periodicannounce[i]) 02042 q->sound_periodicannounce[i] = ast_str_create(16); 02043 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s); 02044 i++; 02045 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 02046 break; 02047 } 02048 q->numperiodicannounce = i; 02049 } else { 02050 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val); 02051 q->numperiodicannounce = 1; 02052 } 02053 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 02054 q->periodicannouncefrequency = atoi(val); 02055 } else if (!strcasecmp(param, "relative-periodic-announce")) { 02056 q->relativeperiodicannounce = ast_true(val); 02057 } else if (!strcasecmp(param, "random-periodic-announce")) { 02058 q->randomperiodicannounce = ast_true(val); 02059 } else if (!strcasecmp(param, "retry")) { 02060 q->retry = atoi(val); 02061 if (q->retry <= 0) 02062 q->retry = DEFAULT_RETRY; 02063 } else if (!strcasecmp(param, "wrapuptime")) { 02064 q->wrapuptime = atoi(val); 02065 } else if (!strcasecmp(param, "penaltymemberslimit")) { 02066 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) { 02067 q->penaltymemberslimit = 0; 02068 } 02069 } else if (!strcasecmp(param, "autofill")) { 02070 q->autofill = ast_true(val); 02071 } else if (!strcasecmp(param, "monitor-type")) { 02072 if (!strcasecmp(val, "mixmonitor")) 02073 q->montype = 1; 02074 } else if (!strcasecmp(param, "autopause")) { 02075 q->autopause = autopause2int(val); 02076 } else if (!strcasecmp(param, "maxlen")) { 02077 q->maxlen = atoi(val); 02078 if (q->maxlen < 0) 02079 q->maxlen = 0; 02080 } else if (!strcasecmp(param, "servicelevel")) { 02081 q->servicelevel= atoi(val); 02082 } else if (!strcasecmp(param, "strategy")) { 02083 int strategy; 02084 02085 /* We are a static queue and already have set this, no need to do it again */ 02086 if (failunknown) { 02087 return; 02088 } 02089 strategy = strat2int(val); 02090 if (strategy < 0) { 02091 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 02092 val, q->name); 02093 q->strategy = QUEUE_STRATEGY_RINGALL; 02094 } 02095 if (strategy == q->strategy) { 02096 return; 02097 } 02098 if (strategy == QUEUE_STRATEGY_LINEAR) { 02099 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n"); 02100 return; 02101 } 02102 q->strategy = strategy; 02103 } else if (!strcasecmp(param, "joinempty")) { 02104 parse_empty_options(val, &q->joinempty, 1); 02105 } else if (!strcasecmp(param, "leavewhenempty")) { 02106 parse_empty_options(val, &q->leavewhenempty, 0); 02107 } else if (!strcasecmp(param, "eventmemberstatus")) { 02108 q->maskmemberstatus = !ast_true(val); 02109 } else if (!strcasecmp(param, "eventwhencalled")) { 02110 if (!strcasecmp(val, "vars")) { 02111 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 02112 } else { 02113 q->eventwhencalled = ast_true(val) ? 1 : 0; 02114 } 02115 } else if (!strcasecmp(param, "reportholdtime")) { 02116 q->reportholdtime = ast_true(val); 02117 } else if (!strcasecmp(param, "memberdelay")) { 02118 q->memberdelay = atoi(val); 02119 } else if (!strcasecmp(param, "weight")) { 02120 q->weight = atoi(val); 02121 } else if (!strcasecmp(param, "timeoutrestart")) { 02122 q->timeoutrestart = ast_true(val); 02123 } else if (!strcasecmp(param, "defaultrule")) { 02124 ast_string_field_set(q, defaultrule, val); 02125 } else if (!strcasecmp(param, "timeoutpriority")) { 02126 if (!strcasecmp(val, "conf")) { 02127 q->timeoutpriority = TIMEOUT_PRIORITY_CONF; 02128 } else { 02129 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 02130 } 02131 } else if (failunknown) { 02132 if (linenum >= 0) { 02133 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 02134 q->name, param, linenum); 02135 } else { 02136 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 02137 } 02138 } 02139 }
| static char* queue_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7503 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.
07504 { 07505 switch ( cmd ) { 07506 case CLI_INIT: 07507 e->command = "queue show"; 07508 e->usage = 07509 "Usage: queue show\n" 07510 " Provides summary information on a specified queue.\n"; 07511 return NULL; 07512 case CLI_GENERATE: 07513 return complete_queue_show(a->line, a->word, a->pos, a->n); 07514 } 07515 07516 return __queues_show(NULL, a->fd, a->argc, a->argv); 07517 }
| static void queue_transfer_destroy | ( | void * | data | ) | [static] |
Definition at line 4481 of file app_queue.c.
References ast_free.
04482 { 04483 struct queue_transfer_ds *qtds = data; 04484 ast_free(qtds); 04485 }
| 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 4504 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().
04505 { 04506 struct queue_transfer_ds *qtds = data; 04507 struct queue_ent *qe = qtds->qe; 04508 struct member *member = qtds->member; 04509 time_t callstart = qtds->starttime; 04510 int callcompletedinsl = qtds->callcompletedinsl; 04511 struct ast_datastore *datastore; 04512 04513 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 04514 new_chan->exten, new_chan->context, (long) (callstart - qe->start), 04515 (long) (time(NULL) - callstart), qe->opos); 04516 04517 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart)); 04518 04519 /* No need to lock the channels because they are already locked in ast_do_masquerade */ 04520 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) { 04521 ast_channel_datastore_remove(old_chan, datastore); 04522 } else { 04523 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n"); 04524 } 04525 }
| static struct call_queue* queue_unref | ( | struct call_queue * | q | ) | [static, read] |
Definition at line 1338 of file app_queue.c.
References ao2_ref.
Referenced by queue_exec(), and queues_data_provider_get().
01339 { 01340 ao2_ref(q, -1); 01341 return NULL; 01342 }
| static int queues_data_provider_get | ( | const struct ast_data_search * | search, | |
| struct ast_data * | data_root | |||
| ) | [static] |
Definition at line 8672 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.
08674 { 08675 struct ao2_iterator i; 08676 struct call_queue *queue, *queue_realtime = NULL; 08677 struct ast_config *cfg; 08678 char *queuename; 08679 08680 /* load realtime queues. */ 08681 cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 08682 if (cfg) { 08683 for (queuename = ast_category_browse(cfg, NULL); 08684 !ast_strlen_zero(queuename); 08685 queuename = ast_category_browse(cfg, queuename)) { 08686 if ((queue = load_realtime_queue(queuename))) { 08687 queue_unref(queue); 08688 } 08689 } 08690 ast_config_destroy(cfg); 08691 } 08692 08693 /* static queues. */ 08694 i = ao2_iterator_init(queues, 0); 08695 while ((queue = ao2_iterator_next(&i))) { 08696 ao2_lock(queue); 08697 if (queue->realtime) { 08698 queue_realtime = load_realtime_queue(queue->name); 08699 if (!queue_realtime) { 08700 ao2_unlock(queue); 08701 queue_unref(queue); 08702 continue; 08703 } 08704 queue_unref(queue_realtime); 08705 } 08706 08707 queues_data_provider_get_helper(search, data_root, queue); 08708 ao2_unlock(queue); 08709 queue_unref(queue); 08710 } 08711 ao2_iterator_destroy(&i); 08712 08713 return 0; 08714 }
| 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 8566 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().
08568 { 08569 struct ao2_iterator im; 08570 struct member *member; 08571 struct queue_ent *qe; 08572 struct ast_data *data_queue, *data_members = NULL, *enum_node; 08573 struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel; 08574 08575 data_queue = ast_data_add_node(data_root, "queue"); 08576 if (!data_queue) { 08577 return; 08578 } 08579 08580 ast_data_add_structure(call_queue, data_queue, queue); 08581 08582 ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy)); 08583 ast_data_add_int(data_queue, "membercount", ao2_container_count(queue->members)); 08584 08585 /* announce position */ 08586 enum_node = ast_data_add_node(data_queue, "announceposition"); 08587 if (!enum_node) { 08588 return; 08589 } 08590 switch (queue->announceposition) { 08591 case ANNOUNCEPOSITION_LIMIT: 08592 ast_data_add_str(enum_node, "text", "limit"); 08593 break; 08594 case ANNOUNCEPOSITION_MORE_THAN: 08595 ast_data_add_str(enum_node, "text", "more"); 08596 break; 08597 case ANNOUNCEPOSITION_YES: 08598 ast_data_add_str(enum_node, "text", "yes"); 08599 break; 08600 case ANNOUNCEPOSITION_NO: 08601 ast_data_add_str(enum_node, "text", "no"); 08602 break; 08603 default: 08604 ast_data_add_str(enum_node, "text", "unknown"); 08605 break; 08606 } 08607 ast_data_add_int(enum_node, "value", queue->announceposition); 08608 08609 /* add queue members */ 08610 im = ao2_iterator_init(queue->members, 0); 08611 while ((member = ao2_iterator_next(&im))) { 08612 if (!data_members) { 08613 data_members = ast_data_add_node(data_queue, "members"); 08614 if (!data_members) { 08615 ao2_ref(member, -1); 08616 continue; 08617 } 08618 } 08619 08620 data_member = ast_data_add_node(data_members, "member"); 08621 if (!data_member) { 08622 ao2_ref(member, -1); 08623 continue; 08624 } 08625 08626 ast_data_add_structure(member, data_member, member); 08627 08628 ao2_ref(member, -1); 08629 } 08630 ao2_iterator_destroy(&im); 08631 08632 /* include the callers inside the result. */ 08633 if (queue->head) { 08634 for (qe = queue->head; qe; qe = qe->next) { 08635 if (!data_callers) { 08636 data_callers = ast_data_add_node(data_queue, "callers"); 08637 if (!data_callers) { 08638 continue; 08639 } 08640 } 08641 08642 data_caller = ast_data_add_node(data_callers, "caller"); 08643 if (!data_caller) { 08644 continue; 08645 } 08646 08647 ast_data_add_structure(queue_ent, data_caller, qe); 08648 08649 /* add the caller channel. */ 08650 data_caller_channel = ast_data_add_node(data_caller, "channel"); 08651 if (!data_caller_channel) { 08652 continue; 08653 } 08654 08655 ast_channel_data_add_structure(data_caller_channel, qe->chan, 1); 08656 } 08657 } 08658 08659 /* if this queue doesn't match remove the added queue. */ 08660 if (!ast_data_search_match(search, data_queue)) { 08661 ast_data_remove_node(data_root, data_queue); 08662 } 08663 }
| static void recalc_holdtime | ( | struct queue_ent * | qe, | |
| int | newholdtime | |||
| ) | [static] |
Definition at line 2840 of file app_queue.c.
References ao2_lock, ao2_unlock, call_queue::holdtime, and queue_ent::parent.
Referenced by try_calling().
02841 { 02842 int oldvalue; 02843 02844 /* Calculate holdtime using an exponential average */ 02845 /* Thanks to SRT for this contribution */ 02846 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 02847 02848 ao2_lock(qe->parent); 02849 oldvalue = qe->parent->holdtime; 02850 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 02851 ao2_unlock(qe->parent); 02852 }
| static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Record that a caller gave up on waiting in queue.
Definition at line 3531 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().
03532 { 03533 set_queue_variables(qe->parent, qe->chan); 03534 ao2_lock(qe->parent); 03535 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 03536 "Queue: %s\r\n" 03537 "Uniqueid: %s\r\n" 03538 "Position: %d\r\n" 03539 "OriginalPosition: %d\r\n" 03540 "HoldTime: %d\r\n", 03541 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 03542 03543 qe->parent->callsabandoned++; 03544 ao2_unlock(qe->parent); 03545 }
| static int reload | ( | void | ) | [static] |
Definition at line 8848 of file app_queue.c.
References AST_FLAGS_ALL, ast_unload_realtime(), QUEUE_RESET_STATS, and reload_handler().
08849 { 08850 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,}; 08851 ast_unload_realtime("queue_members"); 08852 reload_handler(1, &mask, NULL); 08853 return 0; 08854 }
| 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 7223 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().
07224 { 07225 int res = 0; 07226 07227 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) { 07228 res |= reload_queue_rules(reload); 07229 } 07230 if (ast_test_flag(mask, QUEUE_RESET_STATS)) { 07231 res |= clear_stats(queuename); 07232 } 07233 if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) { 07234 res |= reload_queues(reload, mask, queuename); 07235 } 07236 return res; 07237 }
| static void reload_queue_members | ( | void | ) | [static] |
Reload dynamic queue members persisted into the astdb.
Definition at line 5764 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().
05765 { 05766 char *cur_ptr; 05767 const char *queue_name; 05768 char *member; 05769 char *interface; 05770 char *membername = NULL; 05771 char *state_interface; 05772 char *penalty_tok; 05773 int penalty = 0; 05774 char *paused_tok; 05775 int paused = 0; 05776 struct ast_db_entry *db_tree; 05777 struct ast_db_entry *entry; 05778 struct call_queue *cur_queue; 05779 char *queue_data; 05780 05781 /* Each key in 'pm_family' is the name of a queue */ 05782 db_tree = ast_db_gettree(pm_family, NULL); 05783 for (entry = db_tree; entry; entry = entry->next) { 05784 05785 queue_name = entry->key + strlen(pm_family) + 2; 05786 05787 { 05788 struct call_queue tmpq = { 05789 .name = queue_name, 05790 }; 05791 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members"); 05792 } 05793 05794 if (!cur_queue) 05795 cur_queue = load_realtime_queue(queue_name); 05796 05797 if (!cur_queue) { 05798 /* If the queue no longer exists, remove it from the 05799 * database */ 05800 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 05801 ast_db_del(pm_family, queue_name); 05802 continue; 05803 } 05804 05805 if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) { 05806 queue_t_unref(cur_queue, "Expire reload reference"); 05807 continue; 05808 } 05809 05810 cur_ptr = queue_data; 05811 while ((member = strsep(&cur_ptr, ",|"))) { 05812 if (ast_strlen_zero(member)) 05813 continue; 05814 05815 interface = strsep(&member, ";"); 05816 penalty_tok = strsep(&member, ";"); 05817 paused_tok = strsep(&member, ";"); 05818 membername = strsep(&member, ";"); 05819 state_interface = strsep(&member, ";"); 05820 05821 if (!penalty_tok) { 05822 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 05823 break; 05824 } 05825 penalty = strtol(penalty_tok, NULL, 10); 05826 if (errno == ERANGE) { 05827 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 05828 break; 05829 } 05830 05831 if (!paused_tok) { 05832 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 05833 break; 05834 } 05835 paused = strtol(paused_tok, NULL, 10); 05836 if ((errno == ERANGE) || paused < 0 || paused > 1) { 05837 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 05838 break; 05839 } 05840 05841 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 05842 05843 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { 05844 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 05845 break; 05846 } 05847 } 05848 queue_t_unref(cur_queue, "Expire reload reference"); 05849 ast_free(queue_data); 05850 } 05851 05852 if (db_tree) { 05853 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 05854 ast_db_freetree(db_tree); 05855 } 05856 }
| 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 6798 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().
06799 { 06800 struct ast_config *cfg; 06801 struct rule_list *rl_iter, *new_rl; 06802 struct penalty_rule *pr_iter; 06803 char *rulecat = NULL; 06804 struct ast_variable *rulevar = NULL; 06805 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06806 06807 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) { 06808 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n"); 06809 return AST_MODULE_LOAD_SUCCESS; 06810 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06811 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n"); 06812 return AST_MODULE_LOAD_SUCCESS; 06813 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 06814 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n"); 06815 return AST_MODULE_LOAD_SUCCESS; 06816 } 06817 06818 AST_LIST_LOCK(&rule_lists); 06819 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) { 06820 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list))) 06821 ast_free(pr_iter); 06822 ast_free(rl_iter); 06823 } 06824 while ((rulecat = ast_category_browse(cfg, rulecat))) { 06825 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) { 06826 AST_LIST_UNLOCK(&rule_lists); 06827 ast_config_destroy(cfg); 06828 return AST_MODULE_LOAD_FAILURE; 06829 } else { 06830 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name)); 06831 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list); 06832 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next) 06833 if(!strcasecmp(rulevar->name, "penaltychange")) 06834 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno); 06835 else 06836 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno); 06837 } 06838 } 06839 AST_LIST_UNLOCK(&rule_lists); 06840 06841 ast_config_destroy(cfg); 06842 06843 return AST_MODULE_LOAD_SUCCESS; 06844 }
| 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 7128 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().
07129 { 07130 struct ast_config *cfg; 07131 char *cat; 07132 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 07133 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); 07134 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER); 07135 07136 if (!(cfg = ast_config_load("queues.conf", config_flags))) { 07137 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 07138 return -1; 07139 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 07140 return 0; 07141 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 07142 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n"); 07143 return -1; 07144 } 07145 07146 /* We've made it here, so it looks like we're doing operations on all queues. */ 07147 ao2_lock(queues); 07148 07149 /* Mark all queues as dead for the moment if we're reloading queues. 07150 * For clarity, we could just be reloading members, in which case we don't want to mess 07151 * with the other queue parameters at all*/ 07152 if (queue_reload) { 07153 ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename); 07154 } 07155 07156 if (member_reload) { 07157 ao2_callback(queues, OBJ_NODATA, remove_members_and_mark_unfound, (char *) queuename); 07158 } 07159 07160 /* Chug through config file */ 07161 cat = NULL; 07162 while ((cat = ast_category_browse(cfg, cat)) ) { 07163 if (!strcasecmp(cat, "general") && queue_reload) { 07164 queue_set_global_params(cfg); 07165 continue; 07166 } 07167 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename)) 07168 reload_single_queue(cfg, mask, cat); 07169 } 07170 07171 ast_config_destroy(cfg); 07172 /* Unref all the dead queues if we were reloading queues */ 07173 if (queue_reload) { 07174 ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename); 07175 } 07176 ao2_unlock(queues); 07177 return 0; 07178 }
| 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 6877 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().
06878 { 06879 char *membername, *interface, *state_interface, *tmp; 06880 char *parse; 06881 struct member *cur, *newm; 06882 struct member tmpmem; 06883 int penalty; 06884 AST_DECLARE_APP_ARGS(args, 06885 AST_APP_ARG(interface); 06886 AST_APP_ARG(penalty); 06887 AST_APP_ARG(membername); 06888 AST_APP_ARG(state_interface); 06889 ); 06890 06891 if (ast_strlen_zero(memberdata)) { 06892 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n"); 06893 return; 06894 } 06895 06896 /* Add a new member */ 06897 parse = ast_strdupa(memberdata); 06898 06899 AST_STANDARD_APP_ARGS(args, parse); 06900 06901 interface = args.interface; 06902 if (!ast_strlen_zero(args.penalty)) { 06903 tmp = args.penalty; 06904 ast_strip(tmp); 06905 penalty = atoi(tmp); 06906 if (penalty < 0) { 06907 penalty = 0; 06908 } 06909 } else { 06910 penalty = 0; 06911 } 06912 06913 if (!ast_strlen_zero(args.membername)) { 06914 membername = args.membername; 06915 ast_strip(membername); 06916 } else { 06917 membername = interface; 06918 } 06919 06920 if (!ast_strlen_zero(args.state_interface)) { 06921 state_interface = args.state_interface; 06922 ast_strip(state_interface); 06923 } else { 06924 state_interface = interface; 06925 } 06926 06927 /* Find the old position in the list */ 06928 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 06929 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER); 06930 06931 if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) { 06932 if (cur) { 06933 /* Round Robin Queue Position must be copied if this is replacing an existing member */ 06934 ao2_lock(q->members); 06935 newm->queuepos = cur->queuepos; 06936 ao2_link(q->members, newm); 06937 ao2_unlink(q->members, cur); 06938 ao2_unlock(q->members); 06939 } else { 06940 /* Otherwise we need to add using the function that will apply a round robin queue position manually. */ 06941 member_add_to_queue(q, newm); 06942 } 06943 ao2_ref(newm, -1); 06944 } 06945 newm = NULL; 06946 06947 if (cur) { 06948 ao2_ref(cur, -1); 06949 } 06950 }
| 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 6984 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().
06985 { 06986 int new; 06987 struct call_queue *q = NULL; 06988 /*We're defining a queue*/ 06989 struct call_queue tmpq = { 06990 .name = queuename, 06991 }; 06992 const char *tmpvar; 06993 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); 06994 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER); 06995 int prev_weight = 0; 06996 struct ast_variable *var; 06997 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) { 06998 if (queue_reload) { 06999 /* Make one then */ 07000 if (!(q = alloc_queue(queuename))) { 07001 return; 07002 } 07003 } else { 07004 /* Since we're not reloading queues, this means that we found a queue 07005 * in the configuration file which we don't know about yet. Just return. 07006 */ 07007 return; 07008 } 07009 new = 1; 07010 } else { 07011 new = 0; 07012 } 07013 07014 if (!new) { 07015 ao2_lock(q); 07016 prev_weight = q->weight ? 1 : 0; 07017 } 07018 /* Check if we already found a queue with this name in the config file */ 07019 if (q->found) { 07020 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename); 07021 if (!new) { 07022 /* It should be impossible to *not* hit this case*/ 07023 ao2_unlock(q); 07024 } 07025 queue_t_unref(q, "We exist! Expiring temporary pointer"); 07026 return; 07027 } 07028 /* Due to the fact that the "linear" strategy will have a different allocation 07029 * scheme for queue members, we must devise the queue's strategy before other initializations. 07030 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2 07031 * container used will have only a single bucket instead of the typical number. 07032 */ 07033 if (queue_reload) { 07034 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) { 07035 q->strategy = strat2int(tmpvar); 07036 if (q->strategy < 0) { 07037 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 07038 tmpvar, q->name); 07039 q->strategy = QUEUE_STRATEGY_RINGALL; 07040 } 07041 } else { 07042 q->strategy = QUEUE_STRATEGY_RINGALL; 07043 } 07044 init_queue(q); 07045 } 07046 if (member_reload) { 07047 ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL); 07048 q->found = 1; 07049 } 07050 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) { 07051 if (member_reload && !strcasecmp(var->name, "member")) { 07052 reload_single_member(var->value, q); 07053 } else if (queue_reload) { 07054 queue_set_param(q, var->name, var->value, var->lineno, 1); 07055 } 07056 } 07057 /* At this point, we've determined if the queue has a weight, so update use_weight 07058 * as appropriate 07059 */ 07060 if (!q->weight && prev_weight) { 07061 ast_atomic_fetchadd_int(&use_weight, -1); 07062 } 07063 else if (q->weight && !prev_weight) { 07064 ast_atomic_fetchadd_int(&use_weight, +1); 07065 } 07066 07067 /* Free remaining members marked as delme */ 07068 if (member_reload) { 07069 ao2_lock(q->members); 07070 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE, queue_delme_members_decrement_followers, q); 07071 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q); 07072 ao2_unlock(q->members); 07073 } 07074 07075 if (new) { 07076 queues_t_link(queues, q, "Add queue to container"); 07077 } else { 07078 ao2_unlock(q); 07079 } 07080 queue_t_unref(q, "Expiring creation reference"); 07081 }
| 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 5507 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().
05508 { 05509 struct call_queue *q, tmpq = { 05510 .name = queuename, 05511 }; 05512 struct member *mem, tmpmem; 05513 int res = RES_NOSUCHQUEUE; 05514 05515 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 05516 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) { 05517 ao2_lock(q); 05518 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 05519 /* XXX future changes should beware of this assumption!! */ 05520 if (!mem->dynamic) { 05521 ao2_ref(mem, -1); 05522 ao2_unlock(q); 05523 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference"); 05524 return RES_NOT_DYNAMIC; 05525 } 05526 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 05527 "Queue: %s\r\n" 05528 "Location: %s\r\n" 05529 "MemberName: %s\r\n", 05530 q->name, mem->interface, mem->membername); 05531 member_remove_from_queue(q, mem); 05532 ao2_ref(mem, -1); 05533 05534 if (queue_persistent_members) 05535 dump_queue_members(q); 05536 05537 res = RES_OKAY; 05538 } else { 05539 res = RES_EXISTS; 05540 } 05541 ao2_unlock(q); 05542 queue_t_unref(q, "Expiring temporary reference"); 05543 } 05544 05545 return res; 05546 }
| static int remove_members_and_mark_unfound | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 7083 of file app_queue.c.
References ast_strlen_zero(), call_queue::found, and call_queue::realtime.
Referenced by reload_queues().
07084 { 07085 struct call_queue *q = obj; 07086 char *queuename = arg; 07087 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) { 07088 q->found = 0; 07089 07090 } 07091 return 0; 07092 }
| 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 3207 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().
03208 { 03209 int res; 03210 int status; 03211 char tech[256]; 03212 char *location; 03213 const char *macrocontext, *macroexten; 03214 03215 /* on entry here, we know that tmp->chan == NULL */ 03216 if (!can_ring_entry(qe, tmp)) { 03217 if (qe->chan->cdr) { 03218 ast_cdr_busy(qe->chan->cdr); 03219 } 03220 tmp->stillgoing = 0; 03221 ++*busies; 03222 return 0; 03223 } 03224 ast_assert(qe->parent->ringinuse || tmp->member->call_pending); 03225 03226 ast_copy_string(tech, tmp->interface, sizeof(tech)); 03227 if ((location = strchr(tech, '/'))) 03228 *location++ = '\0'; 03229 else 03230 location = ""; 03231 03232 /* Request the peer */ 03233 tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status); 03234 if (!tmp->chan) { /* If we can't, just go on to the next call */ 03235 ao2_lock(qe->parent); 03236 qe->parent->rrpos++; 03237 qe->linpos++; 03238 ao2_unlock(qe->parent); 03239 03240 member_call_pending_clear(tmp->member); 03241 03242 if (qe->chan->cdr) { 03243 ast_cdr_busy(qe->chan->cdr); 03244 } 03245 tmp->stillgoing = 0; 03246 ++*busies; 03247 return 0; 03248 } 03249 03250 ast_channel_lock_both(tmp->chan, qe->chan); 03251 03252 if (qe->cancel_answered_elsewhere) { 03253 ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE); 03254 } 03255 tmp->chan->appl = "AppQueue"; 03256 tmp->chan->data = "(Outgoing Line)"; 03257 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup)); 03258 03259 /* If the new channel has no callerid, try to guess what it should be */ 03260 if (!tmp->chan->caller.id.number.valid) { 03261 if (qe->chan->connected.id.number.valid) { 03262 struct ast_party_caller caller; 03263 03264 ast_party_caller_set_init(&caller, &tmp->chan->caller); 03265 caller.id = qe->chan->connected.id; 03266 caller.ani = qe->chan->connected.ani; 03267 ast_channel_set_caller_event(tmp->chan, &caller, NULL); 03268 } else if (!ast_strlen_zero(qe->chan->dialed.number.str)) { 03269 ast_set_callerid(tmp->chan, qe->chan->dialed.number.str, NULL, NULL); 03270 } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) { 03271 ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL); 03272 } 03273 tmp->dial_callerid_absent = 1; 03274 } 03275 03276 ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting); 03277 03278 tmp->chan->dialed.transit_network_select = qe->chan->dialed.transit_network_select; 03279 03280 ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->caller); 03281 03282 /* Inherit specially named variables from parent channel */ 03283 ast_channel_inherit_variables(qe->chan, tmp->chan); 03284 ast_channel_datastore_inherit(qe->chan, tmp->chan); 03285 03286 /* Presense of ADSI CPE on outgoing channel follows ours */ 03287 tmp->chan->adsicpe = qe->chan->adsicpe; 03288 03289 /* Inherit context and extension */ 03290 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 03291 ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext); 03292 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 03293 if (!ast_strlen_zero(macroexten)) 03294 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 03295 else 03296 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 03297 if (ast_cdr_isset_unanswered()) { 03298 /* they want to see the unanswered dial attempts! */ 03299 /* set up the CDR fields on all the CDRs to give sensical information */ 03300 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name); 03301 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid); 03302 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel); 03303 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src); 03304 strcpy(tmp->chan->cdr->dst, qe->chan->exten); 03305 strcpy(tmp->chan->cdr->dcontext, qe->chan->context); 03306 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp); 03307 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata); 03308 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags; 03309 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode); 03310 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); 03311 } 03312 03313 ast_channel_unlock(tmp->chan); 03314 ast_channel_unlock(qe->chan); 03315 03316 /* Place the call, but don't wait on the answer */ 03317 if ((res = ast_call(tmp->chan, location, 0))) { 03318 /* Again, keep going even if there's an error */ 03319 ast_verb(3, "Couldn't call %s\n", tmp->interface); 03320 do_hang(tmp); 03321 member_call_pending_clear(tmp->member); 03322 ++*busies; 03323 return 0; 03324 } 03325 03326 if (qe->parent->eventwhencalled) { 03327 char vars[2048]; 03328 03329 ast_channel_lock_both(tmp->chan, qe->chan); 03330 03331 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 03332 "Queue: %s\r\n" 03333 "AgentCalled: %s\r\n" 03334 "AgentName: %s\r\n" 03335 "ChannelCalling: %s\r\n" 03336 "DestinationChannel: %s\r\n" 03337 "CallerIDNum: %s\r\n" 03338 "CallerIDName: %s\r\n" 03339 "ConnectedLineNum: %s\r\n" 03340 "ConnectedLineName: %s\r\n" 03341 "Context: %s\r\n" 03342 "Extension: %s\r\n" 03343 "Priority: %d\r\n" 03344 "Uniqueid: %s\r\n" 03345 "%s", 03346 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name, 03347 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"), 03348 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 03349 S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"), 03350 S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), 03351 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid, 03352 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03353 03354 ast_channel_unlock(tmp->chan); 03355 ast_channel_unlock(qe->chan); 03356 03357 ast_verb(3, "Called %s\n", tmp->interface); 03358 } 03359 03360 member_call_pending_clear(tmp->member); 03361 return 1; 03362 }
| 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 3390 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().
03391 { 03392 int ret = 0; 03393 03394 while (ret == 0) { 03395 struct callattempt *best = find_best(outgoing); 03396 if (!best) { 03397 ast_debug(1, "Nobody left to try ringing in queue\n"); 03398 break; 03399 } 03400 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 03401 struct callattempt *cur; 03402 /* Ring everyone who shares this best metric (for ringall) */ 03403 for (cur = outgoing; cur; cur = cur->q_next) { 03404 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 03405 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 03406 ret |= ring_entry(qe, cur, busies); 03407 } 03408 } 03409 } else { 03410 /* Ring just the best channel */ 03411 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric); 03412 ret = ring_entry(qe, best, busies); 03413 } 03414 03415 /* If we have timed out, break out */ 03416 if (qe->expire && (time(NULL) >= qe->expire)) { 03417 ast_debug(1, "Queue timed out while ringing members.\n"); 03418 ret = 0; 03419 break; 03420 } 03421 } 03422 03423 return ret; 03424 }
| 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 3548 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().
03549 { 03550 ast_verb(3, "Nobody picked up in %d ms\n", rnatime); 03551 03552 /* Stop ringing, and resume MOH if specified */ 03553 if (qe->ring_when_ringing) { 03554 ast_indicate(qe->chan, -1); 03555 ast_moh_start(qe->chan, qe->moh, NULL); 03556 } 03557 03558 if (qe->parent->eventwhencalled) { 03559 char vars[2048]; 03560 03561 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer", 03562 "Queue: %s\r\n" 03563 "Uniqueid: %s\r\n" 03564 "Channel: %s\r\n" 03565 "Member: %s\r\n" 03566 "MemberName: %s\r\n" 03567 "Ringtime: %d\r\n" 03568 "%s", 03569 qe->parent->name, 03570 qe->chan->uniqueid, 03571 qe->chan->name, 03572 interface, 03573 membername, 03574 rnatime, 03575 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03576 } 03577 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 03578 if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) { 03579 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) { 03580 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) { 03581 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", 03582 interface, qe->parent->name); 03583 } else { 03584 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 03585 } 03586 } else { 03587 /* If queue autopause is mode all, just don't send any queue to stop. 03588 * the function will stop in all queues */ 03589 if (!set_member_paused("", interface, "Auto-Pause", 1)) { 03590 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n", 03591 interface, qe->parent->name); 03592 } else { 03593 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface); 03594 } 03595 } 03596 } 03597 return; 03598 }
| static int rqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
RemoveQueueMember application.
Definition at line 5931 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().
05932 { 05933 int res=-1; 05934 char *parse, *temppos = NULL; 05935 AST_DECLARE_APP_ARGS(args, 05936 AST_APP_ARG(queuename); 05937 AST_APP_ARG(interface); 05938 ); 05939 05940 05941 if (ast_strlen_zero(data)) { 05942 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n"); 05943 return -1; 05944 } 05945 05946 parse = ast_strdupa(data); 05947 05948 AST_STANDARD_APP_ARGS(args, parse); 05949 05950 if (ast_strlen_zero(args.interface)) { 05951 args.interface = ast_strdupa(chan->name); 05952 temppos = strrchr(args.interface, '-'); 05953 if (temppos) 05954 *temppos = '\0'; 05955 } 05956 05957 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface); 05958 05959 switch (remove_from_queue(args.queuename, args.interface)) { 05960 case RES_OKAY: 05961 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 05962 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 05963 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 05964 res = 0; 05965 break; 05966 case RES_EXISTS: 05967 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 05968 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 05969 res = 0; 05970 break; 05971 case RES_NOSUCHQUEUE: 05972 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 05973 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 05974 res = 0; 05975 break; 05976 case RES_NOT_DYNAMIC: 05977 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 05978 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 05979 res = 0; 05980 break; 05981 } 05982 05983 return res; 05984 }
| 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 2175 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().
02176 { 02177 struct member *m; 02178 struct ao2_iterator mem_iter; 02179 int penalty = 0; 02180 int paused = 0; 02181 int found = 0; 02182 02183 if (ast_strlen_zero(rt_uniqueid)) { 02184 ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL")); 02185 return; 02186 } 02187 02188 if (penalty_str) { 02189 penalty = atoi(penalty_str); 02190 if (penalty < 0) 02191 penalty = 0; 02192 } 02193 02194 if (paused_str) { 02195 paused = atoi(paused_str); 02196 if (paused < 0) 02197 paused = 0; 02198 } 02199 02200 /* Find member by realtime uniqueid and update */ 02201 mem_iter = ao2_iterator_init(q->members, 0); 02202 while ((m = ao2_iterator_next(&mem_iter))) { 02203 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) { 02204 m->dead = 0; /* Do not delete this one. */ 02205 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 02206 if (paused_str) 02207 m->paused = paused; 02208 if (strcasecmp(state_interface, m->state_interface)) { 02209 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); 02210 } 02211 m->penalty = penalty; 02212 found = 1; 02213 ao2_ref(m, -1); 02214 break; 02215 } 02216 ao2_ref(m, -1); 02217 } 02218 ao2_iterator_destroy(&mem_iter); 02219 02220 /* Create a new member */ 02221 if (!found) { 02222 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { 02223 m->dead = 0; 02224 m->realtime = 1; 02225 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 02226 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); 02227 member_add_to_queue(q, m); 02228 ao2_ref(m, -1); 02229 m = NULL; 02230 } 02231 } 02232 }
| static int say_periodic_announcement | ( | struct queue_ent * | qe, | |
| int | ringing | |||
| ) | [static] |
Playback announcement to queued members if period has elapsed.
Definition at line 3475 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().
03476 { 03477 int res = 0; 03478 time_t now; 03479 03480 /* Get the current time */ 03481 time(&now); 03482 03483 /* Check to see if it is time to announce */ 03484 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 03485 return 0; 03486 03487 /* Stop the music on hold so we can play our own file */ 03488 if (ringing) 03489 ast_indicate(qe->chan,-1); 03490 else 03491 ast_moh_stop(qe->chan); 03492 03493 ast_verb(3, "Playing periodic announcement\n"); 03494 03495 if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) { 03496 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce; 03497 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce || 03498 ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) { 03499 qe->last_periodic_announce_sound = 0; 03500 } 03501 03502 /* play the announcement */ 03503 res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])); 03504 03505 if (res > 0 && !valid_exit(qe, res)) 03506 res = 0; 03507 03508 /* Resume Music on Hold if the caller is going to stay in the queue */ 03509 if (!res) { 03510 if (ringing) 03511 ast_indicate(qe->chan, AST_CONTROL_RINGING); 03512 else 03513 ast_moh_start(qe->chan, qe->moh, NULL); 03514 } 03515 03516 /* update last_periodic_announce_time */ 03517 if (qe->parent->relativeperiodicannounce) 03518 time(&qe->last_periodic_announce_time); 03519 else 03520 qe->last_periodic_announce_time = now; 03521 03522 /* Update the current periodic announcement to the next announcement */ 03523 if (!qe->parent->randomperiodicannounce) { 03524 qe->last_periodic_announce_sound++; 03525 } 03526 03527 return res; 03528 }
| static int say_position | ( | struct queue_ent * | qe, | |
| int | ringing | |||
| ) | [static] |
Definition at line 2696 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().
02697 { 02698 int res = 0, avgholdmins, avgholdsecs, announceposition = 0; 02699 int say_thanks = 1; 02700 time_t now; 02701 02702 /* Let minannouncefrequency seconds pass between the start of each position announcement */ 02703 time(&now); 02704 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) 02705 return 0; 02706 02707 /* If either our position has changed, or we are over the freq timer, say position */ 02708 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 02709 return 0; 02710 02711 if (ringing) { 02712 ast_indicate(qe->chan,-1); 02713 } else { 02714 ast_moh_stop(qe->chan); 02715 } 02716 02717 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES || 02718 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN || 02719 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT && 02720 qe->pos <= qe->parent->announcepositionlimit)) 02721 announceposition = 1; 02722 02723 02724 if (announceposition == 1) { 02725 /* Say we're next, if we are */ 02726 if (qe->pos == 1) { 02727 res = play_file(qe->chan, qe->parent->sound_next); 02728 if (res) 02729 goto playout; 02730 else 02731 goto posout; 02732 } else { 02733 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 02734 /* More than Case*/ 02735 res = play_file(qe->chan, qe->parent->queue_quantity1); 02736 if (res) 02737 goto playout; 02738 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 02739 if (res) 02740 goto playout; 02741 } else { 02742 /* Normal Case */ 02743 res = play_file(qe->chan, qe->parent->sound_thereare); 02744 if (res) 02745 goto playout; 02746 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 02747 if (res) 02748 goto playout; 02749 } 02750 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 02751 /* More than Case*/ 02752 res = play_file(qe->chan, qe->parent->queue_quantity2); 02753 if (res) 02754 goto playout; 02755 } else { 02756 res = play_file(qe->chan, qe->parent->sound_calls); 02757 if (res) 02758 goto playout; 02759 } 02760 } 02761 } 02762 /* Round hold time to nearest minute */ 02763 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 02764 02765 /* If they have specified a rounding then round the seconds as well */ 02766 if (qe->parent->roundingseconds) { 02767 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 02768 avgholdsecs *= qe->parent->roundingseconds; 02769 } else { 02770 avgholdsecs = 0; 02771 } 02772 02773 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 02774 02775 /* If the hold time is >1 min, if it's enabled, and if it's not 02776 supposed to be only once and we have already said it, say it */ 02777 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime && 02778 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) || 02779 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) { 02780 res = play_file(qe->chan, qe->parent->sound_holdtime); 02781 if (res) 02782 goto playout; 02783 02784 if (avgholdmins >= 1) { 02785 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL); 02786 if (res) 02787 goto playout; 02788 02789 if (avgholdmins == 1) { 02790 res = play_file(qe->chan, qe->parent->sound_minute); 02791 if (res) 02792 goto playout; 02793 } else { 02794 res = play_file(qe->chan, qe->parent->sound_minutes); 02795 if (res) 02796 goto playout; 02797 } 02798 } 02799 if (avgholdsecs >= 1) { 02800 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL); 02801 if (res) 02802 goto playout; 02803 02804 res = play_file(qe->chan, qe->parent->sound_seconds); 02805 if (res) 02806 goto playout; 02807 } 02808 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) { 02809 say_thanks = 0; 02810 } 02811 02812 posout: 02813 if (qe->parent->announceposition) { 02814 ast_verb(3, "Told %s in %s their queue position (which was %d)\n", 02815 qe->chan->name, qe->parent->name, qe->pos); 02816 } 02817 if (say_thanks) { 02818 res = play_file(qe->chan, qe->parent->sound_thanks); 02819 } 02820 playout: 02821 02822 if ((res > 0 && !valid_exit(qe, res))) 02823 res = 0; 02824 02825 /* Set our last_pos indicators */ 02826 qe->last_pos = now; 02827 qe->last_pos_said = qe->pos; 02828 02829 /* Don't restart music on hold if we're about to exit the caller from the queue */ 02830 if (!res) { 02831 if (ringing) { 02832 ast_indicate(qe->chan, AST_CONTROL_RINGING); 02833 } else { 02834 ast_moh_start(qe->chan, qe->moh, NULL); 02835 } 02836 } 02837 return res; 02838 }
| 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 4438 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().
04441 { 04442 const char *reason = NULL; /* silence dumb compilers */ 04443 04444 if (!qe->parent->eventwhencalled) 04445 return; 04446 04447 switch (rsn) { 04448 case CALLER: 04449 reason = "caller"; 04450 break; 04451 case AGENT: 04452 reason = "agent"; 04453 break; 04454 case TRANSFER: 04455 reason = "transfer"; 04456 break; 04457 } 04458 04459 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 04460 "Queue: %s\r\n" 04461 "Uniqueid: %s\r\n" 04462 "Channel: %s\r\n" 04463 "Member: %s\r\n" 04464 "MemberName: %s\r\n" 04465 "HoldTime: %ld\r\n" 04466 "TalkTime: %ld\r\n" 04467 "Reason: %s\r\n" 04468 "%s", 04469 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 04470 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason, 04471 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : ""); 04472 }
| static int set_member_paused | ( | const char * | queuename, | |
| const char * | interface, | |||
| const char * | reason, | |||
| int | paused | |||
| ) | [static] |
Definition at line 5606 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().
05607 { 05608 int found = 0; 05609 struct call_queue *q; 05610 struct member *mem; 05611 struct ao2_iterator queue_iter; 05612 int failed; 05613 05614 /* Special event for when all queues are paused - individual events still generated */ 05615 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 05616 if (ast_strlen_zero(queuename)) 05617 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 05618 05619 queue_iter = ao2_iterator_init(queues, 0); 05620 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) { 05621 ao2_lock(q); 05622 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 05623 if ((mem = interface_exists(q, interface))) { 05624 if (mem->paused == paused) { 05625 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 05626 } 05627 05628 failed = 0; 05629 if (mem->realtime) { 05630 failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); 05631 } 05632 05633 if (failed) { 05634 ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface); 05635 ao2_ref(mem, -1); 05636 ao2_unlock(q); 05637 queue_t_unref(q, "Done with iterator"); 05638 continue; 05639 } 05640 found++; 05641 mem->paused = paused; 05642 05643 if (queue_persistent_members) 05644 dump_queue_members(q); 05645 05646 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, "")); 05647 05648 if (!ast_strlen_zero(reason)) { 05649 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 05650 "Queue: %s\r\n" 05651 "Location: %s\r\n" 05652 "MemberName: %s\r\n" 05653 "Paused: %d\r\n" 05654 "Reason: %s\r\n", 05655 q->name, mem->interface, mem->membername, paused, reason); 05656 } else { 05657 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 05658 "Queue: %s\r\n" 05659 "Location: %s\r\n" 05660 "MemberName: %s\r\n" 05661 "Paused: %d\r\n", 05662 q->name, mem->interface, mem->membername, paused); 05663 } 05664 ao2_ref(mem, -1); 05665 } 05666 } 05667 05668 if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) { 05669 ao2_unlock(q); 05670 queue_t_unref(q, "Done with iterator"); 05671 break; 05672 } 05673 05674 ao2_unlock(q); 05675 queue_t_unref(q, "Done with iterator"); 05676 } 05677 ao2_iterator_destroy(&queue_iter); 05678 05679 return found ? RESULT_SUCCESS : RESULT_FAILURE; 05680 }
| static int set_member_penalty | ( | const char * | queuename, | |
| const char * | interface, | |||
| int | penalty | |||
| ) | [static] |
Definition at line 5683 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().
05684 { 05685 int foundinterface = 0, foundqueue = 0; 05686 struct call_queue *q; 05687 struct member *mem; 05688 struct ao2_iterator queue_iter; 05689 05690 if (penalty < 0) { 05691 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty); 05692 return RESULT_FAILURE; 05693 } 05694 05695 queue_iter = ao2_iterator_init(queues, 0); 05696 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 05697 ao2_lock(q); 05698 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 05699 foundqueue++; 05700 if ((mem = interface_exists(q, interface))) { 05701 foundinterface++; 05702 mem->penalty = penalty; 05703 05704 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty); 05705 manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty", 05706 "Queue: %s\r\n" 05707 "Location: %s\r\n" 05708 "Penalty: %d\r\n", 05709 q->name, mem->interface, penalty); 05710 ao2_ref(mem, -1); 05711 } 05712 } 05713 ao2_unlock(q); 05714 queue_t_unref(q, "Done with iterator"); 05715 } 05716 ao2_iterator_destroy(&queue_iter); 05717 05718 if (foundinterface) { 05719 return RESULT_SUCCESS; 05720 } else if (!foundqueue) { 05721 ast_log (LOG_ERROR, "Invalid queuename\n"); 05722 } else { 05723 ast_log (LOG_ERROR, "Invalid interface\n"); 05724 } 05725 05726 return RESULT_FAILURE; 05727 }
| static void set_queue_result | ( | struct ast_channel * | chan, | |
| enum queue_result | res | |||
| ) | [static] |
sets the QUEUESTATUS channel variable
Definition at line 1197 of file app_queue.c.
References ARRAY_LEN, pbx_builtin_setvar_helper(), queue_results, and text.
Referenced by queue_exec().
01198 { 01199 int i; 01200 01201 for (i = 0; i < ARRAY_LEN(queue_results); i++) { 01202 if (queue_results[i].id == res) { 01203 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 01204 return; 01205 } 01206 } 01207 }
| static void set_queue_variables | ( | struct call_queue * | q, | |
| struct ast_channel * | chan | |||
| ) | [static] |
Set variables of queue.
Definition at line 1346 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().
01347 { 01348 char interfacevar[256]=""; 01349 float sl = 0; 01350 01351 ao2_lock(q); 01352 01353 if (q->setqueuevar) { 01354 sl = 0; 01355 if (q->callscompleted > 0) 01356 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 01357 01358 snprintf(interfacevar, sizeof(interfacevar), 01359 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 01360 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 01361 01362 ao2_unlock(q); 01363 01364 pbx_builtin_setvar_multiple(chan, interfacevar); 01365 } else { 01366 ao2_unlock(q); 01367 } 01368 }
| 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 4542 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().
04543 { 04544 struct ast_datastore *ds; 04545 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds)); 04546 04547 if (!qtds) { 04548 ast_log(LOG_WARNING, "Memory allocation error!\n"); 04549 return NULL; 04550 } 04551 04552 ast_channel_lock(qe->chan); 04553 if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) { 04554 ast_channel_unlock(qe->chan); 04555 ast_free(qtds); 04556 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n"); 04557 return NULL; 04558 } 04559 04560 qtds->qe = qe; 04561 /* This member is refcounted in try_calling, so no need to add it here, too */ 04562 qtds->member = member; 04563 qtds->starttime = starttime; 04564 qtds->callcompletedinsl = callcompletedinsl; 04565 ds->data = qtds; 04566 ast_channel_datastore_add(qe->chan, ds); 04567 ast_channel_unlock(qe->chan); 04568 return ds; 04569 }
| 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 3451 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().
03452 { 03453 struct callattempt *best = find_best(outgoing); 03454 03455 if (best) { 03456 /* Ring just the best channel */ 03457 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 03458 qe->linpos = best->metric % 1000; 03459 } else { 03460 /* Just increment rrpos */ 03461 if (qe->linwrapped) { 03462 /* No more channels, start over */ 03463 qe->linpos = 0; 03464 } else { 03465 /* Prioritize next entry */ 03466 qe->linpos++; 03467 } 03468 } 03469 qe->linwrapped = 0; 03470 03471 return 0; 03472 }
| 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 3427 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().
03428 { 03429 struct callattempt *best = find_best(outgoing); 03430 03431 if (best) { 03432 /* Ring just the best channel */ 03433 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 03434 qe->parent->rrpos = best->metric % 1000; 03435 } else { 03436 /* Just increment rrpos */ 03437 if (qe->parent->wrapped) { 03438 /* No more channels, start over */ 03439 qe->parent->rrpos = 0; 03440 } else { 03441 /* Prioritize next entry */ 03442 qe->parent->rrpos++; 03443 } 03444 } 03445 qe->parent->wrapped = 0; 03446 03447 return 0; 03448 }
| static int strat2int | ( | const char * | strategy | ) | [static] |
Definition at line 1221 of file app_queue.c.
References ARRAY_LEN, and strategies.
Referenced by find_queue_by_name_rt(), queue_set_param(), and reload_single_queue().
01222 { 01223 int x; 01224 01225 for (x = 0; x < ARRAY_LEN(strategies); x++) { 01226 if (!strcasecmp(strategy, strategies[x].name)) 01227 return strategies[x].strategy; 01228 } 01229 01230 return -1; 01231 }
| 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 4623 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().
04624 { 04625 struct member *cur; 04626 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 04627 int to, orig; 04628 char oldexten[AST_MAX_EXTENSION]=""; 04629 char oldcontext[AST_MAX_CONTEXT]=""; 04630 char queuename[256]=""; 04631 char interfacevar[256]=""; 04632 struct ast_channel *peer; 04633 struct ast_channel *which; 04634 struct callattempt *lpeer; 04635 struct member *member; 04636 struct ast_app *application; 04637 int res = 0, bridge = 0; 04638 int numbusies = 0; 04639 int x=0; 04640 char *announce = NULL; 04641 char digit = 0; 04642 time_t callstart; 04643 time_t now = time(NULL); 04644 struct ast_bridge_config bridge_config; 04645 char nondataquality = 1; 04646 char *agiexec = NULL; 04647 char *macroexec = NULL; 04648 char *gosubexec = NULL; 04649 const char *monitorfilename; 04650 const char *monitor_exec; 04651 const char *monitor_options; 04652 char tmpid[256], tmpid2[256]; 04653 char meid[1024], meid2[1024]; 04654 char mixmonargs[1512]; 04655 struct ast_app *mixmonapp = NULL; 04656 char *p; 04657 char vars[2048]; 04658 int forwardsallowed = 1; 04659 int block_connected_line = 0; 04660 int callcompletedinsl; 04661 struct ao2_iterator memi; 04662 struct ast_datastore *datastore, *transfer_ds; 04663 struct queue_end_bridge *queue_end_bridge = NULL; 04664 04665 ast_channel_lock(qe->chan); 04666 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL); 04667 ast_channel_unlock(qe->chan); 04668 04669 memset(&bridge_config, 0, sizeof(bridge_config)); 04670 tmpid[0] = 0; 04671 meid[0] = 0; 04672 time(&now); 04673 04674 /* If we've already exceeded our timeout, then just stop 04675 * This should be extremely rare. queue_exec will take care 04676 * of removing the caller and reporting the timeout as the reason. 04677 */ 04678 if (qe->expire && now >= qe->expire) { 04679 res = 0; 04680 goto out; 04681 } 04682 04683 for (; options && *options; options++) 04684 switch (*options) { 04685 case 't': 04686 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 04687 break; 04688 case 'T': 04689 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 04690 break; 04691 case 'w': 04692 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 04693 break; 04694 case 'W': 04695 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 04696 break; 04697 case 'c': 04698 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN); 04699 break; 04700 case 'd': 04701 nondataquality = 0; 04702 break; 04703 case 'h': 04704 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 04705 break; 04706 case 'H': 04707 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 04708 break; 04709 case 'k': 04710 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL); 04711 break; 04712 case 'K': 04713 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL); 04714 break; 04715 case 'n': 04716 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) 04717 (*tries)++; 04718 else 04719 *tries = ao2_container_count(qe->parent->members); 04720 *noption = 1; 04721 break; 04722 case 'i': 04723 forwardsallowed = 0; 04724 break; 04725 case 'I': 04726 block_connected_line = 1; 04727 break; 04728 case 'x': 04729 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON); 04730 break; 04731 case 'X': 04732 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON); 04733 break; 04734 case 'C': 04735 qe->cancel_answered_elsewhere = 1; 04736 break; 04737 } 04738 04739 /* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited. 04740 (this is mainly to support chan_local) 04741 */ 04742 if (ast_test_flag(qe->chan, AST_FLAG_ANSWERED_ELSEWHERE)) { 04743 qe->cancel_answered_elsewhere = 1; 04744 } 04745 04746 ao2_lock(qe->parent); 04747 ast_debug(1, "%s is trying to call a queue member.\n", 04748 qe->chan->name); 04749 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 04750 if (!ast_strlen_zero(qe->announce)) 04751 announce = qe->announce; 04752 if (!ast_strlen_zero(announceoverride)) 04753 announce = announceoverride; 04754 04755 memi = ao2_iterator_init(qe->parent->members, 0); 04756 while ((cur = ao2_iterator_next(&memi))) { 04757 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 04758 struct ast_dialed_interface *di; 04759 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 04760 if (!tmp) { 04761 ao2_ref(cur, -1); 04762 ao2_iterator_destroy(&memi); 04763 ao2_unlock(qe->parent); 04764 goto out; 04765 } 04766 if (!datastore) { 04767 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) { 04768 callattempt_free(tmp); 04769 ao2_ref(cur, -1); 04770 ao2_iterator_destroy(&memi); 04771 ao2_unlock(qe->parent); 04772 goto out; 04773 } 04774 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 04775 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 04776 callattempt_free(tmp); 04777 ao2_ref(cur, -1); 04778 ao2_iterator_destroy(&memi); 04779 ao2_unlock(qe->parent); 04780 goto out; 04781 } 04782 datastore->data = dialed_interfaces; 04783 AST_LIST_HEAD_INIT(dialed_interfaces); 04784 04785 ast_channel_lock(qe->chan); 04786 ast_channel_datastore_add(qe->chan, datastore); 04787 ast_channel_unlock(qe->chan); 04788 } else 04789 dialed_interfaces = datastore->data; 04790 04791 AST_LIST_LOCK(dialed_interfaces); 04792 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 04793 if (!strcasecmp(cur->interface, di->interface)) { 04794 ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n", 04795 di->interface); 04796 break; 04797 } 04798 } 04799 AST_LIST_UNLOCK(dialed_interfaces); 04800 04801 if (di) { 04802 callattempt_free(tmp); 04803 ao2_ref(cur, -1); 04804 continue; 04805 } 04806 04807 /* It is always ok to dial a Local interface. We only keep track of 04808 * which "real" interfaces have been dialed. The Local channel will 04809 * inherit this list so that if it ends up dialing a real interface, 04810 * it won't call one that has already been called. */ 04811 if (strncasecmp(cur->interface, "Local/", 6)) { 04812 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) { 04813 callattempt_free(tmp); 04814 ao2_ref(cur, -1); 04815 ao2_iterator_destroy(&memi); 04816 ao2_unlock(qe->parent); 04817 goto out; 04818 } 04819 strcpy(di->interface, cur->interface); 04820 04821 AST_LIST_LOCK(dialed_interfaces); 04822 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 04823 AST_LIST_UNLOCK(dialed_interfaces); 04824 } 04825 04826 /* 04827 * Seed the callattempt's connected line information with previously 04828 * acquired connected line info from the queued channel. The 04829 * previously acquired connected line info could have been set 04830 * through the CONNECTED_LINE dialplan function. 04831 */ 04832 ast_channel_lock(qe->chan); 04833 ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected); 04834 ast_channel_unlock(qe->chan); 04835 04836 tmp->block_connected_update = block_connected_line; 04837 tmp->stillgoing = 1; 04838 tmp->member = cur;/* Place the reference for cur into callattempt. */ 04839 tmp->lastcall = cur->lastcall; 04840 tmp->lastqueue = cur->lastqueue; 04841 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 04842 /* Special case: If we ring everyone, go ahead and ring them, otherwise 04843 just calculate their metric for the appropriate strategy */ 04844 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 04845 /* Put them in the list of outgoing thingies... We're ready now. 04846 XXX If we're forcibly removed, these outgoing calls won't get 04847 hung up XXX */ 04848 tmp->q_next = outgoing; 04849 outgoing = tmp; 04850 /* If this line is up, don't try anybody else */ 04851 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 04852 break; 04853 } else { 04854 callattempt_free(tmp); 04855 } 04856 } 04857 ao2_iterator_destroy(&memi); 04858 04859 if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) { 04860 /* Application arguments have higher timeout priority (behaviour for <=1.6) */ 04861 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 04862 to = (qe->expire - now) * 1000; 04863 else 04864 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 04865 } else { 04866 /* Config timeout is higher priority thatn application timeout */ 04867 if (qe->expire && qe->expire<=now) { 04868 to = 0; 04869 } else if (qe->parent->timeout) { 04870 to = qe->parent->timeout * 1000; 04871 } else { 04872 to = -1; 04873 } 04874 } 04875 orig = to; 04876 ++qe->pending; 04877 ao2_unlock(qe->parent); 04878 ring_one(qe, outgoing, &numbusies); 04879 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, 04880 ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), 04881 forwardsallowed, ringing); 04882 /* The ast_channel_datastore_remove() function could fail here if the 04883 * datastore was moved to another channel during a masquerade. If this is 04884 * the case, don't free the datastore here because later, when the channel 04885 * to which the datastore was moved hangs up, it will attempt to free this 04886 * datastore again, causing a crash 04887 */ 04888 ast_channel_lock(qe->chan); 04889 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) { 04890 ast_datastore_free(datastore); 04891 } 04892 ast_channel_unlock(qe->chan); 04893 ao2_lock(qe->parent); 04894 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) { 04895 store_next_rr(qe, outgoing); 04896 04897 } 04898 if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) { 04899 store_next_lin(qe, outgoing); 04900 } 04901 ao2_unlock(qe->parent); 04902 peer = lpeer ? lpeer->chan : NULL; 04903 if (!peer) { 04904 qe->pending = 0; 04905 if (to) { 04906 /* Must gotten hung up */ 04907 res = -1; 04908 } else { 04909 /* User exited by pressing a digit */ 04910 res = digit; 04911 } 04912 if (res == -1) 04913 ast_debug(1, "%s: Nobody answered.\n", qe->chan->name); 04914 if (ast_cdr_isset_unanswered()) { 04915 /* channel contains the name of one of the outgoing channels 04916 in its CDR; zero out this CDR to avoid a dual-posting */ 04917 struct callattempt *o; 04918 for (o = outgoing; o; o = o->q_next) { 04919 if (!o->chan) { 04920 continue; 04921 } 04922 if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) { 04923 ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED); 04924 break; 04925 } 04926 } 04927 } 04928 } else { /* peer is valid */ 04929 /* Ah ha! Someone answered within the desired timeframe. Of course after this 04930 we will always return with -1 so that it is hung up properly after the 04931 conversation. */ 04932 if (!strcmp(qe->chan->tech->type, "DAHDI")) 04933 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 04934 if (!strcmp(peer->tech->type, "DAHDI")) 04935 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 04936 /* Update parameters for the queue */ 04937 time(&now); 04938 recalc_holdtime(qe, (now - qe->start)); 04939 ao2_lock(qe->parent); 04940 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 04941 ao2_unlock(qe->parent); 04942 member = lpeer->member; 04943 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ 04944 ao2_ref(member, 1); 04945 hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere); 04946 outgoing = NULL; 04947 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 04948 int res2; 04949 04950 res2 = ast_autoservice_start(qe->chan); 04951 if (!res2) { 04952 if (qe->parent->memberdelay) { 04953 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 04954 res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 04955 } 04956 if (!res2 && announce) { 04957 if (play_file(peer, announce) < 0) { 04958 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", announce, peer->name); 04959 } 04960 } 04961 if (!res2 && qe->parent->reportholdtime) { 04962 if (!play_file(peer, qe->parent->sound_reporthold)) { 04963 int holdtime, holdtimesecs; 04964 04965 time(&now); 04966 holdtime = abs((now - qe->start) / 60); 04967 holdtimesecs = abs((now - qe->start) % 60); 04968 if (holdtime > 0) { 04969 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 04970 if (play_file(peer, qe->parent->sound_minutes) < 0) { 04971 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, peer->name); 04972 } 04973 } 04974 if (holdtimesecs > 1) { 04975 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL); 04976 if (play_file(peer, qe->parent->sound_seconds) < 0) { 04977 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, peer->name); 04978 } 04979 } 04980 } 04981 } 04982 ast_autoservice_stop(qe->chan); 04983 } 04984 if (ast_check_hangup(peer)) { 04985 /* Agent must have hung up */ 04986 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name); 04987 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", ""); 04988 if (qe->parent->eventwhencalled) 04989 manager_event(EVENT_FLAG_AGENT, "AgentDump", 04990 "Queue: %s\r\n" 04991 "Uniqueid: %s\r\n" 04992 "Channel: %s\r\n" 04993 "Member: %s\r\n" 04994 "MemberName: %s\r\n" 04995 "%s", 04996 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 04997 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 04998 ast_hangup(peer); 04999 ao2_ref(member, -1); 05000 goto out; 05001 } else if (ast_check_hangup(qe->chan)) { 05002 /* Caller must have hung up just before being connected */ 05003 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 05004 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 05005 record_abandoned(qe); 05006 ast_hangup(peer); 05007 ao2_ref(member, -1); 05008 return -1; 05009 } 05010 } 05011 /* Stop music on hold */ 05012 if (ringing) 05013 ast_indicate(qe->chan,-1); 05014 else 05015 ast_moh_stop(qe->chan); 05016 /* If appropriate, log that we have a destination channel */ 05017 if (qe->chan->cdr) 05018 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 05019 /* Make sure channels are compatible */ 05020 res = ast_channel_make_compatible(qe->chan, peer); 05021 if (res < 0) { 05022 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", ""); 05023 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 05024 record_abandoned(qe); 05025 ast_cdr_failed(qe->chan->cdr); 05026 ast_hangup(peer); 05027 ao2_ref(member, -1); 05028 return -1; 05029 } 05030 05031 /* Play announcement to the caller telling it's his turn if defined */ 05032 if (!ast_strlen_zero(qe->parent->sound_callerannounce)) { 05033 if (play_file(qe->chan, qe->parent->sound_callerannounce)) 05034 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce); 05035 } 05036 05037 ao2_lock(qe->parent); 05038 /* if setinterfacevar is defined, make member variables available to the channel */ 05039 /* use pbx_builtin_setvar to set a load of variables with one call */ 05040 if (qe->parent->setinterfacevar) { 05041 snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d", 05042 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime); 05043 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 05044 pbx_builtin_setvar_multiple(peer, interfacevar); 05045 } 05046 05047 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */ 05048 /* use pbx_builtin_setvar to set a load of variables with one call */ 05049 if (qe->parent->setqueueentryvar) { 05050 snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d", 05051 (long) time(NULL) - qe->start, qe->opos); 05052 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 05053 pbx_builtin_setvar_multiple(peer, interfacevar); 05054 } 05055 05056 ao2_unlock(qe->parent); 05057 05058 /* try to set queue variables if configured to do so*/ 05059 set_queue_variables(qe->parent, qe->chan); 05060 set_queue_variables(qe->parent, peer); 05061 05062 ast_channel_lock(qe->chan); 05063 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) { 05064 monitorfilename = ast_strdupa(monitorfilename); 05065 } 05066 ast_channel_unlock(qe->chan); 05067 /* Begin Monitoring */ 05068 if (qe->parent->monfmt && *qe->parent->monfmt) { 05069 if (!qe->parent->montype) { 05070 const char *monexec; 05071 ast_debug(1, "Starting Monitor as requested.\n"); 05072 ast_channel_lock(qe->chan); 05073 if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) { 05074 which = qe->chan; 05075 monexec = monexec ? ast_strdupa(monexec) : NULL; 05076 } 05077 else 05078 which = peer; 05079 ast_channel_unlock(qe->chan); 05080 if (monitorfilename) { 05081 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT); 05082 } else if (qe->chan->cdr) { 05083 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT); 05084 } else { 05085 /* Last ditch effort -- no CDR, make up something */ 05086 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 05087 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT); 05088 } 05089 if (!ast_strlen_zero(monexec)) { 05090 ast_monitor_setjoinfiles(which, 1); 05091 } 05092 } else { 05093 mixmonapp = pbx_findapp("MixMonitor"); 05094 05095 if (mixmonapp) { 05096 ast_debug(1, "Starting MixMonitor as requested.\n"); 05097 if (!monitorfilename) { 05098 if (qe->chan->cdr) 05099 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)); 05100 else 05101 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 05102 } else { 05103 const char *m = monitorfilename; 05104 for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) { 05105 switch (*m) { 05106 case '^': 05107 if (*(m + 1) == '{') 05108 *p = '$'; 05109 break; 05110 case ',': 05111 *p++ = '\\'; 05112 /* Fall through */ 05113 default: 05114 *p = *m; 05115 } 05116 if (*m == '\0') 05117 break; 05118 } 05119 if (p == tmpid2 + sizeof(tmpid2)) 05120 tmpid2[sizeof(tmpid2) - 1] = '\0'; 05121 05122 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 05123 } 05124 05125 ast_channel_lock(qe->chan); 05126 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) { 05127 monitor_exec = ast_strdupa(monitor_exec); 05128 } 05129 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) { 05130 monitor_options = ast_strdupa(monitor_options); 05131 } else { 05132 monitor_options = ""; 05133 } 05134 ast_channel_unlock(qe->chan); 05135 05136 if (monitor_exec) { 05137 const char *m = monitor_exec; 05138 for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) { 05139 switch (*m) { 05140 case '^': 05141 if (*(m + 1) == '{') 05142 *p = '$'; 05143 break; 05144 case ',': 05145 *p++ = '\\'; 05146 /* Fall through */ 05147 default: 05148 *p = *m; 05149 } 05150 if (*m == '\0') 05151 break; 05152 } 05153 if (p == meid2 + sizeof(meid2)) 05154 meid2[sizeof(meid2) - 1] = '\0'; 05155 05156 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 05157 } 05158 05159 snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt); 05160 05161 if (!ast_strlen_zero(monitor_exec)) 05162 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec); 05163 else 05164 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options); 05165 05166 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 05167 /* We purposely lock the CDR so that pbx_exec does not update the application data */ 05168 if (qe->chan->cdr) 05169 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 05170 pbx_exec(qe->chan, mixmonapp, mixmonargs); 05171 if (qe->chan->cdr) 05172 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 05173 05174 } else { 05175 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 05176 } 05177 } 05178 } 05179 /* Drop out of the queue at this point, to prepare for next caller */ 05180 leave_queue(qe); 05181 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 05182 ast_debug(1, "app_queue: sendurl=%s.\n", url); 05183 ast_channel_sendurl(peer, url); 05184 } 05185 05186 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */ 05187 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */ 05188 if (!ast_strlen_zero(macro)) { 05189 macroexec = ast_strdupa(macro); 05190 } else { 05191 if (qe->parent->membermacro) 05192 macroexec = ast_strdupa(qe->parent->membermacro); 05193 } 05194 05195 if (!ast_strlen_zero(macroexec)) { 05196 ast_debug(1, "app_queue: macro=%s.\n", macroexec); 05197 05198 res = ast_autoservice_start(qe->chan); 05199 if (res) { 05200 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 05201 res = -1; 05202 } 05203 05204 application = pbx_findapp("Macro"); 05205 05206 if (application) { 05207 res = pbx_exec(peer, application, macroexec); 05208 ast_debug(1, "Macro exited with status %d\n", res); 05209 res = 0; 05210 } else { 05211 ast_log(LOG_ERROR, "Could not find application Macro\n"); 05212 res = -1; 05213 } 05214 05215 if (ast_autoservice_stop(qe->chan) < 0) { 05216 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 05217 res = -1; 05218 } 05219 } 05220 05221 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */ 05222 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */ 05223 if (!ast_strlen_zero(gosub)) { 05224 gosubexec = ast_strdupa(gosub); 05225 } else { 05226 if (qe->parent->membergosub) 05227 gosubexec = ast_strdupa(qe->parent->membergosub); 05228 } 05229 05230 if (!ast_strlen_zero(gosubexec)) { 05231 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec); 05232 05233 res = ast_autoservice_start(qe->chan); 05234 if (res) { 05235 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 05236 res = -1; 05237 } 05238 05239 application = pbx_findapp("Gosub"); 05240 05241 if (application) { 05242 char *gosub_args, *gosub_argstart; 05243 05244 /* Set where we came from */ 05245 ast_copy_string(peer->context, "app_queue_gosub_virtual_context", sizeof(peer->context)); 05246 ast_copy_string(peer->exten, "s", sizeof(peer->exten)); 05247 peer->priority = 0; 05248 05249 gosub_argstart = strchr(gosubexec, ','); 05250 if (gosub_argstart) { 05251 const char *what_is_s = "s"; 05252 *gosub_argstart = 0; 05253 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) && 05254 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) { 05255 what_is_s = "~~s~~"; 05256 } 05257 if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) { 05258 gosub_args = NULL; 05259 } 05260 *gosub_argstart = ','; 05261 } else { 05262 const char *what_is_s = "s"; 05263 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) && 05264 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) { 05265 what_is_s = "~~s~~"; 05266 } 05267 if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) { 05268 gosub_args = NULL; 05269 } 05270 } 05271 if (gosub_args) { 05272 res = pbx_exec(peer, application, gosub_args); 05273 if (!res) { 05274 struct ast_pbx_args args; 05275 memset(&args, 0, sizeof(args)); 05276 args.no_hangup_chan = 1; 05277 ast_pbx_run_args(peer, &args); 05278 } 05279 ast_free(gosub_args); 05280 ast_debug(1, "Gosub exited with status %d\n", res); 05281 } else { 05282 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n"); 05283 } 05284 } else { 05285 ast_log(LOG_ERROR, "Could not find application Gosub\n"); 05286 res = -1; 05287 } 05288 05289 if (ast_autoservice_stop(qe->chan) < 0) { 05290 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 05291 res = -1; 05292 } 05293 } 05294 05295 if (!ast_strlen_zero(agi)) { 05296 ast_debug(1, "app_queue: agi=%s.\n", agi); 05297 application = pbx_findapp("agi"); 05298 if (application) { 05299 agiexec = ast_strdupa(agi); 05300 pbx_exec(qe->chan, application, agiexec); 05301 } else 05302 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 05303 } 05304 qe->handled++; 05305 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid, 05306 (long)(orig - to > 0 ? (orig - to) / 1000 : 0)); 05307 05308 if (qe->chan->cdr) { 05309 struct ast_cdr *cdr; 05310 struct ast_cdr *newcdr; 05311 05312 /* Only work with the last CDR in the stack*/ 05313 cdr = qe->chan->cdr; 05314 while (cdr->next) { 05315 cdr = cdr->next; 05316 } 05317 05318 /* If this CDR is not related to us add new one*/ 05319 if ((strcasecmp(cdr->uniqueid, qe->chan->uniqueid)) && 05320 (strcasecmp(cdr->linkedid, qe->chan->uniqueid)) && 05321 (newcdr = ast_cdr_dup(cdr))) { 05322 ast_channel_lock(qe->chan); 05323 ast_cdr_init(newcdr, qe->chan); 05324 ast_cdr_reset(newcdr, 0); 05325 cdr = ast_cdr_append(cdr, newcdr); 05326 cdr = cdr->next; 05327 ast_channel_unlock(qe->chan); 05328 } 05329 05330 if (update_cdr) { 05331 ast_copy_string(cdr->dstchannel, member->membername, sizeof(cdr->dstchannel)); 05332 } 05333 } 05334 05335 if (qe->parent->eventwhencalled) 05336 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 05337 "Queue: %s\r\n" 05338 "Uniqueid: %s\r\n" 05339 "Channel: %s\r\n" 05340 "Member: %s\r\n" 05341 "MemberName: %s\r\n" 05342 "Holdtime: %ld\r\n" 05343 "BridgedChannel: %s\r\n" 05344 "Ringtime: %ld\r\n" 05345 "%s", 05346 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 05347 (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0), 05348 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 05349 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 05350 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 05351 05352 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) { 05353 queue_end_bridge->q = qe->parent; 05354 queue_end_bridge->chan = qe->chan; 05355 bridge_config.end_bridge_callback = end_bridge_callback; 05356 bridge_config.end_bridge_callback_data = queue_end_bridge; 05357 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 05358 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need 05359 * to make sure to increase the refcount of this queue so it cannot be freed until we 05360 * are done with it. We remove this reference in end_bridge_callback. 05361 */ 05362 queue_t_ref(qe->parent, "For bridge_config reference"); 05363 } 05364 05365 time(&callstart); 05366 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl); 05367 bridge = ast_bridge_call(qe->chan, peer, &bridge_config); 05368 05369 /* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log 05370 * when the masquerade occurred. These other "ending" queue_log messages are unnecessary, except for 05371 * the AgentComplete manager event 05372 */ 05373 ast_channel_lock(qe->chan); 05374 if (!attended_transfer_occurred(qe->chan)) { 05375 struct ast_datastore *tds; 05376 05377 /* detect a blind transfer */ 05378 if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) { 05379 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 05380 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 05381 (long) (time(NULL) - callstart), qe->opos); 05382 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER); 05383 } else if (ast_check_hangup(qe->chan) && !ast_check_hangup(peer)) { 05384 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d", 05385 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 05386 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER); 05387 } else { 05388 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 05389 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 05390 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT); 05391 } 05392 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) { 05393 ast_channel_datastore_remove(qe->chan, tds); 05394 } 05395 ast_channel_unlock(qe->chan); 05396 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart)); 05397 } else { 05398 ast_channel_unlock(qe->chan); 05399 05400 /* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */ 05401 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER); 05402 } 05403 05404 if (transfer_ds) { 05405 ast_datastore_free(transfer_ds); 05406 } 05407 ast_hangup(peer); 05408 res = bridge ? bridge : 1; 05409 ao2_ref(member, -1); 05410 } 05411 out: 05412 hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere); 05413 05414 return res; 05415 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 8725 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.
08726 { 08727 int res; 08728 struct ast_context *con; 08729 struct ao2_iterator q_iter; 08730 struct call_queue *q = NULL; 08731 08732 ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue)); 08733 res = ast_manager_unregister("QueueStatus"); 08734 res |= ast_manager_unregister("Queues"); 08735 res |= ast_manager_unregister("QueueRule"); 08736 res |= ast_manager_unregister("QueueSummary"); 08737 res |= ast_manager_unregister("QueueAdd"); 08738 res |= ast_manager_unregister("QueueRemove"); 08739 res |= ast_manager_unregister("QueuePause"); 08740 res |= ast_manager_unregister("QueueLog"); 08741 res |= ast_manager_unregister("QueuePenalty"); 08742 res |= ast_manager_unregister("QueueReload"); 08743 res |= ast_manager_unregister("QueueReset"); 08744 res |= ast_unregister_application(app_aqm); 08745 res |= ast_unregister_application(app_rqm); 08746 res |= ast_unregister_application(app_pqm); 08747 res |= ast_unregister_application(app_upqm); 08748 res |= ast_unregister_application(app_ql); 08749 res |= ast_unregister_application(app); 08750 res |= ast_custom_function_unregister(&queueexists_function); 08751 res |= ast_custom_function_unregister(&queuevar_function); 08752 res |= ast_custom_function_unregister(&queuemembercount_function); 08753 res |= ast_custom_function_unregister(&queuemembercount_dep); 08754 res |= ast_custom_function_unregister(&queuememberlist_function); 08755 res |= ast_custom_function_unregister(&queuewaitingcount_function); 08756 res |= ast_custom_function_unregister(&queuememberpenalty_function); 08757 08758 res |= ast_data_unregister(NULL); 08759 08760 if (device_state_sub) 08761 ast_event_unsubscribe(device_state_sub); 08762 08763 ast_extension_state_del(0, extension_state_cb); 08764 08765 if ((con = ast_context_find("app_queue_gosub_virtual_context"))) { 08766 ast_context_remove_extension2(con, "s", 1, NULL, 0); 08767 ast_context_destroy(con, "app_queue"); /* leave no trace */ 08768 } 08769 08770 q_iter = ao2_iterator_init(queues, 0); 08771 while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) { 08772 queues_t_unlink(queues, q, "Remove queue from container due to unload"); 08773 queue_t_unref(q, "Done with iterator"); 08774 } 08775 ao2_iterator_destroy(&q_iter); 08776 devicestate_tps = ast_taskprocessor_unreference(devicestate_tps); 08777 ao2_ref(queues, -1); 08778 ast_unload_realtime("queue_members"); 08779 return res; 08780 }
| 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 4174 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().
04175 { 04176 int max_penalty = INT_MAX; 04177 04178 if (qe->max_penalty != INT_MAX) { 04179 char max_penalty_str[20]; 04180 04181 if (qe->pr->max_relative) { 04182 max_penalty = qe->max_penalty + qe->pr->max_value; 04183 } else { 04184 max_penalty = qe->pr->max_value; 04185 } 04186 04187 /* a relative change to the penalty could put it below 0 */ 04188 if (max_penalty < 0) { 04189 max_penalty = 0; 04190 } 04191 04192 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty); 04193 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str); 04194 qe->max_penalty = max_penalty; 04195 ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n", 04196 qe->max_penalty, qe->chan->name, qe->pr->time); 04197 } 04198 04199 if (qe->min_penalty != INT_MAX) { 04200 char min_penalty_str[20]; 04201 int min_penalty; 04202 04203 if (qe->pr->min_relative) { 04204 min_penalty = qe->min_penalty + qe->pr->min_value; 04205 } else { 04206 min_penalty = qe->pr->min_value; 04207 } 04208 04209 if (min_penalty < 0) { 04210 min_penalty = 0; 04211 } 04212 04213 if (max_penalty != INT_MAX && min_penalty > max_penalty) { 04214 min_penalty = max_penalty; 04215 } 04216 04217 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty); 04218 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str); 04219 qe->min_penalty = min_penalty; 04220 ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n", 04221 qe->min_penalty, qe->chan->name, qe->pr->time); 04222 } 04223 04224 qe->pr = AST_LIST_NEXT(qe->pr, list); 04225 }
| 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 4313 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().
04314 { 04315 int oldtalktime; 04316 04317 struct member *mem; 04318 struct call_queue *qtmp; 04319 struct ao2_iterator queue_iter; 04320 04321 if (shared_lastcall) { 04322 queue_iter = ao2_iterator_init(queues, 0); 04323 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 04324 ao2_lock(qtmp); 04325 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) { 04326 time(&mem->lastcall); 04327 mem->calls++; 04328 mem->lastqueue = q; 04329 ao2_ref(mem, -1); 04330 } 04331 ao2_unlock(qtmp); 04332 queue_t_unref(qtmp, "Done with iterator"); 04333 } 04334 ao2_iterator_destroy(&queue_iter); 04335 } else { 04336 ao2_lock(q); 04337 time(&member->lastcall); 04338 member->calls++; 04339 member->lastqueue = q; 04340 ao2_unlock(q); 04341 } 04342 ao2_lock(q); 04343 q->callscompleted++; 04344 if (callcompletedinsl) 04345 q->callscompletedinsl++; 04346 /* Calculate talktime using the same exponential average as holdtime code*/ 04347 oldtalktime = q->talktime; 04348 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2; 04349 ao2_unlock(q); 04350 return 0; 04351 }
| static int update_realtime_member_field | ( | struct member * | mem, | |
| const char * | queue_name, | |||
| const char * | field, | |||
| const char * | value | |||
| ) | [static] |
Definition at line 2475 of file app_queue.c.
References ast_strlen_zero(), ast_update_realtime(), member::rt_uniqueid, and SENTINEL.
Referenced by set_member_paused().
02476 { 02477 int ret = -1; 02478 02479 if (ast_strlen_zero(mem->rt_uniqueid)) 02480 return ret; 02481 02482 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0) 02483 ret = 0; 02484 02485 return ret; 02486 }
| static void update_realtime_members | ( | struct call_queue * | q | ) | [static] |
Definition at line 2489 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().
02490 { 02491 struct ast_config *member_config = NULL; 02492 struct member *m; 02493 char *interface = NULL; 02494 struct ao2_iterator mem_iter; 02495 02496 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) { 02497 /* This queue doesn't have realtime members. If the queue still has any realtime 02498 * members in memory, they need to be removed. 02499 */ 02500 ao2_lock(q); 02501 mem_iter = ao2_iterator_init(q->members, 0); 02502 while ((m = ao2_iterator_next(&mem_iter))) { 02503 if (m->realtime) { 02504 member_remove_from_queue(q, m); 02505 } 02506 ao2_ref(m, -1); 02507 } 02508 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name); 02509 ao2_unlock(q); 02510 return; 02511 } 02512 02513 ao2_lock(q); 02514 02515 /* Temporarily set realtime members dead so we can detect deleted ones.*/ 02516 mem_iter = ao2_iterator_init(q->members, 0); 02517 while ((m = ao2_iterator_next(&mem_iter))) { 02518 if (m->realtime) 02519 m->dead = 1; 02520 ao2_ref(m, -1); 02521 } 02522 ao2_iterator_destroy(&mem_iter); 02523 02524 while ((interface = ast_category_browse(member_config, interface))) { 02525 rt_handle_member_record(q, interface, 02526 ast_variable_retrieve(member_config, interface, "uniqueid"), 02527 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), 02528 ast_variable_retrieve(member_config, interface, "penalty"), 02529 ast_variable_retrieve(member_config, interface, "paused"), 02530 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface)); 02531 } 02532 02533 /* Delete all realtime members that have been deleted in DB. */ 02534 mem_iter = ao2_iterator_init(q->members, 0); 02535 while ((m = ao2_iterator_next(&mem_iter))) { 02536 if (m->dead) { 02537 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 02538 member_remove_from_queue(q, m); 02539 } 02540 ao2_ref(m, -1); 02541 } 02542 ao2_iterator_destroy(&mem_iter); 02543 ao2_unlock(q); 02544 ast_config_destroy(member_config); 02545 }
| 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 1482 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().
01483 { 01484 m->status = status; 01485 01486 if (q->maskmemberstatus) 01487 return 0; 01488 01489 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 01490 "Queue: %s\r\n" 01491 "Location: %s\r\n" 01492 "MemberName: %s\r\n" 01493 "Membership: %s\r\n" 01494 "Penalty: %d\r\n" 01495 "CallsTaken: %d\r\n" 01496 "LastCall: %d\r\n" 01497 "Status: %d\r\n" 01498 "Paused: %d\r\n", 01499 q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static", 01500 m->penalty, m->calls, (int)m->lastcall, m->status, m->paused 01501 ); 01502 01503 return 0; 01504 }
| static int upqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
UnPauseQueueMember application.
Definition at line 5895 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().
05896 { 05897 char *parse; 05898 AST_DECLARE_APP_ARGS(args, 05899 AST_APP_ARG(queuename); 05900 AST_APP_ARG(interface); 05901 AST_APP_ARG(options); 05902 AST_APP_ARG(reason); 05903 ); 05904 05905 if (ast_strlen_zero(data)) { 05906 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n"); 05907 return -1; 05908 } 05909 05910 parse = ast_strdupa(data); 05911 05912 AST_STANDARD_APP_ARGS(args, parse); 05913 05914 if (ast_strlen_zero(args.interface)) { 05915 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 05916 return -1; 05917 } 05918 05919 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) { 05920 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 05921 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 05922 return 0; 05923 } 05924 05925 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 05926 05927 return 0; 05928 }
| 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 2662 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().
02663 { 02664 int digitlen = strlen(qe->digits); 02665 02666 /* Prevent possible buffer overflow */ 02667 if (digitlen < sizeof(qe->digits) - 2) { 02668 qe->digits[digitlen] = digit; 02669 qe->digits[digitlen + 1] = '\0'; 02670 } else { 02671 qe->digits[0] = '\0'; 02672 return 0; 02673 } 02674 02675 /* If there's no context to goto, short-circuit */ 02676 if (ast_strlen_zero(qe->context)) 02677 return 0; 02678 02679 /* If the extension is bad, then reset the digits to blank */ 02680 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, 02681 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, NULL))) { 02682 qe->digits[0] = '\0'; 02683 return 0; 02684 } 02685 02686 /* We have an exact match */ 02687 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 02688 qe->valid_digits = 1; 02689 /* Return 1 on a successful goto */ 02690 return 1; 02691 } 02692 02693 return 0; 02694 }
| 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 3050 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().
03051 { 03052 struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1); 03053 const char *tmp; 03054 03055 if (pbx_builtin_serialize_variables(chan, &buf)) { 03056 int i, j; 03057 03058 /* convert "\n" to "\nVariable: " */ 03059 strcpy(vars, "Variable: "); 03060 tmp = ast_str_buffer(buf); 03061 03062 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 03063 vars[j] = tmp[i]; 03064 03065 if (tmp[i + 1] == '\0') 03066 break; 03067 if (tmp[i] == '\n') { 03068 vars[j++] = '\r'; 03069 vars[j++] = '\n'; 03070 03071 ast_copy_string(&(vars[j]), "Variable: ", len - j); 03072 j += 9; 03073 } 03074 } 03075 if (j > len - 3) 03076 j = len - 3; 03077 vars[j++] = '\r'; 03078 vars[j++] = '\n'; 03079 vars[j] = '\0'; 03080 } else { 03081 /* there are no channel variables; leave it blank */ 03082 *vars = '\0'; 03083 } 03084 return vars; 03085 }
| static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 5417 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
05418 { 05419 /* Don't need to hold the lock while we setup the outgoing calls */ 05420 int retrywait = qe->parent->retry * 1000; 05421 05422 int res = ast_waitfordigit(qe->chan, retrywait); 05423 if (res > 0 && !valid_exit(qe, res)) 05424 res = 0; 05425 05426 return res; 05427 }
| 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 3614 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().
03615 { 03616 const char *queue = qe->parent->name; 03617 struct callattempt *o, *start = NULL, *prev = NULL; 03618 int status; 03619 int numbusies = prebusies; 03620 int numnochan = 0; 03621 int stillgoing = 0; 03622 int orig = *to; 03623 struct ast_frame *f; 03624 struct callattempt *peer = NULL; 03625 struct ast_channel *winner; 03626 struct ast_channel *in = qe->chan; 03627 char on[80] = ""; 03628 char membername[80] = ""; 03629 long starttime = 0; 03630 long endtime = 0; 03631 #ifdef HAVE_EPOLL 03632 struct callattempt *epollo; 03633 #endif 03634 struct ast_party_connected_line connected_caller; 03635 char *inchan_name; 03636 struct timeval start_time_tv = ast_tvnow(); 03637 03638 ast_party_connected_line_init(&connected_caller); 03639 03640 ast_channel_lock(qe->chan); 03641 inchan_name = ast_strdupa(qe->chan->name); 03642 ast_channel_unlock(qe->chan); 03643 03644 starttime = (long) time(NULL); 03645 #ifdef HAVE_EPOLL 03646 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 03647 if (epollo->chan) 03648 ast_poll_channel_add(in, epollo->chan); 03649 } 03650 #endif 03651 03652 while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) { 03653 int numlines, retry, pos = 1; 03654 struct ast_channel *watchers[AST_MAX_WATCHERS]; 03655 watchers[0] = in; 03656 start = NULL; 03657 03658 for (retry = 0; retry < 2; retry++) { 03659 numlines = 0; 03660 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 03661 if (o->stillgoing) { /* Keep track of important channels */ 03662 stillgoing = 1; 03663 if (o->chan) { 03664 if (pos < AST_MAX_WATCHERS) { 03665 watchers[pos++] = o->chan; 03666 } 03667 if (!start) 03668 start = o; 03669 else 03670 prev->call_next = o; 03671 prev = o; 03672 } 03673 } 03674 numlines++; 03675 } 03676 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 03677 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 03678 break; 03679 /* On "ringall" strategy we only move to the next penalty level 03680 when *all* ringing phones are done in the current penalty level */ 03681 ring_one(qe, outgoing, &numbusies); 03682 /* and retry... */ 03683 } 03684 if (pos == 1 /* not found */) { 03685 if (numlines == (numbusies + numnochan)) { 03686 ast_debug(1, "Everyone is busy at this time\n"); 03687 } else { 03688 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan); 03689 } 03690 *to = 0; 03691 return NULL; 03692 } 03693 03694 /* Poll for events from both the incoming channel as well as any outgoing channels */ 03695 winner = ast_waitfor_n(watchers, pos, to); 03696 03697 /* Service all of the outgoing channels */ 03698 for (o = start; o; o = o->call_next) { 03699 /* We go with a fixed buffer here instead of using ast_strdupa. Using 03700 * ast_strdupa in a loop like this one can cause a stack overflow 03701 */ 03702 char ochan_name[AST_CHANNEL_NAME]; 03703 03704 if (o->chan) { 03705 ast_channel_lock(o->chan); 03706 ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name)); 03707 ast_channel_unlock(o->chan); 03708 } 03709 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 03710 if (!peer) { 03711 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); 03712 if (!o->block_connected_update) { 03713 if (o->pending_connected_update) { 03714 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { 03715 ast_channel_update_connected_line(in, &o->connected, NULL); 03716 } 03717 } else if (!o->dial_callerid_absent) { 03718 ast_channel_lock(o->chan); 03719 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller); 03720 ast_channel_unlock(o->chan); 03721 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 03722 if (ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) { 03723 ast_channel_update_connected_line(in, &connected_caller, NULL); 03724 } 03725 ast_party_connected_line_free(&connected_caller); 03726 } 03727 } 03728 if (o->aoc_s_rate_list) { 03729 size_t encoded_size; 03730 struct ast_aoc_encoded *encoded; 03731 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) { 03732 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size); 03733 ast_aoc_destroy_encoded(encoded); 03734 } 03735 } 03736 peer = o; 03737 } 03738 } else if (o->chan && (o->chan == winner)) { 03739 03740 ast_copy_string(on, o->member->interface, sizeof(on)); 03741 ast_copy_string(membername, o->member->membername, sizeof(membername)); 03742 03743 /* Before processing channel, go ahead and check for forwarding */ 03744 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { 03745 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward); 03746 numnochan++; 03747 do_hang(o); 03748 winner = NULL; 03749 continue; 03750 } else if (!ast_strlen_zero(o->chan->call_forward)) { 03751 struct ast_channel *original = o->chan; 03752 char tmpchan[256]; 03753 char *stuff; 03754 char *tech; 03755 03756 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 03757 if ((stuff = strchr(tmpchan, '/'))) { 03758 *stuff++ = '\0'; 03759 tech = tmpchan; 03760 } else { 03761 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 03762 stuff = tmpchan; 03763 tech = "Local"; 03764 } 03765 if (!strcasecmp(tech, "Local")) { 03766 /* 03767 * Drop the connected line update block for local channels since 03768 * this is going to run dialplan and the user can change his 03769 * mind about what connected line information he wants to send. 03770 */ 03771 o->block_connected_update = 0; 03772 } 03773 03774 ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL); 03775 03776 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name); 03777 /* Setup parameters */ 03778 o->chan = ast_request(tech, in->nativeformats, in, stuff, &status); 03779 if (!o->chan) { 03780 ast_log(LOG_NOTICE, 03781 "Forwarding failed to create channel to dial '%s/%s'\n", 03782 tech, stuff); 03783 o->stillgoing = 0; 03784 numnochan++; 03785 } else { 03786 ast_channel_lock_both(o->chan, original); 03787 ast_party_redirecting_copy(&o->chan->redirecting, &original->redirecting); 03788 ast_channel_unlock(o->chan); 03789 ast_channel_unlock(original); 03790 03791 ast_channel_lock_both(o->chan, in); 03792 ast_channel_inherit_variables(in, o->chan); 03793 ast_channel_datastore_inherit(in, o->chan); 03794 03795 if (o->pending_connected_update) { 03796 /* 03797 * Re-seed the callattempt's connected line information with 03798 * previously acquired connected line info from the queued 03799 * channel. The previously acquired connected line info could 03800 * have been set through the CONNECTED_LINE dialplan function. 03801 */ 03802 o->pending_connected_update = 0; 03803 ast_party_connected_line_copy(&o->connected, &in->connected); 03804 } 03805 03806 ast_string_field_set(o->chan, accountcode, in->accountcode); 03807 03808 if (!o->chan->redirecting.from.number.valid 03809 || ast_strlen_zero(o->chan->redirecting.from.number.str)) { 03810 /* 03811 * The call was not previously redirected so it is 03812 * now redirected from this number. 03813 */ 03814 ast_party_number_free(&o->chan->redirecting.from.number); 03815 ast_party_number_init(&o->chan->redirecting.from.number); 03816 o->chan->redirecting.from.number.valid = 1; 03817 o->chan->redirecting.from.number.str = 03818 ast_strdup(S_OR(in->macroexten, in->exten)); 03819 } 03820 03821 o->chan->dialed.transit_network_select = in->dialed.transit_network_select; 03822 03823 o->dial_callerid_absent = !o->chan->caller.id.number.valid 03824 || ast_strlen_zero(o->chan->caller.id.number.str); 03825 ast_connected_line_copy_from_caller(&o->chan->connected, &in->caller); 03826 03827 ast_channel_unlock(in); 03828 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL 03829 && !o->block_connected_update) { 03830 struct ast_party_redirecting redirecting; 03831 03832 /* 03833 * Redirecting updates to the caller make sense only on single 03834 * call at a time strategies. 03835 * 03836 * We must unlock o->chan before calling 03837 * ast_channel_redirecting_macro, because we put o->chan into 03838 * autoservice there. That is pretty much a guaranteed 03839 * deadlock. This is why the handling of o->chan's lock may 03840 * seem a bit unusual here. 03841 */ 03842 ast_party_redirecting_init(&redirecting); 03843 ast_party_redirecting_copy(&redirecting, &o->chan->redirecting); 03844 ast_channel_unlock(o->chan); 03845 if (ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0)) { 03846 ast_channel_update_redirecting(in, &redirecting, NULL); 03847 } 03848 ast_party_redirecting_free(&redirecting); 03849 } else { 03850 ast_channel_unlock(o->chan); 03851 } 03852 03853 if (ast_call(o->chan, stuff, 0)) { 03854 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n", 03855 tech, stuff); 03856 do_hang(o); 03857 numnochan++; 03858 } 03859 } 03860 /* Hangup the original channel now, in case we needed it */ 03861 ast_hangup(winner); 03862 continue; 03863 } 03864 f = ast_read(winner); 03865 if (f) { 03866 if (f->frametype == AST_FRAME_CONTROL) { 03867 switch (f->subclass.integer) { 03868 case AST_CONTROL_ANSWER: 03869 /* This is our guy if someone answered. */ 03870 if (!peer) { 03871 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); 03872 if (!o->block_connected_update) { 03873 if (o->pending_connected_update) { 03874 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { 03875 ast_channel_update_connected_line(in, &o->connected, NULL); 03876 } 03877 } else if (!o->dial_callerid_absent) { 03878 ast_channel_lock(o->chan); 03879 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller); 03880 ast_channel_unlock(o->chan); 03881 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 03882 if (ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) { 03883 ast_channel_update_connected_line(in, &connected_caller, NULL); 03884 } 03885 ast_party_connected_line_free(&connected_caller); 03886 } 03887 } 03888 if (o->aoc_s_rate_list) { 03889 size_t encoded_size; 03890 struct ast_aoc_encoded *encoded; 03891 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) { 03892 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size); 03893 ast_aoc_destroy_encoded(encoded); 03894 } 03895 } 03896 peer = o; 03897 } 03898 break; 03899 case AST_CONTROL_BUSY: 03900 ast_verb(3, "%s is busy\n", ochan_name); 03901 if (in->cdr) 03902 ast_cdr_busy(in->cdr); 03903 do_hang(o); 03904 endtime = (long) time(NULL); 03905 endtime -= starttime; 03906 rna(endtime * 1000, qe, on, membername, 0); 03907 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03908 if (qe->parent->timeoutrestart) { 03909 start_time_tv = ast_tvnow(); 03910 } 03911 /* Have enough time for a queue member to answer? */ 03912 if (ast_remaining_ms(start_time_tv, orig) > 500) { 03913 ring_one(qe, outgoing, &numbusies); 03914 starttime = (long) time(NULL); 03915 } 03916 } 03917 numbusies++; 03918 break; 03919 case AST_CONTROL_CONGESTION: 03920 ast_verb(3, "%s is circuit-busy\n", ochan_name); 03921 if (in->cdr) 03922 ast_cdr_busy(in->cdr); 03923 endtime = (long) time(NULL); 03924 endtime -= starttime; 03925 rna(endtime * 1000, qe, on, membername, 0); 03926 do_hang(o); 03927 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03928 if (qe->parent->timeoutrestart) { 03929 start_time_tv = ast_tvnow(); 03930 } 03931 if (ast_remaining_ms(start_time_tv, orig) > 500) { 03932 ring_one(qe, outgoing, &numbusies); 03933 starttime = (long) time(NULL); 03934 } 03935 } 03936 numbusies++; 03937 break; 03938 case AST_CONTROL_RINGING: 03939 ast_verb(3, "%s is ringing\n", ochan_name); 03940 03941 /* Start ring indication when the channel is ringing, if specified */ 03942 if (qe->ring_when_ringing) { 03943 ast_moh_stop(qe->chan); 03944 ast_indicate(qe->chan, AST_CONTROL_RINGING); 03945 } 03946 break; 03947 case AST_CONTROL_OFFHOOK: 03948 /* Ignore going off hook */ 03949 break; 03950 case AST_CONTROL_CONNECTED_LINE: 03951 if (o->block_connected_update) { 03952 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name); 03953 break; 03954 } 03955 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 03956 struct ast_party_connected_line connected; 03957 03958 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name); 03959 ast_party_connected_line_set_init(&connected, &o->connected); 03960 ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected); 03961 ast_party_connected_line_set(&o->connected, &connected, NULL); 03962 ast_party_connected_line_free(&connected); 03963 o->pending_connected_update = 1; 03964 break; 03965 } 03966 03967 /* 03968 * Prevent using the CallerID from the outgoing channel since we 03969 * got a connected line update from it. 03970 */ 03971 o->dial_callerid_absent = 1; 03972 03973 if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) { 03974 ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); 03975 } 03976 break; 03977 case AST_CONTROL_AOC: 03978 { 03979 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan); 03980 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) { 03981 ast_aoc_destroy_decoded(o->aoc_s_rate_list); 03982 o->aoc_s_rate_list = decoded; 03983 } else { 03984 ast_aoc_destroy_decoded(decoded); 03985 } 03986 } 03987 break; 03988 case AST_CONTROL_REDIRECTING: 03989 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 03990 /* 03991 * Redirecting updates to the caller make sense only on single 03992 * call at a time strategies. 03993 */ 03994 break; 03995 } 03996 if (o->block_connected_update) { 03997 ast_verb(3, "Redirecting update to %s prevented\n", 03998 inchan_name); 03999 break; 04000 } 04001 ast_verb(3, "%s redirecting info has changed, passing it to %s\n", 04002 ochan_name, inchan_name); 04003 if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) { 04004 ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); 04005 } 04006 break; 04007 default: 04008 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer); 04009 break; 04010 } 04011 } 04012 ast_frfree(f); 04013 } else { /* ast_read() returned NULL */ 04014 endtime = (long) time(NULL) - starttime; 04015 rna(endtime * 1000, qe, on, membername, 1); 04016 do_hang(o); 04017 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 04018 if (qe->parent->timeoutrestart) { 04019 start_time_tv = ast_tvnow(); 04020 } 04021 if (ast_remaining_ms(start_time_tv, orig) > 500) { 04022 ring_one(qe, outgoing, &numbusies); 04023 starttime = (long) time(NULL); 04024 } 04025 } 04026 } 04027 } 04028 } 04029 04030 /* If we received an event from the caller, deal with it. */ 04031 if (winner == in) { 04032 f = ast_read(in); 04033 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) { 04034 /* Got hung up */ 04035 *to = -1; 04036 if (f) { 04037 if (f->data.uint32) { 04038 in->hangupcause = f->data.uint32; 04039 } 04040 ast_frfree(f); 04041 } 04042 return NULL; 04043 } 04044 04045 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) { 04046 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer); 04047 *to = 0; 04048 ast_frfree(f); 04049 return NULL; 04050 } 04051 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) { 04052 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer); 04053 *to = 0; 04054 *digit = f->subclass.integer; 04055 ast_frfree(f); 04056 return NULL; 04057 } 04058 04059 /* Send the frame from the in channel to all outgoing channels. */ 04060 for (o = start; o; o = o->call_next) { 04061 if (!o->stillgoing || !o->chan) { 04062 /* This outgoing channel has died so don't send the frame to it. */ 04063 continue; 04064 } 04065 switch (f->frametype) { 04066 case AST_FRAME_CONTROL: 04067 switch (f->subclass.integer) { 04068 case AST_CONTROL_CONNECTED_LINE: 04069 if (ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) { 04070 ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen); 04071 } 04072 break; 04073 case AST_CONTROL_REDIRECTING: 04074 if (ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) { 04075 ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen); 04076 } 04077 break; 04078 default: 04079 /* We are not going to do anything with this frame. */ 04080 goto skip_frame; 04081 } 04082 break; 04083 default: 04084 /* We are not going to do anything with this frame. */ 04085 goto skip_frame; 04086 } 04087 } 04088 skip_frame:; 04089 04090 ast_frfree(f); 04091 } 04092 } 04093 04094 /* Make a position announcement, if enabled */ 04095 if (qe->parent->announcefrequency && qe->parent->announce_to_first_user) { 04096 say_position(qe, ringing); 04097 } 04098 04099 /* Make a periodic announcement, if enabled */ 04100 if (qe->parent->periodicannouncefrequency && qe->parent->announce_to_first_user) { 04101 say_periodic_announcement(qe, ringing); 04102 } 04103 04104 if (!*to) { 04105 for (o = start; o; o = o->call_next) { 04106 rna(orig, qe, o->interface, o->member->membername, 1); 04107 } 04108 } 04109 04110 #ifdef HAVE_EPOLL 04111 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 04112 if (epollo->chan) 04113 ast_poll_channel_del(in, epollo->chan); 04114 } 04115 #endif 04116 04117 return peer; 04118 }
| 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 4237 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().
04238 { 04239 int res = 0; 04240 04241 /* This is the holding pen for callers 2 through maxlen */ 04242 for (;;) { 04243 04244 if (is_our_turn(qe)) 04245 break; 04246 04247 /* If we have timed out, break out */ 04248 if (qe->expire && (time(NULL) >= qe->expire)) { 04249 *reason = QUEUE_TIMEOUT; 04250 break; 04251 } 04252 04253 if (qe->parent->leavewhenempty) { 04254 int status = 0; 04255 04256 if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty))) { 04257 *reason = QUEUE_LEAVEEMPTY; 04258 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 04259 leave_queue(qe); 04260 break; 04261 } 04262 } 04263 04264 /* Make a position announcement, if enabled */ 04265 if (qe->parent->announcefrequency && 04266 (res = say_position(qe,ringing))) 04267 break; 04268 04269 /* If we have timed out, break out */ 04270 if (qe->expire && (time(NULL) >= qe->expire)) { 04271 *reason = QUEUE_TIMEOUT; 04272 break; 04273 } 04274 04275 /* Make a periodic announcement, if enabled */ 04276 if (qe->parent->periodicannouncefrequency && 04277 (res = say_periodic_announcement(qe,ringing))) 04278 break; 04279 04280 /* see if we need to move to the next penalty level for this queue */ 04281 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) { 04282 update_qe_rule(qe); 04283 } 04284 04285 /* If we have timed out, break out */ 04286 if (qe->expire && (time(NULL) >= qe->expire)) { 04287 *reason = QUEUE_TIMEOUT; 04288 break; 04289 } 04290 04291 /* Wait a second before checking again */ 04292 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 04293 if (res > 0 && !valid_exit(qe, res)) 04294 res = 0; 04295 else 04296 break; 04297 } 04298 04299 /* If we have timed out, break out */ 04300 if (qe->expire && (time(NULL) >= qe->expire)) { 04301 *reason = QUEUE_TIMEOUT; 04302 break; 04303 } 04304 } 04305 04306 return res; 04307 }
| 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 7399 of file app_queue.c.
Referenced by complete_queue().
07399 { 07400 int list_len, word_len = strlen(word); 07401 const char *find, *end_find, *end_list; 07402 07403 /* strip whitespace from front */ 07404 while (isspace(*list)) { 07405 list++; 07406 } 07407 07408 while ((find = strstr(list, word))) { 07409 /* beginning of find starts inside another word? */ 07410 if (find != list && *(find - 1) != ' ') { 07411 list = find; 07412 /* strip word from front */ 07413 while (!isspace(*list) && *list != '\0') { 07414 list++; 07415 } 07416 /* strip whitespace from front */ 07417 while (isspace(*list)) { 07418 list++; 07419 } 07420 continue; 07421 } 07422 07423 /* end of find ends inside another word or at very end of list? */ 07424 list_len = strlen(list); 07425 end_find = find + word_len; 07426 end_list = list + list_len; 07427 if (end_find == end_list || *end_find != ' ') { 07428 list = find; 07429 /* strip word from front */ 07430 while (!isspace(*list) && *list != '\0') { 07431 list++; 07432 } 07433 /* strip whitespace from front */ 07434 while (isspace(*list)) { 07435 list++; 07436 } 07437 continue; 07438 } 07439 07440 /* terminating conditions satisfied, word at beginning or separated by ' ' */ 07441 return 1; 07442 } 07443 07444 return 0; 07445 }
char* app = "Queue" [static] |
Definition at line 901 of file app_queue.c.
char* app_aqm = "AddQueueMember" [static] |
Definition at line 903 of file app_queue.c.
char* app_pqm = "PauseQueueMember" [static] |
Definition at line 907 of file app_queue.c.
char* app_ql = "QueueLog" [static] |
Definition at line 911 of file app_queue.c.
char* app_rqm = "RemoveQueueMember" [static] |
Definition at line 905 of file app_queue.c.
char* app_upqm = "UnpauseQueueMember" [static] |
Definition at line 909 of file app_queue.c.
int autofill_default = 1 [static] |
queues.conf [general] option
Definition at line 923 of file app_queue.c.
struct autopause autopausesmodes[] [static] |
Referenced by autopause2int().
struct ast_cli_entry cli_queue[] [static] |
Definition at line 8443 of file app_queue.c.
struct ast_event_sub* device_state_sub [static] |
Subscription to device state change events.
Definition at line 932 of file app_queue.c.
struct ast_taskprocessor* devicestate_tps [static] |
Definition at line 885 of file app_queue.c.
| enum queue_result id |
Definition at line 949 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 926 of file app_queue.c.
const char* const pm_family = "Queue/PersistentMembers" [static] |
Persistent Members astdb family.
Definition at line 914 of file app_queue.c.
const char qpm_cmd_usage[] [static] |
"Usage: queue pause member <channel> in <queue> reason <reason>\n"
Definition at line 8434 of file app_queue.c.
const char qsmp_cmd_usage[] [static] |
"Usage: queue set member penalty <channel> from <queue> <penalty>\n"
Definition at line 8440 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 8721 of file app_queue.c.
int queue_persistent_members = 0 [static] |
queues.conf [general] option
Definition at line 917 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 4489 of file app_queue.c.
struct ast_custom_function queueexists_function [static] |
{
.name = "QUEUE_EXISTS",
.read = queue_function_exists,
}
Definition at line 6756 of file app_queue.c.
struct ast_custom_function queuemembercount_dep [static] |
{
.name = "QUEUE_MEMBER_COUNT",
.read = queue_function_qac_dep,
}
Definition at line 6771 of file app_queue.c.
struct ast_custom_function queuemembercount_function [static] |
{
.name = "QUEUE_MEMBER",
.read = queue_function_qac,
}
Definition at line 6766 of file app_queue.c.
struct ast_custom_function queuememberlist_function [static] |
{
.name = "QUEUE_MEMBER_LIST",
.read = queue_function_queuememberlist,
}
Definition at line 6781 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 6786 of file app_queue.c.
struct ao2_container* queues [static] |
Definition at line 1190 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 8716 of file app_queue.c.
struct ast_custom_function queuevar_function [static] |
{
.name = "QUEUE_VARIABLES",
.read = queue_function_var,
}
Definition at line 6761 of file app_queue.c.
struct ast_custom_function queuewaitingcount_function [static] |
{
.name = "QUEUE_WAITING_COUNT",
.read = queue_function_queuewaitingcount,
}
Definition at line 6776 of file app_queue.c.
const char qum_cmd_usage[] [static] |
"Usage: queue unpause member <channel> in <queue> reason <reason>\n"
Definition at line 8437 of file app_queue.c.
int shared_lastcall = 1 [static] |
queues.conf [general] option
Definition at line 929 of file app_queue.c.
struct strategy strategies[] [static] |
Referenced by int2strat(), and strat2int().
| char* text |
Definition at line 950 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 935 of file app_queue.c.
Referenced by login_exec().
int use_weight = 0 [static] |
queues.conf per-queue weight option
Definition at line 920 of file app_queue.c.
1.6.1