#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 | rule_lists |
| 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 | PM_MAX_LEN 8192 |
| #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 void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | add_to_queue (const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface) |
| Add member to queue. | |
| static struct call_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 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 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) |
| 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 (const char *context, const 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_load_queue_rt_friendly (const char *queuename) |
| static struct member * | find_member_by_queuename_and_interface (const char *queuename, const char *interface) |
| 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 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 int | member_cmp_fn (void *obj1, void *obj2, int flags) |
| static int | member_hash_fn (const void *obj, const int flags) |
| 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_exec (struct ast_channel *chan, const char *data) |
| The starting point for all queue calls. | |
| static int | queue_function_exists (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| Check if a given queue exists. | |
| static int | queue_function_mem_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| Get number either busy / free / ready or total members of a specific queue. | |
| static int | queue_function_mem_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
| Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ignorebusy. | |
| static int | queue_function_memberpenalty_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. | |
| static int | queue_function_memberpenalty_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
| Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. | |
| static int | queue_function_qac_dep (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| Get the total number of members in a specific queue (Deprecated). | |
| static int | queue_function_queuememberlist (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue. | |
| static int | queue_function_queuewaitingcount (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue. | |
| static int | queue_function_var (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| create interface var with all queue details. | |
| static int | queue_hash_cb (const void *obj, const int flags) |
| static struct 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 | 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, struct ast_config *member_config) |
| Find rt member record to update otherwise create one. | |
| static int | say_periodic_announcement (struct queue_ent *qe, int ringing) |
| Playback announcement to queued members if period has elapsed. | |
| static int | say_position (struct queue_ent *qe, int ringing) |
| static void | send_agent_complete (const 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 int | set_member_penalty_help_members (struct call_queue *q, 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 update_connectedline) |
| 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. | |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, .nonoptreq = "res_monitor", } |
| static char * | app = "Queue" |
| static char * | app_aqm = "AddQueueMember" |
| static char * | app_pqm = "PauseQueueMember" |
| static char * | app_ql = "QueueLog" |
| static char * | app_rqm = "RemoveQueueMember" |
| static char * | app_upqm = "UnpauseQueueMember" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static int | autofill_default = 1 |
| queues.conf [general] option | |
| static struct autopause | autopausesmodes [] |
| static int | check_state_unknown = 0 |
| queues.conf [general] option | |
| 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 | log_membername_as_agent = 0 |
| queues.conf [general] option | |
| static int | montype_default = 0 |
| queues.conf [general] option | |
| static int | negative_penalty_invalid = 0 |
| queues.conf [general] option | |
| static const char *const | pm_family = "Queue/PersistentMembers" |
| Persistent Members astdb family. | |
| static 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 | |
These features added by David C. Troy <dave@toad.net>:
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 |
| #define ANNOUNCEHOLDTIME_ONCE 2 |
| #define ANNOUNCEPOSITION_LIMIT 4 |
We not announce position more than <limit>
Definition at line 1103 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 1102 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 1101 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 1100 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 3534 of file app_queue.c.
| #define DATA_EXPORT_CALL_QUEUE | ( | MEMBER | ) |
Definition at line 8356 of file app_queue.c.
| #define DATA_EXPORT_MEMBER | ( | MEMBER | ) |
Definition at line 8420 of file app_queue.c.
| #define DATA_EXPORT_QUEUE_ENT | ( | MEMBER | ) |
Definition at line 8434 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 906 of file app_queue.c.
Referenced by init_queue().
| #define DEFAULT_RETRY 5 |
| #define DEFAULT_TIMEOUT 15 |
| #define MAX_PERIODIC_ANNOUNCEMENTS 10 |
The maximum periodic announcements we can have
Definition at line 905 of file app_queue.c.
Referenced by destroy_queue(), init_queue(), and queue_set_param().
| #define MAX_QUEUE_BUCKETS 53 |
| #define PM_MAX_LEN 8192 |
Definition at line 931 of file app_queue.c.
Referenced by dump_queue_members(), and reload_queue_members().
| #define QUEUE_EVENT_VARIABLES 3 |
Definition at line 1089 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) |
| #define queue_t_unref | ( | a, | |||
| b | ) | queue_unref(a) |
Definition at line 1302 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_load_queue_rt_friendly(), find_member_by_queuename_and_interface(), find_queue_by_name_rt(), get_member_penalty(), handle_statechange(), join_queue(), leave_queue(), manager_queues_status(), manager_queues_summary(), queue_function_exists(), queue_function_mem_read(), 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(), unload_module(), and update_queue().
| #define queues_t_link | ( | c, | |||
| q, | |||||
| tag | ) | ao2_t_link(c,q,tag) |
Definition at line 1303 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 1304 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 904 of file app_queue.c.
Referenced by wait_our_turn().
| #define RES_EXISTS (-1) |
Entry already exists
Definition at line 911 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 913 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 914 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 910 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 912 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 851 of file app_queue.c.
00851 { 00852 QUEUE_STRATEGY_RINGALL = 0, 00853 QUEUE_STRATEGY_LEASTRECENT, 00854 QUEUE_STRATEGY_FEWESTCALLS, 00855 QUEUE_STRATEGY_RANDOM, 00856 QUEUE_STRATEGY_RRMEMORY, 00857 QUEUE_STRATEGY_LINEAR, 00858 QUEUE_STRATEGY_WRANDOM, 00859 QUEUE_STRATEGY_RRORDERED, 00860 };
| anonymous enum |
Definition at line 862 of file app_queue.c.
00862 { 00863 QUEUE_AUTOPAUSE_OFF = 0, 00864 QUEUE_AUTOPAUSE_ON, 00865 QUEUE_AUTOPAUSE_ALL 00866 };
| 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 1075 of file app_queue.c.
01075 { 01076 QUEUE_EMPTY_PENALTY = (1 << 0), 01077 QUEUE_EMPTY_PAUSED = (1 << 1), 01078 QUEUE_EMPTY_INUSE = (1 << 2), 01079 QUEUE_EMPTY_RINGING = (1 << 3), 01080 QUEUE_EMPTY_UNAVAILABLE = (1 << 4), 01081 QUEUE_EMPTY_INVALID = (1 << 5), 01082 QUEUE_EMPTY_UNKNOWN = (1 << 6), 01083 QUEUE_EMPTY_WRAPUP = (1 << 7), 01084 };
| enum queue_reload_mask |
Definition at line 868 of file app_queue.c.
00868 { 00869 QUEUE_RELOAD_PARAMETERS = (1 << 0), 00870 QUEUE_RELOAD_MEMBER = (1 << 1), 00871 QUEUE_RELOAD_RULES = (1 << 2), 00872 QUEUE_RESET_STATS = (1 << 3), 00873 };
| enum queue_result |
| QUEUE_UNKNOWN | |
| QUEUE_TIMEOUT | |
| QUEUE_JOINEMPTY | |
| QUEUE_LEAVEEMPTY | |
| QUEUE_JOINUNAVAIL | |
| QUEUE_LEAVEUNAVAIL | |
| QUEUE_FULL | |
| QUEUE_CONTINUE |
Definition at line 963 of file app_queue.c.
00963 { 00964 QUEUE_UNKNOWN = 0, 00965 QUEUE_TIMEOUT = 1, 00966 QUEUE_JOINEMPTY = 2, 00967 QUEUE_LEAVEEMPTY = 3, 00968 QUEUE_JOINUNAVAIL = 4, 00969 QUEUE_LEAVEUNAVAIL = 5, 00970 QUEUE_FULL = 6, 00971 QUEUE_CONTINUE = 7, 00972 };
Definition at line 988 of file app_queue.c.
00988 { 00989 TIMEOUT_PRIORITY_APP, 00990 TIMEOUT_PRIORITY_CONF, 00991 };
| 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 7210 of file app_queue.c.
References ao2_container_count(), ao2_iterator_destroy(), AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_category_browse(), ast_channel_name(), ast_check_realtime(), ast_config_destroy(), ast_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, find_load_queue_rt_friendly(), call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, call_queue::maxlen, member::membername, call_queue::members, call_queue::name, queue_ent::next, 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::state_interface, member::status, call_queue::strategy, call_queue::talktime, and call_queue::weight.
Referenced by manager_queues_show(), and queue_show().
07211 { 07212 struct call_queue *q; 07213 struct ast_str *out = ast_str_alloca(240); 07214 int found = 0; 07215 time_t now = time(NULL); 07216 struct ao2_iterator queue_iter; 07217 struct ao2_iterator mem_iter; 07218 07219 if (argc != 2 && argc != 3) { 07220 return CLI_SHOWUSAGE; 07221 } 07222 07223 if (argc == 3) { /* specific queue */ 07224 if ((q = find_load_queue_rt_friendly(argv[2]))) { 07225 queue_t_unref(q, "Done with temporary pointer"); 07226 } 07227 } else if (ast_check_realtime("queues")) { 07228 /* This block is to find any queues which are defined in realtime but 07229 * which have not yet been added to the in-core container 07230 */ 07231 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 07232 char *queuename; 07233 if (cfg) { 07234 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { 07235 if ((q = find_load_queue_rt_friendly(queuename))) { 07236 queue_t_unref(q, "Done with temporary pointer"); 07237 } 07238 } 07239 ast_config_destroy(cfg); 07240 } 07241 } 07242 07243 ao2_lock(queues); 07244 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); 07245 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07246 float sl; 07247 struct call_queue *realtime_queue = NULL; 07248 07249 ao2_lock(q); 07250 /* This check is to make sure we don't print information for realtime 07251 * queues which have been deleted from realtime but which have not yet 07252 * been deleted from the in-core container 07253 */ 07254 if (q->realtime) { 07255 realtime_queue = find_load_queue_rt_friendly(q->name); 07256 if (!realtime_queue) { 07257 ao2_unlock(q); 07258 queue_t_unref(q, "Done with iterator"); 07259 continue; 07260 } 07261 queue_t_unref(realtime_queue, "Queue is already in memory"); 07262 } 07263 07264 if (argc == 3 && strcasecmp(q->name, argv[2])) { 07265 ao2_unlock(q); 07266 queue_t_unref(q, "Done with iterator"); 07267 continue; 07268 } 07269 found = 1; 07270 07271 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count); 07272 if (q->maxlen) 07273 ast_str_append(&out, 0, "%d", q->maxlen); 07274 else 07275 ast_str_append(&out, 0, "unlimited"); 07276 sl = 0; 07277 if (q->callscompleted > 0) 07278 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 07279 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds", 07280 int2strat(q->strategy), q->holdtime, q->talktime, q->weight, 07281 q->callscompleted, q->callsabandoned,sl,q->servicelevel); 07282 do_print(s, fd, ast_str_buffer(out)); 07283 if (!ao2_container_count(q->members)) { 07284 do_print(s, fd, " No Members"); 07285 } else { 07286 struct member *mem; 07287 07288 do_print(s, fd, " Members: "); 07289 mem_iter = ao2_iterator_init(q->members, 0); 07290 while ((mem = ao2_iterator_next(&mem_iter))) { 07291 ast_str_set(&out, 0, " %s", mem->membername); 07292 if (strcasecmp(mem->membername, mem->interface)) { 07293 ast_str_append(&out, 0, " (%s", mem->interface); 07294 if (mem->state_interface) { 07295 ast_str_append(&out, 0, " from %s", mem->state_interface); 07296 } 07297 ast_str_append(&out, 0, ")"); 07298 } 07299 if (mem->penalty) { 07300 ast_str_append(&out, 0, " with penalty %d", mem->penalty); 07301 } 07302 ast_str_append(&out, 0, "%s%s%s (%s)", 07303 mem->dynamic ? " (dynamic)" : "", 07304 mem->realtime ? " (realtime)" : "", 07305 mem->paused ? " (paused)" : "", 07306 ast_devstate2str(mem->status)); 07307 if (mem->calls) { 07308 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)", 07309 mem->calls, (long) (time(NULL) - mem->lastcall)); 07310 } else { 07311 ast_str_append(&out, 0, " has taken no calls yet"); 07312 } 07313 do_print(s, fd, ast_str_buffer(out)); 07314 ao2_ref(mem, -1); 07315 } 07316 ao2_iterator_destroy(&mem_iter); 07317 } 07318 if (!q->head) { 07319 do_print(s, fd, " No Callers"); 07320 } else { 07321 struct queue_ent *qe; 07322 int pos = 1; 07323 07324 do_print(s, fd, " Callers: "); 07325 for (qe = q->head; qe; qe = qe->next) { 07326 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)", 07327 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60, 07328 (long) (now - qe->start) % 60, qe->prio); 07329 do_print(s, fd, ast_str_buffer(out)); 07330 } 07331 } 07332 do_print(s, fd, ""); /* blank line between entries */ 07333 ao2_unlock(q); 07334 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */ 07335 } 07336 ao2_iterator_destroy(&queue_iter); 07337 ao2_unlock(queues); 07338 if (!found) { 07339 if (argc == 3) { 07340 ast_str_set(&out, 0, "No such queue: %s.", argv[2]); 07341 } else { 07342 ast_str_set(&out, 0, "No queues."); 07343 } 07344 do_print(s, fd, ast_str_buffer(out)); 07345 } 07346 return CLI_SUCCESS; 07347 }
| static void __reg_module | ( | void | ) | [static] |
Definition at line 8777 of file app_queue.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 8777 of file app_queue.c.
| static int add_to_queue | ( | const char * | queuename, | |
| const char * | interface, | |||
| const char * | membername, | |||
| int | penalty, | |||
| int | paused, | |||
| int | dump, | |||
| const char * | state_interface | |||
| ) | [static] |
Add member to queue.
| 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 5350 of file app_queue.c.
References ao2_link, ao2_lock, ao2_ref, ao2_unlock, member::calls, create_queue_member(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, find_load_queue_rt_friendly(), member::interface, interface_exists(), member::lastcall, manager_event, member::membername, call_queue::members, call_queue::name, 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().
05351 { 05352 struct call_queue *q; 05353 struct member *new_member, *old_member; 05354 int res = RES_NOSUCHQUEUE; 05355 05356 /*! \note Ensure the appropriate realtime queue is loaded. Note that this 05357 * short-circuits if the queue is already in memory. */ 05358 if (!(q = find_load_queue_rt_friendly(queuename))) { 05359 return res; 05360 } 05361 05362 ao2_lock(q); 05363 if ((old_member = interface_exists(q, interface)) == NULL) { 05364 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { 05365 new_member->dynamic = 1; 05366 ao2_link(q->members, new_member); 05367 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 05368 "Queue: %s\r\n" 05369 "Location: %s\r\n" 05370 "MemberName: %s\r\n" 05371 "StateInterface: %s\r\n" 05372 "Membership: %s\r\n" 05373 "Penalty: %d\r\n" 05374 "CallsTaken: %d\r\n" 05375 "LastCall: %d\r\n" 05376 "Status: %d\r\n" 05377 "Paused: %d\r\n", 05378 q->name, new_member->interface, new_member->membername, state_interface, 05379 "dynamic", 05380 new_member->penalty, new_member->calls, (int) new_member->lastcall, 05381 new_member->status, new_member->paused); 05382 05383 ao2_ref(new_member, -1); 05384 new_member = NULL; 05385 05386 if (dump) { 05387 dump_queue_members(q); 05388 } 05389 05390 res = RES_OKAY; 05391 } else { 05392 res = RES_OUTOFMEMORY; 05393 } 05394 } else { 05395 ao2_ref(old_member, -1); 05396 res = RES_EXISTS; 05397 } 05398 ao2_unlock(q); 05399 queue_t_unref(q, "Expiring temporary reference"); 05400 05401 return res; 05402 }
| static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static, read] |
Definition at line 2242 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().
02243 { 02244 struct call_queue *q; 02245 02246 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) { 02247 if (ast_string_field_init(q, 64)) { 02248 queue_t_unref(q, "String field allocation failed"); 02249 return NULL; 02250 } 02251 ast_string_field_set(q, name, queuename); 02252 } 02253 return q; 02254 }
| static int aqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
AddQueueMember application.
Definition at line 5849 of file app_queue.c.
References add_to_queue(), args, AST_APP_ARG, ast_channel_name(), ast_channel_uniqueid(), AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), member::interface, LOG_ERROR, LOG_NOTICE, LOG_WARNING, member::membername, parse(), pbx_builtin_setvar_helper(), member::penalty, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and member::state_interface.
Referenced by load_module().
05850 { 05851 int res=-1; 05852 char *parse, *temppos = NULL; 05853 AST_DECLARE_APP_ARGS(args, 05854 AST_APP_ARG(queuename); 05855 AST_APP_ARG(interface); 05856 AST_APP_ARG(penalty); 05857 AST_APP_ARG(options); 05858 AST_APP_ARG(membername); 05859 AST_APP_ARG(state_interface); 05860 ); 05861 int penalty = 0; 05862 05863 if (ast_strlen_zero(data)) { 05864 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n"); 05865 return -1; 05866 } 05867 05868 parse = ast_strdupa(data); 05869 05870 AST_STANDARD_APP_ARGS(args, parse); 05871 05872 if (ast_strlen_zero(args.interface)) { 05873 args.interface = ast_strdupa(ast_channel_name(chan)); 05874 temppos = strrchr(args.interface, '-'); 05875 if (temppos) 05876 *temppos = '\0'; 05877 } 05878 05879 if (!ast_strlen_zero(args.penalty)) { 05880 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) { 05881 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 05882 penalty = 0; 05883 } 05884 } 05885 05886 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { 05887 case RES_OKAY: 05888 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) { 05889 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", ""); 05890 } else { 05891 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", ""); 05892 } 05893 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 05894 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 05895 res = 0; 05896 break; 05897 case RES_EXISTS: 05898 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 05899 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 05900 res = 0; 05901 break; 05902 case RES_NOSUCHQUEUE: 05903 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 05904 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 05905 res = 0; 05906 break; 05907 case RES_OUTOFMEMORY: 05908 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename); 05909 break; 05910 } 05911 05912 return res; 05913 }
| AST_DATA_STRUCTURE | ( | queue_ent | , | |
| DATA_EXPORT_QUEUE_ENT | ||||
| ) |
| AST_DATA_STRUCTURE | ( | member | , | |
| DATA_EXPORT_MEMBER | ||||
| ) |
| AST_DATA_STRUCTURE | ( | call_queue | , | |
| DATA_EXPORT_CALL_QUEUE | ||||
| ) |
| static int 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 4337 of file app_queue.c.
References ast_channel_datastore_find(), and queue_transfer_info.
Referenced by try_calling().
04338 { 04339 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1; 04340 }
| static int autopause2int | ( | const char * | autopause | ) | [static] |
Definition at line 1260 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().
01261 { 01262 int x; 01263 /*This 'double check' that default value is OFF */ 01264 if (ast_strlen_zero(autopause)) 01265 return QUEUE_AUTOPAUSE_OFF; 01266 01267 /*This 'double check' is to ensure old values works */ 01268 if(ast_true(autopause)) 01269 return QUEUE_AUTOPAUSE_ON; 01270 01271 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) { 01272 if (!strcasecmp(autopause, autopausesmodes[x].name)) 01273 return autopausesmodes[x].autopause; 01274 } 01275 01276 /*This 'double check' that default value is OFF */ 01277 return QUEUE_AUTOPAUSE_OFF; 01278 }
| 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 4164 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, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.
Referenced by try_calling().
04165 { 04166 /* disregarding penalty on too few members? */ 04167 int membercount = ao2_container_count(q->members); 04168 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1; 04169 04170 if (usepenalty) { 04171 if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || 04172 (qe->min_penalty && (mem->penalty < qe->min_penalty))) { 04173 return -1; 04174 } 04175 } else { 04176 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n", 04177 membercount, q->penaltymemberslimit); 04178 } 04179 04180 switch (q->strategy) { 04181 case QUEUE_STRATEGY_RINGALL: 04182 /* Everyone equal, except for penalty */ 04183 tmp->metric = mem->penalty * 1000000 * usepenalty; 04184 break; 04185 case QUEUE_STRATEGY_LINEAR: 04186 if (pos < qe->linpos) { 04187 tmp->metric = 1000 + pos; 04188 } else { 04189 if (pos > qe->linpos) 04190 /* Indicate there is another priority */ 04191 qe->linwrapped = 1; 04192 tmp->metric = pos; 04193 } 04194 tmp->metric += mem->penalty * 1000000 * usepenalty; 04195 break; 04196 case QUEUE_STRATEGY_RRORDERED: 04197 case QUEUE_STRATEGY_RRMEMORY: 04198 if (pos < q->rrpos) { 04199 tmp->metric = 1000 + pos; 04200 } else { 04201 if (pos > q->rrpos) 04202 /* Indicate there is another priority */ 04203 q->wrapped = 1; 04204 tmp->metric = pos; 04205 } 04206 tmp->metric += mem->penalty * 1000000 * usepenalty; 04207 break; 04208 case QUEUE_STRATEGY_RANDOM: 04209 tmp->metric = ast_random() % 1000; 04210 tmp->metric += mem->penalty * 1000000 * usepenalty; 04211 break; 04212 case QUEUE_STRATEGY_WRANDOM: 04213 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000); 04214 break; 04215 case QUEUE_STRATEGY_FEWESTCALLS: 04216 tmp->metric = mem->calls; 04217 tmp->metric += mem->penalty * 1000000 * usepenalty; 04218 break; 04219 case QUEUE_STRATEGY_LEASTRECENT: 04220 if (!mem->lastcall) 04221 tmp->metric = 0; 04222 else 04223 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 04224 tmp->metric += mem->penalty * 1000000 * usepenalty; 04225 break; 04226 default: 04227 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 04228 break; 04229 } 04230 return 0; 04231 }
| static void callattempt_free | ( | struct callattempt * | doomed | ) | [static] |
Definition at line 2905 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().
02906 { 02907 if (doomed->member) { 02908 ao2_ref(doomed->member, -1); 02909 } 02910 ast_party_connected_line_free(&doomed->connected); 02911 ast_free(doomed); 02912 }
| static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 1778 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().
01779 { 01780 q->holdtime = 0; 01781 q->callscompleted = 0; 01782 q->callsabandoned = 0; 01783 q->callscompletedinsl = 0; 01784 q->talktime = 0; 01785 01786 if (q->members) { 01787 struct member *mem; 01788 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01789 while ((mem = ao2_iterator_next(&mem_iter))) { 01790 mem->calls = 0; 01791 mem->lastcall = 0; 01792 ao2_ref(mem, -1); 01793 } 01794 ao2_iterator_destroy(&mem_iter); 01795 } 01796 }
| 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 7149 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_t_iterator_next, ao2_unlock, ast_strlen_zero(), clear_queue(), call_queue::name, queue_t_unref, and queues.
Referenced by reload_handler().
07150 { 07151 struct call_queue *q; 07152 struct ao2_iterator queue_iter; 07153 07154 queue_iter = ao2_iterator_init(queues, 0); 07155 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07156 ao2_lock(q); 07157 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) 07158 clear_queue(q); 07159 ao2_unlock(q); 07160 queue_t_unref(q, "Done with iterator"); 07161 } 07162 ao2_iterator_destroy(&queue_iter); 07163 return 0; 07164 }
| static int compare_weight | ( | struct call_queue * | rq, | |
| struct member * | member | |||
| ) | [static] |
Definition at line 2993 of file app_queue.c.
References ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_debug, call_queue::count, member::interface, call_queue::members, call_queue::name, num_available_members(), OBJ_POINTER, queue_t_unref, queues, and call_queue::weight.
Referenced by ring_entry().
02994 { 02995 struct call_queue *q; 02996 struct member *mem; 02997 int found = 0; 02998 struct ao2_iterator queue_iter; 02999 03000 queue_iter = ao2_iterator_init(queues, 0); 03001 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 03002 if (q == rq) { /* don't check myself, could deadlock */ 03003 queue_t_unref(q, "Done with iterator"); 03004 continue; 03005 } 03006 ao2_lock(q); 03007 if (q->count && q->members) { 03008 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 03009 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 03010 if (q->weight > rq->weight && q->count >= num_available_members(q)) { 03011 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); 03012 found = 1; 03013 } 03014 ao2_ref(mem, -1); 03015 } 03016 } 03017 ao2_unlock(q); 03018 queue_t_unref(q, "Done with iterator"); 03019 if (found) { 03020 break; 03021 } 03022 } 03023 ao2_iterator_destroy(&queue_iter); 03024 return found; 03025 }
| static char* complete_queue | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 7349 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_strdup, call_queue::name, queue_t_unref, and queues.
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().
07350 { 07351 struct call_queue *q; 07352 char *ret = NULL; 07353 int which = 0; 07354 int wordlen = strlen(word); 07355 struct ao2_iterator queue_iter; 07356 07357 queue_iter = ao2_iterator_init(queues, 0); 07358 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07359 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 07360 ret = ast_strdup(q->name); 07361 queue_t_unref(q, "Done with iterator"); 07362 break; 07363 } 07364 queue_t_unref(q, "Done with iterator"); 07365 } 07366 ao2_iterator_destroy(&queue_iter); 07367 07368 return ret; 07369 }
| static char* complete_queue_add_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 7813 of file app_queue.c.
References ast_malloc, ast_strdup, and complete_queue().
Referenced by handle_queue_add_member().
07814 { 07815 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 07816 switch (pos) { 07817 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 07818 return NULL; 07819 case 4: /* only one possible match, "to" */ 07820 return state == 0 ? ast_strdup("to") : NULL; 07821 case 5: /* <queue> */ 07822 return complete_queue(line, word, pos, state); 07823 case 6: /* only one possible match, "penalty" */ 07824 return state == 0 ? ast_strdup("penalty") : NULL; 07825 case 7: 07826 if (state < 100) { /* 0-99 */ 07827 char *num; 07828 if ((num = ast_malloc(3))) { 07829 sprintf(num, "%d", state); 07830 } 07831 return num; 07832 } else { 07833 return NULL; 07834 } 07835 case 8: /* only one possible match, "as" */ 07836 return state == 0 ? ast_strdup("as") : NULL; 07837 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 07838 return NULL; 07839 default: 07840 return NULL; 07841 } 07842 }
| static char* complete_queue_pause_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 8049 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_pause_member().
08050 { 08051 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */ 08052 switch (pos) { 08053 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 08054 return NULL; 08055 case 4: /* only one possible match, "queue" */ 08056 return state == 0 ? ast_strdup("queue") : NULL; 08057 case 5: /* <queue> */ 08058 return complete_queue(line, word, pos, state); 08059 case 6: /* "reason" */ 08060 return state == 0 ? ast_strdup("reason") : NULL; 08061 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */ 08062 return NULL; 08063 default: 08064 return NULL; 08065 } 08066 }
| static char* complete_queue_remove_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 7947 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().
07948 { 07949 int which = 0; 07950 struct call_queue *q; 07951 struct member *m; 07952 struct ao2_iterator queue_iter; 07953 struct ao2_iterator mem_iter; 07954 int wordlen = strlen(word); 07955 07956 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 07957 if (pos > 5 || pos < 3) 07958 return NULL; 07959 if (pos == 4) /* only one possible match, 'from' */ 07960 return (state == 0 ? ast_strdup("from") : NULL); 07961 07962 if (pos == 5) /* No need to duplicate code */ 07963 return complete_queue(line, word, pos, state); 07964 07965 /* here is the case for 3, <member> */ 07966 queue_iter = ao2_iterator_init(queues, 0); 07967 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07968 ao2_lock(q); 07969 mem_iter = ao2_iterator_init(q->members, 0); 07970 while ((m = ao2_iterator_next(&mem_iter))) { 07971 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) { 07972 char *tmp; 07973 tmp = ast_strdup(m->interface); 07974 ao2_ref(m, -1); 07975 ao2_iterator_destroy(&mem_iter); 07976 ao2_unlock(q); 07977 queue_t_unref(q, "Done with iterator, returning interface name"); 07978 ao2_iterator_destroy(&queue_iter); 07979 return tmp; 07980 } 07981 ao2_ref(m, -1); 07982 } 07983 ao2_iterator_destroy(&mem_iter); 07984 ao2_unlock(q); 07985 queue_t_unref(q, "Done with iterator"); 07986 } 07987 ao2_iterator_destroy(&queue_iter); 07988 07989 return NULL; 07990 }
| static char* complete_queue_rule_show | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 8182 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().
08183 { 08184 int which = 0; 08185 struct rule_list *rl_iter; 08186 int wordlen = strlen(word); 08187 char *ret = NULL; 08188 if (pos != 3) /* Wha? */ { 08189 return NULL; 08190 } 08191 08192 AST_LIST_LOCK(&rule_lists); 08193 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 08194 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) { 08195 ret = ast_strdup(rl_iter->name); 08196 break; 08197 } 08198 } 08199 AST_LIST_UNLOCK(&rule_lists); 08200 08201 return ret; 08202 }
| static char* complete_queue_set_member_penalty | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 8119 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_set_member_penalty().
08120 { 08121 /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/ 08122 switch (pos) { 08123 case 4: 08124 if (state == 0) { 08125 return ast_strdup("on"); 08126 } else { 08127 return NULL; 08128 } 08129 case 6: 08130 if (state == 0) { 08131 return ast_strdup("in"); 08132 } else { 08133 return NULL; 08134 } 08135 case 7: 08136 return complete_queue(line, word, pos, state); 08137 default: 08138 return NULL; 08139 } 08140 }
| static char* complete_queue_show | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 7371 of file app_queue.c.
References complete_queue().
Referenced by queue_show().
07372 { 07373 if (pos == 2) 07374 return complete_queue(line, word, pos, state); 07375 return NULL; 07376 }
| static int compress_char | ( | const char | c | ) | [static] |
Definition at line 1662 of file app_queue.c.
Referenced by member_hash_fn().
01663 { 01664 if (c < 32) 01665 return 0; 01666 else if (c > 96) 01667 return c - 64; 01668 else 01669 return c - 32; 01670 }
| static void copy_rules | ( | struct queue_ent * | qe, | |
| const char * | rulename | |||
| ) | [static] |
Copy rule from global list into specified queue.
Definition at line 5950 of file app_queue.c.
References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), call_queue::defaultrule, LOG_ERROR, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, queue_ent::parent, queue_ent::qe_rules, rule_list::rules, and penalty_rule::time.
Referenced by queue_exec().
05951 { 05952 struct penalty_rule *pr_iter; 05953 struct rule_list *rl_iter; 05954 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename; 05955 AST_LIST_LOCK(&rule_lists); 05956 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 05957 if (!strcasecmp(rl_iter->name, tmp)) 05958 break; 05959 } 05960 if (rl_iter) { 05961 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 05962 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr)); 05963 if (!new_pr) { 05964 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n"); 05965 break; 05966 } 05967 new_pr->time = pr_iter->time; 05968 new_pr->max_value = pr_iter->max_value; 05969 new_pr->min_value = pr_iter->min_value; 05970 new_pr->max_relative = pr_iter->max_relative; 05971 new_pr->min_relative = pr_iter->min_relative; 05972 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list); 05973 } 05974 } 05975 AST_LIST_UNLOCK(&rule_lists); 05976 }
| 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 1627 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, member::status, and strsep().
Referenced by add_to_queue(), reload_single_member(), and rt_handle_member_record().
01628 { 01629 struct member *cur; 01630 01631 if ((cur = ao2_alloc(sizeof(*cur), NULL))) { 01632 cur->penalty = penalty; 01633 cur->paused = paused; 01634 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 01635 if (!ast_strlen_zero(state_interface)) { 01636 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); 01637 } else { 01638 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface)); 01639 } 01640 if (!ast_strlen_zero(membername)) { 01641 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 01642 } else { 01643 ast_copy_string(cur->membername, interface, sizeof(cur->membername)); 01644 } 01645 if (!strchr(cur->interface, '/')) { 01646 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 01647 } 01648 if (!strncmp(cur->state_interface, "hint:", 5)) { 01649 char *tmp = ast_strdupa(cur->state_interface), *context = tmp; 01650 char *exten = strsep(&context, "@") + 5; 01651 01652 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten)); 01653 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context)); 01654 } 01655 cur->status = get_queue_member_status(cur); 01656 } 01657 01658 return cur; 01659 }
| static void destroy_queue | ( | void * | obj | ) | [static] |
Free queue's member list then its string fields.
Definition at line 2228 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().
02229 { 02230 struct call_queue *q = obj; 02231 int i; 02232 02233 free_members(q, 1); 02234 ast_string_field_free_memory(q); 02235 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 02236 if (q->sound_periodicannounce[i]) 02237 free(q->sound_periodicannounce[i]); 02238 } 02239 ao2_ref(q->members, -1); 02240 }
| static void device_state_cb | ( | const struct ast_event * | event, | |
| void * | unused | |||
| ) | [static] |
Definition at line 1525 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(), LOG_ERROR, and statechange::state.
Referenced by load_module(), and load_pbx().
01526 { 01527 enum ast_device_state state; 01528 const char *device; 01529 struct statechange *sc; 01530 size_t datapsize; 01531 01532 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE); 01533 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE); 01534 01535 if (ast_strlen_zero(device)) { 01536 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n"); 01537 return; 01538 } 01539 datapsize = sizeof(*sc) + strlen(device) + 1; 01540 if (!(sc = ast_calloc(1, datapsize))) { 01541 ast_log(LOG_ERROR, "failed to calloc a state change struct\n"); 01542 return; 01543 } 01544 sc->state = state; 01545 strcpy(sc->dev, device); 01546 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) { 01547 ast_free(sc); 01548 } 01549 }
| static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 3028 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry(), and wait_for_answer().
03029 { 03030 o->stillgoing = 0; 03031 ast_hangup(o->chan); 03032 o->chan = NULL; 03033 }
| 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 7196 of file app_queue.c.
References ast_cli(), and astman_append().
Referenced by __queues_show().
07197 { 07198 if (s) 07199 astman_append(s, "%s\r\n", str); 07200 else 07201 ast_cli(fd, "%s\n", str); 07202 }
| 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 5252 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_db_del(), ast_db_put(), ast_log(), member::dynamic, member::interface, LOG_WARNING, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, PM_MAX_LEN, member::state_interface, and value.
Referenced by add_to_queue(), remove_from_queue(), and set_member_paused().
05253 { 05254 struct member *cur_member; 05255 char value[PM_MAX_LEN]; 05256 int value_len = 0; 05257 int res; 05258 struct ao2_iterator mem_iter; 05259 05260 memset(value, 0, sizeof(value)); 05261 05262 if (!pm_queue) 05263 return; 05264 05265 mem_iter = ao2_iterator_init(pm_queue->members, 0); 05266 while ((cur_member = ao2_iterator_next(&mem_iter))) { 05267 if (!cur_member->dynamic) { 05268 ao2_ref(cur_member, -1); 05269 continue; 05270 } 05271 05272 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s", 05273 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface); 05274 05275 ao2_ref(cur_member, -1); 05276 05277 if (res != strlen(value + value_len)) { 05278 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 05279 break; 05280 } 05281 value_len += res; 05282 } 05283 ao2_iterator_destroy(&mem_iter); 05284 05285 if (value_len && !cur_member) { 05286 if (ast_db_put(pm_family, pm_queue->name, value)) 05287 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 05288 } else 05289 /* Delete the entry if the queue is empty or there is an error */ 05290 ast_db_del(pm_family, pm_queue->name); 05291 }
| static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 4384 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().
04385 { 04386 struct queue_end_bridge *qeb = data; 04387 struct call_queue *q = qeb->q; 04388 struct ast_channel *chan = qeb->chan; 04389 04390 if (ao2_ref(qeb, -1) == 1) { 04391 set_queue_variables(q, chan); 04392 /* This unrefs the reference we made in try_calling when we allocated qeb */ 04393 queue_t_unref(q, "Expire bridge_config reference"); 04394 } 04395 }
| static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
| struct ast_channel * | originator, | |||
| struct ast_channel * | terminator | |||
| ) | [static] |
Definition at line 4377 of file app_queue.c.
References ao2_ref, queue_end_bridge::chan, and ast_bridge_config::end_bridge_callback_data.
04378 { 04379 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data; 04380 ao2_ref(qeb, +1); 04381 qeb->chan = originator; 04382 }
| static int extension_state_cb | ( | const char * | context, | |
| const char * | exten, | |||
| enum ast_extension_states | state, | |||
| void * | data | |||
| ) | [static] |
Definition at line 1583 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().
01584 { 01585 struct ao2_iterator miter, qiter; 01586 struct member *m; 01587 struct call_queue *q; 01588 int found = 0, device_state = extensionstate2devicestate(state); 01589 01590 qiter = ao2_iterator_init(queues, 0); 01591 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) { 01592 ao2_lock(q); 01593 01594 miter = ao2_iterator_init(q->members, 0); 01595 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) { 01596 if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) { 01597 update_status(q, m, device_state); 01598 ao2_ref(m, -1); 01599 found = 1; 01600 break; 01601 } 01602 } 01603 ao2_iterator_destroy(&miter); 01604 01605 ao2_unlock(q); 01606 queue_t_unref(q, "Done with iterator"); 01607 } 01608 ao2_iterator_destroy(&qiter); 01609 01610 if (found) { 01611 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state)); 01612 } else { 01613 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", 01614 exten, context, device_state, ast_devstate2str(device_state)); 01615 } 01616 01617 return 0; 01618 }
| static int extensionstate2devicestate | ( | int | state | ) | [static] |
Helper function which converts from extension state to device state values.
Definition at line 1552 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().
01553 { 01554 switch (state) { 01555 case AST_EXTENSION_NOT_INUSE: 01556 state = AST_DEVICE_NOT_INUSE; 01557 break; 01558 case AST_EXTENSION_INUSE: 01559 state = AST_DEVICE_INUSE; 01560 break; 01561 case AST_EXTENSION_BUSY: 01562 state = AST_DEVICE_BUSY; 01563 break; 01564 case AST_EXTENSION_RINGING: 01565 state = AST_DEVICE_RINGING; 01566 break; 01567 case AST_EXTENSION_ONHOLD: 01568 state = AST_DEVICE_ONHOLD; 01569 break; 01570 case AST_EXTENSION_UNAVAILABLE: 01571 state = AST_DEVICE_UNAVAILABLE; 01572 break; 01573 case AST_EXTENSION_REMOVED: 01574 case AST_EXTENSION_DEACTIVATED: 01575 default: 01576 state = AST_DEVICE_INVALID; 01577 break; 01578 } 01579 01580 return state; 01581 }
| static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static, read] |
find the entry with the best metric, or NULL
Definition at line 3285 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
Referenced by ast_cli_command_full(), ring_one(), store_next_lin(), and store_next_rr().
03286 { 03287 struct callattempt *best = NULL, *cur; 03288 03289 for (cur = outgoing; cur; cur = cur->q_next) { 03290 if (cur->stillgoing && /* Not already done */ 03291 !cur->chan && /* Isn't already going */ 03292 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 03293 best = cur; 03294 } 03295 } 03296 03297 return best; 03298 }
| static struct call_queue* find_load_queue_rt_friendly | ( | const char * | queuename | ) | [static, read] |
note
Definition at line 2409 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(), call_queue::name, OBJ_POINTER, queue_t_unref, queues, call_queue::realtime, SENTINEL, update_realtime_members(), and call_queue::weight.
Referenced by __queues_show(), add_to_queue(), find_member_by_queuename_and_interface(), join_queue(), queue_function_exists(), queue_function_mem_read(), queue_function_mem_write(), queue_function_qac_dep(), queues_data_provider_get(), reload_queue_members(), and set_member_penalty().
02410 { 02411 struct ast_variable *queue_vars; 02412 struct ast_config *member_config = NULL; 02413 struct call_queue *q = NULL, tmpq = { 02414 .name = queuename, 02415 }; 02416 int prev_weight = 0; 02417 02418 /* Find the queue in the in-core list first. */ 02419 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first"); 02420 02421 if (!q || q->realtime) { 02422 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all 02423 queue operations while waiting for the DB. 02424 02425 This will be two separate database transactions, so we might 02426 see queue parameters as they were before another process 02427 changed the queue and member list as it was after the change. 02428 Thus we might see an empty member list when a queue is 02429 deleted. In practise, this is unlikely to cause a problem. */ 02430 02431 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL); 02432 if (queue_vars) { 02433 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL); 02434 if (!member_config) { 02435 ast_debug(1, "No queue_members defined in config extconfig.conf\n"); 02436 member_config = ast_config_new(); 02437 } 02438 } 02439 if (q) { 02440 prev_weight = q->weight ? 1 : 0; 02441 queue_t_unref(q, "Need to find realtime queue"); 02442 } 02443 02444 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 02445 ast_config_destroy(member_config); 02446 ast_variables_destroy(queue_vars); 02447 02448 /* update the use_weight value if the queue's has gained or lost a weight */ 02449 if (q) { 02450 if (!q->weight && prev_weight) { 02451 ast_atomic_fetchadd_int(&use_weight, -1); 02452 } 02453 if (q->weight && !prev_weight) { 02454 ast_atomic_fetchadd_int(&use_weight, +1); 02455 } 02456 } 02457 /* Other cases will end up with the proper value for use_weight */ 02458 } else { 02459 update_realtime_members(q); 02460 } 02461 return q; 02462 }
| static struct member * find_member_by_queuename_and_interface | ( | const char * | queuename, | |
| const char * | interface | |||
| ) | [static, read] |
Definition at line 8757 of file app_queue.c.
References ao2_find, ao2_lock, ao2_unlock, find_load_queue_rt_friendly(), call_queue::members, OBJ_KEY, and queue_t_unref.
Referenced by handle_queue_remove_member(), manager_remove_queue_member(), and rqm_exec().
08758 { 08759 struct member *mem = NULL; 08760 struct call_queue *q; 08761 08762 if ((q = find_load_queue_rt_friendly(queuename))) { 08763 ao2_lock(q); 08764 mem = ao2_find(q->members, interface, OBJ_KEY); 08765 ao2_unlock(q); 08766 queue_t_unref(q, "Expiring temporary reference."); 08767 } 08768 return mem; 08769 }
| 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 2266 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_unlink, ao2_unlock, ast_category_browse(), ast_copy_string(), ast_debug, ast_log(), ast_queue_log(), ast_strlen_zero(), clear_queue(), member::dead, call_queue::dead, init_queue(), member::interface, LOG_WARNING, member::membername, call_queue::members, ast_variable::name, call_queue::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(), strat2int(), call_queue::strategy, and ast_variable::value.
Referenced by find_load_queue_rt_friendly().
02267 { 02268 struct ast_variable *v; 02269 struct call_queue *q, tmpq = { 02270 .name = queuename, 02271 }; 02272 struct member *m; 02273 struct ao2_iterator mem_iter; 02274 char *interface = NULL; 02275 const char *tmp_name; 02276 char *tmp; 02277 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 02278 02279 /* Static queues override realtime. */ 02280 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) { 02281 ao2_lock(q); 02282 if (!q->realtime) { 02283 if (q->dead) { 02284 ao2_unlock(q); 02285 queue_t_unref(q, "Queue is dead; can't return it"); 02286 return NULL; 02287 } else { 02288 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); 02289 ao2_unlock(q); 02290 return q; 02291 } 02292 } 02293 } else if (!member_config) { 02294 /* Not found in the list, and it's not realtime ... */ 02295 return NULL; 02296 } 02297 /* Check if queue is defined in realtime. */ 02298 if (!queue_vars) { 02299 /* Delete queue from in-core list if it has been deleted in realtime. */ 02300 if (q) { 02301 /*! \note Hmm, can't seem to distinguish a DB failure from a not 02302 found condition... So we might delete an in-core queue 02303 in case of DB failure. */ 02304 ast_debug(1, "Queue %s not found in realtime.\n", queuename); 02305 02306 q->dead = 1; 02307 /* Delete if unused (else will be deleted when last caller leaves). */ 02308 queues_t_unlink(queues, q, "Unused; removing from container"); 02309 ao2_unlock(q); 02310 queue_t_unref(q, "Queue is dead; can't return it"); 02311 } 02312 return NULL; 02313 } 02314 02315 /* Create a new queue if an in-core entry does not exist yet. */ 02316 if (!q) { 02317 struct ast_variable *tmpvar = NULL; 02318 if (!(q = alloc_queue(queuename))) { 02319 return NULL; 02320 } 02321 ao2_lock(q); 02322 clear_queue(q); 02323 q->realtime = 1; 02324 /*Before we initialize the queue, we need to set the strategy, so that linear strategy 02325 * will allocate the members properly 02326 */ 02327 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) { 02328 if (!strcasecmp(tmpvar->name, "strategy")) { 02329 q->strategy = strat2int(tmpvar->value); 02330 if (q->strategy < 0) { 02331 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 02332 tmpvar->value, q->name); 02333 q->strategy = QUEUE_STRATEGY_RINGALL; 02334 } 02335 break; 02336 } 02337 } 02338 /* We traversed all variables and didn't find a strategy */ 02339 if (!tmpvar) { 02340 q->strategy = QUEUE_STRATEGY_RINGALL; 02341 } 02342 queues_t_link(queues, q, "Add queue to container"); 02343 } 02344 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 02345 02346 memset(tmpbuf, 0, sizeof(tmpbuf)); 02347 for (v = queue_vars; v; v = v->next) { 02348 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 02349 if ((tmp = strchr(v->name, '_'))) { 02350 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 02351 tmp_name = tmpbuf; 02352 tmp = tmpbuf; 02353 while ((tmp = strchr(tmp, '_'))) 02354 *tmp++ = '-'; 02355 } else 02356 tmp_name = v->name; 02357 02358 /* NULL values don't get returned from realtime; blank values should 02359 * still get set. If someone doesn't want a value to be set, they 02360 * should set the realtime column to NULL, not blank. */ 02361 queue_set_param(q, tmp_name, v->value, -1, 0); 02362 } 02363 02364 /* Temporarily set realtime members dead so we can detect deleted ones. */ 02365 mem_iter = ao2_iterator_init(q->members, 0); 02366 while ((m = ao2_iterator_next(&mem_iter))) { 02367 if (m->realtime) { 02368 m->dead = 1; 02369 } 02370 ao2_ref(m, -1); 02371 } 02372 ao2_iterator_destroy(&mem_iter); 02373 02374 while ((interface = ast_category_browse(member_config, interface))) { 02375 rt_handle_member_record(q, interface, member_config); 02376 } 02377 02378 /* Delete all realtime members that have been deleted in DB. */ 02379 mem_iter = ao2_iterator_init(q->members, 0); 02380 while ((m = ao2_iterator_next(&mem_iter))) { 02381 if (m->dead) { 02382 if (ast_strlen_zero(m->membername) || !log_membername_as_agent) { 02383 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 02384 } else { 02385 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", ""); 02386 } 02387 ao2_unlink(q->members, m); 02388 } 02389 ao2_ref(m, -1); 02390 } 02391 ao2_iterator_destroy(&mem_iter); 02392 02393 ao2_unlock(q); 02394 02395 return q; 02396 }
| static void free_members | ( | struct call_queue * | q, | |
| int | all | |||
| ) | [static] |
Iterate through queue's member list and delete them.
Definition at line 2212 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ao2_unlink, member::dynamic, and call_queue::members.
Referenced by destroy_queue().
02213 { 02214 /* Free non-dynamic members */ 02215 struct member *cur; 02216 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 02217 02218 while ((cur = ao2_iterator_next(&mem_iter))) { 02219 if (all || !cur->dynamic) { 02220 ao2_unlink(q->members, cur); 02221 } 02222 ao2_ref(cur, -1); 02223 } 02224 ao2_iterator_destroy(&mem_iter); 02225 }
| static int get_member_penalty | ( | char * | queuename, | |
| char * | interface | |||
| ) | [static] |
Definition at line 5578 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().
05579 { 05580 int foundqueue = 0, penalty; 05581 struct call_queue *q, tmpq = { 05582 .name = queuename, 05583 }; 05584 struct member *mem; 05585 05586 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) { 05587 foundqueue = 1; 05588 ao2_lock(q); 05589 if ((mem = interface_exists(q, interface))) { 05590 penalty = mem->penalty; 05591 ao2_ref(mem, -1); 05592 ao2_unlock(q); 05593 queue_t_unref(q, "Search complete"); 05594 return penalty; 05595 } 05596 ao2_unlock(q); 05597 queue_t_unref(q, "Search complete"); 05598 } 05599 05600 /* some useful debuging */ 05601 if (foundqueue) { 05602 ast_log (LOG_ERROR, "Invalid queuename\n"); 05603 } else { 05604 ast_log (LOG_ERROR, "Invalid interface\n"); 05605 } 05606 05607 return RESULT_FAILURE; 05608 }
| 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 1374 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().
01375 { 01376 struct member *member; 01377 struct ao2_iterator mem_iter; 01378 01379 ao2_lock(q); 01380 mem_iter = ao2_iterator_init(q->members, 0); 01381 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) { 01382 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) { 01383 if (conditions & QUEUE_EMPTY_PENALTY) { 01384 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty); 01385 continue; 01386 } 01387 } 01388 01389 switch (member->status) { 01390 case AST_DEVICE_INVALID: 01391 if (conditions & QUEUE_EMPTY_INVALID) { 01392 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername); 01393 break; 01394 } 01395 goto default_case; 01396 case AST_DEVICE_UNAVAILABLE: 01397 if (conditions & QUEUE_EMPTY_UNAVAILABLE) { 01398 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername); 01399 break; 01400 } 01401 goto default_case; 01402 case AST_DEVICE_INUSE: 01403 if (conditions & QUEUE_EMPTY_INUSE) { 01404 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername); 01405 break; 01406 } 01407 goto default_case; 01408 case AST_DEVICE_RINGING: 01409 if (conditions & QUEUE_EMPTY_RINGING) { 01410 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername); 01411 break; 01412 } 01413 goto default_case; 01414 case AST_DEVICE_UNKNOWN: 01415 if (conditions & QUEUE_EMPTY_UNKNOWN) { 01416 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername); 01417 break; 01418 } 01419 /* Fall-through */ 01420 default: 01421 default_case: 01422 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) { 01423 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername); 01424 break; 01425 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) { 01426 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); 01427 break; 01428 } else { 01429 ao2_ref(member, -1); 01430 ao2_iterator_destroy(&mem_iter); 01431 ao2_unlock(q); 01432 ast_debug(4, "%s is available.\n", member->membername); 01433 return 0; 01434 } 01435 break; 01436 } 01437 } 01438 ao2_iterator_destroy(&mem_iter); 01439 01440 ao2_unlock(q); 01441 return -1; 01442 }
| static int get_queue_member_status | ( | struct member * | cur | ) | [static] |
Return the current state of a member.
Definition at line 1621 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 create_queue_member(), kill_dead_members(), and ring_entry().
01622 { 01623 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten)); 01624 }
| static char* handle_queue_add_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7869 of file app_queue.c.
References add_to_queue(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_add_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, ast_cli_entry::usage, and ast_cli_args::word.
07870 { 07871 const char *queuename, *interface, *membername = NULL, *state_interface = NULL; 07872 int penalty; 07873 07874 switch ( cmd ) { 07875 case CLI_INIT: 07876 e->command = "queue add member"; 07877 e->usage = 07878 "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n" 07879 " Add a channel to a queue with optionally: a penalty, membername and a state_interface\n"; 07880 return NULL; 07881 case CLI_GENERATE: 07882 return complete_queue_add_member(a->line, a->word, a->pos, a->n); 07883 } 07884 07885 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) { 07886 return CLI_SHOWUSAGE; 07887 } else if (strcmp(a->argv[4], "to")) { 07888 return CLI_SHOWUSAGE; 07889 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) { 07890 return CLI_SHOWUSAGE; 07891 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) { 07892 return CLI_SHOWUSAGE; 07893 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) { 07894 return CLI_SHOWUSAGE; 07895 } 07896 07897 queuename = a->argv[5]; 07898 interface = a->argv[3]; 07899 if (a->argc >= 8) { 07900 if (sscanf(a->argv[7], "%30d", &penalty) == 1) { 07901 if (penalty < 0) { 07902 ast_cli(a->fd, "Penalty must be >= 0\n"); 07903 penalty = 0; 07904 } 07905 } else { 07906 ast_cli(a->fd, "Penalty must be an integer >= 0\n"); 07907 penalty = 0; 07908 } 07909 } else { 07910 penalty = 0; 07911 } 07912 07913 if (a->argc >= 10) { 07914 membername = a->argv[9]; 07915 } 07916 07917 if (a->argc >= 12) { 07918 state_interface = a->argv[11]; 07919 } 07920 07921 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { 07922 case RES_OKAY: 07923 if (ast_strlen_zero(membername) || !log_membername_as_agent) { 07924 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 07925 } else { 07926 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", ""); 07927 } 07928 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 07929 return CLI_SUCCESS; 07930 case RES_EXISTS: 07931 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 07932 return CLI_FAILURE; 07933 case RES_NOSUCHQUEUE: 07934 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 07935 return CLI_FAILURE; 07936 case RES_OUTOFMEMORY: 07937 ast_cli(a->fd, "Out of memory\n"); 07938 return CLI_FAILURE; 07939 case RES_NOT_DYNAMIC: 07940 ast_cli(a->fd, "Member not dynamic\n"); 07941 return CLI_FAILURE; 07942 default: 07943 return CLI_FAILURE; 07944 } 07945 }
| static char* handle_queue_pause_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8068 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_pause_member(), ast_cli_args::fd, member::interface, ast_cli_args::line, ast_cli_args::n, member::paused, ast_cli_args::pos, RESULT_SUCCESS, set_member_paused(), ast_cli_entry::usage, and word.
08069 { 08070 const char *queuename, *interface, *reason; 08071 int paused; 08072 08073 switch (cmd) { 08074 case CLI_INIT: 08075 e->command = "queue {pause|unpause} member"; 08076 e->usage = 08077 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n" 08078 " Pause or unpause a queue member. Not specifying a particular queue\n" 08079 " will pause or unpause a member across all queues to which the member\n" 08080 " belongs.\n"; 08081 return NULL; 08082 case CLI_GENERATE: 08083 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n); 08084 } 08085 08086 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) { 08087 return CLI_SHOWUSAGE; 08088 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) { 08089 return CLI_SHOWUSAGE; 08090 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) { 08091 return CLI_SHOWUSAGE; 08092 } 08093 08094 08095 interface = a->argv[3]; 08096 queuename = a->argc >= 6 ? a->argv[5] : NULL; 08097 reason = a->argc == 8 ? a->argv[7] : NULL; 08098 paused = !strcasecmp(a->argv[1], "pause"); 08099 08100 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) { 08101 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface); 08102 if (!ast_strlen_zero(queuename)) 08103 ast_cli(a->fd, " in queue '%s'", queuename); 08104 if (!ast_strlen_zero(reason)) 08105 ast_cli(a->fd, " for reason '%s'", reason); 08106 ast_cli(a->fd, "\n"); 08107 return CLI_SUCCESS; 08108 } else { 08109 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface); 08110 if (!ast_strlen_zero(queuename)) 08111 ast_cli(a->fd, " in queue '%s'", queuename); 08112 if (!ast_strlen_zero(reason)) 08113 ast_cli(a->fd, " for reason '%s'", reason); 08114 ast_cli(a->fd, "\n"); 08115 return CLI_FAILURE; 08116 } 08117 }
| static char* handle_queue_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8277 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.
08278 { 08279 struct ast_flags mask = {0,}; 08280 int i; 08281 08282 switch (cmd) { 08283 case CLI_INIT: 08284 e->command = "queue reload {parameters|members|rules|all}"; 08285 e->usage = 08286 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n" 08287 "Reload queues. If <queuenames> are specified, only reload information pertaining\n" 08288 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n" 08289 "specified in order to know what information to reload. Below is an explanation\n" 08290 "of each of these qualifiers.\n" 08291 "\n" 08292 "\t'members' - reload queue members from queues.conf\n" 08293 "\t'parameters' - reload all queue options except for queue members\n" 08294 "\t'rules' - reload the queuerules.conf file\n" 08295 "\t'all' - reload queue rules, parameters, and members\n" 08296 "\n" 08297 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n" 08298 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n" 08299 "one queue is specified when using this command, reloading queue rules may cause\n" 08300 "other queues to be affected\n"; 08301 return NULL; 08302 case CLI_GENERATE: 08303 if (a->pos >= 3) { 08304 return complete_queue(a->line, a->word, a->pos, a->n); 08305 } else { 08306 return NULL; 08307 } 08308 } 08309 08310 if (a->argc < 3) 08311 return CLI_SHOWUSAGE; 08312 08313 if (!strcasecmp(a->argv[2], "rules")) { 08314 ast_set_flag(&mask, QUEUE_RELOAD_RULES); 08315 } else if (!strcasecmp(a->argv[2], "members")) { 08316 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER); 08317 } else if (!strcasecmp(a->argv[2], "parameters")) { 08318 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); 08319 } else if (!strcasecmp(a->argv[2], "all")) { 08320 ast_set_flag(&mask, AST_FLAGS_ALL); 08321 } 08322 08323 if (a->argc == 3) { 08324 reload_handler(1, &mask, NULL); 08325 return CLI_SUCCESS; 08326 } 08327 08328 for (i = 3; i < a->argc; ++i) { 08329 reload_handler(1, &mask, a->argv[i]); 08330 } 08331 08332 return CLI_SUCCESS; 08333 }
| static char* handle_queue_remove_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7992 of file app_queue.c.
References ao2_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_remove_member(), ast_cli_args::fd, find_member_by_queuename_and_interface(), ast_cli_args::line, member::membername, ast_cli_args::n, 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.
07993 { 07994 const char *queuename, *interface; 07995 struct member *mem = NULL; 07996 07997 switch (cmd) { 07998 case CLI_INIT: 07999 e->command = "queue remove member"; 08000 e->usage = 08001 "Usage: queue remove member <channel> from <queue>\n" 08002 " Remove a specific channel from a queue.\n"; 08003 return NULL; 08004 case CLI_GENERATE: 08005 return complete_queue_remove_member(a->line, a->word, a->pos, a->n); 08006 } 08007 08008 if (a->argc != 6) { 08009 return CLI_SHOWUSAGE; 08010 } else if (strcmp(a->argv[4], "from")) { 08011 return CLI_SHOWUSAGE; 08012 } 08013 08014 queuename = a->argv[5]; 08015 interface = a->argv[3]; 08016 08017 switch (remove_from_queue(queuename, interface)) { 08018 case RES_OKAY: 08019 if (log_membername_as_agent) { 08020 mem = find_member_by_queuename_and_interface(queuename, interface); 08021 } 08022 if (!mem || ast_strlen_zero(mem->membername)) { 08023 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 08024 } else { 08025 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", ""); 08026 } 08027 if (mem) { 08028 ao2_ref(mem, -1); 08029 } 08030 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename); 08031 return CLI_SUCCESS; 08032 case RES_EXISTS: 08033 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 08034 return CLI_FAILURE; 08035 case RES_NOSUCHQUEUE: 08036 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 08037 return CLI_FAILURE; 08038 case RES_OUTOFMEMORY: 08039 ast_cli(a->fd, "Out of memory\n"); 08040 return CLI_FAILURE; 08041 case RES_NOT_DYNAMIC: 08042 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename); 08043 return CLI_FAILURE; 08044 default: 08045 return CLI_FAILURE; 08046 } 08047 }
| static char* handle_queue_reset | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8238 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.
08239 { 08240 struct ast_flags mask = {QUEUE_RESET_STATS,}; 08241 int i; 08242 08243 switch (cmd) { 08244 case CLI_INIT: 08245 e->command = "queue reset stats"; 08246 e->usage = 08247 "Usage: queue reset stats [<queuenames>]\n" 08248 "\n" 08249 "Issuing this command will reset statistics for\n" 08250 "<queuenames>, or for all queues if no queue is\n" 08251 "specified.\n"; 08252 return NULL; 08253 case CLI_GENERATE: 08254 if (a->pos >= 3) { 08255 return complete_queue(a->line, a->word, a->pos, a->n); 08256 } else { 08257 return NULL; 08258 } 08259 } 08260 08261 if (a->argc < 3) { 08262 return CLI_SHOWUSAGE; 08263 } 08264 08265 if (a->argc == 3) { 08266 reload_handler(1, &mask, NULL); 08267 return CLI_SUCCESS; 08268 } 08269 08270 for (i = 3; i < a->argc; ++i) { 08271 reload_handler(1, &mask, a->argv[i]); 08272 } 08273 08274 return CLI_SUCCESS; 08275 }
| static char* handle_queue_rule_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8204 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, rule_list::rules, penalty_rule::time, ast_cli_entry::usage, and ast_cli_args::word.
08205 { 08206 const char *rule; 08207 struct rule_list *rl_iter; 08208 struct penalty_rule *pr_iter; 08209 switch (cmd) { 08210 case CLI_INIT: 08211 e->command = "queue show rules"; 08212 e->usage = 08213 "Usage: queue show rules [rulename]\n" 08214 " Show the list of rules associated with rulename. If no\n" 08215 " rulename is specified, list all rules defined in queuerules.conf\n"; 08216 return NULL; 08217 case CLI_GENERATE: 08218 return complete_queue_rule_show(a->line, a->word, a->pos, a->n); 08219 } 08220 08221 if (a->argc != 3 && a->argc != 4) 08222 return CLI_SHOWUSAGE; 08223 08224 rule = a->argc == 4 ? a->argv[3] : ""; 08225 AST_LIST_LOCK(&rule_lists); 08226 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 08227 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) { 08228 ast_cli(a->fd, "Rule: %s\n", rl_iter->name); 08229 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 08230 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); 08231 } 08232 } 08233 } 08234 AST_LIST_UNLOCK(&rule_lists); 08235 return CLI_SUCCESS; 08236 }
| static char* handle_queue_set_member_penalty | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 8142 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, member::interface, ast_cli_args::line, ast_cli_args::n, member::penalty, ast_cli_args::pos, RESULT_FAILURE, RESULT_SUCCESS, set_member_penalty(), ast_cli_entry::usage, and ast_cli_args::word.
08143 { 08144 const char *queuename = NULL, *interface; 08145 int penalty = 0; 08146 08147 switch (cmd) { 08148 case CLI_INIT: 08149 e->command = "queue set penalty"; 08150 e->usage = 08151 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n" 08152 " Set a member's penalty in the queue specified. If no queue is specified\n" 08153 " then that interface's penalty is set in all queues to which that interface is a member\n"; 08154 return NULL; 08155 case CLI_GENERATE: 08156 return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n); 08157 } 08158 08159 if (a->argc != 6 && a->argc != 8) { 08160 return CLI_SHOWUSAGE; 08161 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) { 08162 return CLI_SHOWUSAGE; 08163 } 08164 08165 if (a->argc == 8) 08166 queuename = a->argv[7]; 08167 interface = a->argv[5]; 08168 penalty = atoi(a->argv[3]); 08169 08170 switch (set_member_penalty(queuename, interface, penalty)) { 08171 case RESULT_SUCCESS: 08172 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename); 08173 return CLI_SUCCESS; 08174 case RESULT_FAILURE: 08175 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename); 08176 return CLI_FAILURE; 08177 default: 08178 return CLI_FAILURE; 08179 } 08180 }
| static int handle_statechange | ( | void * | datap | ) | [static] |
set a member's status based on device state of that member's interface
Definition at line 1481 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, statechange::state, member::state_interface, and update_status().
Referenced by device_state_cb().
01482 { 01483 struct statechange *sc = datap; 01484 struct ao2_iterator miter, qiter; 01485 struct member *m; 01486 struct call_queue *q; 01487 char interface[80], *slash_pos; 01488 int found = 0; 01489 01490 qiter = ao2_iterator_init(queues, 0); 01491 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) { 01492 ao2_lock(q); 01493 01494 miter = ao2_iterator_init(q->members, 0); 01495 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) { 01496 ast_copy_string(interface, m->state_interface, sizeof(interface)); 01497 01498 if ((slash_pos = strchr(interface, '/'))) 01499 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) 01500 *slash_pos = '\0'; 01501 01502 if (!strcasecmp(interface, sc->dev)) { 01503 found = 1; 01504 update_status(q, m, sc->state); 01505 ao2_ref(m, -1); 01506 break; 01507 } 01508 } 01509 ao2_iterator_destroy(&miter); 01510 01511 ao2_unlock(q); 01512 queue_t_unref(q, "Done with iterator"); 01513 } 01514 ao2_iterator_destroy(&qiter); 01515 01516 if (found) 01517 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state)); 01518 else 01519 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)); 01520 01521 ast_free(sc); 01522 return 0; 01523 }
| 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 2915 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().
02916 { 02917 struct callattempt *oo; 02918 02919 while (outgoing) { 02920 /* If someone else answered the call we should indicate this in the CANCEL */ 02921 /* Hangup any existing lines we have open */ 02922 if (outgoing->chan && (outgoing->chan != exception)) { 02923 if (exception || cancel_answered_elsewhere) 02924 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE); 02925 ast_hangup(outgoing->chan); 02926 } 02927 oo = outgoing; 02928 outgoing = outgoing->q_next; 02929 ast_aoc_destroy_decoded(oo->aoc_s_rate_list); 02930 callattempt_free(oo); 02931 } 02932 }
| static void init_queue | ( | struct call_queue * | q | ) | [static] |
Initialize Queue default values.
Definition at line 1701 of file app_queue.c.
References 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::autopausedelay, 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::rules, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::setqueueentryvar, call_queue::setqueuevar, call_queue::sound_periodicannounce, call_queue::strategy, call_queue::timeout, TIMEOUT_PRIORITY_APP, call_queue::timeoutpriority, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_single_queue().
01702 { 01703 int i; 01704 struct penalty_rule *pr_iter; 01705 01706 q->dead = 0; 01707 q->retry = DEFAULT_RETRY; 01708 q->timeout = DEFAULT_TIMEOUT; 01709 q->maxlen = 0; 01710 q->announcefrequency = 0; 01711 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY; 01712 q->announceholdtime = 1; 01713 q->announcepositionlimit = 10; /* Default 10 positions */ 01714 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */ 01715 q->roundingseconds = 0; /* Default - don't announce seconds */ 01716 q->servicelevel = 0; 01717 q->ringinuse = 1; 01718 q->setinterfacevar = 0; 01719 q->setqueuevar = 0; 01720 q->setqueueentryvar = 0; 01721 q->autofill = autofill_default; 01722 q->montype = montype_default; 01723 q->monfmt[0] = '\0'; 01724 q->reportholdtime = 0; 01725 q->wrapuptime = 0; 01726 q->penaltymemberslimit = 0; 01727 q->joinempty = 0; 01728 q->leavewhenempty = 0; 01729 q->memberdelay = 0; 01730 q->maskmemberstatus = 0; 01731 q->eventwhencalled = 0; 01732 q->weight = 0; 01733 q->timeoutrestart = 0; 01734 q->periodicannouncefrequency = 0; 01735 q->randomperiodicannounce = 0; 01736 q->numperiodicannounce = 0; 01737 q->autopause = QUEUE_AUTOPAUSE_OFF; 01738 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 01739 q->autopausedelay = 0; 01740 if (!q->members) { 01741 if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) 01742 /* linear strategy depends on order, so we have to place all members in a single bucket */ 01743 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn); 01744 else 01745 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn); 01746 } 01747 q->found = 1; 01748 01749 ast_string_field_set(q, sound_next, "queue-youarenext"); 01750 ast_string_field_set(q, sound_thereare, "queue-thereare"); 01751 ast_string_field_set(q, sound_calls, "queue-callswaiting"); 01752 ast_string_field_set(q, queue_quantity1, "queue-quantity1"); 01753 ast_string_field_set(q, queue_quantity2, "queue-quantity2"); 01754 ast_string_field_set(q, sound_holdtime, "queue-holdtime"); 01755 ast_string_field_set(q, sound_minutes, "queue-minutes"); 01756 ast_string_field_set(q, sound_minute, "queue-minute"); 01757 ast_string_field_set(q, sound_seconds, "queue-seconds"); 01758 ast_string_field_set(q, sound_thanks, "queue-thankyou"); 01759 ast_string_field_set(q, sound_reporthold, "queue-reporthold"); 01760 01761 if (!q->sound_periodicannounce[0]) { 01762 q->sound_periodicannounce[0] = ast_str_create(32); 01763 } 01764 01765 if (q->sound_periodicannounce[0]) { 01766 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce"); 01767 } 01768 01769 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 01770 if (q->sound_periodicannounce[i]) 01771 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", ""); 01772 } 01773 01774 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) 01775 ast_free(pr_iter); 01776 }
| 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 1344 of file app_queue.c.
References call_queue::head, queue_ent::next, and queue_ref().
Referenced by join_queue().
01345 { 01346 struct queue_ent *cur; 01347 01348 if (!q || !new) 01349 return; 01350 if (prev) { 01351 cur = prev->next; 01352 prev->next = new; 01353 } else { 01354 cur = q->head; 01355 q->head = new; 01356 } 01357 new->next = cur; 01358 01359 /* every queue_ent must have a reference to it's parent call_queue, this 01360 * reference does not go away until the end of the queue_ent's life, meaning 01361 * that even when the queue_ent leaves the call_queue this ref must remain. */ 01362 queue_ref(q); 01363 new->parent = q; 01364 new->pos = ++(*pos); 01365 new->opos = *pos; 01366 }
| 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 1807 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, rule_list::rules, and penalty_rule::time.
Referenced by reload_queue_rules().
01808 { 01809 char *timestr, *maxstr, *minstr, *contentdup; 01810 struct penalty_rule *rule = NULL, *rule_iter; 01811 struct rule_list *rl_iter; 01812 int penaltychangetime, inserted = 0; 01813 01814 if (!(rule = ast_calloc(1, sizeof(*rule)))) { 01815 return -1; 01816 } 01817 01818 contentdup = ast_strdupa(content); 01819 01820 if (!(maxstr = strchr(contentdup, ','))) { 01821 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum); 01822 ast_free(rule); 01823 return -1; 01824 } 01825 01826 *maxstr++ = '\0'; 01827 timestr = contentdup; 01828 01829 if ((penaltychangetime = atoi(timestr)) < 0) { 01830 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum); 01831 ast_free(rule); 01832 return -1; 01833 } 01834 01835 rule->time = penaltychangetime; 01836 01837 if ((minstr = strchr(maxstr,','))) 01838 *minstr++ = '\0'; 01839 01840 /* The last check will evaluate true if either no penalty change is indicated for a given rule 01841 * OR if a min penalty change is indicated but no max penalty change is */ 01842 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') { 01843 rule->max_relative = 1; 01844 } 01845 01846 rule->max_value = atoi(maxstr); 01847 01848 if (!ast_strlen_zero(minstr)) { 01849 if (*minstr == '+' || *minstr == '-') 01850 rule->min_relative = 1; 01851 rule->min_value = atoi(minstr); 01852 } else /*there was no minimum specified, so assume this means no change*/ 01853 rule->min_relative = 1; 01854 01855 /*We have the rule made, now we need to insert it where it belongs*/ 01856 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){ 01857 if (strcasecmp(rl_iter->name, list_name)) 01858 continue; 01859 01860 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) { 01861 if (rule->time < rule_iter->time) { 01862 AST_LIST_INSERT_BEFORE_CURRENT(rule, list); 01863 inserted = 1; 01864 break; 01865 } 01866 } 01867 AST_LIST_TRAVERSE_SAFE_END; 01868 01869 if (!inserted) { 01870 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list); 01871 } 01872 } 01873 01874 return 0; 01875 }
| static const char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 1236 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().
01237 { 01238 int x; 01239 01240 for (x = 0; x < ARRAY_LEN(strategies); x++) { 01241 if (strategy == strategies[x].strategy) 01242 return strategies[x].name; 01243 } 01244 01245 return "<unknown>"; 01246 }
| static struct member * interface_exists | ( | struct call_queue * | q, | |
| const char * | interface | |||
| ) | [static, read] |
Definition at line 5226 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(), queue_function_mem_read(), queue_function_mem_write(), rna(), set_member_paused(), and set_member_penalty_help_members().
05227 { 05228 struct member *mem; 05229 struct ao2_iterator mem_iter; 05230 05231 if (!q) { 05232 return NULL; 05233 } 05234 mem_iter = ao2_iterator_init(q->members, 0); 05235 while ((mem = ao2_iterator_next(&mem_iter))) { 05236 if (!strcasecmp(interface, mem->interface)) { 05237 ao2_iterator_destroy(&mem_iter); 05238 return mem; 05239 } 05240 ao2_ref(mem, -1); 05241 } 05242 ao2_iterator_destroy(&mem_iter); 05243 05244 return NULL; 05245 }
| 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 3965 of file app_queue.c.
References ao2_lock, ao2_unlock, ast_channel_name(), ast_debug, call_queue::autofill, queue_ent::chan, call_queue::head, queue_ent::next, num_available_members(), queue_ent::parent, queue_ent::pending, and queue_ent::pos.
Referenced by queue_exec(), and wait_our_turn().
03966 { 03967 struct queue_ent *ch; 03968 int res; 03969 int avl; 03970 int idx = 0; 03971 /* This needs a lock. How many members are available to be served? */ 03972 ao2_lock(qe->parent); 03973 03974 avl = num_available_members(qe->parent); 03975 03976 ch = qe->parent->head; 03977 03978 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member"); 03979 03980 while ((idx < avl) && (ch) && (ch != qe)) { 03981 if (!ch->pending) 03982 idx++; 03983 ch = ch->next; 03984 } 03985 03986 ao2_unlock(qe->parent); 03987 /* If the queue entry is within avl [the number of available members] calls from the top ... 03988 * Autofill and position check added to support autofill=no (as only calls 03989 * from the front of the queue are valid when autofill is disabled) 03990 */ 03991 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) { 03992 ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan)); 03993 res = 1; 03994 } else { 03995 ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan)); 03996 res = 0; 03997 } 03998 03999 return res; 04000 }
| static int join_queue | ( | char * | queuename, | |
| struct queue_ent * | qe, | |||
| enum queue_result * | reason, | |||
| int | position | |||
| ) | [static] |
Definition at line 2524 of file app_queue.c.
References call_queue::announce, queue_ent::announce, ao2_lock, ao2_unlock, ast_channel_name(), ast_channel_uniqueid(), ast_copy_string(), ast_debug, ast_log(), ast_manager_event, ast_channel::caller, queue_ent::chan, ast_channel::connected, call_queue::context, queue_ent::context, call_queue::count, EVENT_FLAG_CALL, find_load_queue_rt_friendly(), get_member_status(), call_queue::head, ast_party_connected_line::id, ast_party_caller::id, insert_entry(), call_queue::joinempty, LOG_NOTICE, queue_ent::max_penalty, call_queue::maxlen, queue_ent::min_penalty, call_queue::moh, queue_ent::moh, call_queue::name, ast_party_id::name, queue_ent::next, 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().
02525 { 02526 struct call_queue *q; 02527 struct queue_ent *cur, *prev = NULL; 02528 int res = -1; 02529 int pos = 0; 02530 int inserted = 0; 02531 02532 if (!(q = find_load_queue_rt_friendly(queuename))) { 02533 return res; 02534 } 02535 ao2_lock(q); 02536 02537 /* This is our one */ 02538 if (q->joinempty) { 02539 int status = 0; 02540 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) { 02541 *reason = QUEUE_JOINEMPTY; 02542 ao2_unlock(q); 02543 queue_t_unref(q, "Done with realtime queue"); 02544 return res; 02545 } 02546 } 02547 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) 02548 *reason = QUEUE_FULL; 02549 else if (*reason == QUEUE_UNKNOWN) { 02550 /* There's space for us, put us at the right position inside 02551 * the queue. 02552 * Take into account the priority of the calling user */ 02553 inserted = 0; 02554 prev = NULL; 02555 cur = q->head; 02556 while (cur) { 02557 /* We have higher priority than the current user, enter 02558 * before him, after all the other users with priority 02559 * higher or equal to our priority. */ 02560 if ((!inserted) && (qe->prio > cur->prio)) { 02561 insert_entry(q, prev, qe, &pos); 02562 inserted = 1; 02563 } 02564 /* <= is necessary for the position comparison because it may not be possible to enter 02565 * at our desired position since higher-priority callers may have taken the position we want 02566 */ 02567 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) { 02568 insert_entry(q, prev, qe, &pos); 02569 /*pos is incremented inside insert_entry, so don't need to add 1 here*/ 02570 if (position < pos) { 02571 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos); 02572 } 02573 inserted = 1; 02574 } 02575 cur->pos = ++pos; 02576 prev = cur; 02577 cur = cur->next; 02578 } 02579 /* No luck, join at the end of the queue */ 02580 if (!inserted) 02581 insert_entry(q, prev, qe, &pos); 02582 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 02583 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 02584 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 02585 q->count++; 02586 res = 0; 02587 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join", 02588 "Channel: %s\r\n" 02589 "CallerIDNum: %s\r\n" 02590 "CallerIDName: %s\r\n" 02591 "ConnectedLineNum: %s\r\n" 02592 "ConnectedLineName: %s\r\n" 02593 "Queue: %s\r\n" 02594 "Position: %d\r\n" 02595 "Count: %d\r\n" 02596 "Uniqueid: %s\r\n", 02597 ast_channel_name(qe->chan), 02598 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */ 02599 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 02600 S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */ 02601 S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), 02602 q->name, qe->pos, q->count, ast_channel_uniqueid(qe->chan)); 02603 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos ); 02604 } 02605 ao2_unlock(q); 02606 queue_t_unref(q, "Done with realtime queue"); 02607 02608 return res; 02609 }
| static int kill_dead_members | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 6937 of file app_queue.c.
References CMP_MATCH, member::delme, get_queue_member_status(), and member::status.
Referenced by reload_single_queue().
06938 { 06939 struct member *member = obj; 06940 06941 if (!member->delme) { 06942 member->status = get_queue_member_status(member); 06943 return 0; 06944 } else { 06945 return CMP_MATCH; 06946 } 06947 }
| static int kill_dead_queues | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 7066 of file app_queue.c.
References ast_strlen_zero(), CMP_MATCH, call_queue::dead, and call_queue::name.
Referenced by reload_queues().
07067 { 07068 struct call_queue *q = obj; 07069 char *queuename = arg; 07070 if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) { 07071 return CMP_MATCH; 07072 } else { 07073 return 0; 07074 } 07075 }
| 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 2836 of file app_queue.c.
References ao2_lock, ao2_unlock, ast_channel_name(), ast_channel_uniqueid(), 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, call_queue::name, queue_ent::next, queue_ent::parent, pbx_builtin_setvar_helper(), queue_ent::pos, queue_ent::qe_rules, 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().
02837 { 02838 struct call_queue *q; 02839 struct queue_ent *current, *prev = NULL; 02840 struct penalty_rule *pr_iter; 02841 int pos = 0; 02842 02843 if (!(q = qe->parent)) { 02844 return; 02845 } 02846 queue_t_ref(q, "Copy queue pointer from queue entry"); 02847 ao2_lock(q); 02848 02849 prev = NULL; 02850 for (current = q->head; current; current = current->next) { 02851 if (current == qe) { 02852 char posstr[20]; 02853 q->count--; 02854 02855 /* Take us out of the queue */ 02856 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave", 02857 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n", 02858 ast_channel_name(qe->chan), q->name, q->count, qe->pos, ast_channel_uniqueid(qe->chan)); 02859 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan)); 02860 /* Take us out of the queue */ 02861 if (prev) 02862 prev->next = current->next; 02863 else 02864 q->head = current->next; 02865 /* Free penalty rules */ 02866 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) 02867 ast_free(pr_iter); 02868 snprintf(posstr, sizeof(posstr), "%d", qe->pos); 02869 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr); 02870 } else { 02871 /* Renumber the people after us in the queue based on a new count */ 02872 current->pos = ++pos; 02873 prev = current; 02874 } 02875 } 02876 ao2_unlock(q); 02877 02878 /*If the queue is a realtime queue, check to see if it's still defined in real time*/ 02879 if (q->realtime) { 02880 struct ast_variable *var; 02881 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) { 02882 q->dead = 1; 02883 } else { 02884 ast_variables_destroy(var); 02885 } 02886 } 02887 02888 if (q->dead) { 02889 /* It's dead and nobody is in it, so kill it */ 02890 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container"); 02891 } 02892 /* unref the explicit ref earlier in the function */ 02893 queue_t_unref(q, "Expire copied reference"); 02894 }
| static int load_module | ( | void | ) | [static] |
Definition at line 8680 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(), cli_queue, 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_data_providers, queue_exec(), queue_hash_cb(), queueexists_function, queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queuevar_function, queuewaitingcount_function, reload_handler(), reload_queue_members(), RQ_INTEGER1, RQ_UINTEGER2, rqm_exec(), SENTINEL, and upqm_exec().
08681 { 08682 int res; 08683 struct ast_context *con; 08684 struct ast_flags mask = {AST_FLAGS_ALL, }; 08685 08686 queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb); 08687 08688 use_weight = 0; 08689 08690 if (reload_handler(0, &mask, NULL)) 08691 return AST_MODULE_LOAD_DECLINE; 08692 08693 con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue"); 08694 if (!con) 08695 ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n"); 08696 else 08697 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue"); 08698 08699 if (queue_persistent_members) 08700 reload_queue_members(); 08701 08702 ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers)); 08703 08704 ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue)); 08705 res = ast_register_application_xml(app, queue_exec); 08706 res |= ast_register_application_xml(app_aqm, aqm_exec); 08707 res |= ast_register_application_xml(app_rqm, rqm_exec); 08708 res |= ast_register_application_xml(app_pqm, pqm_exec); 08709 res |= ast_register_application_xml(app_upqm, upqm_exec); 08710 res |= ast_register_application_xml(app_ql, ql_exec); 08711 res |= ast_manager_register_xml("Queues", 0, manager_queues_show); 08712 res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status); 08713 res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary); 08714 res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member); 08715 res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member); 08716 res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member); 08717 res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom); 08718 res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty); 08719 res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show); 08720 res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload); 08721 res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset); 08722 res |= ast_custom_function_register(&queuevar_function); 08723 res |= ast_custom_function_register(&queueexists_function); 08724 res |= ast_custom_function_register(&queuemembercount_function); 08725 res |= ast_custom_function_register(&queuemembercount_dep); 08726 res |= ast_custom_function_register(&queuememberlist_function); 08727 res |= ast_custom_function_register(&queuewaitingcount_function); 08728 res |= ast_custom_function_register(&queuememberpenalty_function); 08729 08730 if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) { 08731 ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n"); 08732 } 08733 08734 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */ 08735 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) { 08736 res = -1; 08737 } 08738 08739 ast_extension_state_add(NULL, NULL, extension_state_cb, NULL); 08740 08741 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL); 08742 08743 return res ? AST_MODULE_LOAD_DECLINE : 0; 08744 }
| static int manager_add_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7619 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().
07620 { 07621 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; 07622 int paused, penalty = 0; 07623 07624 queuename = astman_get_header(m, "Queue"); 07625 interface = astman_get_header(m, "Interface"); 07626 penalty_s = astman_get_header(m, "Penalty"); 07627 paused_s = astman_get_header(m, "Paused"); 07628 membername = astman_get_header(m, "MemberName"); 07629 state_interface = astman_get_header(m, "StateInterface"); 07630 07631 if (ast_strlen_zero(queuename)) { 07632 astman_send_error(s, m, "'Queue' not specified."); 07633 return 0; 07634 } 07635 07636 if (ast_strlen_zero(interface)) { 07637 astman_send_error(s, m, "'Interface' not specified."); 07638 return 0; 07639 } 07640 07641 if (ast_strlen_zero(penalty_s)) 07642 penalty = 0; 07643 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) 07644 penalty = 0; 07645 07646 if (ast_strlen_zero(paused_s)) 07647 paused = 0; 07648 else 07649 paused = abs(ast_true(paused_s)); 07650 07651 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { 07652 case RES_OKAY: 07653 if (ast_strlen_zero(membername) || !log_membername_as_agent) { 07654 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); 07655 } else { 07656 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); 07657 } 07658 astman_send_ack(s, m, "Added interface to queue"); 07659 break; 07660 case RES_EXISTS: 07661 astman_send_error(s, m, "Unable to add interface: Already there"); 07662 break; 07663 case RES_NOSUCHQUEUE: 07664 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 07665 break; 07666 case RES_OUTOFMEMORY: 07667 astman_send_error(s, m, "Out of memory"); 07668 break; 07669 } 07670 07671 return 0; 07672 }
| static int manager_pause_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7721 of file app_queue.c.
References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), member::interface, member::paused, and set_member_paused().
Referenced by load_module().
07722 { 07723 const char *queuename, *interface, *paused_s, *reason; 07724 int paused; 07725 07726 interface = astman_get_header(m, "Interface"); 07727 paused_s = astman_get_header(m, "Paused"); 07728 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 07729 reason = astman_get_header(m, "Reason"); /* Optional - Only used for logging purposes */ 07730 07731 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 07732 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 07733 return 0; 07734 } 07735 07736 paused = abs(ast_true(paused_s)); 07737 07738 if (set_member_paused(queuename, interface, reason, paused)) 07739 astman_send_error(s, m, "Interface not found"); 07740 else 07741 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 07742 return 0; 07743 }
| static int manager_queue_log_custom | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7745 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), member::interface, and S_OR.
Referenced by load_module().
07746 { 07747 const char *queuename, *event, *message, *interface, *uniqueid; 07748 07749 queuename = astman_get_header(m, "Queue"); 07750 uniqueid = astman_get_header(m, "UniqueId"); 07751 interface = astman_get_header(m, "Interface"); 07752 event = astman_get_header(m, "Event"); 07753 message = astman_get_header(m, "Message"); 07754 07755 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) { 07756 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters."); 07757 return 0; 07758 } 07759 07760 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message); 07761 astman_send_ack(s, m, "Event added successfully"); 07762 07763 return 0; 07764 }
| static int manager_queue_member_penalty | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7844 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().
07845 { 07846 const char *queuename, *interface, *penalty_s; 07847 int penalty; 07848 07849 interface = astman_get_header(m, "Interface"); 07850 penalty_s = astman_get_header(m, "Penalty"); 07851 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */ 07852 queuename = astman_get_header(m, "Queue"); 07853 07854 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) { 07855 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters."); 07856 return 0; 07857 } 07858 07859 penalty = atoi(penalty_s); 07860 07861 if (set_member_penalty((char *)queuename, (char *)interface, penalty)) 07862 astman_send_error(s, m, "Invalid interface, queuename or penalty"); 07863 else 07864 astman_send_ack(s, m, "Interface penalty set successfully"); 07865 07866 return 0; 07867 }
| static int manager_queue_reload | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7766 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().
07767 { 07768 struct ast_flags mask = {0,}; 07769 const char *queuename = NULL; 07770 int header_found = 0; 07771 07772 queuename = astman_get_header(m, "Queue"); 07773 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) { 07774 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER); 07775 header_found = 1; 07776 } 07777 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) { 07778 ast_set_flag(&mask, QUEUE_RELOAD_RULES); 07779 header_found = 1; 07780 } 07781 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) { 07782 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); 07783 header_found = 1; 07784 } 07785 07786 if (!header_found) { 07787 ast_set_flag(&mask, AST_FLAGS_ALL); 07788 } 07789 07790 if (!reload_handler(1, &mask, queuename)) { 07791 astman_send_ack(s, m, "Queue reloaded successfully"); 07792 } else { 07793 astman_send_error(s, m, "Error encountered while reloading queue"); 07794 } 07795 return 0; 07796 }
| static int manager_queue_reset | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7798 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().
07799 { 07800 const char *queuename = NULL; 07801 struct ast_flags mask = {QUEUE_RESET_STATS,}; 07802 07803 queuename = astman_get_header(m, "Queue"); 07804 07805 if (!reload_handler(1, &mask, queuename)) { 07806 astman_send_ack(s, m, "Queue stats reset successfully"); 07807 } else { 07808 astman_send_error(s, m, "Error encountered while resetting queue stats"); 07809 } 07810 return 0; 07811 }
| static int manager_queue_rule_show | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7407 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, RESULT_SUCCESS, rule_list::rules, and penalty_rule::time.
Referenced by load_module().
07408 { 07409 const char *rule = astman_get_header(m, "Rule"); 07410 const char *id = astman_get_header(m, "ActionID"); 07411 struct rule_list *rl_iter; 07412 struct penalty_rule *pr_iter; 07413 07414 astman_append(s, "Response: Success\r\n"); 07415 if (!ast_strlen_zero(id)) { 07416 astman_append(s, "ActionID: %s\r\n", id); 07417 } 07418 07419 AST_LIST_LOCK(&rule_lists); 07420 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 07421 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) { 07422 astman_append(s, "RuleList: %s\r\n", rl_iter->name); 07423 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 07424 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 ); 07425 } 07426 if (!ast_strlen_zero(rule)) 07427 break; 07428 } 07429 } 07430 AST_LIST_UNLOCK(&rule_lists); 07431 07432 /* 07433 * Two blank lines instead of one because the Response and 07434 * ActionID headers used to not be present. 07435 */ 07436 astman_append(s, "\r\n\r\n"); 07437 07438 return RESULT_SUCCESS; 07439 }
| static int manager_queues_show | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7397 of file app_queue.c.
References __queues_show(), astman_append(), and RESULT_SUCCESS.
Referenced by load_module().
07398 { 07399 static const char * const a[] = { "queue", "show" }; 07400 07401 __queues_show(s, -1, 2, a); 07402 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 07403 07404 return RESULT_SUCCESS; 07405 }
| static int manager_queues_status | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Queue status info via AMI.
Definition at line 7517 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_channel_name(), ast_channel_uniqueid(), 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, call_queue::name, queue_ent::next, ast_party_id::number, member::paused, member::penalty, queue_ent::pos, queue_t_unref, queues, RESULT_SUCCESS, S_COR, call_queue::servicelevel, queue_ent::start, member::state_interface, member::status, ast_party_name::str, ast_party_number::str, call_queue::strategy, call_queue::talktime, ast_party_name::valid, ast_party_number::valid, and call_queue::weight.
Referenced by load_module().
07518 { 07519 time_t now; 07520 int pos; 07521 const char *id = astman_get_header(m,"ActionID"); 07522 const char *queuefilter = astman_get_header(m,"Queue"); 07523 const char *memberfilter = astman_get_header(m,"Member"); 07524 char idText[256] = ""; 07525 struct call_queue *q; 07526 struct queue_ent *qe; 07527 float sl = 0; 07528 struct member *mem; 07529 struct ao2_iterator queue_iter; 07530 struct ao2_iterator mem_iter; 07531 07532 astman_send_ack(s, m, "Queue status will follow"); 07533 time(&now); 07534 if (!ast_strlen_zero(id)) 07535 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 07536 07537 queue_iter = ao2_iterator_init(queues, 0); 07538 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07539 ao2_lock(q); 07540 07541 /* List queue properties */ 07542 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 07543 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 07544 astman_append(s, "Event: QueueParams\r\n" 07545 "Queue: %s\r\n" 07546 "Max: %d\r\n" 07547 "Strategy: %s\r\n" 07548 "Calls: %d\r\n" 07549 "Holdtime: %d\r\n" 07550 "TalkTime: %d\r\n" 07551 "Completed: %d\r\n" 07552 "Abandoned: %d\r\n" 07553 "ServiceLevel: %d\r\n" 07554 "ServicelevelPerf: %2.1f\r\n" 07555 "Weight: %d\r\n" 07556 "%s" 07557 "\r\n", 07558 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, 07559 q->callsabandoned, q->servicelevel, sl, q->weight, idText); 07560 /* List Queue Members */ 07561 mem_iter = ao2_iterator_init(q->members, 0); 07562 while ((mem = ao2_iterator_next(&mem_iter))) { 07563 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) { 07564 astman_append(s, "Event: QueueMember\r\n" 07565 "Queue: %s\r\n" 07566 "Name: %s\r\n" 07567 "Location: %s\r\n" 07568 "StateInterface: %s\r\n" 07569 "Membership: %s\r\n" 07570 "Penalty: %d\r\n" 07571 "CallsTaken: %d\r\n" 07572 "LastCall: %d\r\n" 07573 "Status: %d\r\n" 07574 "Paused: %d\r\n" 07575 "%s" 07576 "\r\n", 07577 q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static", 07578 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 07579 } 07580 ao2_ref(mem, -1); 07581 } 07582 ao2_iterator_destroy(&mem_iter); 07583 /* List Queue Entries */ 07584 pos = 1; 07585 for (qe = q->head; qe; qe = qe->next) { 07586 astman_append(s, "Event: QueueEntry\r\n" 07587 "Queue: %s\r\n" 07588 "Position: %d\r\n" 07589 "Channel: %s\r\n" 07590 "Uniqueid: %s\r\n" 07591 "CallerIDNum: %s\r\n" 07592 "CallerIDName: %s\r\n" 07593 "ConnectedLineNum: %s\r\n" 07594 "ConnectedLineName: %s\r\n" 07595 "Wait: %ld\r\n" 07596 "%s" 07597 "\r\n", 07598 q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan), 07599 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"), 07600 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 07601 S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"), 07602 S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), 07603 (long) (now - qe->start), idText); 07604 } 07605 } 07606 ao2_unlock(q); 07607 queue_t_unref(q, "Done with iterator"); 07608 } 07609 ao2_iterator_destroy(&queue_iter); 07610 07611 astman_append(s, 07612 "Event: QueueStatusComplete\r\n" 07613 "%s" 07614 "\r\n",idText); 07615 07616 return RESULT_SUCCESS; 07617 }
| static int manager_queues_summary | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Summary of queue info via the AMI.
Definition at line 7442 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_NOT_INUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), call_queue::head, call_queue::holdtime, call_queue::members, call_queue::name, queue_ent::next, member::paused, queue_t_unref, queues, RESULT_SUCCESS, queue_ent::start, member::status, and call_queue::talktime.
Referenced by load_module().
07443 { 07444 time_t now; 07445 int qmemcount = 0; 07446 int qmemavail = 0; 07447 int qchancount = 0; 07448 int qlongestholdtime = 0; 07449 const char *id = astman_get_header(m, "ActionID"); 07450 const char *queuefilter = astman_get_header(m, "Queue"); 07451 char idText[256] = ""; 07452 struct call_queue *q; 07453 struct queue_ent *qe; 07454 struct member *mem; 07455 struct ao2_iterator queue_iter; 07456 struct ao2_iterator mem_iter; 07457 07458 astman_send_ack(s, m, "Queue summary will follow"); 07459 time(&now); 07460 if (!ast_strlen_zero(id)) 07461 snprintf(idText, 256, "ActionID: %s\r\n", id); 07462 queue_iter = ao2_iterator_init(queues, 0); 07463 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07464 ao2_lock(q); 07465 07466 /* List queue properties */ 07467 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 07468 /* Reset the necessary local variables if no queuefilter is set*/ 07469 qmemcount = 0; 07470 qmemavail = 0; 07471 qchancount = 0; 07472 qlongestholdtime = 0; 07473 07474 /* List Queue Members */ 07475 mem_iter = ao2_iterator_init(q->members, 0); 07476 while ((mem = ao2_iterator_next(&mem_iter))) { 07477 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) { 07478 ++qmemcount; 07479 if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) { 07480 ++qmemavail; 07481 } 07482 } 07483 ao2_ref(mem, -1); 07484 } 07485 ao2_iterator_destroy(&mem_iter); 07486 for (qe = q->head; qe; qe = qe->next) { 07487 if ((now - qe->start) > qlongestholdtime) { 07488 qlongestholdtime = now - qe->start; 07489 } 07490 ++qchancount; 07491 } 07492 astman_append(s, "Event: QueueSummary\r\n" 07493 "Queue: %s\r\n" 07494 "LoggedIn: %d\r\n" 07495 "Available: %d\r\n" 07496 "Callers: %d\r\n" 07497 "HoldTime: %d\r\n" 07498 "TalkTime: %d\r\n" 07499 "LongestHoldTime: %d\r\n" 07500 "%s" 07501 "\r\n", 07502 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText); 07503 } 07504 ao2_unlock(q); 07505 queue_t_unref(q, "Done with iterator"); 07506 } 07507 ao2_iterator_destroy(&queue_iter); 07508 astman_append(s, 07509 "Event: QueueSummaryComplete\r\n" 07510 "%s" 07511 "\r\n", idText); 07512 07513 return RESULT_SUCCESS; 07514 }
| static int manager_remove_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 7674 of file app_queue.c.
References ao2_ref, ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), find_member_by_queuename_and_interface(), member::membername, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and RES_OUTOFMEMORY.
Referenced by load_module().
07675 { 07676 const char *queuename, *interface; 07677 struct member *mem = NULL; 07678 07679 queuename = astman_get_header(m, "Queue"); 07680 interface = astman_get_header(m, "Interface"); 07681 07682 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 07683 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 07684 return 0; 07685 } 07686 07687 if (log_membername_as_agent) { 07688 mem = find_member_by_queuename_and_interface(queuename, interface); 07689 } 07690 07691 switch (remove_from_queue(queuename, interface)) { 07692 case RES_OKAY: 07693 if (!mem || ast_strlen_zero(mem->membername)) { 07694 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 07695 } else { 07696 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", ""); 07697 } 07698 astman_send_ack(s, m, "Removed interface from queue"); 07699 break; 07700 case RES_EXISTS: 07701 astman_send_error(s, m, "Unable to remove interface: Not there"); 07702 break; 07703 case RES_NOSUCHQUEUE: 07704 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 07705 break; 07706 case RES_OUTOFMEMORY: 07707 astman_send_error(s, m, "Out of memory"); 07708 break; 07709 case RES_NOT_DYNAMIC: 07710 astman_send_error(s, m, "Member not dynamic"); 07711 break; 07712 } 07713 07714 if (mem) { 07715 ao2_ref(mem, -1); 07716 } 07717 07718 return 0; 07719 }
| static int mark_dead_and_unfound | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 7055 of file app_queue.c.
References ast_strlen_zero(), call_queue::dead, call_queue::found, call_queue::name, and call_queue::realtime.
Referenced by reload_queues().
07056 { 07057 struct call_queue *q = obj; 07058 char *queuename = arg; 07059 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) { 07060 q->dead = 1; 07061 q->found = 0; 07062 } 07063 return 0; 07064 }
| static int mark_member_dead | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 6928 of file app_queue.c.
References member::delme, and member::dynamic.
Referenced by reload_single_queue().
06929 { 06930 struct member *member = obj; 06931 if (!member->dynamic) { 06932 member->delme = 1; 06933 } 06934 return 0; 06935 }
| static int member_cmp_fn | ( | void * | obj1, | |
| void * | obj2, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1688 of file app_queue.c.
References CMP_MATCH, CMP_STOP, member::interface, and OBJ_KEY.
Referenced by init_queue().
01689 { 01690 struct member *mem1 = obj1; 01691 struct member *mem2 = obj2; 01692 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface; 01693 01694 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP; 01695 }
| static int member_hash_fn | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 1672 of file app_queue.c.
References compress_char(), member::interface, and OBJ_KEY.
Referenced by init_queue().
01673 { 01674 const struct member *mem = obj; 01675 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface; 01676 const char *chname = strchr(interface, '/'); 01677 int ret = 0, i; 01678 01679 if (!chname) { 01680 chname = interface; 01681 } 01682 for (i = 0; i < 5 && chname[i]; i++) { 01683 ret += compress_char(chname[i]) << (i * 6); 01684 } 01685 return ret; 01686 }
| 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 2942 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, call_queue::autofill, member::ignorebusy, 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().
02943 { 02944 struct member *mem; 02945 int avl = 0; 02946 struct ao2_iterator mem_iter; 02947 02948 mem_iter = ao2_iterator_init(q->members, 0); 02949 while ((mem = ao2_iterator_next(&mem_iter))) { 02950 switch (mem->status) { 02951 case AST_DEVICE_INVALID: 02952 case AST_DEVICE_UNAVAILABLE: 02953 break; 02954 case AST_DEVICE_INUSE: 02955 case AST_DEVICE_BUSY: 02956 case AST_DEVICE_RINGING: 02957 case AST_DEVICE_RINGINUSE: 02958 case AST_DEVICE_ONHOLD: 02959 if ((!q->ringinuse) || (!mem->ignorebusy)) { 02960 break; 02961 } 02962 /* else fall through */ 02963 case AST_DEVICE_NOT_INUSE: 02964 case AST_DEVICE_UNKNOWN: 02965 if (!mem->paused) { 02966 avl++; 02967 } 02968 break; 02969 } 02970 ao2_ref(mem, -1); 02971 02972 /* If autofill is not enabled or if the queue's strategy is ringall, then 02973 * we really don't care about the number of available members so much as we 02974 * do that there is at least one available. 02975 * 02976 * In fact, we purposely will return from this function stating that only 02977 * one member is available if either of those conditions hold. That way, 02978 * functions which determine what action to take based on the number of available 02979 * members will operate properly. The reasoning is that even if multiple 02980 * members are available, only the head caller can actually be serviced. 02981 */ 02982 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) { 02983 break; 02984 } 02985 } 02986 ao2_iterator_destroy(&mem_iter); 02987 02988 return avl; 02989 }
| static void parse_empty_options | ( | const char * | value, | |
| enum empty_conditions * | empty, | |||
| int | joinempty | |||
| ) | [static] |
Definition at line 1877 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, QUEUE_EMPTY_WRAPUP, and strsep().
Referenced by queue_set_param().
01878 { 01879 char *value_copy = ast_strdupa(value); 01880 char *option = NULL; 01881 while ((option = strsep(&value_copy, ","))) { 01882 if (!strcasecmp(option, "paused")) { 01883 *empty |= QUEUE_EMPTY_PAUSED; 01884 } else if (!strcasecmp(option, "penalty")) { 01885 *empty |= QUEUE_EMPTY_PENALTY; 01886 } else if (!strcasecmp(option, "inuse")) { 01887 *empty |= QUEUE_EMPTY_INUSE; 01888 } else if (!strcasecmp(option, "ringing")) { 01889 *empty |= QUEUE_EMPTY_RINGING; 01890 } else if (!strcasecmp(option, "invalid")) { 01891 *empty |= QUEUE_EMPTY_INVALID; 01892 } else if (!strcasecmp(option, "wrapup")) { 01893 *empty |= QUEUE_EMPTY_WRAPUP; 01894 } else if (!strcasecmp(option, "unavailable")) { 01895 *empty |= QUEUE_EMPTY_UNAVAILABLE; 01896 } else if (!strcasecmp(option, "unknown")) { 01897 *empty |= QUEUE_EMPTY_UNKNOWN; 01898 } else if (!strcasecmp(option, "loose")) { 01899 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID); 01900 } else if (!strcasecmp(option, "strict")) { 01901 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE); 01902 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) { 01903 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED); 01904 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) { 01905 *empty = 0; 01906 } else { 01907 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty"); 01908 } 01909 } 01910 }
| static int play_file | ( | struct ast_channel * | chan, | |
| const char * | filename | |||
| ) | [static] |
Definition at line 2611 of file app_queue.c.
References ast_channel_language(), 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().
02612 { 02613 int res; 02614 02615 if (ast_strlen_zero(filename)) { 02616 return 0; 02617 } 02618 02619 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) { 02620 return 0; 02621 } 02622 02623 ast_stopstream(chan); 02624 02625 res = ast_streamfile(chan, filename, ast_channel_language(chan)); 02626 if (!res) 02627 res = ast_waitstream(chan, AST_DIGIT_ANY); 02628 02629 ast_stopstream(chan); 02630 02631 return res; 02632 }
| static int pqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
PauseQueueMember application.
Definition at line 5706 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().
05707 { 05708 char *parse; 05709 AST_DECLARE_APP_ARGS(args, 05710 AST_APP_ARG(queuename); 05711 AST_APP_ARG(interface); 05712 AST_APP_ARG(options); 05713 AST_APP_ARG(reason); 05714 ); 05715 05716 if (ast_strlen_zero(data)) { 05717 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n"); 05718 return -1; 05719 } 05720 05721 parse = ast_strdupa(data); 05722 05723 AST_STANDARD_APP_ARGS(args, parse); 05724 05725 if (ast_strlen_zero(args.interface)) { 05726 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 05727 return -1; 05728 } 05729 05730 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) { 05731 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 05732 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 05733 return 0; 05734 } 05735 05736 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 05737 05738 return 0; 05739 }
| static int ql_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
QueueLog application.
Definition at line 5916 of file app_queue.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, member::membername, and parse().
Referenced by load_module().
05917 { 05918 char *parse; 05919 05920 AST_DECLARE_APP_ARGS(args, 05921 AST_APP_ARG(queuename); 05922 AST_APP_ARG(uniqueid); 05923 AST_APP_ARG(membername); 05924 AST_APP_ARG(event); 05925 AST_APP_ARG(params); 05926 ); 05927 05928 if (ast_strlen_zero(data)) { 05929 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n"); 05930 return -1; 05931 } 05932 05933 parse = ast_strdupa(data); 05934 05935 AST_STANDARD_APP_ARGS(args, parse); 05936 05937 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 05938 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 05939 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n"); 05940 return -1; 05941 } 05942 05943 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 05944 "%s", args.params ? args.params : ""); 05945 05946 return 0; 05947 }
| static int queue_cmp_cb | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1287 of file app_queue.c.
References CMP_MATCH, CMP_STOP, and call_queue::name.
Referenced by load_module().
01288 { 01289 struct call_queue *q = obj, *q2 = arg; 01290 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0; 01291 }
| 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 5990 of file app_queue.c.
References call_queue::announcefrequency, ao2_container_count(), args, AST_APP_ARG, ast_channel_lock, ast_channel_name(), ast_channel_uniqueid(), ast_channel_unlock, AST_CONTROL_RINGING, ast_debug, AST_DECLARE_APP_ARGS, ast_indicate(), AST_LIST_FIRST, ast_log(), ast_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, call_queue::name, ast_party_id::number, queue_ent::opos, queue_ent::parent, parse(), pbx_builtin_getvar_helper(), call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::pr, queue_ent::prio, queue_ent::qe_rules, 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, penalty_rule::time, 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().
05991 { 05992 int res=-1; 05993 int ringing=0; 05994 const char *user_priority; 05995 const char *max_penalty_str; 05996 const char *min_penalty_str; 05997 int prio; 05998 int qcontinue = 0; 05999 int max_penalty, min_penalty; 06000 enum queue_result reason = QUEUE_UNKNOWN; 06001 /* whether to exit Queue application after the timeout hits */ 06002 int tries = 0; 06003 int noption = 0; 06004 char *parse; 06005 int makeannouncement = 0; 06006 int position = 0; 06007 AST_DECLARE_APP_ARGS(args, 06008 AST_APP_ARG(queuename); 06009 AST_APP_ARG(options); 06010 AST_APP_ARG(url); 06011 AST_APP_ARG(announceoverride); 06012 AST_APP_ARG(queuetimeoutstr); 06013 AST_APP_ARG(agi); 06014 AST_APP_ARG(macro); 06015 AST_APP_ARG(gosub); 06016 AST_APP_ARG(rule); 06017 AST_APP_ARG(position); 06018 ); 06019 /* Our queue entry */ 06020 struct queue_ent qe = { 0 }; 06021 06022 if (ast_strlen_zero(data)) { 06023 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n"); 06024 return -1; 06025 } 06026 06027 parse = ast_strdupa(data); 06028 AST_STANDARD_APP_ARGS(args, parse); 06029 06030 /* Setup our queue entry */ 06031 qe.start = time(NULL); 06032 06033 /* set the expire time based on the supplied timeout; */ 06034 if (!ast_strlen_zero(args.queuetimeoutstr)) 06035 qe.expire = qe.start + atoi(args.queuetimeoutstr); 06036 else 06037 qe.expire = 0; 06038 06039 /* Get the priority from the variable ${QUEUE_PRIO} */ 06040 ast_channel_lock(chan); 06041 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 06042 if (user_priority) { 06043 if (sscanf(user_priority, "%30d", &prio) == 1) { 06044 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", ast_channel_name(chan), prio); 06045 } else { 06046 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 06047 user_priority, ast_channel_name(chan)); 06048 prio = 0; 06049 } 06050 } else { 06051 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n"); 06052 prio = 0; 06053 } 06054 06055 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 06056 06057 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 06058 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) { 06059 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", ast_channel_name(chan), max_penalty); 06060 } else { 06061 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 06062 max_penalty_str, ast_channel_name(chan)); 06063 max_penalty = 0; 06064 } 06065 } else { 06066 max_penalty = 0; 06067 } 06068 06069 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) { 06070 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) { 06071 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", ast_channel_name(chan), min_penalty); 06072 } else { 06073 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n", 06074 min_penalty_str, ast_channel_name(chan)); 06075 min_penalty = 0; 06076 } 06077 } else { 06078 min_penalty = 0; 06079 } 06080 ast_channel_unlock(chan); 06081 06082 if (args.options && (strchr(args.options, 'r'))) 06083 ringing = 1; 06084 06085 if (ringing != 1 && args.options && (strchr(args.options, 'R'))) { 06086 qe.ring_when_ringing = 1; 06087 } 06088 06089 if (args.options && (strchr(args.options, 'c'))) 06090 qcontinue = 1; 06091 06092 if (args.position) { 06093 position = atoi(args.position); 06094 if (position < 0) { 06095 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename); 06096 position = 0; 06097 } 06098 } 06099 06100 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 06101 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 06102 06103 qe.chan = chan; 06104 qe.prio = prio; 06105 qe.max_penalty = max_penalty; 06106 qe.min_penalty = min_penalty; 06107 qe.last_pos_said = 0; 06108 qe.last_pos = 0; 06109 qe.last_periodic_announce_time = time(NULL); 06110 qe.last_periodic_announce_sound = 0; 06111 qe.valid_digits = 0; 06112 if (join_queue(args.queuename, &qe, &reason, position)) { 06113 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 06114 set_queue_result(chan, reason); 06115 return 0; 06116 } 06117 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d", 06118 S_OR(args.url, ""), 06119 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""), 06120 qe.opos); 06121 copy_rules(&qe, args.rule); 06122 qe.pr = AST_LIST_FIRST(&qe.qe_rules); 06123 check_turns: 06124 if (ringing) { 06125 ast_indicate(chan, AST_CONTROL_RINGING); 06126 } else { 06127 ast_moh_start(chan, qe.moh, NULL); 06128 } 06129 06130 /* This is the wait loop for callers 2 through maxlen */ 06131 res = wait_our_turn(&qe, ringing, &reason); 06132 if (res) { 06133 goto stop; 06134 } 06135 06136 makeannouncement = 0; 06137 06138 for (;;) { 06139 /* This is the wait loop for the head caller*/ 06140 /* To exit, they may get their call answered; */ 06141 /* they may dial a digit from the queue context; */ 06142 /* or, they may timeout. */ 06143 06144 /* Leave if we have exceeded our queuetimeout */ 06145 if (qe.expire && (time(NULL) >= qe.expire)) { 06146 record_abandoned(&qe); 06147 reason = QUEUE_TIMEOUT; 06148 res = 0; 06149 ast_queue_log(args.queuename, ast_channel_uniqueid(chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 06150 qe.pos, qe.opos, (long) time(NULL) - qe.start); 06151 break; 06152 } 06153 06154 if (makeannouncement) { 06155 /* Make a position announcement, if enabled */ 06156 if (qe.parent->announcefrequency) 06157 if ((res = say_position(&qe,ringing))) 06158 goto stop; 06159 } 06160 makeannouncement = 1; 06161 06162 /* Make a periodic announcement, if enabled */ 06163 if (qe.parent->periodicannouncefrequency) 06164 if ((res = say_periodic_announcement(&qe,ringing))) 06165 goto stop; 06166 06167 /* Leave if we have exceeded our queuetimeout */ 06168 if (qe.expire && (time(NULL) >= qe.expire)) { 06169 record_abandoned(&qe); 06170 reason = QUEUE_TIMEOUT; 06171 res = 0; 06172 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 06173 break; 06174 } 06175 06176 /* see if we need to move to the next penalty level for this queue */ 06177 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) { 06178 update_qe_rule(&qe); 06179 } 06180 06181 /* Try calling all queue members for 'timeout' seconds */ 06182 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing); 06183 if (res) { 06184 goto stop; 06185 } 06186 06187 if (qe.parent->leavewhenempty) { 06188 int status = 0; 06189 if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty))) { 06190 record_abandoned(&qe); 06191 reason = QUEUE_LEAVEEMPTY; 06192 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 06193 res = 0; 06194 break; 06195 } 06196 } 06197 06198 /* exit after 'timeout' cycle if 'n' option enabled */ 06199 if (noption && tries >= ao2_container_count(qe.parent->members)) { 06200 ast_verb(3, "Exiting on time-out cycle\n"); 06201 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 06202 record_abandoned(&qe); 06203 reason = QUEUE_TIMEOUT; 06204 res = 0; 06205 break; 06206 } 06207 06208 06209 /* Leave if we have exceeded our queuetimeout */ 06210 if (qe.expire && (time(NULL) >= qe.expire)) { 06211 record_abandoned(&qe); 06212 reason = QUEUE_TIMEOUT; 06213 res = 0; 06214 ast_queue_log(qe.parent->name, ast_channel_uniqueid(qe.chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start); 06215 break; 06216 } 06217 06218 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 06219 update_realtime_members(qe.parent); 06220 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 06221 res = wait_a_bit(&qe); 06222 if (res) 06223 goto stop; 06224 06225 /* Since this is a priority queue and 06226 * it is not sure that we are still at the head 06227 * of the queue, go and check for our turn again. 06228 */ 06229 if (!is_our_turn(&qe)) { 06230 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", ast_channel_name(qe.chan)); 06231 goto check_turns; 06232 } 06233 } 06234 06235 stop: 06236 if (res) { 06237 if (res < 0) { 06238 if (!qe.handled) { 06239 record_abandoned(&qe); 06240 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ABANDON", 06241 "%d|%d|%ld", qe.pos, qe.opos, 06242 (long) time(NULL) - qe.start); 06243 res = -1; 06244 } else if (qcontinue) { 06245 reason = QUEUE_CONTINUE; 06246 res = 0; 06247 } 06248 } else if (qe.valid_digits) { 06249 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY", 06250 "%s|%d", qe.digits, qe.pos); 06251 } 06252 } 06253 06254 /* Don't allow return code > 0 */ 06255 if (res >= 0) { 06256 res = 0; 06257 if (ringing) { 06258 ast_indicate(chan, -1); 06259 } else { 06260 ast_moh_stop(chan); 06261 } 06262 ast_stopstream(chan); 06263 } 06264 06265 set_queue_variables(qe.parent, qe.chan); 06266 06267 leave_queue(&qe); 06268 if (reason != QUEUE_UNKNOWN) 06269 set_queue_result(chan, reason); 06270 06271 if (qe.parent) { 06272 /* every queue_ent is given a reference to it's parent call_queue when it joins the queue. 06273 * This ref must be taken away right before the queue_ent is destroyed. In this case 06274 * the queue_ent is about to be returned on the stack */ 06275 qe.parent = queue_unref(qe.parent); 06276 } 06277 06278 return res; 06279 }
| 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 6333 of file app_queue.c.
References ast_log(), ast_strlen_zero(), find_load_queue_rt_friendly(), LOG_ERROR, and queue_t_unref.
06334 { 06335 struct call_queue *q; 06336 06337 buf[0] = '\0'; 06338 06339 if (ast_strlen_zero(data)) { 06340 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06341 return -1; 06342 } 06343 q = find_load_queue_rt_friendly(data); 06344 snprintf(buf, len, "%d", q != NULL? 1 : 0); 06345 if (q) { 06346 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()"); 06347 } 06348 06349 return 0; 06350 }
| static int queue_function_mem_read | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Get number either busy / free / ready or total members of a specific queue.
Get or set member properties penalty / paused / ignorebusy
| number | of members (busy / free / ready / total) or member info (penalty / paused / ignorebusy) | |
| -1 | on error |
Definition at line 6358 of file app_queue.c.
References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), call_queue::count, find_load_queue_rt_friendly(), member::ignorebusy, interface_exists(), member::lastcall, LOG_ERROR, LOG_WARNING, call_queue::members, member::paused, member::penalty, queue_t_unref, member::status, and call_queue::wrapuptime.
06359 { 06360 int count = 0; 06361 struct member *m; 06362 struct ao2_iterator mem_iter; 06363 struct call_queue *q; 06364 06365 AST_DECLARE_APP_ARGS(args, 06366 AST_APP_ARG(queuename); 06367 AST_APP_ARG(option); 06368 AST_APP_ARG(interface); 06369 ); 06370 /* Make sure the returned value on error is zero length string. */ 06371 buf[0] = '\0'; 06372 06373 if (ast_strlen_zero(data)) { 06374 ast_log(LOG_ERROR, "Missing required argument. %s(<queuename>,<option>[<interface>])\n", cmd); 06375 return -1; 06376 } 06377 06378 AST_STANDARD_APP_ARGS(args, data); 06379 06380 if (args.argc < 2) { 06381 ast_log(LOG_ERROR, "Missing required argument. %s(<queuename>,<option>[<interface>])\n", cmd); 06382 return -1; 06383 } 06384 06385 if ((q = find_load_queue_rt_friendly(args.queuename))) { 06386 ao2_lock(q); 06387 if (!strcasecmp(args.option, "logged")) { 06388 mem_iter = ao2_iterator_init(q->members, 0); 06389 while ((m = ao2_iterator_next(&mem_iter))) { 06390 /* Count the agents who are logged in and presently answering calls */ 06391 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 06392 count++; 06393 } 06394 ao2_ref(m, -1); 06395 } 06396 ao2_iterator_destroy(&mem_iter); 06397 } else if (!strcasecmp(args.option, "free")) { 06398 mem_iter = ao2_iterator_init(q->members, 0); 06399 while ((m = ao2_iterator_next(&mem_iter))) { 06400 /* Count the agents who are logged in and presently answering calls */ 06401 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) { 06402 count++; 06403 } 06404 ao2_ref(m, -1); 06405 } 06406 ao2_iterator_destroy(&mem_iter); 06407 } else if (!strcasecmp(args.option, "ready")) { 06408 time_t now; 06409 time(&now); 06410 mem_iter = ao2_iterator_init(q->members, 0); 06411 while ((m = ao2_iterator_next(&mem_iter))) { 06412 /* Count the agents who are logged in, not paused and not wrapping up */ 06413 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) && 06414 !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) { 06415 count++; 06416 } 06417 ao2_ref(m, -1); 06418 } 06419 ao2_iterator_destroy(&mem_iter); 06420 } else if (!strcasecmp(args.option, "count") || ast_strlen_zero(args.option)) { 06421 count = ao2_container_count(q->members); 06422 } else if (!strcasecmp(args.option, "penalty") && !ast_strlen_zero(args.interface) && 06423 ((m = interface_exists(q, args.interface)))) { 06424 count = m->penalty; 06425 ao2_ref(m, -1); 06426 } else if (!strcasecmp(args.option, "paused") && !ast_strlen_zero(args.interface) && 06427 ((m = interface_exists(q, args.interface)))) { 06428 count = m->paused; 06429 ao2_ref(m, -1); 06430 } else if (!strcasecmp(args.option, "ignorebusy") && !ast_strlen_zero(args.interface) && 06431 ((m = interface_exists(q, args.interface)))) { 06432 count = m->ignorebusy; 06433 ao2_ref(m, -1); 06434 } else { 06435 ast_log(LOG_ERROR, "Unknown option %s provided to %s, valid values are: " 06436 "logged, free, ready, count, penalty, paused, ignorebusy\n", args.option, cmd); 06437 } 06438 ao2_unlock(q); 06439 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()"); 06440 } else { 06441 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename); 06442 } 06443 06444 snprintf(buf, len, "%d", count); 06445 06446 return 0; 06447 }
| static int queue_function_mem_write | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| const char * | value | |||
| ) | [static] |
Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ignorebusy.
Definition at line 6450 of file app_queue.c.
References ao2_lock, ao2_ref, ao2_unlock, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), find_load_queue_rt_friendly(), member::ignorebusy, member::interface, interface_exists(), LOG_ERROR, call_queue::name, member::paused, member::realtime, set_member_penalty(), and update_realtime_member_field().
06451 { 06452 int memvalue; 06453 struct call_queue *q; 06454 struct member *m; 06455 char rtvalue[80]; 06456 06457 AST_DECLARE_APP_ARGS(args, 06458 AST_APP_ARG(queuename); 06459 AST_APP_ARG(option); 06460 AST_APP_ARG(interface); 06461 ); 06462 06463 if (ast_strlen_zero(data)) { 06464 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER(<queuename>,<option>,<interface>)\n"); 06465 return -1; 06466 } 06467 06468 AST_STANDARD_APP_ARGS(args, data); 06469 06470 if (args.argc < 3) { 06471 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06472 return -1; 06473 } 06474 06475 if (ast_strlen_zero(args.interface) && ast_strlen_zero(args.option)) { 06476 ast_log (LOG_ERROR, "<interface> and <option> parameter's can't be null\n"); 06477 return -1; 06478 } 06479 06480 memvalue = atoi(value); 06481 06482 if (!strcasecmp(args.option, "penalty")) { 06483 /* if queuename = NULL then penalty will be set for interface in all the queues.*/ 06484 if (set_member_penalty(args.queuename, args.interface, memvalue)) { 06485 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); 06486 return -1; 06487 } 06488 } else if ((q = find_load_queue_rt_friendly(args.queuename))) { 06489 ao2_lock(q); 06490 if ((m = interface_exists(q, args.interface))) { 06491 sprintf(rtvalue, "%s",(memvalue <= 0) ? "0" : "1"); 06492 if (!strcasecmp(args.option, "paused")) { 06493 if (m->realtime) { 06494 update_realtime_member_field(m, q->name, args.option, rtvalue); 06495 } else { 06496 m->paused = (memvalue <= 0) ? 0 : 1; 06497 } 06498 } else if (!strcasecmp(args.option, "ignorebusy")) { 06499 if (m->realtime) { 06500 update_realtime_member_field(m, q->name, args.option, rtvalue); 06501 } else { 06502 m->ignorebusy = (memvalue <= 0) ? 0 : 1; 06503 } 06504 } else { 06505 ast_log(LOG_ERROR, "Invalid option, only penalty , paused or ignorebusy are valid\n"); 06506 ao2_ref(m, -1); 06507 ao2_unlock(q); 06508 ao2_ref(q, -1); 06509 return -1; 06510 } 06511 ao2_ref(m, -1); 06512 } else { 06513 ao2_unlock(q); 06514 ao2_ref(q, -1); 06515 ast_log(LOG_ERROR, "Invalid interface for queue\n"); 06516 return -1; 06517 } 06518 ao2_unlock(q); 06519 ao2_ref(q, -1); 06520 } else { 06521 ast_log(LOG_ERROR, "Invalid queue\n"); 06522 return -1; 06523 } 06524 return 0; 06525 }
| 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 6659 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.
06660 { 06661 int penalty; 06662 AST_DECLARE_APP_ARGS(args, 06663 AST_APP_ARG(queuename); 06664 AST_APP_ARG(interface); 06665 ); 06666 /* Make sure the returned value on error is NULL. */ 06667 buf[0] = '\0'; 06668 06669 if (ast_strlen_zero(data)) { 06670 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06671 return -1; 06672 } 06673 06674 AST_STANDARD_APP_ARGS(args, data); 06675 06676 if (args.argc < 2) { 06677 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06678 return -1; 06679 } 06680 06681 penalty = get_member_penalty (args.queuename, args.interface); 06682 06683 if (penalty >= 0) /* remember that buf is already '\0' */ 06684 snprintf (buf, len, "%d", penalty); 06685 06686 return 0; 06687 }
| 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 6690 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().
06691 { 06692 int penalty; 06693 AST_DECLARE_APP_ARGS(args, 06694 AST_APP_ARG(queuename); 06695 AST_APP_ARG(interface); 06696 ); 06697 06698 if (ast_strlen_zero(data)) { 06699 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06700 return -1; 06701 } 06702 06703 AST_STANDARD_APP_ARGS(args, data); 06704 06705 if (args.argc < 2) { 06706 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06707 return -1; 06708 } 06709 06710 penalty = atoi(value); 06711 06712 if (ast_strlen_zero(args.interface)) { 06713 ast_log (LOG_ERROR, "<interface> parameter can't be null\n"); 06714 return -1; 06715 } 06716 06717 /* if queuename = NULL then penalty will be set for interface in all the queues. */ 06718 if (set_member_penalty(args.queuename, args.interface, penalty)) { 06719 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); 06720 return -1; 06721 } 06722 06723 return 0; 06724 }
| 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 6532 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(), find_load_queue_rt_friendly(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, call_queue::members, queue_t_unref, and member::status.
06533 { 06534 int count = 0; 06535 struct member *m; 06536 struct call_queue *q; 06537 struct ao2_iterator mem_iter; 06538 static int depflag = 1; 06539 06540 if (depflag) { 06541 depflag = 0; 06542 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"); 06543 } 06544 06545 if (ast_strlen_zero(data)) { 06546 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06547 return -1; 06548 } 06549 06550 if ((q = find_load_queue_rt_friendly(data))) { 06551 ao2_lock(q); 06552 mem_iter = ao2_iterator_init(q->members, 0); 06553 while ((m = ao2_iterator_next(&mem_iter))) { 06554 /* Count the agents who are logged in and presently answering calls */ 06555 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 06556 count++; 06557 } 06558 ao2_ref(m, -1); 06559 } 06560 ao2_iterator_destroy(&mem_iter); 06561 ao2_unlock(q); 06562 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT"); 06563 } else { 06564 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06565 } 06566 06567 snprintf(buf, len, "%d", count); 06568 06569 return 0; 06570 }
| 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 6609 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.
06610 { 06611 struct call_queue *q, tmpq = { 06612 .name = data, 06613 }; 06614 struct member *m; 06615 06616 /* Ensure an otherwise empty list doesn't return garbage */ 06617 buf[0] = '\0'; 06618 06619 if (ast_strlen_zero(data)) { 06620 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 06621 return -1; 06622 } 06623 06624 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) { 06625 int buflen = 0, count = 0; 06626 struct ao2_iterator mem_iter; 06627 06628 ao2_lock(q); 06629 mem_iter = ao2_iterator_init(q->members, 0); 06630 while ((m = ao2_iterator_next(&mem_iter))) { 06631 /* strcat() is always faster than printf() */ 06632 if (count++) { 06633 strncat(buf + buflen, ",", len - buflen - 1); 06634 buflen++; 06635 } 06636 strncat(buf + buflen, m->interface, len - buflen - 1); 06637 buflen += strlen(m->interface); 06638 /* Safeguard against overflow (negative length) */ 06639 if (buflen >= len - 2) { 06640 ao2_ref(m, -1); 06641 ast_log(LOG_WARNING, "Truncating list\n"); 06642 break; 06643 } 06644 ao2_ref(m, -1); 06645 } 06646 ao2_iterator_destroy(&mem_iter); 06647 ao2_unlock(q); 06648 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()"); 06649 } else 06650 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06651 06652 /* We should already be terminated, but let's make sure. */ 06653 buf[len - 1] = '\0'; 06654 06655 return 0; 06656 }
| 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 6573 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.
06574 { 06575 int count = 0; 06576 struct call_queue *q, tmpq = { 06577 .name = data, 06578 }; 06579 struct ast_variable *var = NULL; 06580 06581 buf[0] = '\0'; 06582 06583 if (ast_strlen_zero(data)) { 06584 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n"); 06585 return -1; 06586 } 06587 06588 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) { 06589 ao2_lock(q); 06590 count = q->count; 06591 ao2_unlock(q); 06592 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()"); 06593 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) { 06594 /* if the queue is realtime but was not found in memory, this 06595 * means that the queue had been deleted from memory since it was 06596 * "dead." This means it has a 0 waiting count 06597 */ 06598 count = 0; 06599 ast_variables_destroy(var); 06600 } else 06601 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06602 06603 snprintf(buf, len, "%d", count); 06604 06605 return 0; 06606 }
| 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 6286 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.
06287 { 06288 int res = -1; 06289 struct call_queue *q, tmpq = { 06290 .name = data, 06291 }; 06292 06293 char interfacevar[256] = ""; 06294 float sl = 0; 06295 06296 if (ast_strlen_zero(data)) { 06297 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06298 return -1; 06299 } 06300 06301 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) { 06302 ao2_lock(q); 06303 if (q->setqueuevar) { 06304 sl = 0; 06305 res = 0; 06306 06307 if (q->callscompleted > 0) { 06308 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 06309 } 06310 06311 snprintf(interfacevar, sizeof(interfacevar), 06312 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 06313 q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 06314 06315 pbx_builtin_setvar_multiple(chan, interfacevar); 06316 } 06317 06318 ao2_unlock(q); 06319 queue_t_unref(q, "Done with QUEUE() function"); 06320 } else { 06321 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06322 } 06323 06324 snprintf(buf, len, "%d", res); 06325 06326 return 0; 06327 }
| static int queue_hash_cb | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 1280 of file app_queue.c.
References ast_str_case_hash(), and call_queue::name.
Referenced by load_module().
01281 { 01282 const struct call_queue *q = obj; 01283 01284 return ast_str_case_hash(q->name); 01285 }
| static struct call_queue* queue_ref | ( | struct call_queue * | q | ) | [static, read] |
Definition at line 1305 of file app_queue.c.
References ao2_ref.
Referenced by insert_entry().
01306 { 01307 ao2_ref(q, 1); 01308 return q; 01309 }
| 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 6818 of file app_queue.c.
References ast_true(), and ast_variable_retrieve().
Referenced by reload_queues().
06819 { 06820 const char *general_val = NULL; 06821 queue_persistent_members = 0; 06822 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) { 06823 queue_persistent_members = ast_true(general_val); 06824 } 06825 autofill_default = 0; 06826 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) { 06827 autofill_default = ast_true(general_val); 06828 } 06829 montype_default = 0; 06830 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) { 06831 if (!strcasecmp(general_val, "mixmonitor")) 06832 montype_default = 1; 06833 } 06834 update_cdr = 0; 06835 if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr"))) { 06836 update_cdr = ast_true(general_val); 06837 } 06838 shared_lastcall = 0; 06839 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) { 06840 shared_lastcall = ast_true(general_val); 06841 } 06842 negative_penalty_invalid = 0; 06843 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) { 06844 negative_penalty_invalid = ast_true(general_val); 06845 } 06846 log_membername_as_agent = 0; 06847 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) { 06848 log_membername_as_agent = ast_true(general_val); 06849 } 06850 check_state_unknown = 0; 06851 if ((general_val = ast_variable_retrieve(cfg, "general", "check_state_unknown"))) { 06852 check_state_unknown = ast_true(general_val); 06853 } 06854 }
| 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 1920 of file app_queue.c.
References queue_ent::announce, 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(), call_queue::autopausebusy, call_queue::autopausedelay, call_queue::autopauseunavail, 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::name, 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, strsep(), call_queue::timeout, TIMEOUT_PRIORITY_APP, TIMEOUT_PRIORITY_CONF, call_queue::timeoutpriority, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_single_queue().
01921 { 01922 if (!strcasecmp(param, "musicclass") || 01923 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 01924 ast_string_field_set(q, moh, val); 01925 } else if (!strcasecmp(param, "announce")) { 01926 ast_string_field_set(q, announce, val); 01927 } else if (!strcasecmp(param, "context")) { 01928 ast_string_field_set(q, context, val); 01929 } else if (!strcasecmp(param, "timeout")) { 01930 q->timeout = atoi(val); 01931 if (q->timeout < 0) 01932 q->timeout = DEFAULT_TIMEOUT; 01933 } else if (!strcasecmp(param, "ringinuse")) { 01934 q->ringinuse = ast_true(val); 01935 } else if (!strcasecmp(param, "setinterfacevar")) { 01936 q->setinterfacevar = ast_true(val); 01937 } else if (!strcasecmp(param, "setqueuevar")) { 01938 q->setqueuevar = ast_true(val); 01939 } else if (!strcasecmp(param, "setqueueentryvar")) { 01940 q->setqueueentryvar = ast_true(val); 01941 } else if (!strcasecmp(param, "monitor-format")) { 01942 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 01943 } else if (!strcasecmp(param, "membermacro")) { 01944 ast_string_field_set(q, membermacro, val); 01945 } else if (!strcasecmp(param, "membergosub")) { 01946 ast_string_field_set(q, membergosub, val); 01947 } else if (!strcasecmp(param, "queue-youarenext")) { 01948 ast_string_field_set(q, sound_next, val); 01949 } else if (!strcasecmp(param, "queue-thereare")) { 01950 ast_string_field_set(q, sound_thereare, val); 01951 } else if (!strcasecmp(param, "queue-callswaiting")) { 01952 ast_string_field_set(q, sound_calls, val); 01953 } else if (!strcasecmp(param, "queue-quantity1")) { 01954 ast_string_field_set(q, queue_quantity1, val); 01955 } else if (!strcasecmp(param, "queue-quantity2")) { 01956 ast_string_field_set(q, queue_quantity2, val); 01957 } else if (!strcasecmp(param, "queue-holdtime")) { 01958 ast_string_field_set(q, sound_holdtime, val); 01959 } else if (!strcasecmp(param, "queue-minutes")) { 01960 ast_string_field_set(q, sound_minutes, val); 01961 } else if (!strcasecmp(param, "queue-minute")) { 01962 ast_string_field_set(q, sound_minute, val); 01963 } else if (!strcasecmp(param, "queue-seconds")) { 01964 ast_string_field_set(q, sound_seconds, val); 01965 } else if (!strcasecmp(param, "queue-thankyou")) { 01966 ast_string_field_set(q, sound_thanks, val); 01967 } else if (!strcasecmp(param, "queue-callerannounce")) { 01968 ast_string_field_set(q, sound_callerannounce, val); 01969 } else if (!strcasecmp(param, "queue-reporthold")) { 01970 ast_string_field_set(q, sound_reporthold, val); 01971 } else if (!strcasecmp(param, "announce-frequency")) { 01972 q->announcefrequency = atoi(val); 01973 } else if (!strcasecmp(param, "min-announce-frequency")) { 01974 q->minannouncefrequency = atoi(val); 01975 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name); 01976 } else if (!strcasecmp(param, "announce-round-seconds")) { 01977 q->roundingseconds = atoi(val); 01978 /* Rounding to any other values just doesn't make sense... */ 01979 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10 01980 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) { 01981 if (linenum >= 0) { 01982 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01983 "using 0 instead for queue '%s' at line %d of queues.conf\n", 01984 val, param, q->name, linenum); 01985 } else { 01986 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01987 "using 0 instead for queue '%s'\n", val, param, q->name); 01988 } 01989 q->roundingseconds=0; 01990 } 01991 } else if (!strcasecmp(param, "announce-holdtime")) { 01992 if (!strcasecmp(val, "once")) 01993 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 01994 else if (ast_true(val)) 01995 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 01996 else 01997 q->announceholdtime = 0; 01998 } else if (!strcasecmp(param, "announce-position")) { 01999 if (!strcasecmp(val, "limit")) 02000 q->announceposition = ANNOUNCEPOSITION_LIMIT; 02001 else if (!strcasecmp(val, "more")) 02002 q->announceposition = ANNOUNCEPOSITION_MORE_THAN; 02003 else if (ast_true(val)) 02004 q->announceposition = ANNOUNCEPOSITION_YES; 02005 else 02006 q->announceposition = ANNOUNCEPOSITION_NO; 02007 } else if (!strcasecmp(param, "announce-position-limit")) { 02008 q->announcepositionlimit = atoi(val); 02009 } else if (!strcasecmp(param, "periodic-announce")) { 02010 if (strchr(val, ',')) { 02011 char *s, *buf = ast_strdupa(val); 02012 unsigned int i = 0; 02013 02014 while ((s = strsep(&buf, ",|"))) { 02015 if (!q->sound_periodicannounce[i]) 02016 q->sound_periodicannounce[i] = ast_str_create(16); 02017 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s); 02018 i++; 02019 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 02020 break; 02021 } 02022 q->numperiodicannounce = i; 02023 } else { 02024 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val); 02025 q->numperiodicannounce = 1; 02026 } 02027 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 02028 q->periodicannouncefrequency = atoi(val); 02029 } else if (!strcasecmp(param, "relative-periodic-announce")) { 02030 q->relativeperiodicannounce = ast_true(val); 02031 } else if (!strcasecmp(param, "random-periodic-announce")) { 02032 q->randomperiodicannounce = ast_true(val); 02033 } else if (!strcasecmp(param, "retry")) { 02034 q->retry = atoi(val); 02035 if (q->retry <= 0) 02036 q->retry = DEFAULT_RETRY; 02037 } else if (!strcasecmp(param, "wrapuptime")) { 02038 q->wrapuptime = atoi(val); 02039 } else if (!strcasecmp(param, "penaltymemberslimit")) { 02040 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) { 02041 q->penaltymemberslimit = 0; 02042 } 02043 } else if (!strcasecmp(param, "autofill")) { 02044 q->autofill = ast_true(val); 02045 } else if (!strcasecmp(param, "monitor-type")) { 02046 if (!strcasecmp(val, "mixmonitor")) 02047 q->montype = 1; 02048 } else if (!strcasecmp(param, "autopause")) { 02049 q->autopause = autopause2int(val); 02050 } else if (!strcasecmp(param, "autopausedelay")) { 02051 q->autopausedelay = atoi(val); 02052 } else if (!strcasecmp(param, "autopausebusy")) { 02053 q->autopausebusy = ast_true(val); 02054 } else if (!strcasecmp(param, "autopauseunavail")) { 02055 q->autopauseunavail = ast_true(val); 02056 } else if (!strcasecmp(param, "maxlen")) { 02057 q->maxlen = atoi(val); 02058 if (q->maxlen < 0) 02059 q->maxlen = 0; 02060 } else if (!strcasecmp(param, "servicelevel")) { 02061 q->servicelevel= atoi(val); 02062 } else if (!strcasecmp(param, "strategy")) { 02063 int strategy; 02064 02065 /* We are a static queue and already have set this, no need to do it again */ 02066 if (failunknown) { 02067 return; 02068 } 02069 strategy = strat2int(val); 02070 if (strategy < 0) { 02071 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 02072 val, q->name); 02073 q->strategy = QUEUE_STRATEGY_RINGALL; 02074 } 02075 if (strategy == q->strategy) { 02076 return; 02077 } 02078 if (strategy == QUEUE_STRATEGY_LINEAR) { 02079 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n"); 02080 return; 02081 } 02082 q->strategy = strategy; 02083 } else if (!strcasecmp(param, "joinempty")) { 02084 parse_empty_options(val, &q->joinempty, 1); 02085 } else if (!strcasecmp(param, "leavewhenempty")) { 02086 parse_empty_options(val, &q->leavewhenempty, 0); 02087 } else if (!strcasecmp(param, "eventmemberstatus")) { 02088 q->maskmemberstatus = !ast_true(val); 02089 } else if (!strcasecmp(param, "eventwhencalled")) { 02090 if (!strcasecmp(val, "vars")) { 02091 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 02092 } else { 02093 q->eventwhencalled = ast_true(val) ? 1 : 0; 02094 } 02095 } else if (!strcasecmp(param, "reportholdtime")) { 02096 q->reportholdtime = ast_true(val); 02097 } else if (!strcasecmp(param, "memberdelay")) { 02098 q->memberdelay = atoi(val); 02099 } else if (!strcasecmp(param, "weight")) { 02100 q->weight = atoi(val); 02101 } else if (!strcasecmp(param, "timeoutrestart")) { 02102 q->timeoutrestart = ast_true(val); 02103 } else if (!strcasecmp(param, "defaultrule")) { 02104 ast_string_field_set(q, defaultrule, val); 02105 } else if (!strcasecmp(param, "timeoutpriority")) { 02106 if (!strcasecmp(val, "conf")) { 02107 q->timeoutpriority = TIMEOUT_PRIORITY_CONF; 02108 } else { 02109 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 02110 } 02111 } else if (failunknown) { 02112 if (linenum >= 0) { 02113 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 02114 q->name, param, linenum); 02115 } else { 02116 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 02117 } 02118 } 02119 }
| static char* queue_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7378 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.
07379 { 07380 switch ( cmd ) { 07381 case CLI_INIT: 07382 e->command = "queue show"; 07383 e->usage = 07384 "Usage: queue show\n" 07385 " Provides summary information on a specified queue.\n"; 07386 return NULL; 07387 case CLI_GENERATE: 07388 return complete_queue_show(a->line, a->word, a->pos, a->n); 07389 } 07390 07391 return __queues_show(NULL, a->fd, a->argc, a->argv); 07392 }
| static void queue_transfer_destroy | ( | void * | data | ) | [static] |
Definition at line 4283 of file app_queue.c.
References ast_free.
04284 { 04285 struct queue_transfer_ds *qtds = data; 04286 ast_free(qtds); 04287 }
| 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 4306 of file app_queue.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_uniqueid(), 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, call_queue::name, queue_ent::opos, queue_ent::parent, queue_transfer_ds::qe, queue_transfer_info, queue_ent::start, queue_transfer_ds::starttime, and update_queue().
04307 { 04308 struct queue_transfer_ds *qtds = data; 04309 struct queue_ent *qe = qtds->qe; 04310 struct member *member = qtds->member; 04311 time_t callstart = qtds->starttime; 04312 int callcompletedinsl = qtds->callcompletedinsl; 04313 struct ast_datastore *datastore; 04314 04315 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 04316 new_chan->exten, new_chan->context, (long) (callstart - qe->start), 04317 (long) (time(NULL) - callstart), qe->opos); 04318 04319 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart)); 04320 04321 /* No need to lock the channels because they are already locked in ast_do_masquerade */ 04322 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) { 04323 ast_channel_datastore_remove(old_chan, datastore); 04324 } else { 04325 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n"); 04326 } 04327 }
| static struct call_queue* queue_unref | ( | struct call_queue * | q | ) | [static, read] |
Definition at line 1311 of file app_queue.c.
References ao2_ref.
Referenced by queue_exec(), and queues_data_provider_get().
01312 { 01313 ao2_ref(q, -1); 01314 return NULL; 01315 }
| static int queues_data_provider_get | ( | const struct ast_data_search * | search, | |
| struct ast_data * | data_root | |||
| ) | [static] |
Definition at line 8572 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(), find_load_queue_rt_friendly(), call_queue::name, queue_unref(), queues, queues_data_provider_get_helper(), call_queue::realtime, and SENTINEL.
08574 { 08575 struct ao2_iterator i; 08576 struct call_queue *queue, *queue_realtime = NULL; 08577 struct ast_config *cfg; 08578 char *queuename; 08579 08580 /* load realtime queues. */ 08581 cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 08582 if (cfg) { 08583 for (queuename = ast_category_browse(cfg, NULL); 08584 !ast_strlen_zero(queuename); 08585 queuename = ast_category_browse(cfg, queuename)) { 08586 if ((queue = find_load_queue_rt_friendly(queuename))) { 08587 queue_unref(queue); 08588 } 08589 } 08590 ast_config_destroy(cfg); 08591 } 08592 08593 /* static queues. */ 08594 i = ao2_iterator_init(queues, 0); 08595 while ((queue = ao2_iterator_next(&i))) { 08596 ao2_lock(queue); 08597 if (queue->realtime) { 08598 queue_realtime = find_load_queue_rt_friendly(queue->name); 08599 if (!queue_realtime) { 08600 ao2_unlock(queue); 08601 queue_unref(queue); 08602 continue; 08603 } 08604 queue_unref(queue_realtime); 08605 } 08606 08607 queues_data_provider_get_helper(search, data_root, queue); 08608 ao2_unlock(queue); 08609 queue_unref(queue); 08610 } 08611 ao2_iterator_destroy(&i); 08612 08613 return 0; 08614 }
| 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 8466 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, queue_ent::next, and call_queue::strategy.
Referenced by queues_data_provider_get().
08468 { 08469 struct ao2_iterator im; 08470 struct member *member; 08471 struct queue_ent *qe; 08472 struct ast_data *data_queue, *data_members = NULL, *enum_node; 08473 struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel; 08474 08475 data_queue = ast_data_add_node(data_root, "queue"); 08476 if (!data_queue) { 08477 return; 08478 } 08479 08480 ast_data_add_structure(call_queue, data_queue, queue); 08481 08482 ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy)); 08483 ast_data_add_int(data_queue, "membercount", ao2_container_count(queue->members)); 08484 08485 /* announce position */ 08486 enum_node = ast_data_add_node(data_queue, "announceposition"); 08487 if (!enum_node) { 08488 return; 08489 } 08490 switch (queue->announceposition) { 08491 case ANNOUNCEPOSITION_LIMIT: 08492 ast_data_add_str(enum_node, "text", "limit"); 08493 break; 08494 case ANNOUNCEPOSITION_MORE_THAN: 08495 ast_data_add_str(enum_node, "text", "more"); 08496 break; 08497 case ANNOUNCEPOSITION_YES: 08498 ast_data_add_str(enum_node, "text", "yes"); 08499 break; 08500 case ANNOUNCEPOSITION_NO: 08501 ast_data_add_str(enum_node, "text", "no"); 08502 break; 08503 default: 08504 ast_data_add_str(enum_node, "text", "unknown"); 08505 break; 08506 } 08507 ast_data_add_int(enum_node, "value", queue->announceposition); 08508 08509 /* add queue members */ 08510 im = ao2_iterator_init(queue->members, 0); 08511 while ((member = ao2_iterator_next(&im))) { 08512 if (!data_members) { 08513 data_members = ast_data_add_node(data_queue, "members"); 08514 if (!data_members) { 08515 ao2_ref(member, -1); 08516 continue; 08517 } 08518 } 08519 08520 data_member = ast_data_add_node(data_members, "member"); 08521 if (!data_member) { 08522 ao2_ref(member, -1); 08523 continue; 08524 } 08525 08526 ast_data_add_structure(member, data_member, member); 08527 08528 ao2_ref(member, -1); 08529 } 08530 ao2_iterator_destroy(&im); 08531 08532 /* include the callers inside the result. */ 08533 if (queue->head) { 08534 for (qe = queue->head; qe; qe = qe->next) { 08535 if (!data_callers) { 08536 data_callers = ast_data_add_node(data_queue, "callers"); 08537 if (!data_callers) { 08538 continue; 08539 } 08540 } 08541 08542 data_caller = ast_data_add_node(data_callers, "caller"); 08543 if (!data_caller) { 08544 continue; 08545 } 08546 08547 ast_data_add_structure(queue_ent, data_caller, qe); 08548 08549 /* add the caller channel. */ 08550 data_caller_channel = ast_data_add_node(data_caller, "channel"); 08551 if (!data_caller_channel) { 08552 continue; 08553 } 08554 08555 ast_channel_data_add_structure(data_caller_channel, qe->chan, 1); 08556 } 08557 } 08558 08559 /* if this queue doesn't match remove the added queue. */ 08560 if (!ast_data_search_match(search, data_queue)) { 08561 ast_data_remove_node(data_root, data_queue); 08562 } 08563 }
| static void recalc_holdtime | ( | struct queue_ent * | qe, | |
| int | newholdtime | |||
| ) | [static] |
Definition at line 2817 of file app_queue.c.
References ao2_lock, ao2_unlock, call_queue::holdtime, and queue_ent::parent.
Referenced by try_calling().
02818 { 02819 int oldvalue; 02820 02821 /* Calculate holdtime using an exponential average */ 02822 /* Thanks to SRT for this contribution */ 02823 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 02824 02825 ao2_lock(qe->parent); 02826 oldvalue = qe->parent->holdtime; 02827 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 02828 ao2_unlock(qe->parent); 02829 }
| static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Record that a caller gave up on waiting in queue.
Definition at line 3451 of file app_queue.c.
References ao2_lock, ao2_unlock, ast_channel_uniqueid(), call_queue::callsabandoned, queue_ent::chan, EVENT_FLAG_AGENT, manager_event, call_queue::name, queue_ent::opos, queue_ent::parent, queue_ent::pos, set_queue_variables(), and queue_ent::start.
Referenced by queue_exec(), and try_calling().
03452 { 03453 set_queue_variables(qe->parent, qe->chan); 03454 ao2_lock(qe->parent); 03455 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 03456 "Queue: %s\r\n" 03457 "Uniqueid: %s\r\n" 03458 "Position: %d\r\n" 03459 "OriginalPosition: %d\r\n" 03460 "HoldTime: %d\r\n", 03461 qe->parent->name, ast_channel_uniqueid(qe->chan), qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 03462 03463 qe->parent->callsabandoned++; 03464 ao2_unlock(qe->parent); 03465 }
| static int reload | ( | void | ) | [static] |
Definition at line 8746 of file app_queue.c.
References AST_FLAGS_ALL, ast_unload_realtime(), QUEUE_RESET_STATS, and reload_handler().
08747 { 08748 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,}; 08749 ast_unload_realtime("queue_members"); 08750 reload_handler(1, &mask, NULL); 08751 return 0; 08752 }
| 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 7179 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().
07180 { 07181 int res = 0; 07182 07183 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) { 07184 res |= reload_queue_rules(reload); 07185 } 07186 if (ast_test_flag(mask, QUEUE_RESET_STATS)) { 07187 res |= clear_stats(queuename); 07188 } 07189 if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) { 07190 res |= reload_queues(reload, mask, queuename); 07191 } 07192 return res; 07193 }
| static void reload_queue_members | ( | void | ) | [static] |
Reload dynamic queue members persisted into the astdb.
Definition at line 5611 of file app_queue.c.
References add_to_queue(), ao2_t_find, ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), ast_debug, ast_log(), ast_strlen_zero(), ERANGE, errno, find_load_queue_rt_friendly(), member::interface, ast_db_entry::key, LOG_ERROR, LOG_NOTICE, LOG_WARNING, member::membername, call_queue::name, ast_db_entry::next, OBJ_POINTER, member::paused, member::penalty, PM_MAX_LEN, queue_t_unref, queues, RES_OUTOFMEMORY, member::state_interface, and strsep().
Referenced by load_module().
05612 { 05613 char *cur_ptr; 05614 const char *queue_name; 05615 char *member; 05616 char *interface; 05617 char *membername = NULL; 05618 char *state_interface; 05619 char *penalty_tok; 05620 int penalty = 0; 05621 char *paused_tok; 05622 int paused = 0; 05623 struct ast_db_entry *db_tree; 05624 struct ast_db_entry *entry; 05625 struct call_queue *cur_queue; 05626 char queue_data[PM_MAX_LEN]; 05627 05628 /* Each key in 'pm_family' is the name of a queue */ 05629 db_tree = ast_db_gettree(pm_family, NULL); 05630 for (entry = db_tree; entry; entry = entry->next) { 05631 05632 queue_name = entry->key + strlen(pm_family) + 2; 05633 05634 { 05635 struct call_queue tmpq = { 05636 .name = queue_name, 05637 }; 05638 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members"); 05639 } 05640 05641 if (!cur_queue) { 05642 cur_queue = find_load_queue_rt_friendly(queue_name); 05643 } 05644 05645 if (!cur_queue) { 05646 /* If the queue no longer exists, remove it from the 05647 * database */ 05648 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 05649 ast_db_del(pm_family, queue_name); 05650 continue; 05651 } 05652 05653 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) { 05654 queue_t_unref(cur_queue, "Expire reload reference"); 05655 continue; 05656 } 05657 05658 cur_ptr = queue_data; 05659 while ((member = strsep(&cur_ptr, ",|"))) { 05660 if (ast_strlen_zero(member)) 05661 continue; 05662 05663 interface = strsep(&member, ";"); 05664 penalty_tok = strsep(&member, ";"); 05665 paused_tok = strsep(&member, ";"); 05666 membername = strsep(&member, ";"); 05667 state_interface = strsep(&member, ";"); 05668 05669 if (!penalty_tok) { 05670 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 05671 break; 05672 } 05673 penalty = strtol(penalty_tok, NULL, 10); 05674 if (errno == ERANGE) { 05675 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 05676 break; 05677 } 05678 05679 if (!paused_tok) { 05680 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 05681 break; 05682 } 05683 paused = strtol(paused_tok, NULL, 10); 05684 if ((errno == ERANGE) || paused < 0 || paused > 1) { 05685 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 05686 break; 05687 } 05688 05689 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 05690 05691 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { 05692 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 05693 break; 05694 } 05695 } 05696 queue_t_unref(cur_queue, "Expire reload reference"); 05697 } 05698 05699 if (db_tree) { 05700 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 05701 ast_db_freetree(db_tree); 05702 } 05703 }
| 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 6769 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, rule_list::rules, and ast_variable::value.
Referenced by reload_handler().
06770 { 06771 struct ast_config *cfg; 06772 struct rule_list *rl_iter, *new_rl; 06773 struct penalty_rule *pr_iter; 06774 char *rulecat = NULL; 06775 struct ast_variable *rulevar = NULL; 06776 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06777 06778 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) { 06779 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n"); 06780 return AST_MODULE_LOAD_SUCCESS; 06781 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06782 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n"); 06783 return AST_MODULE_LOAD_SUCCESS; 06784 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 06785 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n"); 06786 return AST_MODULE_LOAD_SUCCESS; 06787 } 06788 06789 AST_LIST_LOCK(&rule_lists); 06790 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) { 06791 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list))) 06792 ast_free(pr_iter); 06793 ast_free(rl_iter); 06794 } 06795 while ((rulecat = ast_category_browse(cfg, rulecat))) { 06796 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) { 06797 AST_LIST_UNLOCK(&rule_lists); 06798 ast_config_destroy(cfg); 06799 return AST_MODULE_LOAD_FAILURE; 06800 } else { 06801 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name)); 06802 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list); 06803 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next) 06804 if(!strcasecmp(rulevar->name, "penaltychange")) 06805 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno); 06806 else 06807 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno); 06808 } 06809 } 06810 AST_LIST_UNLOCK(&rule_lists); 06811 06812 ast_config_destroy(cfg); 06813 06814 return AST_MODULE_LOAD_SUCCESS; 06815 }
| 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 7089 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_NOLOCK, OBJ_UNLINK, QUEUE_RELOAD_PARAMETERS, queue_set_global_params(), queues, and reload_single_queue().
Referenced by reload_handler().
07090 { 07091 struct ast_config *cfg; 07092 char *cat; 07093 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 07094 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); 07095 07096 if (!(cfg = ast_config_load("queues.conf", config_flags))) { 07097 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 07098 return -1; 07099 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 07100 return 0; 07101 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 07102 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n"); 07103 return -1; 07104 } 07105 07106 /* We've made it here, so it looks like we're doing operations on all queues. */ 07107 ao2_lock(queues); 07108 07109 /* Mark all queues as dead for the moment if we're reloading queues. 07110 * For clarity, we could just be reloading members, in which case we don't want to mess 07111 * with the other queue parameters at all*/ 07112 if (queue_reload) { 07113 ao2_callback(queues, OBJ_NODATA | OBJ_NOLOCK, mark_dead_and_unfound, (char *) queuename); 07114 } 07115 07116 /* Chug through config file */ 07117 cat = NULL; 07118 while ((cat = ast_category_browse(cfg, cat)) ) { 07119 if (!strcasecmp(cat, "general") && queue_reload) { 07120 queue_set_global_params(cfg); 07121 continue; 07122 } 07123 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename)) 07124 reload_single_queue(cfg, mask, cat); 07125 } 07126 07127 ast_config_destroy(cfg); 07128 /* Unref all the dead queues if we were reloading queues */ 07129 if (queue_reload) { 07130 ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NOLOCK, kill_dead_queues, (char *) queuename); 07131 } 07132 ao2_unlock(queues); 07133 return 0; 07134 }
| 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 6864 of file app_queue.c.
References ao2_find, ao2_link, ao2_ref, 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, call_queue::members, OBJ_POINTER, OBJ_UNLINK, parse(), member::paused, and member::penalty.
Referenced by reload_single_queue().
06865 { 06866 char *membername, *interface, *state_interface, *tmp; 06867 char *parse; 06868 struct member *cur, *newm; 06869 struct member tmpmem; 06870 int penalty; 06871 AST_DECLARE_APP_ARGS(args, 06872 AST_APP_ARG(interface); 06873 AST_APP_ARG(penalty); 06874 AST_APP_ARG(membername); 06875 AST_APP_ARG(state_interface); 06876 ); 06877 06878 if (ast_strlen_zero(memberdata)) { 06879 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n"); 06880 return; 06881 } 06882 06883 /* Add a new member */ 06884 parse = ast_strdupa(memberdata); 06885 06886 AST_STANDARD_APP_ARGS(args, parse); 06887 06888 interface = args.interface; 06889 if (!ast_strlen_zero(args.penalty)) { 06890 tmp = args.penalty; 06891 ast_strip(tmp); 06892 penalty = atoi(tmp); 06893 if (penalty < 0) { 06894 penalty = 0; 06895 } 06896 } else { 06897 penalty = 0; 06898 } 06899 06900 if (!ast_strlen_zero(args.membername)) { 06901 membername = args.membername; 06902 ast_strip(membername); 06903 } else { 06904 membername = interface; 06905 } 06906 06907 if (!ast_strlen_zero(args.state_interface)) { 06908 state_interface = args.state_interface; 06909 ast_strip(state_interface); 06910 } else { 06911 state_interface = interface; 06912 } 06913 06914 /* Find the old position in the list */ 06915 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 06916 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); 06917 if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) { 06918 ao2_link(q->members, newm); 06919 ao2_ref(newm, -1); 06920 } 06921 newm = NULL; 06922 06923 if (cur) { 06924 ao2_ref(cur, -1); 06925 } 06926 }
| 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 6960 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, call_queue::name, ast_variable::next, OBJ_MULTIPLE, OBJ_NODATA, OBJ_POINTER, OBJ_UNLINK, 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().
06961 { 06962 int new; 06963 struct call_queue *q = NULL; 06964 /*We're defining a queue*/ 06965 struct call_queue tmpq = { 06966 .name = queuename, 06967 }; 06968 const char *tmpvar; 06969 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); 06970 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER); 06971 int prev_weight = 0; 06972 struct ast_variable *var; 06973 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) { 06974 if (queue_reload) { 06975 /* Make one then */ 06976 if (!(q = alloc_queue(queuename))) { 06977 return; 06978 } 06979 } else { 06980 /* Since we're not reloading queues, this means that we found a queue 06981 * in the configuration file which we don't know about yet. Just return. 06982 */ 06983 return; 06984 } 06985 new = 1; 06986 } else { 06987 new = 0; 06988 } 06989 06990 if (!new) { 06991 ao2_lock(q); 06992 prev_weight = q->weight ? 1 : 0; 06993 } 06994 /* Check if we already found a queue with this name in the config file */ 06995 if (q->found) { 06996 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename); 06997 if (!new) { 06998 /* It should be impossible to *not* hit this case*/ 06999 ao2_unlock(q); 07000 } 07001 queue_t_unref(q, "We exist! Expiring temporary pointer"); 07002 return; 07003 } 07004 /* Due to the fact that the "linear" strategy will have a different allocation 07005 * scheme for queue members, we must devise the queue's strategy before other initializations. 07006 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2 07007 * container used will have only a single bucket instead of the typical number. 07008 */ 07009 if (queue_reload) { 07010 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) { 07011 q->strategy = strat2int(tmpvar); 07012 if (q->strategy < 0) { 07013 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 07014 tmpvar, q->name); 07015 q->strategy = QUEUE_STRATEGY_RINGALL; 07016 } 07017 } else { 07018 q->strategy = QUEUE_STRATEGY_RINGALL; 07019 } 07020 init_queue(q); 07021 } 07022 if (member_reload) { 07023 ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL); 07024 } 07025 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) { 07026 if (member_reload && !strcasecmp(var->name, "member")) { 07027 reload_single_member(var->value, q); 07028 } else if (queue_reload) { 07029 queue_set_param(q, var->name, var->value, var->lineno, 1); 07030 } 07031 } 07032 /* At this point, we've determined if the queue has a weight, so update use_weight 07033 * as appropriate 07034 */ 07035 if (!q->weight && prev_weight) { 07036 ast_atomic_fetchadd_int(&use_weight, -1); 07037 } 07038 else if (q->weight && !prev_weight) { 07039 ast_atomic_fetchadd_int(&use_weight, +1); 07040 } 07041 07042 /* Free remaining members marked as delme */ 07043 if (member_reload) { 07044 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q); 07045 } 07046 07047 if (new) { 07048 queues_t_link(queues, q, "Add queue to container"); 07049 } else { 07050 ao2_unlock(q); 07051 } 07052 queue_t_unref(q, "Expiring creation reference"); 07053 }
| 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 5299 of file app_queue.c.
References ao2_find, ao2_lock, ao2_ref, ao2_t_find, ao2_unlink, ao2_unlock, ast_copy_string(), ast_strlen_zero(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, manager_event, member::membername, call_queue::members, call_queue::name, OBJ_POINTER, queue_t_unref, queues, member::realtime, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, member::rt_uniqueid, and update_realtime_member_field().
Referenced by attempt_thread(), handle_queue_remove_member(), manager_remove_queue_member(), rqm_exec(), and scan_service().
05300 { 05301 struct call_queue *q, tmpq = { 05302 .name = queuename, 05303 }; 05304 struct member *mem, tmpmem; 05305 int res = RES_NOSUCHQUEUE; 05306 05307 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 05308 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) { 05309 ao2_lock(q); 05310 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 05311 /* XXX future changes should beware of this assumption!! */ 05312 /*Change Penalty on realtime users*/ 05313 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid) && negative_penalty_invalid) { 05314 update_realtime_member_field(mem, q->name, "penalty", "-1"); 05315 } else if (!mem->dynamic) { 05316 ao2_ref(mem, -1); 05317 ao2_unlock(q); 05318 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference"); 05319 return RES_NOT_DYNAMIC; 05320 } 05321 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 05322 "Queue: %s\r\n" 05323 "Location: %s\r\n" 05324 "MemberName: %s\r\n", 05325 q->name, mem->interface, mem->membername); 05326 ao2_unlink(q->members, mem); 05327 ao2_ref(mem, -1); 05328 05329 if (queue_persistent_members) 05330 dump_queue_members(q); 05331 05332 res = RES_OKAY; 05333 } else { 05334 res = RES_EXISTS; 05335 } 05336 ao2_unlock(q); 05337 queue_t_unref(q, "Expiring temporary reference"); 05338 } 05339 05340 return res; 05341 }
| 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 3087 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_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_name(), ast_channel_set_caller_event(), ast_channel_uniqueid(), ast_channel_unlock, ast_connected_line_copy_from_caller(), ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, ast_devstate2str(), ast_devstate_changed_literal(), AST_FLAG_ANSWERED_ELSEWHERE, ast_log(), ast_party_caller_set_init(), ast_party_redirecting_copy(), ast_request(), ast_set_callerid(), ast_set_flag, ast_strlen_zero(), ast_verb, ast_channel::caller, queue_ent::cancel_answered_elsewhere, ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_cdr::channel, ast_cdr::clid, compare_weight(), ast_channel::connected, ast_channel::context, ast_channel::data, ast_cdr::dcontext, callattempt::dial_callerid_absent, ast_channel::dialed, do_hang(), ast_cdr::dst, EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, get_queue_member_status(), ast_party_connected_line::id, ast_party_caller::id, member::ignorebusy, member::interface, callattempt::interface, ast_cdr::lastapp, callattempt::lastcall, ast_cdr::lastdata, callattempt::lastqueue, queue_ent::linpos, LOG_WARNING, ast_channel::macroexten, manager_event, callattempt::member, member::membername, ast_party_id::name, call_queue::name, ast_channel::nativeformats, ast_party_dialed::number, ast_party_id::number, queue_ent::parent, member::paused, 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, member::status, status, callattempt::stillgoing, ast_party_name::str, ast_party_number::str, ast_party_dialed::str, ast_party_dialed::transit_network_select, update_status(), ast_cdr::userfield, ast_party_name::valid, ast_party_number::valid, vars2manager(), ast_channel::whentohangup, and call_queue::wrapuptime.
Referenced by ring_one().
03088 { 03089 int res; 03090 int status; 03091 char tech[256]; 03092 char *location; 03093 const char *macrocontext, *macroexten; 03094 enum ast_device_state newstate; 03095 03096 /* on entry here, we know that tmp->chan == NULL */ 03097 if (tmp->member->paused) { 03098 ast_debug(1, "%s paused, can't receive call\n", tmp->interface); 03099 if (qe->chan->cdr) { 03100 ast_cdr_busy(qe->chan->cdr); 03101 } 03102 tmp->stillgoing = 0; 03103 return 0; 03104 } 03105 03106 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) || 03107 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) { 03108 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 03109 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface); 03110 if (qe->chan->cdr) { 03111 ast_cdr_busy(qe->chan->cdr); 03112 } 03113 tmp->stillgoing = 0; 03114 (*busies)++; 03115 return 0; 03116 } 03117 03118 if (!qe->parent->ringinuse || !tmp->member->ignorebusy) { 03119 if (check_state_unknown && (tmp->member->status == AST_DEVICE_UNKNOWN)) { 03120 newstate = ast_device_state(tmp->member->interface); 03121 if (newstate != tmp->member->status) { 03122 ast_log(LOG_WARNING, "Found a channel matching iterface %s while status was %s changed to %s\n", 03123 tmp->member->interface, ast_devstate2str(tmp->member->status), ast_devstate2str(newstate)); 03124 ast_devstate_changed_literal(newstate, tmp->member->interface); 03125 } 03126 } 03127 if ((tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 03128 ast_debug(1, "%s in use, can't receive call\n", tmp->interface); 03129 if (qe->chan->cdr) { 03130 ast_cdr_busy(qe->chan->cdr); 03131 } 03132 tmp->stillgoing = 0; 03133 return 0; 03134 } 03135 } 03136 03137 if (use_weight && compare_weight(qe->parent,tmp->member)) { 03138 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 03139 if (qe->chan->cdr) { 03140 ast_cdr_busy(qe->chan->cdr); 03141 } 03142 tmp->stillgoing = 0; 03143 (*busies)++; 03144 return 0; 03145 } 03146 03147 ast_copy_string(tech, tmp->interface, sizeof(tech)); 03148 if ((location = strchr(tech, '/'))) 03149 *location++ = '\0'; 03150 else 03151 location = ""; 03152 03153 /* Request the peer */ 03154 tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status); 03155 if (!tmp->chan) { /* If we can't, just go on to the next call */ 03156 if (qe->chan->cdr) { 03157 ast_cdr_busy(qe->chan->cdr); 03158 } 03159 tmp->stillgoing = 0; 03160 03161 ao2_lock(qe->parent); 03162 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member)); 03163 qe->parent->rrpos++; 03164 qe->linpos++; 03165 ao2_unlock(qe->parent); 03166 03167 (*busies)++; 03168 return 0; 03169 } 03170 03171 ast_channel_lock_both(tmp->chan, qe->chan); 03172 03173 if (qe->cancel_answered_elsewhere) { 03174 ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE); 03175 } 03176 tmp->chan->appl = "AppQueue"; 03177 tmp->chan->data = "(Outgoing Line)"; 03178 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup)); 03179 03180 /* If the new channel has no callerid, try to guess what it should be */ 03181 if (!tmp->chan->caller.id.number.valid) { 03182 if (qe->chan->connected.id.number.valid) { 03183 struct ast_party_caller caller; 03184 03185 ast_party_caller_set_init(&caller, &tmp->chan->caller); 03186 caller.id = qe->chan->connected.id; 03187 caller.ani = qe->chan->connected.ani; 03188 ast_channel_set_caller_event(tmp->chan, &caller, NULL); 03189 } else if (!ast_strlen_zero(qe->chan->dialed.number.str)) { 03190 ast_set_callerid(tmp->chan, qe->chan->dialed.number.str, NULL, NULL); 03191 } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) { 03192 ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL); 03193 } 03194 tmp->dial_callerid_absent = 1; 03195 } 03196 03197 ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting); 03198 03199 tmp->chan->dialed.transit_network_select = qe->chan->dialed.transit_network_select; 03200 03201 ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->caller); 03202 03203 /* Inherit specially named variables from parent channel */ 03204 ast_channel_inherit_variables(qe->chan, tmp->chan); 03205 ast_channel_datastore_inherit(qe->chan, tmp->chan); 03206 03207 /* Presense of ADSI CPE on outgoing channel follows ours */ 03208 tmp->chan->adsicpe = qe->chan->adsicpe; 03209 03210 /* Inherit context and extension */ 03211 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 03212 ast_channel_dialcontext_set(tmp->chan, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext); 03213 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 03214 if (!ast_strlen_zero(macroexten)) 03215 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 03216 else 03217 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 03218 if (ast_cdr_isset_unanswered()) { 03219 /* they want to see the unanswered dial attempts! */ 03220 /* set up the CDR fields on all the CDRs to give sensical information */ 03221 ast_cdr_setdestchan(tmp->chan->cdr, ast_channel_name(tmp->chan)); 03222 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid); 03223 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel); 03224 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src); 03225 strcpy(tmp->chan->cdr->dst, qe->chan->exten); 03226 strcpy(tmp->chan->cdr->dcontext, qe->chan->context); 03227 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp); 03228 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata); 03229 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags; 03230 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode); 03231 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); 03232 } 03233 03234 ast_channel_unlock(tmp->chan); 03235 ast_channel_unlock(qe->chan); 03236 03237 /* Place the call, but don't wait on the answer */ 03238 if ((res = ast_call(tmp->chan, location, 0))) { 03239 /* Again, keep going even if there's an error */ 03240 ast_debug(1, "ast call on peer returned %d\n", res); 03241 ast_verb(3, "Couldn't call %s\n", tmp->interface); 03242 do_hang(tmp); 03243 (*busies)++; 03244 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member)); 03245 return 0; 03246 } else if (qe->parent->eventwhencalled) { 03247 char vars[2048]; 03248 03249 ast_channel_lock_both(tmp->chan, qe->chan); 03250 03251 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 03252 "Queue: %s\r\n" 03253 "AgentCalled: %s\r\n" 03254 "AgentName: %s\r\n" 03255 "ChannelCalling: %s\r\n" 03256 "DestinationChannel: %s\r\n" 03257 "CallerIDNum: %s\r\n" 03258 "CallerIDName: %s\r\n" 03259 "ConnectedLineNum: %s\r\n" 03260 "ConnectedLineName: %s\r\n" 03261 "Context: %s\r\n" 03262 "Extension: %s\r\n" 03263 "Priority: %d\r\n" 03264 "Uniqueid: %s\r\n" 03265 "%s", 03266 qe->parent->name, tmp->interface, tmp->member->membername, ast_channel_name(qe->chan), ast_channel_name(tmp->chan), 03267 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"), 03268 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 03269 S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"), 03270 S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), 03271 qe->chan->context, qe->chan->exten, qe->chan->priority, ast_channel_uniqueid(qe->chan), 03272 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03273 03274 ast_channel_unlock(tmp->chan); 03275 ast_channel_unlock(qe->chan); 03276 03277 ast_verb(3, "Called %s\n", tmp->interface); 03278 } 03279 03280 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member)); 03281 return 1; 03282 }
| 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 3310 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().
03311 { 03312 int ret = 0; 03313 03314 while (ret == 0) { 03315 struct callattempt *best = find_best(outgoing); 03316 if (!best) { 03317 ast_debug(1, "Nobody left to try ringing in queue\n"); 03318 break; 03319 } 03320 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 03321 struct callattempt *cur; 03322 /* Ring everyone who shares this best metric (for ringall) */ 03323 for (cur = outgoing; cur; cur = cur->q_next) { 03324 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 03325 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 03326 ret |= ring_entry(qe, cur, busies); 03327 } 03328 } 03329 } else { 03330 /* Ring just the best channel */ 03331 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric); 03332 ret = ring_entry(qe, best, busies); 03333 } 03334 03335 /* If we have timed out, break out */ 03336 if (qe->expire && (time(NULL) >= qe->expire)) { 03337 ast_debug(1, "Queue timed out while ringing members.\n"); 03338 ret = 0; 03339 break; 03340 } 03341 } 03342 03343 return ret; 03344 }
| 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 3468 of file app_queue.c.
References ao2_lock, ao2_ref, ao2_unlock, ast_channel_name(), ast_channel_uniqueid(), ast_indicate(), ast_moh_start(), ast_queue_log(), ast_verb, call_queue::autopause, call_queue::autopausedelay, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, interface_exists(), member::lastcall, manager_event, queue_ent::moh, call_queue::name, 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().
03469 { 03470 ast_verb(3, "Nobody picked up in %d ms\n", rnatime); 03471 03472 /* Stop ringing, and resume MOH if specified */ 03473 if (qe->ring_when_ringing) { 03474 ast_indicate(qe->chan, -1); 03475 ast_moh_start(qe->chan, qe->moh, NULL); 03476 } 03477 03478 if (qe->parent->eventwhencalled) { 03479 char vars[2048]; 03480 03481 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer", 03482 "Queue: %s\r\n" 03483 "Uniqueid: %s\r\n" 03484 "Channel: %s\r\n" 03485 "Member: %s\r\n" 03486 "MemberName: %s\r\n" 03487 "Ringtime: %d\r\n" 03488 "%s", 03489 qe->parent->name, 03490 ast_channel_uniqueid(qe->chan), 03491 ast_channel_name(qe->chan), 03492 interface, 03493 membername, 03494 rnatime, 03495 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03496 } 03497 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime); 03498 if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) { 03499 if (qe->parent->autopausedelay > 0) { 03500 struct member *mem; 03501 ao2_lock(qe->parent); 03502 if ((mem = interface_exists(qe->parent, interface))) { 03503 time_t idletime = time(&idletime)-mem->lastcall; 03504 if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) { 03505 ao2_unlock(qe->parent); 03506 ao2_ref(mem, -1); 03507 return; 03508 } 03509 ao2_ref(mem, -1); 03510 } 03511 ao2_unlock(qe->parent); 03512 } 03513 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) { 03514 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) { 03515 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", 03516 interface, qe->parent->name); 03517 } else { 03518 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 03519 } 03520 } else { 03521 /* If queue autopause is mode all, just don't send any queue to stop. 03522 * the function will stop in all queues */ 03523 if (!set_member_paused("", interface, "Auto-Pause", 1)) { 03524 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n", 03525 interface, qe->parent->name); 03526 } else { 03527 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface); 03528 } 03529 } 03530 } 03531 return; 03532 }
| static int rqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
RemoveQueueMember application.
Definition at line 5778 of file app_queue.c.
References ao2_ref, args, AST_APP_ARG, ast_channel_name(), ast_channel_uniqueid(), ast_debug, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), find_member_by_queuename_and_interface(), member::interface, LOG_NOTICE, LOG_WARNING, member::membername, parse(), pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, and RES_OKAY.
Referenced by load_module().
05779 { 05780 int res=-1; 05781 char *parse, *temppos = NULL; 05782 struct member *mem = NULL; 05783 05784 AST_DECLARE_APP_ARGS(args, 05785 AST_APP_ARG(queuename); 05786 AST_APP_ARG(interface); 05787 AST_APP_ARG(options); 05788 ); 05789 05790 05791 if (ast_strlen_zero(data)) { 05792 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n"); 05793 return -1; 05794 } 05795 05796 parse = ast_strdupa(data); 05797 05798 AST_STANDARD_APP_ARGS(args, parse); 05799 05800 if (ast_strlen_zero(args.interface)) { 05801 args.interface = ast_strdupa(ast_channel_name(chan)); 05802 temppos = strrchr(args.interface, '-'); 05803 if (temppos) 05804 *temppos = '\0'; 05805 } 05806 05807 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface); 05808 05809 if (log_membername_as_agent) { 05810 mem = find_member_by_queuename_and_interface(args.queuename, args.interface); 05811 } 05812 05813 switch (remove_from_queue(args.queuename, args.interface)) { 05814 case RES_OKAY: 05815 if (!mem || ast_strlen_zero(mem->membername)) { 05816 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", ""); 05817 } else { 05818 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", ""); 05819 } 05820 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 05821 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 05822 res = 0; 05823 break; 05824 case RES_EXISTS: 05825 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 05826 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 05827 res = 0; 05828 break; 05829 case RES_NOSUCHQUEUE: 05830 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 05831 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 05832 res = 0; 05833 break; 05834 case RES_NOT_DYNAMIC: 05835 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 05836 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 05837 res = 0; 05838 break; 05839 } 05840 05841 if (mem) { 05842 ao2_ref(mem, -1); 05843 } 05844 05845 return res; 05846 }
| static void rt_handle_member_record | ( | struct call_queue * | q, | |
| char * | interface, | |||
| struct ast_config * | member_config | |||
| ) | [static] |
Find rt member record to update otherwise create one.
Search for member in queue, if found update penalty/paused state, if no member exists create one flag it as a RT member and add to queue member list.
Definition at line 2127 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_ref, ast_copy_string(), ast_log(), ast_queue_log(), ast_strlen_zero(), ast_true(), ast_variable_retrieve(), create_queue_member(), member::dead, member::ignorebusy, member::interface, LOG_WARNING, member::membername, call_queue::members, call_queue::name, 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().
02128 { 02129 struct member *m; 02130 struct ao2_iterator mem_iter; 02131 int penalty = 0; 02132 int paused = 0; 02133 int found = 0; 02134 int ignorebusy = 0; 02135 02136 const char *config_val; 02137 const char *rt_uniqueid = ast_variable_retrieve(member_config, interface, "uniqueid"); 02138 const char *membername = S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface); 02139 const char *state_interface = S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface); 02140 const char *penalty_str = ast_variable_retrieve(member_config, interface, "penalty"); 02141 const char *paused_str = ast_variable_retrieve(member_config, interface, "paused"); 02142 02143 if (ast_strlen_zero(rt_uniqueid)) { 02144 ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL")); 02145 return; 02146 } 02147 02148 if (penalty_str) { 02149 penalty = atoi(penalty_str); 02150 if ((penalty < 0) && negative_penalty_invalid) { 02151 return; 02152 } else if (penalty < 0) { 02153 penalty = 0; 02154 } 02155 } 02156 02157 if (paused_str) { 02158 paused = atoi(paused_str); 02159 if (paused < 0) { 02160 paused = 0; 02161 } 02162 } 02163 02164 if ((config_val = ast_variable_retrieve(member_config, interface, "ignorebusy"))) { 02165 ignorebusy = ast_true(config_val); 02166 } else { 02167 ignorebusy = 1; 02168 } 02169 02170 /* Find member by realtime uniqueid and update */ 02171 mem_iter = ao2_iterator_init(q->members, 0); 02172 while ((m = ao2_iterator_next(&mem_iter))) { 02173 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) { 02174 m->dead = 0; /* Do not delete this one. */ 02175 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 02176 if (paused_str) { 02177 m->paused = paused; 02178 } 02179 if (strcasecmp(state_interface, m->state_interface)) { 02180 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); 02181 } 02182 m->penalty = penalty; 02183 m->ignorebusy = ignorebusy; 02184 found = 1; 02185 ao2_ref(m, -1); 02186 break; 02187 } 02188 ao2_ref(m, -1); 02189 } 02190 ao2_iterator_destroy(&mem_iter); 02191 02192 /* Create a new member */ 02193 if (!found) { 02194 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { 02195 m->dead = 0; 02196 m->realtime = 1; 02197 m->ignorebusy = ignorebusy; 02198 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 02199 if (!log_membername_as_agent) { 02200 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); 02201 } else { 02202 ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); 02203 } 02204 ao2_link(q->members, m); 02205 ao2_ref(m, -1); 02206 m = NULL; 02207 } 02208 } 02209 }
| static int say_periodic_announcement | ( | struct queue_ent * | qe, | |
| int | ringing | |||
| ) | [static] |
Playback announcement to queued members if period has elapsed.
Definition at line 3395 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(), and wait_our_turn().
03396 { 03397 int res = 0; 03398 time_t now; 03399 03400 /* Get the current time */ 03401 time(&now); 03402 03403 /* Check to see if it is time to announce */ 03404 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 03405 return 0; 03406 03407 /* Stop the music on hold so we can play our own file */ 03408 if (ringing) 03409 ast_indicate(qe->chan,-1); 03410 else 03411 ast_moh_stop(qe->chan); 03412 03413 ast_verb(3, "Playing periodic announcement\n"); 03414 03415 if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) { 03416 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce; 03417 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce || 03418 ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) { 03419 qe->last_periodic_announce_sound = 0; 03420 } 03421 03422 /* play the announcement */ 03423 res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])); 03424 03425 if (res > 0 && !valid_exit(qe, res)) 03426 res = 0; 03427 03428 /* Resume Music on Hold if the caller is going to stay in the queue */ 03429 if (!res) { 03430 if (ringing) 03431 ast_indicate(qe->chan, AST_CONTROL_RINGING); 03432 else 03433 ast_moh_start(qe->chan, qe->moh, NULL); 03434 } 03435 03436 /* update last_periodic_announce_time */ 03437 if (qe->parent->relativeperiodicannounce) 03438 time(&qe->last_periodic_announce_time); 03439 else 03440 qe->last_periodic_announce_time = now; 03441 03442 /* Update the current periodic announcement to the next announcement */ 03443 if (!qe->parent->randomperiodicannounce) { 03444 qe->last_periodic_announce_sound++; 03445 } 03446 03447 return res; 03448 }
| static int say_position | ( | struct queue_ent * | qe, | |
| int | ringing | |||
| ) | [static] |
Definition at line 2673 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_channel_language(), ast_channel_name(), AST_CONTROL_RINGING, AST_DIGIT_ANY, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_say_number(), ast_verb, queue_ent::chan, call_queue::holdtime, queue_ent::last_pos, queue_ent::last_pos_said, call_queue::minannouncefrequency, queue_ent::moh, call_queue::name, queue_ent::parent, play_file(), queue_ent::pos, call_queue::queue_quantity1, call_queue::queue_quantity2, call_queue::roundingseconds, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_minute, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, queue_ent::start, and valid_exit().
Referenced by queue_exec(), and wait_our_turn().
02674 { 02675 int res = 0, avgholdmins, avgholdsecs, announceposition = 0; 02676 int say_thanks = 1; 02677 time_t now; 02678 02679 /* Let minannouncefrequency seconds pass between the start of each position announcement */ 02680 time(&now); 02681 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) 02682 return 0; 02683 02684 /* If either our position has changed, or we are over the freq timer, say position */ 02685 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 02686 return 0; 02687 02688 if (ringing) { 02689 ast_indicate(qe->chan,-1); 02690 } else { 02691 ast_moh_stop(qe->chan); 02692 } 02693 02694 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES || 02695 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN || 02696 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT && 02697 qe->pos <= qe->parent->announcepositionlimit)) 02698 announceposition = 1; 02699 02700 02701 if (announceposition == 1) { 02702 /* Say we're next, if we are */ 02703 if (qe->pos == 1) { 02704 res = play_file(qe->chan, qe->parent->sound_next); 02705 if (res) 02706 goto playout; 02707 else 02708 goto posout; 02709 } else { 02710 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 02711 /* More than Case*/ 02712 res = play_file(qe->chan, qe->parent->queue_quantity1); 02713 if (res) 02714 goto playout; 02715 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL); /* Needs gender */ 02716 if (res) 02717 goto playout; 02718 } else { 02719 /* Normal Case */ 02720 res = play_file(qe->chan, qe->parent->sound_thereare); 02721 if (res) 02722 goto playout; 02723 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL); /* Needs gender */ 02724 if (res) 02725 goto playout; 02726 } 02727 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 02728 /* More than Case*/ 02729 res = play_file(qe->chan, qe->parent->queue_quantity2); 02730 if (res) 02731 goto playout; 02732 } else { 02733 res = play_file(qe->chan, qe->parent->sound_calls); 02734 if (res) 02735 goto playout; 02736 } 02737 } 02738 } 02739 /* Round hold time to nearest minute */ 02740 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 02741 02742 /* If they have specified a rounding then round the seconds as well */ 02743 if (qe->parent->roundingseconds) { 02744 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 02745 avgholdsecs *= qe->parent->roundingseconds; 02746 } else { 02747 avgholdsecs = 0; 02748 } 02749 02750 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 02751 02752 /* If the hold time is >1 min, if it's enabled, and if it's not 02753 supposed to be only once and we have already said it, say it */ 02754 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime && 02755 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) || 02756 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) { 02757 res = play_file(qe->chan, qe->parent->sound_holdtime); 02758 if (res) 02759 goto playout; 02760 02761 if (avgholdmins >= 1) { 02762 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL); 02763 if (res) 02764 goto playout; 02765 02766 if (avgholdmins == 1) { 02767 res = play_file(qe->chan, qe->parent->sound_minute); 02768 if (res) 02769 goto playout; 02770 } else { 02771 res = play_file(qe->chan, qe->parent->sound_minutes); 02772 if (res) 02773 goto playout; 02774 } 02775 } 02776 if (avgholdsecs >= 1) { 02777 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL); 02778 if (res) 02779 goto playout; 02780 02781 res = play_file(qe->chan, qe->parent->sound_seconds); 02782 if (res) 02783 goto playout; 02784 } 02785 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) { 02786 say_thanks = 0; 02787 } 02788 02789 posout: 02790 if (qe->parent->announceposition) { 02791 ast_verb(3, "Told %s in %s their queue position (which was %d)\n", 02792 ast_channel_name(qe->chan), qe->parent->name, qe->pos); 02793 } 02794 if (say_thanks) { 02795 res = play_file(qe->chan, qe->parent->sound_thanks); 02796 } 02797 playout: 02798 02799 if ((res > 0 && !valid_exit(qe, res))) 02800 res = 0; 02801 02802 /* Set our last_pos indicators */ 02803 qe->last_pos = now; 02804 qe->last_pos_said = qe->pos; 02805 02806 /* Don't restart music on hold if we're about to exit the caller from the queue */ 02807 if (!res) { 02808 if (ringing) { 02809 ast_indicate(qe->chan, AST_CONTROL_RINGING); 02810 } else { 02811 ast_moh_start(qe->chan, qe->moh, NULL); 02812 } 02813 } 02814 return res; 02815 }
| 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 4240 of file app_queue.c.
References AGENT, ast_channel_name(), ast_channel_uniqueid(), 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().
04243 { 04244 const char *reason = NULL; /* silence dumb compilers */ 04245 04246 if (!qe->parent->eventwhencalled) 04247 return; 04248 04249 switch (rsn) { 04250 case CALLER: 04251 reason = "caller"; 04252 break; 04253 case AGENT: 04254 reason = "agent"; 04255 break; 04256 case TRANSFER: 04257 reason = "transfer"; 04258 break; 04259 } 04260 04261 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 04262 "Queue: %s\r\n" 04263 "Uniqueid: %s\r\n" 04264 "Channel: %s\r\n" 04265 "Member: %s\r\n" 04266 "MemberName: %s\r\n" 04267 "HoldTime: %ld\r\n" 04268 "TalkTime: %ld\r\n" 04269 "Reason: %s\r\n" 04270 "%s", 04271 queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername, 04272 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason, 04273 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : ""); 04274 }
| static int set_member_paused | ( | const char * | queuename, | |
| const char * | interface, | |||
| const char * | reason, | |||
| int | paused | |||
| ) | [static] |
Definition at line 5404 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, call_queue::name, 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().
05405 { 05406 int found = 0; 05407 struct call_queue *q; 05408 struct member *mem; 05409 struct ao2_iterator queue_iter; 05410 int failed; 05411 05412 /* Special event for when all queues are paused - individual events still generated */ 05413 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 05414 if (ast_strlen_zero(queuename)) 05415 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 05416 05417 queue_iter = ao2_iterator_init(queues, 0); 05418 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) { 05419 ao2_lock(q); 05420 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 05421 if ((mem = interface_exists(q, interface))) { 05422 if (mem->paused == paused) { 05423 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 05424 } 05425 05426 failed = 0; 05427 if (mem->realtime) { 05428 failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); 05429 } 05430 05431 if (failed) { 05432 ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface); 05433 ao2_ref(mem, -1); 05434 ao2_unlock(q); 05435 queue_t_unref(q, "Done with iterator"); 05436 continue; 05437 } 05438 found++; 05439 mem->paused = paused; 05440 05441 if (queue_persistent_members) 05442 dump_queue_members(q); 05443 05444 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, "")); 05445 05446 if (!ast_strlen_zero(reason)) { 05447 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 05448 "Queue: %s\r\n" 05449 "Location: %s\r\n" 05450 "MemberName: %s\r\n" 05451 "Paused: %d\r\n" 05452 "Reason: %s\r\n", 05453 q->name, mem->interface, mem->membername, paused, reason); 05454 } else { 05455 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 05456 "Queue: %s\r\n" 05457 "Location: %s\r\n" 05458 "MemberName: %s\r\n" 05459 "Paused: %d\r\n", 05460 q->name, mem->interface, mem->membername, paused); 05461 } 05462 ao2_ref(mem, -1); 05463 } 05464 } 05465 05466 if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) { 05467 ao2_unlock(q); 05468 queue_t_unref(q, "Done with iterator"); 05469 break; 05470 } 05471 05472 ao2_unlock(q); 05473 queue_t_unref(q, "Done with iterator"); 05474 } 05475 ao2_iterator_destroy(&queue_iter); 05476 05477 return found ? RESULT_SUCCESS : RESULT_FAILURE; 05478 }
| static int set_member_penalty | ( | const char * | queuename, | |
| const char * | interface, | |||
| int | penalty | |||
| ) | [static] |
Definition at line 5524 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_category_browse(), ast_check_realtime(), ast_load_realtime_multientry(), ast_log(), ast_strlen_zero(), find_load_queue_rt_friendly(), LOG_ERROR, queues, RESULT_FAILURE, RESULT_SUCCESS, SENTINEL, and set_member_penalty_help_members().
Referenced by handle_queue_set_member_penalty(), manager_queue_member_penalty(), queue_function_mem_write(), and queue_function_memberpenalty_write().
05525 { 05526 int foundinterface = 0, foundqueue = 0; 05527 struct call_queue *q; 05528 struct ast_config *queue_config = NULL; 05529 struct ao2_iterator queue_iter; 05530 05531 if (penalty < 0 && !negative_penalty_invalid) { 05532 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty); 05533 return RESULT_FAILURE; 05534 } 05535 05536 if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */ 05537 if (ast_check_realtime("queues")) { 05538 char *queuename; 05539 queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 05540 if (queue_config) { 05541 for (queuename = ast_category_browse(queue_config, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(queue_config, queuename)) { 05542 if ((q = find_load_queue_rt_friendly(queuename))) { 05543 foundqueue++; 05544 foundinterface += set_member_penalty_help_members(q, interface, penalty); 05545 } 05546 } 05547 } 05548 } 05549 05550 /* After hitting realtime queues, go back and get the regular ones. */ 05551 queue_iter = ao2_iterator_init(queues, 0); 05552 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 05553 foundqueue++; 05554 foundinterface += set_member_penalty_help_members(q, interface, penalty); 05555 } 05556 ao2_iterator_destroy(&queue_iter); 05557 } else { /* We actually have a queuename, so we can just act on the single queue. */ 05558 if ((q = find_load_queue_rt_friendly(queuename))) { 05559 foundqueue++; 05560 foundinterface += set_member_penalty_help_members(q, interface, penalty); 05561 } 05562 } 05563 05564 if (foundinterface) { 05565 return RESULT_SUCCESS; 05566 } else if (!foundqueue) { 05567 ast_log (LOG_ERROR, "Invalid queuename\n"); 05568 } else { 05569 ast_log (LOG_ERROR, "Invalid interface\n"); 05570 } 05571 05572 return RESULT_FAILURE; 05573 }
| static int set_member_penalty_help_members | ( | struct call_queue * | q, | |
| const char * | interface, | |||
| int | penalty | |||
| ) | [static] |
Definition at line 5489 of file app_queue.c.
References ao2_lock, ao2_ref, ao2_unlock, ast_queue_log(), EVENT_FLAG_AGENT, member::interface, interface_exists(), manager_event, call_queue::name, member::penalty, member::realtime, and update_realtime_member_field().
Referenced by set_member_penalty().
05490 { 05491 struct member *mem; 05492 int foundinterface = 0; 05493 char rtpenalty[80]; 05494 05495 ao2_lock(q); 05496 if ((mem = interface_exists(q, interface))) { 05497 foundinterface++; 05498 if (!mem->realtime) { 05499 mem->penalty = penalty; 05500 } else { 05501 sprintf(rtpenalty, "%i", penalty); 05502 update_realtime_member_field(mem, q->name, "penalty", rtpenalty); 05503 } 05504 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty); 05505 manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty", 05506 "Queue: %s\r\n" 05507 "Location: %s\r\n" 05508 "Penalty: %d\r\n", 05509 q->name, mem->interface, penalty); 05510 ao2_ref(mem, -1); 05511 } 05512 ao2_unlock(q); 05513 05514 return foundinterface; 05515 }
| static void set_queue_result | ( | struct ast_channel * | chan, | |
| enum queue_result | res | |||
| ) | [static] |
sets the QUEUESTATUS channel variable
Definition at line 1224 of file app_queue.c.
References ARRAY_LEN, pbx_builtin_setvar_helper(), queue_results, and text.
Referenced by queue_exec().
01225 { 01226 int i; 01227 01228 for (i = 0; i < ARRAY_LEN(queue_results); i++) { 01229 if (queue_results[i].id == res) { 01230 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 01231 return; 01232 } 01233 } 01234 }
| static void set_queue_variables | ( | struct call_queue * | q, | |
| struct ast_channel * | chan | |||
| ) | [static] |
Set variables of queue.
Definition at line 1319 of file app_queue.c.
References ao2_lock, ao2_unlock, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::count, call_queue::holdtime, int2strat(), call_queue::maxlen, call_queue::name, pbx_builtin_setvar_multiple(), call_queue::servicelevel, call_queue::setqueuevar, call_queue::strategy, and call_queue::talktime.
Referenced by end_bridge_callback(), queue_exec(), record_abandoned(), and try_calling().
01320 { 01321 char interfacevar[256]=""; 01322 float sl = 0; 01323 01324 ao2_lock(q); 01325 01326 if (q->setqueuevar) { 01327 sl = 0; 01328 if (q->callscompleted > 0) 01329 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 01330 01331 snprintf(interfacevar, sizeof(interfacevar), 01332 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 01333 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 01334 01335 ao2_unlock(q); 01336 01337 pbx_builtin_setvar_multiple(chan, interfacevar); 01338 } else { 01339 ao2_unlock(q); 01340 } 01341 }
| 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 4344 of file app_queue.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_log(), queue_transfer_ds::callcompletedinsl, queue_ent::chan, ast_datastore::data, LOG_WARNING, queue_transfer_ds::member, queue_transfer_ds::qe, queue_transfer_info, and queue_transfer_ds::starttime.
Referenced by try_calling().
04345 { 04346 struct ast_datastore *ds; 04347 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds)); 04348 04349 if (!qtds) { 04350 ast_log(LOG_WARNING, "Memory allocation error!\n"); 04351 return NULL; 04352 } 04353 04354 ast_channel_lock(qe->chan); 04355 if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) { 04356 ast_channel_unlock(qe->chan); 04357 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n"); 04358 return NULL; 04359 } 04360 04361 qtds->qe = qe; 04362 /* This member is refcounted in try_calling, so no need to add it here, too */ 04363 qtds->member = member; 04364 qtds->starttime = starttime; 04365 qtds->callcompletedinsl = callcompletedinsl; 04366 ds->data = qtds; 04367 ast_channel_datastore_add(qe->chan, ds); 04368 ast_channel_unlock(qe->chan); 04369 return ds; 04370 }
| 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 3371 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().
03372 { 03373 struct callattempt *best = find_best(outgoing); 03374 03375 if (best) { 03376 /* Ring just the best channel */ 03377 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 03378 qe->linpos = best->metric % 1000; 03379 } else { 03380 /* Just increment rrpos */ 03381 if (qe->linwrapped) { 03382 /* No more channels, start over */ 03383 qe->linpos = 0; 03384 } else { 03385 /* Prioritize next entry */ 03386 qe->linpos++; 03387 } 03388 } 03389 qe->linwrapped = 0; 03390 03391 return 0; 03392 }
| 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 3347 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().
03348 { 03349 struct callattempt *best = find_best(outgoing); 03350 03351 if (best) { 03352 /* Ring just the best channel */ 03353 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 03354 qe->parent->rrpos = best->metric % 1000; 03355 } else { 03356 /* Just increment rrpos */ 03357 if (qe->parent->wrapped) { 03358 /* No more channels, start over */ 03359 qe->parent->rrpos = 0; 03360 } else { 03361 /* Prioritize next entry */ 03362 qe->parent->rrpos++; 03363 } 03364 } 03365 qe->parent->wrapped = 0; 03366 03367 return 0; 03368 }
| static int strat2int | ( | const char * | strategy | ) | [static] |
Definition at line 1248 of file app_queue.c.
References ARRAY_LEN, and strategies.
Referenced by find_queue_by_name_rt(), queue_set_param(), and reload_single_queue().
01249 { 01250 int x; 01251 01252 for (x = 0; x < ARRAY_LEN(strategies); x++) { 01253 if (!strcasecmp(strategy, strategies[x].name)) 01254 return strategies[x].strategy; 01255 } 01256 01257 return -1; 01258 }
| 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 4424 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, 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_language(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_name(), ast_channel_sendurl(), ast_channel_setoption(), ast_channel_supports_html(), ast_channel_uniqueid(), 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(), 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, errno, 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, call_queue::membergosub, call_queue::membermacro, member::membername, call_queue::members, call_queue::monfmt, call_queue::montype, call_queue::name, 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, queue_transfer_info, 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(), call_queue::sound_callerannounce, call_queue::sound_minutes, call_queue::sound_reporthold, call_queue::sound_seconds, 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_connectedline(), update_queue(), ast_party_number::valid, vars2manager(), wait_for_answer(), X_REC_IN, and X_REC_OUT.
Referenced by queue_exec().
04425 { 04426 struct member *cur; 04427 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 04428 int to, orig; 04429 char oldexten[AST_MAX_EXTENSION]=""; 04430 char oldcontext[AST_MAX_CONTEXT]=""; 04431 char queuename[256]=""; 04432 char interfacevar[256]=""; 04433 struct ast_channel *peer; 04434 struct ast_channel *which; 04435 struct callattempt *lpeer; 04436 struct member *member; 04437 struct ast_app *application; 04438 int res = 0, bridge = 0; 04439 int numbusies = 0; 04440 int x=0; 04441 char *announce = NULL; 04442 char digit = 0; 04443 time_t callstart; 04444 time_t now = time(NULL); 04445 struct ast_bridge_config bridge_config; 04446 char nondataquality = 1; 04447 char *agiexec = NULL; 04448 char *macroexec = NULL; 04449 char *gosubexec = NULL; 04450 const char *monitorfilename; 04451 const char *monitor_exec; 04452 const char *monitor_options; 04453 char tmpid[256], tmpid2[256]; 04454 char meid[1024], meid2[1024]; 04455 char mixmonargs[1512]; 04456 struct ast_app *mixmonapp = NULL; 04457 char *p; 04458 char vars[2048]; 04459 int forwardsallowed = 1; 04460 int update_connectedline = 1; 04461 int callcompletedinsl; 04462 struct ao2_iterator memi; 04463 struct ast_datastore *datastore, *transfer_ds; 04464 struct queue_end_bridge *queue_end_bridge = NULL; 04465 04466 ast_channel_lock(qe->chan); 04467 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL); 04468 ast_channel_unlock(qe->chan); 04469 04470 memset(&bridge_config, 0, sizeof(bridge_config)); 04471 tmpid[0] = 0; 04472 meid[0] = 0; 04473 time(&now); 04474 04475 /* If we've already exceeded our timeout, then just stop 04476 * This should be extremely rare. queue_exec will take care 04477 * of removing the caller and reporting the timeout as the reason. 04478 */ 04479 if (qe->expire && now >= qe->expire) { 04480 res = 0; 04481 goto out; 04482 } 04483 04484 for (; options && *options; options++) 04485 switch (*options) { 04486 case 't': 04487 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 04488 break; 04489 case 'T': 04490 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 04491 break; 04492 case 'w': 04493 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 04494 break; 04495 case 'W': 04496 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 04497 break; 04498 case 'c': 04499 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN); 04500 break; 04501 case 'd': 04502 nondataquality = 0; 04503 break; 04504 case 'h': 04505 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 04506 break; 04507 case 'H': 04508 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 04509 break; 04510 case 'k': 04511 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL); 04512 break; 04513 case 'K': 04514 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL); 04515 break; 04516 case 'n': 04517 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) 04518 (*tries)++; 04519 else 04520 *tries = ao2_container_count(qe->parent->members); 04521 *noption = 1; 04522 break; 04523 case 'i': 04524 forwardsallowed = 0; 04525 break; 04526 case 'I': 04527 update_connectedline = 0; 04528 break; 04529 case 'x': 04530 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON); 04531 break; 04532 case 'X': 04533 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON); 04534 break; 04535 case 'C': 04536 qe->cancel_answered_elsewhere = 1; 04537 break; 04538 } 04539 04540 /* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited. 04541 (this is mainly to support chan_local) 04542 */ 04543 if (ast_test_flag(qe->chan, AST_FLAG_ANSWERED_ELSEWHERE)) { 04544 qe->cancel_answered_elsewhere = 1; 04545 } 04546 04547 ao2_lock(qe->parent); 04548 ast_debug(1, "%s is trying to call a queue member.\n", 04549 ast_channel_name(qe->chan)); 04550 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 04551 if (!ast_strlen_zero(qe->announce)) 04552 announce = qe->announce; 04553 if (!ast_strlen_zero(announceoverride)) 04554 announce = announceoverride; 04555 04556 memi = ao2_iterator_init(qe->parent->members, 0); 04557 while ((cur = ao2_iterator_next(&memi))) { 04558 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 04559 struct ast_dialed_interface *di; 04560 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 04561 if (!tmp) { 04562 ao2_ref(cur, -1); 04563 ao2_iterator_destroy(&memi); 04564 ao2_unlock(qe->parent); 04565 goto out; 04566 } 04567 if (!datastore) { 04568 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) { 04569 callattempt_free(tmp); 04570 ao2_ref(cur, -1); 04571 ao2_iterator_destroy(&memi); 04572 ao2_unlock(qe->parent); 04573 goto out; 04574 } 04575 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 04576 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 04577 callattempt_free(tmp); 04578 ao2_ref(cur, -1); 04579 ao2_iterator_destroy(&memi); 04580 ao2_unlock(&qe->parent); 04581 goto out; 04582 } 04583 datastore->data = dialed_interfaces; 04584 AST_LIST_HEAD_INIT(dialed_interfaces); 04585 04586 ast_channel_lock(qe->chan); 04587 ast_channel_datastore_add(qe->chan, datastore); 04588 ast_channel_unlock(qe->chan); 04589 } else 04590 dialed_interfaces = datastore->data; 04591 04592 AST_LIST_LOCK(dialed_interfaces); 04593 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 04594 if (!strcasecmp(cur->interface, di->interface)) { 04595 ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n", 04596 di->interface); 04597 break; 04598 } 04599 } 04600 AST_LIST_UNLOCK(dialed_interfaces); 04601 04602 if (di) { 04603 callattempt_free(tmp); 04604 ao2_ref(cur, -1); 04605 continue; 04606 } 04607 04608 /* It is always ok to dial a Local interface. We only keep track of 04609 * which "real" interfaces have been dialed. The Local channel will 04610 * inherit this list so that if it ends up dialing a real interface, 04611 * it won't call one that has already been called. */ 04612 if (strncasecmp(cur->interface, "Local/", 6)) { 04613 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) { 04614 callattempt_free(tmp); 04615 ao2_ref(cur, -1); 04616 ao2_iterator_destroy(&memi); 04617 ao2_unlock(qe->parent); 04618 goto out; 04619 } 04620 strcpy(di->interface, cur->interface); 04621 04622 AST_LIST_LOCK(dialed_interfaces); 04623 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 04624 AST_LIST_UNLOCK(dialed_interfaces); 04625 } 04626 04627 ast_channel_lock(qe->chan); 04628 /* 04629 * Seed the callattempt's connected line information with previously 04630 * acquired connected line info from the queued channel. The 04631 * previously acquired connected line info could have been set 04632 * through the CONNECTED_LINE dialplan function. 04633 */ 04634 ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected); 04635 ast_channel_unlock(qe->chan); 04636 04637 tmp->stillgoing = -1; 04638 tmp->member = cur;/* Place the reference for cur into callattempt. */ 04639 tmp->lastcall = cur->lastcall; 04640 tmp->lastqueue = cur->lastqueue; 04641 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 04642 /* Special case: If we ring everyone, go ahead and ring them, otherwise 04643 just calculate their metric for the appropriate strategy */ 04644 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 04645 /* Put them in the list of outgoing thingies... We're ready now. 04646 XXX If we're forcibly removed, these outgoing calls won't get 04647 hung up XXX */ 04648 tmp->q_next = outgoing; 04649 outgoing = tmp; 04650 /* If this line is up, don't try anybody else */ 04651 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 04652 break; 04653 } else { 04654 callattempt_free(tmp); 04655 } 04656 } 04657 ao2_iterator_destroy(&memi); 04658 04659 if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) { 04660 /* Application arguments have higher timeout priority (behaviour for <=1.6) */ 04661 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 04662 to = (qe->expire - now) * 1000; 04663 else 04664 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 04665 } else { 04666 /* Config timeout is higher priority thatn application timeout */ 04667 if (qe->expire && qe->expire<=now) { 04668 to = 0; 04669 } else if (qe->parent->timeout) { 04670 to = qe->parent->timeout * 1000; 04671 } else { 04672 to = -1; 04673 } 04674 } 04675 orig = to; 04676 ++qe->pending; 04677 ao2_unlock(qe->parent); 04678 ring_one(qe, outgoing, &numbusies); 04679 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline); 04680 /* The ast_channel_datastore_remove() function could fail here if the 04681 * datastore was moved to another channel during a masquerade. If this is 04682 * the case, don't free the datastore here because later, when the channel 04683 * to which the datastore was moved hangs up, it will attempt to free this 04684 * datastore again, causing a crash 04685 */ 04686 ast_channel_lock(qe->chan); 04687 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) { 04688 ast_datastore_free(datastore); 04689 } 04690 ast_channel_unlock(qe->chan); 04691 ao2_lock(qe->parent); 04692 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) { 04693 store_next_rr(qe, outgoing); 04694 04695 } 04696 if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) { 04697 store_next_lin(qe, outgoing); 04698 } 04699 ao2_unlock(qe->parent); 04700 peer = lpeer ? lpeer->chan : NULL; 04701 if (!peer) { 04702 qe->pending = 0; 04703 if (to) { 04704 /* Must gotten hung up */ 04705 res = -1; 04706 } else { 04707 /* User exited by pressing a digit */ 04708 res = digit; 04709 } 04710 if (res == -1) 04711 ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan)); 04712 if (ast_cdr_isset_unanswered()) { 04713 /* channel contains the name of one of the outgoing channels 04714 in its CDR; zero out this CDR to avoid a dual-posting */ 04715 struct callattempt *o; 04716 for (o = outgoing; o; o = o->q_next) { 04717 if (!o->chan) { 04718 continue; 04719 } 04720 if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) { 04721 ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED); 04722 break; 04723 } 04724 } 04725 } 04726 } else { /* peer is valid */ 04727 /* Ah ha! Someone answered within the desired timeframe. Of course after this 04728 we will always return with -1 so that it is hung up properly after the 04729 conversation. */ 04730 if (!strcmp(qe->chan->tech->type, "DAHDI")) 04731 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 04732 if (!strcmp(peer->tech->type, "DAHDI")) 04733 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 04734 /* Update parameters for the queue */ 04735 time(&now); 04736 recalc_holdtime(qe, (now - qe->start)); 04737 ao2_lock(qe->parent); 04738 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 04739 ao2_unlock(qe->parent); 04740 member = lpeer->member; 04741 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ 04742 ao2_ref(member, 1); 04743 hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere); 04744 outgoing = NULL; 04745 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 04746 int res2; 04747 04748 res2 = ast_autoservice_start(qe->chan); 04749 if (!res2) { 04750 if (qe->parent->memberdelay) { 04751 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 04752 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 04753 } 04754 if (!res2 && announce) { 04755 play_file(peer, announce); 04756 } 04757 if (!res2 && qe->parent->reportholdtime) { 04758 if (!play_file(peer, qe->parent->sound_reporthold)) { 04759 int holdtime, holdtimesecs; 04760 04761 time(&now); 04762 holdtime = abs((now - qe->start) / 60); 04763 holdtimesecs = abs((now - qe->start) % 60); 04764 if (holdtime > 0) { 04765 ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), NULL); 04766 play_file(peer, qe->parent->sound_minutes); 04767 } 04768 if (holdtimesecs > 1) { 04769 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), NULL); 04770 play_file(peer, qe->parent->sound_seconds); 04771 } 04772 } 04773 } 04774 } 04775 res2 |= ast_autoservice_stop(qe->chan); 04776 if (ast_check_hangup(peer)) { 04777 /* Agent must have hung up */ 04778 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer)); 04779 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", ""); 04780 if (qe->parent->eventwhencalled) 04781 manager_event(EVENT_FLAG_AGENT, "AgentDump", 04782 "Queue: %s\r\n" 04783 "Uniqueid: %s\r\n" 04784 "Channel: %s\r\n" 04785 "Member: %s\r\n" 04786 "MemberName: %s\r\n" 04787 "%s", 04788 queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername, 04789 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 04790 ast_hangup(peer); 04791 ao2_ref(member, -1); 04792 goto out; 04793 } else if (res2) { 04794 /* Caller must have hung up just before being connected*/ 04795 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer)); 04796 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 04797 record_abandoned(qe); 04798 ast_hangup(peer); 04799 ao2_ref(member, -1); 04800 return -1; 04801 } 04802 } 04803 /* Stop music on hold */ 04804 if (ringing) 04805 ast_indicate(qe->chan,-1); 04806 else 04807 ast_moh_stop(qe->chan); 04808 /* If appropriate, log that we have a destination channel */ 04809 if (qe->chan->cdr) { 04810 ast_cdr_setdestchan(qe->chan->cdr, ast_channel_name(peer)); 04811 } 04812 /* Make sure channels are compatible */ 04813 res = ast_channel_make_compatible(qe->chan, peer); 04814 if (res < 0) { 04815 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", ""); 04816 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(qe->chan), ast_channel_name(peer)); 04817 record_abandoned(qe); 04818 ast_cdr_failed(qe->chan->cdr); 04819 ast_hangup(peer); 04820 ao2_ref(member, -1); 04821 return -1; 04822 } 04823 04824 /* Play announcement to the caller telling it's his turn if defined */ 04825 if (!ast_strlen_zero(qe->parent->sound_callerannounce)) { 04826 if (play_file(qe->chan, qe->parent->sound_callerannounce)) 04827 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce); 04828 } 04829 04830 ao2_lock(qe->parent); 04831 /* if setinterfacevar is defined, make member variables available to the channel */ 04832 /* use pbx_builtin_setvar to set a load of variables with one call */ 04833 if (qe->parent->setinterfacevar) { 04834 snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d", 04835 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime); 04836 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 04837 pbx_builtin_setvar_multiple(peer, interfacevar); 04838 } 04839 04840 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */ 04841 /* use pbx_builtin_setvar to set a load of variables with one call */ 04842 if (qe->parent->setqueueentryvar) { 04843 snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d", 04844 (long) time(NULL) - qe->start, qe->opos); 04845 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 04846 pbx_builtin_setvar_multiple(peer, interfacevar); 04847 } 04848 04849 ao2_unlock(qe->parent); 04850 04851 /* try to set queue variables if configured to do so*/ 04852 set_queue_variables(qe->parent, qe->chan); 04853 set_queue_variables(qe->parent, peer); 04854 04855 ast_channel_lock(qe->chan); 04856 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) { 04857 monitorfilename = ast_strdupa(monitorfilename); 04858 } 04859 ast_channel_unlock(qe->chan); 04860 /* Begin Monitoring */ 04861 if (qe->parent->monfmt && *qe->parent->monfmt) { 04862 if (!qe->parent->montype) { 04863 const char *monexec; 04864 ast_debug(1, "Starting Monitor as requested.\n"); 04865 ast_channel_lock(qe->chan); 04866 if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) { 04867 which = qe->chan; 04868 monexec = monexec ? ast_strdupa(monexec) : NULL; 04869 } 04870 else 04871 which = peer; 04872 ast_channel_unlock(qe->chan); 04873 if (monitorfilename) { 04874 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT); 04875 } else if (qe->chan->cdr) { 04876 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT); 04877 } else { 04878 /* Last ditch effort -- no CDR, make up something */ 04879 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 04880 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT); 04881 } 04882 if (!ast_strlen_zero(monexec)) { 04883 ast_monitor_setjoinfiles(which, 1); 04884 } 04885 } else { 04886 mixmonapp = pbx_findapp("MixMonitor"); 04887 04888 if (mixmonapp) { 04889 ast_debug(1, "Starting MixMonitor as requested.\n"); 04890 if (!monitorfilename) { 04891 if (qe->chan->cdr) { 04892 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)); 04893 } else { 04894 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 04895 } 04896 } else { 04897 const char *m = monitorfilename; 04898 for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) { 04899 switch (*m) { 04900 case '^': 04901 if (*(m + 1) == '{') 04902 *p = '$'; 04903 break; 04904 case ',': 04905 *p++ = '\\'; 04906 /* Fall through */ 04907 default: 04908 *p = *m; 04909 } 04910 if (*m == '\0') 04911 break; 04912 } 04913 if (p == tmpid2 + sizeof(tmpid2)) 04914 tmpid2[sizeof(tmpid2) - 1] = '\0'; 04915 04916 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 04917 } 04918 04919 ast_channel_lock(qe->chan); 04920 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) { 04921 monitor_exec = ast_strdupa(monitor_exec); 04922 } 04923 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) { 04924 monitor_options = ast_strdupa(monitor_options); 04925 } else { 04926 monitor_options = ""; 04927 } 04928 ast_channel_unlock(qe->chan); 04929 04930 if (monitor_exec) { 04931 const char *m = monitor_exec; 04932 for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) { 04933 switch (*m) { 04934 case '^': 04935 if (*(m + 1) == '{') 04936 *p = '$'; 04937 break; 04938 case ',': 04939 *p++ = '\\'; 04940 /* Fall through */ 04941 default: 04942 *p = *m; 04943 } 04944 if (*m == '\0') 04945 break; 04946 } 04947 if (p == meid2 + sizeof(meid2)) 04948 meid2[sizeof(meid2) - 1] = '\0'; 04949 04950 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 04951 } 04952 04953 snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt); 04954 04955 if (!ast_strlen_zero(monitor_exec)) 04956 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec); 04957 else 04958 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options); 04959 04960 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 04961 /* We purposely lock the CDR so that pbx_exec does not update the application data */ 04962 if (qe->chan->cdr) { 04963 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 04964 } 04965 pbx_exec(qe->chan, mixmonapp, mixmonargs); 04966 if (qe->chan->cdr) { 04967 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 04968 } 04969 } else { 04970 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 04971 } 04972 } 04973 } 04974 /* Drop out of the queue at this point, to prepare for next caller */ 04975 leave_queue(qe); 04976 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 04977 ast_debug(1, "app_queue: sendurl=%s.\n", url); 04978 ast_channel_sendurl(peer, url); 04979 } 04980 04981 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */ 04982 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */ 04983 if (!ast_strlen_zero(macro)) { 04984 macroexec = ast_strdupa(macro); 04985 } else { 04986 if (qe->parent->membermacro) 04987 macroexec = ast_strdupa(qe->parent->membermacro); 04988 } 04989 04990 if (!ast_strlen_zero(macroexec)) { 04991 ast_debug(1, "app_queue: macro=%s.\n", macroexec); 04992 04993 res = ast_autoservice_start(qe->chan); 04994 if (res) { 04995 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 04996 res = -1; 04997 } 04998 04999 application = pbx_findapp("Macro"); 05000 05001 if (application) { 05002 res = pbx_exec(peer, application, macroexec); 05003 ast_debug(1, "Macro exited with status %d\n", res); 05004 res = 0; 05005 } else { 05006 ast_log(LOG_ERROR, "Could not find application Macro\n"); 05007 res = -1; 05008 } 05009 05010 if (ast_autoservice_stop(qe->chan) < 0) { 05011 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 05012 res = -1; 05013 } 05014 } 05015 05016 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */ 05017 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */ 05018 if (!ast_strlen_zero(gosub)) { 05019 gosubexec = ast_strdupa(gosub); 05020 } else { 05021 if (qe->parent->membergosub) 05022 gosubexec = ast_strdupa(qe->parent->membergosub); 05023 } 05024 05025 if (!ast_strlen_zero(gosubexec)) { 05026 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec); 05027 05028 res = ast_autoservice_start(qe->chan); 05029 if (res) { 05030 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 05031 res = -1; 05032 } 05033 05034 application = pbx_findapp("Gosub"); 05035 05036 if (application) { 05037 char *gosub_args, *gosub_argstart; 05038 05039 /* Set where we came from */ 05040 ast_copy_string(peer->context, "app_queue_gosub_virtual_context", sizeof(peer->context)); 05041 ast_copy_string(peer->exten, "s", sizeof(peer->exten)); 05042 peer->priority = 0; 05043 05044 gosub_argstart = strchr(gosubexec, ','); 05045 if (gosub_argstart) { 05046 const char *what_is_s = "s"; 05047 *gosub_argstart = 0; 05048 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) && 05049 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) { 05050 what_is_s = "~~s~~"; 05051 } 05052 if (asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) { 05053 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 05054 gosub_args = NULL; 05055 } 05056 *gosub_argstart = ','; 05057 } else { 05058 const char *what_is_s = "s"; 05059 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) && 05060 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) { 05061 what_is_s = "~~s~~"; 05062 } 05063 if (asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) { 05064 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 05065 gosub_args = NULL; 05066 } 05067 } 05068 if (gosub_args) { 05069 res = pbx_exec(peer, application, gosub_args); 05070 if (!res) { 05071 struct ast_pbx_args args; 05072 memset(&args, 0, sizeof(args)); 05073 args.no_hangup_chan = 1; 05074 ast_pbx_run_args(peer, &args); 05075 } 05076 ast_free(gosub_args); 05077 ast_debug(1, "Gosub exited with status %d\n", res); 05078 } else { 05079 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n"); 05080 } 05081 } else { 05082 ast_log(LOG_ERROR, "Could not find application Gosub\n"); 05083 res = -1; 05084 } 05085 05086 if (ast_autoservice_stop(qe->chan) < 0) { 05087 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 05088 res = -1; 05089 } 05090 } 05091 05092 if (!ast_strlen_zero(agi)) { 05093 ast_debug(1, "app_queue: agi=%s.\n", agi); 05094 application = pbx_findapp("agi"); 05095 if (application) { 05096 agiexec = ast_strdupa(agi); 05097 pbx_exec(qe->chan, application, agiexec); 05098 } else 05099 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 05100 } 05101 qe->handled++; 05102 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, ast_channel_uniqueid(peer), 05103 (long)(orig - to > 0 ? (orig - to) / 1000 : 0)); 05104 05105 if (qe->chan->cdr) { 05106 struct ast_cdr *cdr; 05107 struct ast_cdr *newcdr; 05108 05109 /* Only work with the last CDR in the stack*/ 05110 cdr = qe->chan->cdr; 05111 while (cdr->next) { 05112 cdr = cdr->next; 05113 } 05114 05115 /* If this CDR is not related to us add new one*/ 05116 if ((strcasecmp(cdr->uniqueid, ast_channel_uniqueid(qe->chan))) && 05117 (strcasecmp(cdr->linkedid, ast_channel_uniqueid(qe->chan))) && 05118 (newcdr = ast_cdr_dup(cdr))) { 05119 ast_channel_lock(qe->chan); 05120 ast_cdr_init(newcdr, qe->chan); 05121 ast_cdr_reset(newcdr, 0); 05122 cdr = ast_cdr_append(cdr, newcdr); 05123 cdr = cdr->next; 05124 ast_channel_unlock(qe->chan); 05125 } 05126 05127 if (update_cdr) { 05128 ast_copy_string(cdr->dstchannel, member->membername, sizeof(cdr->dstchannel)); 05129 } 05130 } 05131 05132 if (qe->parent->eventwhencalled) 05133 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 05134 "Queue: %s\r\n" 05135 "Uniqueid: %s\r\n" 05136 "Channel: %s\r\n" 05137 "Member: %s\r\n" 05138 "MemberName: %s\r\n" 05139 "Holdtime: %ld\r\n" 05140 "BridgedChannel: %s\r\n" 05141 "Ringtime: %ld\r\n" 05142 "%s", 05143 queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername, 05144 (long) time(NULL) - qe->start, ast_channel_uniqueid(peer), (long)(orig - to > 0 ? (orig - to) / 1000 : 0), 05145 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 05146 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 05147 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 05148 05149 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) { 05150 queue_end_bridge->q = qe->parent; 05151 queue_end_bridge->chan = qe->chan; 05152 bridge_config.end_bridge_callback = end_bridge_callback; 05153 bridge_config.end_bridge_callback_data = queue_end_bridge; 05154 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 05155 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need 05156 * to make sure to increase the refcount of this queue so it cannot be freed until we 05157 * are done with it. We remove this reference in end_bridge_callback. 05158 */ 05159 queue_t_ref(qe->parent, "For bridge_config reference"); 05160 } 05161 05162 time(&callstart); 05163 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl); 05164 bridge = ast_bridge_call(qe->chan,peer, &bridge_config); 05165 05166 /* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log 05167 * when the masquerade occurred. These other "ending" queue_log messages are unnecessary, except for 05168 * the AgentComplete manager event 05169 */ 05170 ast_channel_lock(qe->chan); 05171 if (!attended_transfer_occurred(qe->chan)) { 05172 struct ast_datastore *tds; 05173 05174 /* detect a blind transfer */ 05175 if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) { 05176 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 05177 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 05178 (long) (time(NULL) - callstart), qe->opos); 05179 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER); 05180 } else if (ast_check_hangup(qe->chan)) { 05181 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "COMPLETECALLER", "%ld|%ld|%d", 05182 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 05183 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER); 05184 } else { 05185 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 05186 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 05187 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT); 05188 } 05189 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) { 05190 ast_channel_datastore_remove(qe->chan, tds); 05191 } 05192 ast_channel_unlock(qe->chan); 05193 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart)); 05194 } else { 05195 ast_channel_unlock(qe->chan); 05196 05197 /* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */ 05198 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER); 05199 } 05200 05201 if (transfer_ds) { 05202 ast_datastore_free(transfer_ds); 05203 } 05204 ast_hangup(peer); 05205 res = bridge ? bridge : 1; 05206 ao2_ref(member, -1); 05207 } 05208 out: 05209 hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere); 05210 05211 return res; 05212 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 8625 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(), cli_queue, extension_state_cb(), queue_t_unref, queueexists_function, queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queues_t_unlink, queuevar_function, and queuewaitingcount_function.
08626 { 08627 int res; 08628 struct ast_context *con; 08629 struct ao2_iterator q_iter; 08630 struct call_queue *q = NULL; 08631 08632 ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue)); 08633 res = ast_manager_unregister("QueueStatus"); 08634 res |= ast_manager_unregister("Queues"); 08635 res |= ast_manager_unregister("QueueRule"); 08636 res |= ast_manager_unregister("QueueSummary"); 08637 res |= ast_manager_unregister("QueueAdd"); 08638 res |= ast_manager_unregister("QueueRemove"); 08639 res |= ast_manager_unregister("QueuePause"); 08640 res |= ast_manager_unregister("QueueLog"); 08641 res |= ast_manager_unregister("QueuePenalty"); 08642 res |= ast_unregister_application(app_aqm); 08643 res |= ast_unregister_application(app_rqm); 08644 res |= ast_unregister_application(app_pqm); 08645 res |= ast_unregister_application(app_upqm); 08646 res |= ast_unregister_application(app_ql); 08647 res |= ast_unregister_application(app); 08648 res |= ast_custom_function_unregister(&queueexists_function); 08649 res |= ast_custom_function_unregister(&queuevar_function); 08650 res |= ast_custom_function_unregister(&queuemembercount_function); 08651 res |= ast_custom_function_unregister(&queuemembercount_dep); 08652 res |= ast_custom_function_unregister(&queuememberlist_function); 08653 res |= ast_custom_function_unregister(&queuewaitingcount_function); 08654 res |= ast_custom_function_unregister(&queuememberpenalty_function); 08655 08656 res |= ast_data_unregister(NULL); 08657 08658 if (device_state_sub) 08659 ast_event_unsubscribe(device_state_sub); 08660 08661 ast_extension_state_del(0, extension_state_cb); 08662 08663 if ((con = ast_context_find("app_queue_gosub_virtual_context"))) { 08664 ast_context_remove_extension2(con, "s", 1, NULL, 0); 08665 ast_context_destroy(con, "app_queue"); /* leave no trace */ 08666 } 08667 08668 q_iter = ao2_iterator_init(queues, 0); 08669 while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) { 08670 queues_t_unlink(queues, q, "Remove queue from container due to unload"); 08671 queue_t_unref(q, "Done with iterator"); 08672 } 08673 ao2_iterator_destroy(&q_iter); 08674 ao2_ref(queues, -1); 08675 devicestate_tps = ast_taskprocessor_unreference(devicestate_tps); 08676 ast_unload_realtime("queue_members"); 08677 return res; 08678 }
| 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 4008 of file app_queue.c.
References ast_channel_name(), ast_debug, AST_LIST_NEXT, queue_ent::chan, queue_ent::max_penalty, penalty_rule::max_relative, penalty_rule::max_value, queue_ent::min_penalty, penalty_rule::min_relative, penalty_rule::min_value, pbx_builtin_setvar_helper(), queue_ent::pr, and penalty_rule::time.
Referenced by queue_exec(), and wait_our_turn().
04009 { 04010 int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value; 04011 int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value; 04012 char max_penalty_str[20], min_penalty_str[20]; 04013 /* a relative change to the penalty could put it below 0 */ 04014 if (max_penalty < 0) 04015 max_penalty = 0; 04016 if (min_penalty < 0) 04017 min_penalty = 0; 04018 if (min_penalty > max_penalty) 04019 min_penalty = max_penalty; 04020 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty); 04021 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty); 04022 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str); 04023 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str); 04024 qe->max_penalty = max_penalty; 04025 qe->min_penalty = min_penalty; 04026 ast_debug(3, "Setting max penalty to %d and min penalty to %d for caller %s since %d seconds have elapsed\n", qe->max_penalty, qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time); 04027 qe->pr = AST_LIST_NEXT(qe->pr, list); 04028 }
| 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 4116 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().
04117 { 04118 int oldtalktime; 04119 04120 struct member *mem; 04121 struct call_queue *qtmp; 04122 struct ao2_iterator queue_iter; 04123 04124 if (shared_lastcall) { 04125 queue_iter = ao2_iterator_init(queues, 0); 04126 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 04127 ao2_lock(qtmp); 04128 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) { 04129 time(&mem->lastcall); 04130 mem->calls++; 04131 mem->lastqueue = q; 04132 ao2_ref(mem, -1); 04133 } 04134 ao2_unlock(qtmp); 04135 queue_t_unref(qtmp, "Done with iterator"); 04136 } 04137 ao2_iterator_destroy(&queue_iter); 04138 } else { 04139 ao2_lock(q); 04140 time(&member->lastcall); 04141 member->calls++; 04142 member->lastqueue = q; 04143 ao2_unlock(q); 04144 } 04145 ao2_lock(q); 04146 q->callscompleted++; 04147 if (callcompletedinsl) 04148 q->callscompletedinsl++; 04149 /* Calculate talktime using the same exponential average as holdtime code*/ 04150 oldtalktime = q->talktime; 04151 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2; 04152 ao2_unlock(q); 04153 return 0; 04154 }
| static int update_realtime_member_field | ( | struct member * | mem, | |
| const char * | queue_name, | |||
| const char * | field, | |||
| const char * | value | |||
| ) | [static] |
Definition at line 2464 of file app_queue.c.
References ast_strlen_zero(), ast_update_realtime(), member::rt_uniqueid, and SENTINEL.
Referenced by queue_function_mem_write(), remove_from_queue(), set_member_paused(), and set_member_penalty_help_members().
02465 { 02466 int ret = -1; 02467 02468 if (ast_strlen_zero(mem->rt_uniqueid)) 02469 return ret; 02470 02471 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0) 02472 ret = 0; 02473 02474 return ret; 02475 }
| static void update_realtime_members | ( | struct call_queue * | q | ) | [static] |
Definition at line 2478 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ast_category_browse(), ast_config_destroy(), ast_debug, ast_load_realtime_multientry(), ast_queue_log(), ast_strlen_zero(), member::dead, member::interface, member::membername, call_queue::members, call_queue::name, member::realtime, rt_handle_member_record(), and SENTINEL.
Referenced by find_load_queue_rt_friendly(), and queue_exec().
02479 { 02480 struct ast_config *member_config = NULL; 02481 struct member *m; 02482 char *interface = NULL; 02483 struct ao2_iterator mem_iter; 02484 02485 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) { 02486 /*This queue doesn't have realtime members*/ 02487 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name); 02488 return; 02489 } 02490 02491 ao2_lock(q); 02492 02493 /* Temporarily set realtime members dead so we can detect deleted ones.*/ 02494 mem_iter = ao2_iterator_init(q->members, 0); 02495 while ((m = ao2_iterator_next(&mem_iter))) { 02496 if (m->realtime) 02497 m->dead = 1; 02498 ao2_ref(m, -1); 02499 } 02500 ao2_iterator_destroy(&mem_iter); 02501 02502 while ((interface = ast_category_browse(member_config, interface))) { 02503 rt_handle_member_record(q, interface, member_config); 02504 } 02505 02506 /* Delete all realtime members that have been deleted in DB. */ 02507 mem_iter = ao2_iterator_init(q->members, 0); 02508 while ((m = ao2_iterator_next(&mem_iter))) { 02509 if (m->dead) { 02510 if (ast_strlen_zero(m->membername) || !log_membername_as_agent) { 02511 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 02512 } else { 02513 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", ""); 02514 } 02515 ao2_unlink(q->members, m); 02516 } 02517 ao2_ref(m, -1); 02518 } 02519 ao2_iterator_destroy(&mem_iter); 02520 ao2_unlock(q); 02521 ast_config_destroy(member_config); 02522 }
| 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 1455 of file app_queue.c.
References EVENT_FLAG_AGENT, and manager_event.
Referenced by extension_state_cb(), handle_statechange(), and ring_entry().
01456 { 01457 m->status = status; 01458 01459 if (q->maskmemberstatus) 01460 return 0; 01461 01462 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 01463 "Queue: %s\r\n" 01464 "Location: %s\r\n" 01465 "MemberName: %s\r\n" 01466 "StateInterface: %s\r\n" 01467 "Membership: %s\r\n" 01468 "Penalty: %d\r\n" 01469 "CallsTaken: %d\r\n" 01470 "LastCall: %d\r\n" 01471 "Status: %d\r\n" 01472 "Paused: %d\r\n", 01473 q->name, m->interface, m->membername, m->state_interface, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static", 01474 m->penalty, m->calls, (int)m->lastcall, m->status, m->paused 01475 ); 01476 01477 return 0; 01478 }
| static int upqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
UnPauseQueueMember application.
Definition at line 5742 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().
05743 { 05744 char *parse; 05745 AST_DECLARE_APP_ARGS(args, 05746 AST_APP_ARG(queuename); 05747 AST_APP_ARG(interface); 05748 AST_APP_ARG(options); 05749 AST_APP_ARG(reason); 05750 ); 05751 05752 if (ast_strlen_zero(data)) { 05753 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n"); 05754 return -1; 05755 } 05756 05757 parse = ast_strdupa(data); 05758 05759 AST_STANDARD_APP_ARGS(args, parse); 05760 05761 if (ast_strlen_zero(args.interface)) { 05762 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 05763 return -1; 05764 } 05765 05766 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) { 05767 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 05768 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 05769 return 0; 05770 } 05771 05772 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 05773 05774 return 0; 05775 }
| 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 2639 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().
02640 { 02641 int digitlen = strlen(qe->digits); 02642 02643 /* Prevent possible buffer overflow */ 02644 if (digitlen < sizeof(qe->digits) - 2) { 02645 qe->digits[digitlen] = digit; 02646 qe->digits[digitlen + 1] = '\0'; 02647 } else { 02648 qe->digits[0] = '\0'; 02649 return 0; 02650 } 02651 02652 /* If there's no context to goto, short-circuit */ 02653 if (ast_strlen_zero(qe->context)) 02654 return 0; 02655 02656 /* If the extension is bad, then reset the digits to blank */ 02657 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, 02658 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, NULL))) { 02659 qe->digits[0] = '\0'; 02660 return 0; 02661 } 02662 02663 /* We have an exact match */ 02664 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 02665 qe->valid_digits = 1; 02666 /* Return 1 on a successful goto */ 02667 return 1; 02668 } 02669 02670 return 0; 02671 }
| 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 3036 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().
03037 { 03038 struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1); 03039 const char *tmp; 03040 03041 if (pbx_builtin_serialize_variables(chan, &buf)) { 03042 int i, j; 03043 03044 /* convert "\n" to "\nVariable: " */ 03045 strcpy(vars, "Variable: "); 03046 tmp = ast_str_buffer(buf); 03047 03048 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 03049 vars[j] = tmp[i]; 03050 03051 if (tmp[i + 1] == '\0') 03052 break; 03053 if (tmp[i] == '\n') { 03054 vars[j++] = '\r'; 03055 vars[j++] = '\n'; 03056 03057 ast_copy_string(&(vars[j]), "Variable: ", len - j); 03058 j += 9; 03059 } 03060 } 03061 if (j > len - 3) 03062 j = len - 3; 03063 vars[j++] = '\r'; 03064 vars[j++] = '\n'; 03065 vars[j] = '\0'; 03066 } else { 03067 /* there are no channel variables; leave it blank */ 03068 *vars = '\0'; 03069 } 03070 return vars; 03071 }
| static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 5214 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
05215 { 05216 /* Don't need to hold the lock while we setup the outgoing calls */ 05217 int retrywait = qe->parent->retry * 1000; 05218 05219 int res = ast_waitfordigit(qe->chan, retrywait); 05220 if (res > 0 && !valid_exit(qe, res)) 05221 res = 0; 05222 05223 return res; 05224 }
| 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 | update_connectedline | |||
| ) | [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() |
| [in] | update_connectedline | Allow connected line and redirecting updates to pass through. |
Definition at line 3549 of file app_queue.c.
References ast_channel::_state, 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_accountcode(), ast_channel_call_forward(), 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_name(), ast_channel_redirecting_macro(), ast_channel_set_redirecting(), 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_caller_copy(), 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_request(), AST_STATE_UP, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_verb, ast_waitfor_n(), call_queue::autopausebusy, call_queue::autopauseunavail, 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_frame_subclass::integer, callattempt::interface, member::interface, LOG_NOTICE, ast_channel::macroexten, callattempt::member, member::membername, call_queue::name, ast_channel::nativeformats, ast_party_id::number, queue_ent::parent, callattempt::pending_connected_update, 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, ast_party_connected_line::source, queue_ent::start, starttime, 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().
03550 { 03551 const char *queue = qe->parent->name; 03552 struct callattempt *o, *start = NULL, *prev = NULL; 03553 int res; 03554 int status; 03555 int numbusies = prebusies; 03556 int numnochan = 0; 03557 int stillgoing = 0; 03558 int orig = *to; 03559 struct ast_frame *f; 03560 struct callattempt *peer = NULL; 03561 struct ast_channel *winner; 03562 struct ast_channel *in = qe->chan; 03563 char on[80] = ""; 03564 char membername[80] = ""; 03565 long starttime = 0; 03566 long endtime = 0; 03567 #ifdef HAVE_EPOLL 03568 struct callattempt *epollo; 03569 #endif 03570 struct ast_party_connected_line connected_caller; 03571 char *inchan_name; 03572 03573 ast_party_connected_line_init(&connected_caller); 03574 03575 ast_channel_lock(qe->chan); 03576 inchan_name = ast_strdupa(ast_channel_name(qe->chan)); 03577 ast_channel_unlock(qe->chan); 03578 03579 starttime = (long) time(NULL); 03580 #ifdef HAVE_EPOLL 03581 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 03582 if (epollo->chan) 03583 ast_poll_channel_add(in, epollo->chan); 03584 } 03585 #endif 03586 03587 while (*to && !peer) { 03588 int numlines, retry, pos = 1; 03589 struct ast_channel *watchers[AST_MAX_WATCHERS]; 03590 watchers[0] = in; 03591 start = NULL; 03592 03593 for (retry = 0; retry < 2; retry++) { 03594 numlines = 0; 03595 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 03596 if (o->stillgoing) { /* Keep track of important channels */ 03597 stillgoing = 1; 03598 if (o->chan) { 03599 if (pos < AST_MAX_WATCHERS) { 03600 watchers[pos++] = o->chan; 03601 } 03602 if (!start) 03603 start = o; 03604 else 03605 prev->call_next = o; 03606 prev = o; 03607 } 03608 } 03609 numlines++; 03610 } 03611 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 03612 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 03613 break; 03614 /* On "ringall" strategy we only move to the next penalty level 03615 when *all* ringing phones are done in the current penalty level */ 03616 ring_one(qe, outgoing, &numbusies); 03617 /* and retry... */ 03618 } 03619 if (pos == 1 /* not found */) { 03620 if (numlines == (numbusies + numnochan)) { 03621 ast_debug(1, "Everyone is busy at this time\n"); 03622 } else { 03623 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan); 03624 } 03625 *to = 0; 03626 return NULL; 03627 } 03628 03629 /* Poll for events from both the incoming channel as well as any outgoing channels */ 03630 winner = ast_waitfor_n(watchers, pos, to); 03631 03632 /* Service all of the outgoing channels */ 03633 for (o = start; o; o = o->call_next) { 03634 /* We go with a static buffer here instead of using ast_strdupa. Using 03635 * ast_strdupa in a loop like this one can cause a stack overflow 03636 */ 03637 char ochan_name[AST_CHANNEL_NAME]; 03638 if (o->chan) { 03639 ast_channel_lock(o->chan); 03640 ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name)); 03641 ast_channel_unlock(o->chan); 03642 } 03643 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 03644 if (!peer) { 03645 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); 03646 if (update_connectedline) { 03647 if (o->pending_connected_update) { 03648 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { 03649 ast_channel_update_connected_line(in, &o->connected, NULL); 03650 } 03651 } else if (!o->dial_callerid_absent) { 03652 ast_channel_lock(o->chan); 03653 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller); 03654 ast_channel_unlock(o->chan); 03655 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 03656 ast_channel_update_connected_line(in, &connected_caller, NULL); 03657 ast_party_connected_line_free(&connected_caller); 03658 } 03659 } 03660 if (o->aoc_s_rate_list) { 03661 size_t encoded_size; 03662 struct ast_aoc_encoded *encoded; 03663 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) { 03664 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size); 03665 ast_aoc_destroy_encoded(encoded); 03666 } 03667 } 03668 peer = o; 03669 } 03670 } else if (o->chan && (o->chan == winner)) { 03671 03672 ast_copy_string(on, o->member->interface, sizeof(on)); 03673 ast_copy_string(membername, o->member->membername, sizeof(membername)); 03674 03675 if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) { 03676 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan)); 03677 numnochan++; 03678 do_hang(o); 03679 winner = NULL; 03680 continue; 03681 } else if (!ast_strlen_zero(ast_channel_call_forward(o->chan))) { 03682 struct ast_channel *original = o->chan; 03683 char tmpchan[256]; 03684 char *stuff; 03685 char *tech; 03686 03687 ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan)); 03688 if ((stuff = strchr(tmpchan, '/'))) { 03689 *stuff++ = '\0'; 03690 tech = tmpchan; 03691 } else { 03692 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), o->chan->context); 03693 stuff = tmpchan; 03694 tech = "Local"; 03695 } 03696 03697 ast_cel_report_event(in, AST_CEL_FORWARD, NULL, ast_channel_call_forward(o->chan), NULL); 03698 03699 /* Before processing channel, go ahead and check for forwarding */ 03700 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name); 03701 /* Setup parameters */ 03702 o->chan = ast_request(tech, in->nativeformats, in, stuff, &status); 03703 if (!o->chan) { 03704 ast_log(LOG_NOTICE, 03705 "Forwarding failed to create channel to dial '%s/%s'\n", 03706 tech, stuff); 03707 o->stillgoing = 0; 03708 numnochan++; 03709 } else { 03710 struct ast_party_redirecting redirecting; 03711 03712 ast_channel_lock_both(o->chan, in); 03713 ast_channel_inherit_variables(in, o->chan); 03714 ast_channel_datastore_inherit(in, o->chan); 03715 03716 ast_channel_accountcode_set(o->chan, ast_channel_accountcode(in)); 03717 03718 ast_channel_set_redirecting(o->chan, &original->redirecting, NULL); 03719 if (!o->chan->redirecting.from.number.valid 03720 || ast_strlen_zero(o->chan->redirecting.from.number.str)) { 03721 /* 03722 * The call was not previously redirected so it is 03723 * now redirected from this number. 03724 */ 03725 ast_party_number_free(&o->chan->redirecting.from.number); 03726 ast_party_number_init(&o->chan->redirecting.from.number); 03727 o->chan->redirecting.from.number.valid = 1; 03728 o->chan->redirecting.from.number.str = 03729 ast_strdup(S_OR(in->macroexten, in->exten)); 03730 } 03731 03732 o->chan->dialed.transit_network_select = in->dialed.transit_network_select; 03733 03734 ast_party_caller_copy(&o->chan->caller, &in->caller); 03735 ast_party_connected_line_copy(&o->chan->connected, &original->connected); 03736 03737 /* 03738 * We must unlock o->chan before calling 03739 * ast_channel_redirecting_macro, because we put o->chan into 03740 * autoservice there. That is pretty much a guaranteed 03741 * deadlock. This is why the handling of o->chan's lock may 03742 * seem a bit unusual here. 03743 */ 03744 ast_party_redirecting_init(&redirecting); 03745 ast_party_redirecting_copy(&redirecting, &o->chan->redirecting); 03746 ast_channel_unlock(o->chan); 03747 res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0); 03748 if (res) { 03749 ast_channel_update_redirecting(in, &redirecting, NULL); 03750 } 03751 ast_party_redirecting_free(&redirecting); 03752 ast_channel_unlock(in); 03753 03754 update_connectedline = 1; 03755 03756 if (ast_call(o->chan, stuff, 0)) { 03757 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n", 03758 tech, stuff); 03759 do_hang(o); 03760 numnochan++; 03761 } 03762 } 03763 /* Hangup the original channel now, in case we needed it */ 03764 ast_hangup(winner); 03765 continue; 03766 } 03767 f = ast_read(winner); 03768 if (f) { 03769 if (f->frametype == AST_FRAME_CONTROL) { 03770 switch (f->subclass.integer) { 03771 case AST_CONTROL_ANSWER: 03772 /* This is our guy if someone answered. */ 03773 if (!peer) { 03774 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); 03775 if (update_connectedline) { 03776 if (o->pending_connected_update) { 03777 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { 03778 ast_channel_update_connected_line(in, &o->connected, NULL); 03779 } 03780 } else if (!o->dial_callerid_absent) { 03781 ast_channel_lock(o->chan); 03782 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller); 03783 ast_channel_unlock(o->chan); 03784 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 03785 ast_channel_update_connected_line(in, &connected_caller, NULL); 03786 ast_party_connected_line_free(&connected_caller); 03787 } 03788 } 03789 if (o->aoc_s_rate_list) { 03790 size_t encoded_size; 03791 struct ast_aoc_encoded *encoded; 03792 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) { 03793 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size); 03794 ast_aoc_destroy_encoded(encoded); 03795 } 03796 } 03797 peer = o; 03798 } 03799 break; 03800 case AST_CONTROL_BUSY: 03801 ast_verb(3, "%s is busy\n", ochan_name); 03802 if (in->cdr) 03803 ast_cdr_busy(in->cdr); 03804 do_hang(o); 03805 endtime = (long) time(NULL); 03806 endtime -= starttime; 03807 rna(endtime * 1000, qe, on, membername, qe->parent->autopausebusy); 03808 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03809 if (qe->parent->timeoutrestart) 03810 *to = orig; 03811 /* Have enough time for a queue member to answer? */ 03812 if (*to > 500) { 03813 ring_one(qe, outgoing, &numbusies); 03814 starttime = (long) time(NULL); 03815 } 03816 } 03817 numbusies++; 03818 break; 03819 case AST_CONTROL_CONGESTION: 03820 ast_verb(3, "%s is circuit-busy\n", ochan_name); 03821 if (in->cdr) 03822 ast_cdr_busy(in->cdr); 03823 endtime = (long) time(NULL); 03824 endtime -= starttime; 03825 rna(endtime * 1000, qe, on, membername, qe->parent->autopauseunavail); 03826 do_hang(o); 03827 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03828 if (qe->parent->timeoutrestart) 03829 *to = orig; 03830 if (*to > 500) { 03831 ring_one(qe, outgoing, &numbusies); 03832 starttime = (long) time(NULL); 03833 } 03834 } 03835 numbusies++; 03836 break; 03837 case AST_CONTROL_RINGING: 03838 ast_verb(3, "%s is ringing\n", ochan_name); 03839 03840 /* Start ring indication when the channel is ringing, if specified */ 03841 if (qe->ring_when_ringing) { 03842 ast_moh_stop(qe->chan); 03843 ast_indicate(qe->chan, AST_CONTROL_RINGING); 03844 } 03845 break; 03846 case AST_CONTROL_OFFHOOK: 03847 /* Ignore going off hook */ 03848 break; 03849 case AST_CONTROL_CONNECTED_LINE: 03850 if (!update_connectedline) { 03851 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name); 03852 } else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 03853 struct ast_party_connected_line connected; 03854 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name); 03855 ast_party_connected_line_set_init(&connected, &o->connected); 03856 ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected); 03857 ast_party_connected_line_set(&o->connected, &connected, NULL); 03858 ast_party_connected_line_free(&connected); 03859 o->pending_connected_update = 1; 03860 } else { 03861 if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) { 03862 ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); 03863 } 03864 } 03865 break; 03866 case AST_CONTROL_AOC: 03867 { 03868 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan); 03869 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) { 03870 ast_aoc_destroy_decoded(o->aoc_s_rate_list); 03871 o->aoc_s_rate_list = decoded; 03872 } else { 03873 ast_aoc_destroy_decoded(decoded); 03874 } 03875 } 03876 break; 03877 case AST_CONTROL_REDIRECTING: 03878 if (!update_connectedline) { 03879 ast_verb(3, "Redirecting update to %s prevented\n", inchan_name); 03880 } else if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03881 ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name); 03882 if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) { 03883 ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); 03884 } 03885 } 03886 break; 03887 default: 03888 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer); 03889 break; 03890 } 03891 } 03892 ast_frfree(f); 03893 } else { /* ast_read() returned NULL */ 03894 endtime = (long) time(NULL) - starttime; 03895 rna(endtime * 1000, qe, on, membername, 1); 03896 do_hang(o); 03897 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03898 if (qe->parent->timeoutrestart) 03899 *to = orig; 03900 if (*to > 500) { 03901 ring_one(qe, outgoing, &numbusies); 03902 starttime = (long) time(NULL); 03903 } 03904 } 03905 } 03906 } 03907 } 03908 03909 /* If we received an event from the caller, deal with it. */ 03910 if (winner == in) { 03911 f = ast_read(in); 03912 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) { 03913 /* Got hung up */ 03914 *to = -1; 03915 if (f) { 03916 if (f->data.uint32) { 03917 in->hangupcause = f->data.uint32; 03918 } 03919 ast_frfree(f); 03920 } 03921 return NULL; 03922 } 03923 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) { 03924 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer); 03925 *to = 0; 03926 ast_frfree(f); 03927 return NULL; 03928 } 03929 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) { 03930 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer); 03931 *to = 0; 03932 *digit = f->subclass.integer; 03933 ast_frfree(f); 03934 return NULL; 03935 } 03936 ast_frfree(f); 03937 } 03938 if (!*to) { 03939 for (o = start; o; o = o->call_next) 03940 rna(orig, qe, o->interface, o->member->membername, 1); 03941 } 03942 } 03943 03944 #ifdef HAVE_EPOLL 03945 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 03946 if (epollo->chan) 03947 ast_poll_channel_del(in, epollo->chan); 03948 } 03949 #endif 03950 03951 return peer; 03952 }
| 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 4040 of file app_queue.c.
References call_queue::announcefrequency, ast_channel_uniqueid(), ast_queue_log(), ast_waitfordigit(), queue_ent::chan, queue_ent::expire, get_member_status(), is_our_turn(), leave_queue(), call_queue::leavewhenempty, queue_ent::max_penalty, queue_ent::min_penalty, call_queue::name, queue_ent::opos, queue_ent::parent, call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::pr, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, RECHECK, say_periodic_announcement(), say_position(), queue_ent::start, status, penalty_rule::time, update_qe_rule(), and valid_exit().
Referenced by queue_exec().
04041 { 04042 int res = 0; 04043 04044 /* This is the holding pen for callers 2 through maxlen */ 04045 for (;;) { 04046 04047 if (is_our_turn(qe)) 04048 break; 04049 04050 /* If we have timed out, break out */ 04051 if (qe->expire && (time(NULL) >= qe->expire)) { 04052 *reason = QUEUE_TIMEOUT; 04053 break; 04054 } 04055 04056 if (qe->parent->leavewhenempty) { 04057 int status = 0; 04058 04059 if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty))) { 04060 *reason = QUEUE_LEAVEEMPTY; 04061 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 04062 leave_queue(qe); 04063 break; 04064 } 04065 } 04066 04067 /* Make a position announcement, if enabled */ 04068 if (qe->parent->announcefrequency && 04069 (res = say_position(qe,ringing))) 04070 break; 04071 04072 /* If we have timed out, break out */ 04073 if (qe->expire && (time(NULL) >= qe->expire)) { 04074 *reason = QUEUE_TIMEOUT; 04075 break; 04076 } 04077 04078 /* Make a periodic announcement, if enabled */ 04079 if (qe->parent->periodicannouncefrequency && 04080 (res = say_periodic_announcement(qe,ringing))) 04081 break; 04082 04083 /* see if we need to move to the next penalty level for this queue */ 04084 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) { 04085 update_qe_rule(qe); 04086 } 04087 04088 /* If we have timed out, break out */ 04089 if (qe->expire && (time(NULL) >= qe->expire)) { 04090 *reason = QUEUE_TIMEOUT; 04091 break; 04092 } 04093 04094 /* Wait a second before checking again */ 04095 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 04096 if (res > 0 && !valid_exit(qe, res)) 04097 res = 0; 04098 else 04099 break; 04100 } 04101 04102 /* If we have timed out, break out */ 04103 if (qe->expire && (time(NULL) >= qe->expire)) { 04104 *reason = QUEUE_TIMEOUT; 04105 break; 04106 } 04107 } 04108 04109 return res; 04110 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, .nonoptreq = "res_monitor", } [static] |
Definition at line 8777 of file app_queue.c.
char* app = "Queue" [static] |
Definition at line 916 of file app_queue.c.
char* app_aqm = "AddQueueMember" [static] |
Definition at line 918 of file app_queue.c.
char* app_pqm = "PauseQueueMember" [static] |
Definition at line 922 of file app_queue.c.
char* app_ql = "QueueLog" [static] |
Definition at line 926 of file app_queue.c.
char* app_rqm = "RemoveQueueMember" [static] |
Definition at line 920 of file app_queue.c.
char* app_upqm = "UnpauseQueueMember" [static] |
Definition at line 924 of file app_queue.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 8777 of file app_queue.c.
int autofill_default = 1 [static] |
struct autopause autopausesmodes[] [static] |
Referenced by autopause2int().
int check_state_unknown = 0 [static] |
struct ast_cli_entry cli_queue[] [static] |
struct ast_event_sub* device_state_sub [static] |
Subscription to device state change events.
Definition at line 949 of file app_queue.c.
Referenced by load_pbx().
struct ast_taskprocessor* devicestate_tps [static] |
Definition at line 900 of file app_queue.c.
| enum queue_result id |
Definition at line 975 of file app_queue.c.
Referenced by _sip_show_peers(), _skinny_show_devices(), _skinny_show_lines(), amixer_max(), ast_cc_extension_monitor_add_dialstring(), frame_trace_helper(), idemodulator(), jb_helper(), load_format_config(), and setamixer().
int log_membername_as_agent = 0 [static] |
int montype_default = 0 [static] |
int negative_penalty_invalid = 0 [static] |
const char* const pm_family = "Queue/PersistentMembers" [static] |
const char qpm_cmd_usage[] [static] |
Initial value:
"Usage: queue pause member <channel> in <queue> reason <reason>\n"
Definition at line 8335 of file app_queue.c.
const char qsmp_cmd_usage[] [static] |
Initial value:
"Usage: queue set member penalty <channel> from <queue> <penalty>\n"
Definition at line 8341 of file app_queue.c.
struct ast_data_entry queue_data_providers[] [static] |
Initial value:
{
AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider),
}
Definition at line 8621 of file app_queue.c.
Referenced by load_module().
int queue_persistent_members = 0 [static] |
struct { ... } queue_results[] [static] |
Referenced by set_queue_result().
struct ast_datastore_info queue_transfer_info [static] |
Initial value:
{
.type = "queue_transfer",
.chan_fixup = queue_transfer_fixup,
.destroy = queue_transfer_destroy,
}
Definition at line 4291 of file app_queue.c.
Referenced by attended_transfer_occurred(), queue_transfer_fixup(), setup_transfer_datastore(), and try_calling().
struct ast_custom_function queueexists_function [static] |
Initial value:
{
.name = "QUEUE_EXISTS",
.read = queue_function_exists,
}
Definition at line 6726 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuemembercount_dep [static] |
Initial value:
{
.name = "QUEUE_MEMBER_COUNT",
.read = queue_function_qac_dep,
}
Definition at line 6742 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuemembercount_function [static] |
Initial value:
{
.name = "QUEUE_MEMBER",
.read = queue_function_mem_read,
.write = queue_function_mem_write,
}
Definition at line 6736 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuememberlist_function [static] |
Initial value:
{
.name = "QUEUE_MEMBER_LIST",
.read = queue_function_queuememberlist,
}
Definition at line 6752 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuememberpenalty_function [static] |
Initial value:
{
.name = "QUEUE_MEMBER_PENALTY",
.read = queue_function_memberpenalty_read,
.write = queue_function_memberpenalty_write,
}
Definition at line 6757 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ao2_container* queues [static] |
Definition at line 1214 of file app_queue.c.
Referenced by __queues_show(), clear_stats(), compare_weight(), complete_queue(), complete_queue_remove_member(), extension_state_cb(), find_load_queue_rt_friendly(), find_queue_by_name_rt(), get_member_penalty(), handle_statechange(), leave_queue(), load_module(), 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] |
Initial value:
{
.version = AST_DATA_HANDLER_VERSION,
.get = queues_data_provider_get
}
Definition at line 8616 of file app_queue.c.
struct ast_custom_function queuevar_function [static] |
Initial value:
{
.name = "QUEUE_VARIABLES",
.read = queue_function_var,
}
Definition at line 6731 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuewaitingcount_function [static] |
Initial value:
{
.name = "QUEUE_WAITING_COUNT",
.read = queue_function_queuewaitingcount,
}
Definition at line 6747 of file app_queue.c.
Referenced by load_module(), and unload_module().
const char qum_cmd_usage[] [static] |
Initial value:
"Usage: queue unpause member <channel> in <queue> reason <reason>\n"
Definition at line 8338 of file app_queue.c.
int shared_lastcall = 1 [static] |
struct strategy strategies[] [static] |
Referenced by int2strat(), and strat2int().
| char* text |
Definition at line 976 of file app_queue.c.
Referenced by _sip_show_peer(), 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(), and set_queue_result().
int update_cdr = 0 [static] |
queues.conf [general] option
Definition at line 952 of file app_queue.c.
Referenced by login_exec().
int use_weight = 0 [static] |
1.5.6