#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 (char *context, char *exten, enum ast_extension_states state, void *data) |
static int | extensionstate2devicestate (int state) |
Helper function which converts from extension state to device state values. | |
static struct callattempt * | find_best (struct callattempt *outgoing) |
find the entry with the best metric, or NULL | |
static struct call_queue * | find_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config) |
Reload a single queue via realtime. | |
static void | free_members (struct call_queue *q, int all) |
Iterate through queue's member list and delete them. | |
static int | get_member_penalty (char *queuename, char *interface) |
static int | get_member_status (struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions) |
Check if members are available. | |
static int | get_queue_member_status (struct member *cur) |
Return the current state of a member. | |
static char * | handle_queue_add_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_pause_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_remove_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_reset (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_rule_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_set_member_penalty (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static int | handle_statechange (void *datap) |
set a member's status based on device state of that member's interface | |
static void | hangupcalls (struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere) |
Hang up a list of outgoing calls. | |
static void | init_queue (struct call_queue *q) |
Initialize Queue default values. | |
static void | insert_entry (struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos) |
Insert the 'new' entry after the 'prev' entry of queue 'q'. | |
static int | insert_penaltychange (const char *list_name, const char *content, const int linenum) |
Change queue penalty by adding rule. | |
static const char * | int2strat (int strategy) |
static struct member * | interface_exists (struct call_queue *q, const char *interface) |
static int | is_our_turn (struct queue_ent *qe) |
Check if we should start attempting to call queue members. | |
static int | join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason, int position) |
static int | kill_dead_members (void *obj, void *arg, int flags) |
static int | kill_dead_queues (void *obj, void *arg, int flags) |
static void | leave_queue (struct queue_ent *qe) |
Caller leaving queue. | |
static int | load_module (void) |
static struct call_queue * | load_realtime_queue (const char *queuename) |
static int | manager_add_queue_member (struct mansession *s, const struct message *m) |
static int | manager_pause_queue_member (struct mansession *s, const struct message *m) |
static int | manager_queue_log_custom (struct mansession *s, const struct message *m) |
static int | manager_queue_member_penalty (struct mansession *s, const struct message *m) |
static int | manager_queue_reload (struct mansession *s, const struct message *m) |
static int | manager_queue_reset (struct mansession *s, const struct message *m) |
static int | manager_queue_rule_show (struct mansession *s, const struct message *m) |
static int | manager_queues_show (struct mansession *s, const struct message *m) |
static int | manager_queues_status (struct mansession *s, const struct message *m) |
Queue status info via AMI. | |
static int | manager_queues_summary (struct mansession *s, const struct message *m) |
Summary of queue info via the AMI. | |
static int | manager_remove_queue_member (struct mansession *s, const struct message *m) |
static int | mark_dead_and_unfound (void *obj, void *arg, int flags) |
static int | mark_member_dead (void *obj, void *arg, int flags) |
static 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_memberpenalty_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. | |
static int | queue_function_memberpenalty_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. | |
static int | queue_function_qac (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
Get number either busy / free / ready or total members of a specific queue. | |
static int | queue_function_qac_dep (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
Get the total number of members in a specific queue (Deprecated). | |
static int | queue_function_queuememberlist (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue. | |
static int | queue_function_queuewaitingcount (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue. | |
static int | queue_function_var (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
create interface var with all queue details. | |
static int | queue_hash_cb (const void *obj, const int flags) |
static 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, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface) |
Find rt member record to update otherwise create one. | |
static int | say_periodic_announcement (struct queue_ent *qe, int ringing) |
Playback announcement to queued members if period has elapsed. | |
static int | say_position (struct queue_ent *qe, int ringing) |
static void | send_agent_complete (const struct queue_ent *qe, const char *queuename, const struct ast_channel *peer, const struct member *member, time_t callstart, char *vars, size_t vars_len, enum agent_complete_reason rsn) |
Send out AMI message with member call completion status information. | |
static int | set_member_paused (const char *queuename, const char *interface, const char *reason, int paused) |
static int | set_member_penalty (const char *queuename, const char *interface, int penalty) |
static void | set_queue_result (struct ast_channel *chan, enum queue_result res) |
sets the QUEUESTATUS channel variable | |
static void | set_queue_variables (struct call_queue *q, struct ast_channel *chan) |
Set variables of queue. | |
static struct ast_datastore * | setup_transfer_datastore (struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl) |
create a datastore for storing relevant info to log attended transfers in the queue_log | |
static int | store_next_lin (struct queue_ent *qe, struct callattempt *outgoing) |
Search for best metric and add to Linear queue. | |
static int | store_next_rr (struct queue_ent *qe, struct callattempt *outgoing) |
Search for best metric and add to Round Robbin queue. | |
static int | strat2int (const char *strategy) |
static int | try_calling (struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing) |
A large function which calls members, updates statistics, and bridges the caller and a member. | |
static int | unload_module (void) |
static void | update_qe_rule (struct queue_ent *qe) |
update rules for queues | |
static int | update_queue (struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime) |
update the queue status | |
static int | update_realtime_member_field (struct member *mem, const char *queue_name, const char *field, const char *value) |
static void | update_realtime_members (struct call_queue *q) |
static int | update_status (struct call_queue *q, struct member *m, const int status) |
set a member's status based on device state of that member's state_interface. | |
static int | upqm_exec (struct ast_channel *chan, const char *data) |
UnPauseQueueMember application. | |
static int | valid_exit (struct queue_ent *qe, char digit) |
Check for valid exit from queue via goto. | |
static char * | vars2manager (struct ast_channel *chan, char *vars, size_t len) |
convert "\n" to "\nVariable: " ready for manager to use | |
static int | wait_a_bit (struct queue_ent *qe) |
static struct callattempt * | wait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int 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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 struct ast_cli_entry | cli_queue [] |
static struct ast_event_sub * | device_state_sub |
Subscription to device state change events. | |
static struct ast_taskprocessor * | devicestate_tps |
static int | montype_default = 0 |
queues.conf [general] option | |
static const char *const | pm_family = "Queue/PersistentMembers" |
Persistent Members astdb family. | |
static const char | qpm_cmd_usage [] |
static const char | qsmp_cmd_usage [] |
static struct ast_data_entry | queue_data_providers [] |
static int | queue_persistent_members = 0 |
queues.conf [general] option | |
struct { | |
enum queue_result id | |
char * text | |
} | queue_results [] |
static struct ast_datastore_info | queue_transfer_info |
a datastore used to help correctly log attended transfers of queue callers | |
static struct ast_custom_function | queueexists_function |
static struct ast_custom_function | queuemembercount_dep |
static struct ast_custom_function | queuemembercount_function |
static struct ast_custom_function | queuememberlist_function |
static struct ast_custom_function | queuememberpenalty_function |
static struct ao2_container * | queues |
static struct ast_data_handler | queues_data_provider |
static struct ast_custom_function | queuevar_function |
static struct ast_custom_function | queuewaitingcount_function |
static const char | qum_cmd_usage [] |
static int | shared_lastcall = 1 |
queues.conf [general] option | |
static struct strategy | strategies [] |
static int | update_cdr = 0 |
queues.conf [general] option | |
static int | use_weight = 0 |
queues.conf per-queue weight option |
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 1078 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 1077 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 1076 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 1075 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 3409 of file app_queue.c.
#define DATA_EXPORT_CALL_QUEUE | ( | MEMBER | ) |
Definition at line 7989 of file app_queue.c.
#define DATA_EXPORT_MEMBER | ( | MEMBER | ) |
Definition at line 8053 of file app_queue.c.
#define DATA_EXPORT_QUEUE_ENT | ( | MEMBER | ) |
Definition at line 8067 of file app_queue.c.
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 |
The minimum number of seconds between position announcements \ The default value of 15 provides backwards compatibility
Definition at line 891 of file app_queue.c.
Referenced by init_queue().
#define DEFAULT_RETRY 5 |
#define DEFAULT_TIMEOUT 15 |
#define MAX_PERIODIC_ANNOUNCEMENTS 10 |
The maximum periodic announcements we can have
Definition at line 890 of file app_queue.c.
Referenced by destroy_queue(), init_queue(), and queue_set_param().
#define MAX_QUEUE_BUCKETS 53 |
#define PM_MAX_LEN 8192 |
Definition at line 916 of file app_queue.c.
Referenced by dump_queue_members(), and reload_queue_members().
#define QUEUE_EVENT_VARIABLES 3 |
Definition at line 1064 of file app_queue.c.
Referenced by queue_set_param(), ring_entry(), rna(), and send_agent_complete().
#define queue_t_ref | ( | a, | |||
b | ) | queue_ref(a) |
#define queue_t_unref | ( | a, | |||
b | ) | queue_unref(a) |
Definition at line 1271 of file app_queue.c.
Referenced by __queues_show(), add_to_queue(), alloc_queue(), clear_stats(), compare_weight(), complete_queue(), complete_queue_remove_member(), end_bridge_callback(), extension_state_cb(), find_queue_by_name_rt(), get_member_penalty(), handle_statechange(), join_queue(), leave_queue(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), queue_function_exists(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), reload_queue_members(), reload_single_queue(), remove_from_queue(), set_member_paused(), set_member_penalty(), unload_module(), and update_queue().
#define queues_t_link | ( | c, | |||
q, | |||||
tag | ) | ao2_t_link(c,q,tag) |
Definition at line 1272 of file app_queue.c.
#define queues_t_unlink | ( | c, | |||
q, | |||||
tag | ) | ao2_t_unlink(c,q,tag) |
Definition at line 1273 of file app_queue.c.
Referenced by find_queue_by_name_rt(), leave_queue(), and unload_module().
#define RECHECK 1 |
Recheck every second to see we we're at the top yet
Definition at line 889 of file app_queue.c.
#define RES_EXISTS (-1) |
Entry already exists
Definition at line 896 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
#define RES_NOSUCHQUEUE (-3) |
No such queue
Definition at line 898 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
#define RES_NOT_DYNAMIC (-4) |
Member is not dynamic
Definition at line 899 of file app_queue.c.
Referenced by handle_queue_add_member(), handle_queue_remove_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
#define RES_OKAY 0 |
Action completed
Definition at line 895 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
#define RES_OUTOFMEMORY (-2) |
Out of memory
Definition at line 897 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), and reload_queue_members().
anonymous enum |
QUEUE_STRATEGY_RINGALL | |
QUEUE_STRATEGY_LEASTRECENT | |
QUEUE_STRATEGY_FEWESTCALLS | |
QUEUE_STRATEGY_RANDOM | |
QUEUE_STRATEGY_RRMEMORY | |
QUEUE_STRATEGY_LINEAR | |
QUEUE_STRATEGY_WRANDOM | |
QUEUE_STRATEGY_RRORDERED |
Definition at line 836 of file app_queue.c.
00836 { 00837 QUEUE_STRATEGY_RINGALL = 0, 00838 QUEUE_STRATEGY_LEASTRECENT, 00839 QUEUE_STRATEGY_FEWESTCALLS, 00840 QUEUE_STRATEGY_RANDOM, 00841 QUEUE_STRATEGY_RRMEMORY, 00842 QUEUE_STRATEGY_LINEAR, 00843 QUEUE_STRATEGY_WRANDOM, 00844 QUEUE_STRATEGY_RRORDERED, 00845 };
anonymous enum |
Definition at line 847 of file app_queue.c.
00847 { 00848 QUEUE_AUTOPAUSE_OFF = 0, 00849 QUEUE_AUTOPAUSE_ON, 00850 QUEUE_AUTOPAUSE_ALL 00851 };
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 1050 of file app_queue.c.
01050 { 01051 QUEUE_EMPTY_PENALTY = (1 << 0), 01052 QUEUE_EMPTY_PAUSED = (1 << 1), 01053 QUEUE_EMPTY_INUSE = (1 << 2), 01054 QUEUE_EMPTY_RINGING = (1 << 3), 01055 QUEUE_EMPTY_UNAVAILABLE = (1 << 4), 01056 QUEUE_EMPTY_INVALID = (1 << 5), 01057 QUEUE_EMPTY_UNKNOWN = (1 << 6), 01058 QUEUE_EMPTY_WRAPUP = (1 << 7), 01059 };
enum queue_reload_mask |
Definition at line 853 of file app_queue.c.
00853 { 00854 QUEUE_RELOAD_PARAMETERS = (1 << 0), 00855 QUEUE_RELOAD_MEMBER = (1 << 1), 00856 QUEUE_RELOAD_RULES = (1 << 2), 00857 QUEUE_RESET_STATS = (1 << 3), 00858 };
enum queue_result |
QUEUE_UNKNOWN | |
QUEUE_TIMEOUT | |
QUEUE_JOINEMPTY | |
QUEUE_LEAVEEMPTY | |
QUEUE_JOINUNAVAIL | |
QUEUE_LEAVEUNAVAIL | |
QUEUE_FULL | |
QUEUE_CONTINUE |
Definition at line 939 of file app_queue.c.
00939 { 00940 QUEUE_UNKNOWN = 0, 00941 QUEUE_TIMEOUT = 1, 00942 QUEUE_JOINEMPTY = 2, 00943 QUEUE_LEAVEEMPTY = 3, 00944 QUEUE_JOINUNAVAIL = 4, 00945 QUEUE_LEAVEUNAVAIL = 5, 00946 QUEUE_FULL = 6, 00947 QUEUE_CONTINUE = 7, 00948 };
Definition at line 964 of file app_queue.c.
00964 { 00965 TIMEOUT_PRIORITY_APP, 00966 TIMEOUT_PRIORITY_CONF, 00967 };
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 6884 of file app_queue.c.
References ao2_container_count(), ao2_iterator_destroy(), AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_category_browse(), ast_check_realtime(), ast_config_destroy(), ast_devstate2str(), ast_load_realtime_multientry(), ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_strlen_zero(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, CLI_SHOWUSAGE, CLI_SUCCESS, call_queue::count, do_print(), member::dynamic, call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, load_realtime_queue(), call_queue::maxlen, member::membername, call_queue::members, ast_channel::name, 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::status, call_queue::strategy, call_queue::talktime, and call_queue::weight.
Referenced by manager_queues_show(), and queue_show().
06885 { 06886 struct call_queue *q; 06887 struct ast_str *out = ast_str_alloca(240); 06888 int found = 0; 06889 time_t now = time(NULL); 06890 struct ao2_iterator queue_iter; 06891 struct ao2_iterator mem_iter; 06892 06893 if (argc != 2 && argc != 3) 06894 return CLI_SHOWUSAGE; 06895 06896 if (argc == 3) { /* specific queue */ 06897 if ((q = load_realtime_queue(argv[2]))) { 06898 queue_t_unref(q, "Done with temporary pointer"); 06899 } 06900 } else if (ast_check_realtime("queues")) { 06901 /* This block is to find any queues which are defined in realtime but 06902 * which have not yet been added to the in-core container 06903 */ 06904 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 06905 char *queuename; 06906 if (cfg) { 06907 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { 06908 if ((q = load_realtime_queue(queuename))) { 06909 queue_t_unref(q, "Done with temporary pointer"); 06910 } 06911 } 06912 ast_config_destroy(cfg); 06913 } 06914 } 06915 06916 ao2_lock(queues); 06917 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); 06918 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 06919 float sl; 06920 struct call_queue *realtime_queue = NULL; 06921 06922 ao2_lock(q); 06923 /* This check is to make sure we don't print information for realtime 06924 * queues which have been deleted from realtime but which have not yet 06925 * been deleted from the in-core container 06926 */ 06927 if (q->realtime) { 06928 realtime_queue = load_realtime_queue(q->name); 06929 if (!realtime_queue) { 06930 ao2_unlock(q); 06931 queue_t_unref(q, "Done with iterator"); 06932 continue; 06933 } 06934 queue_t_unref(realtime_queue, "Queue is already in memory"); 06935 } 06936 06937 if (argc == 3 && strcasecmp(q->name, argv[2])) { 06938 ao2_unlock(q); 06939 queue_t_unref(q, "Done with iterator"); 06940 continue; 06941 } 06942 found = 1; 06943 06944 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count); 06945 if (q->maxlen) 06946 ast_str_append(&out, 0, "%d", q->maxlen); 06947 else 06948 ast_str_append(&out, 0, "unlimited"); 06949 sl = 0; 06950 if (q->callscompleted > 0) 06951 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 06952 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds", 06953 int2strat(q->strategy), q->holdtime, q->talktime, q->weight, 06954 q->callscompleted, q->callsabandoned,sl,q->servicelevel); 06955 do_print(s, fd, ast_str_buffer(out)); 06956 if (!ao2_container_count(q->members)) 06957 do_print(s, fd, " No Members"); 06958 else { 06959 struct member *mem; 06960 06961 do_print(s, fd, " Members: "); 06962 mem_iter = ao2_iterator_init(q->members, 0); 06963 while ((mem = ao2_iterator_next(&mem_iter))) { 06964 ast_str_set(&out, 0, " %s", mem->membername); 06965 if (strcasecmp(mem->membername, mem->interface)) { 06966 ast_str_append(&out, 0, " (%s)", mem->interface); 06967 } 06968 if (mem->penalty) 06969 ast_str_append(&out, 0, " with penalty %d", mem->penalty); 06970 ast_str_append(&out, 0, "%s%s%s (%s)", 06971 mem->dynamic ? " (dynamic)" : "", 06972 mem->realtime ? " (realtime)" : "", 06973 mem->paused ? " (paused)" : "", 06974 ast_devstate2str(mem->status)); 06975 if (mem->calls) 06976 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)", 06977 mem->calls, (long) (time(NULL) - mem->lastcall)); 06978 else 06979 ast_str_append(&out, 0, " has taken no calls yet"); 06980 do_print(s, fd, ast_str_buffer(out)); 06981 ao2_ref(mem, -1); 06982 } 06983 ao2_iterator_destroy(&mem_iter); 06984 } 06985 if (!q->head) 06986 do_print(s, fd, " No Callers"); 06987 else { 06988 struct queue_ent *qe; 06989 int pos = 1; 06990 06991 do_print(s, fd, " Callers: "); 06992 for (qe = q->head; qe; qe = qe->next) { 06993 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)", 06994 pos++, qe->chan->name, (long) (now - qe->start) / 60, 06995 (long) (now - qe->start) % 60, qe->prio); 06996 do_print(s, fd, ast_str_buffer(out)); 06997 } 06998 } 06999 do_print(s, fd, ""); /* blank line between entries */ 07000 ao2_unlock(q); 07001 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */ 07002 } 07003 ao2_iterator_destroy(&queue_iter); 07004 ao2_unlock(queues); 07005 if (!found) { 07006 if (argc == 3) 07007 ast_str_set(&out, 0, "No such queue: %s.", argv[2]); 07008 else 07009 ast_str_set(&out, 0, "No queues."); 07010 do_print(s, fd, ast_str_buffer(out)); 07011 } 07012 return CLI_SUCCESS; 07013 }
static void __reg_module | ( | void | ) | [static] |
Definition at line 8393 of file app_queue.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 8393 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 5219 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, member::interface, interface_exists(), member::lastcall, load_realtime_queue(), 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().
05220 { 05221 struct call_queue *q; 05222 struct member *new_member, *old_member; 05223 int res = RES_NOSUCHQUEUE; 05224 05225 /*! \note Ensure the appropriate realtime queue is loaded. Note that this 05226 * short-circuits if the queue is already in memory. */ 05227 if (!(q = load_realtime_queue(queuename))) 05228 return res; 05229 05230 ao2_lock(q); 05231 if ((old_member = interface_exists(q, interface)) == NULL) { 05232 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { 05233 new_member->dynamic = 1; 05234 ao2_link(q->members, new_member); 05235 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 05236 "Queue: %s\r\n" 05237 "Location: %s\r\n" 05238 "MemberName: %s\r\n" 05239 "Membership: %s\r\n" 05240 "Penalty: %d\r\n" 05241 "CallsTaken: %d\r\n" 05242 "LastCall: %d\r\n" 05243 "Status: %d\r\n" 05244 "Paused: %d\r\n", 05245 q->name, new_member->interface, new_member->membername, 05246 "dynamic", 05247 new_member->penalty, new_member->calls, (int) new_member->lastcall, 05248 new_member->status, new_member->paused); 05249 05250 ao2_ref(new_member, -1); 05251 new_member = NULL; 05252 05253 if (dump) 05254 dump_queue_members(q); 05255 05256 res = RES_OKAY; 05257 } else { 05258 res = RES_OUTOFMEMORY; 05259 } 05260 } else { 05261 ao2_ref(old_member, -1); 05262 res = RES_EXISTS; 05263 } 05264 ao2_unlock(q); 05265 queue_t_unref(q, "Expiring temporary reference"); 05266 05267 return res; 05268 }
static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static] |
Definition at line 2168 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().
02169 { 02170 struct call_queue *q; 02171 02172 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) { 02173 if (ast_string_field_init(q, 64)) { 02174 queue_t_unref(q, "String field allocation failed"); 02175 return NULL; 02176 } 02177 ast_string_field_set(q, name, queuename); 02178 } 02179 return q; 02180 }
static int aqm_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
AddQueueMember application.
Definition at line 5651 of file app_queue.c.
References add_to_queue(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::name, parse(), pbx_builtin_setvar_helper(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and ast_channel::uniqueid.
Referenced by load_module().
05652 { 05653 int res=-1; 05654 char *parse, *temppos = NULL; 05655 AST_DECLARE_APP_ARGS(args, 05656 AST_APP_ARG(queuename); 05657 AST_APP_ARG(interface); 05658 AST_APP_ARG(penalty); 05659 AST_APP_ARG(options); 05660 AST_APP_ARG(membername); 05661 AST_APP_ARG(state_interface); 05662 ); 05663 int penalty = 0; 05664 05665 if (ast_strlen_zero(data)) { 05666 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n"); 05667 return -1; 05668 } 05669 05670 parse = ast_strdupa(data); 05671 05672 AST_STANDARD_APP_ARGS(args, parse); 05673 05674 if (ast_strlen_zero(args.interface)) { 05675 args.interface = ast_strdupa(chan->name); 05676 temppos = strrchr(args.interface, '-'); 05677 if (temppos) 05678 *temppos = '\0'; 05679 } 05680 05681 if (!ast_strlen_zero(args.penalty)) { 05682 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) { 05683 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 05684 penalty = 0; 05685 } 05686 } 05687 05688 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { 05689 case RES_OKAY: 05690 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 05691 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 05692 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 05693 res = 0; 05694 break; 05695 case RES_EXISTS: 05696 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 05697 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 05698 res = 0; 05699 break; 05700 case RES_NOSUCHQUEUE: 05701 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 05702 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 05703 res = 0; 05704 break; 05705 case RES_OUTOFMEMORY: 05706 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 05707 break; 05708 } 05709 05710 return res; 05711 }
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 4212 of file app_queue.c.
References ast_channel_datastore_find(), and queue_transfer_info.
04213 { 04214 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1; 04215 }
static int autopause2int | ( | const char * | autopause | ) | [static] |
Definition at line 1229 of file app_queue.c.
References ARRAY_LEN, ast_strlen_zero(), ast_true(), autopause::autopause, autopausesmodes, QUEUE_AUTOPAUSE_OFF, and QUEUE_AUTOPAUSE_ON.
Referenced by queue_set_param().
01230 { 01231 int x; 01232 /*This 'double check' that default value is OFF */ 01233 if (ast_strlen_zero(autopause)) 01234 return QUEUE_AUTOPAUSE_OFF; 01235 01236 /*This 'double check' is to ensure old values works */ 01237 if(ast_true(autopause)) 01238 return QUEUE_AUTOPAUSE_ON; 01239 01240 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) { 01241 if (!strcasecmp(autopause, autopausesmodes[x].name)) 01242 return autopausesmodes[x].autopause; 01243 } 01244 01245 /*This 'double check' that default value is OFF */ 01246 return QUEUE_AUTOPAUSE_OFF; 01247 }
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 4039 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.
04040 { 04041 /* disregarding penalty on too few members? */ 04042 int membercount = ao2_container_count(q->members); 04043 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1; 04044 04045 if (usepenalty) { 04046 if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || 04047 (qe->min_penalty && (mem->penalty < qe->min_penalty))) { 04048 return -1; 04049 } 04050 } else { 04051 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n", 04052 membercount, q->penaltymemberslimit); 04053 } 04054 04055 switch (q->strategy) { 04056 case QUEUE_STRATEGY_RINGALL: 04057 /* Everyone equal, except for penalty */ 04058 tmp->metric = mem->penalty * 1000000 * usepenalty; 04059 break; 04060 case QUEUE_STRATEGY_LINEAR: 04061 if (pos < qe->linpos) { 04062 tmp->metric = 1000 + pos; 04063 } else { 04064 if (pos > qe->linpos) 04065 /* Indicate there is another priority */ 04066 qe->linwrapped = 1; 04067 tmp->metric = pos; 04068 } 04069 tmp->metric += mem->penalty * 1000000 * usepenalty; 04070 break; 04071 case QUEUE_STRATEGY_RRORDERED: 04072 case QUEUE_STRATEGY_RRMEMORY: 04073 if (pos < q->rrpos) { 04074 tmp->metric = 1000 + pos; 04075 } else { 04076 if (pos > q->rrpos) 04077 /* Indicate there is another priority */ 04078 q->wrapped = 1; 04079 tmp->metric = pos; 04080 } 04081 tmp->metric += mem->penalty * 1000000 * usepenalty; 04082 break; 04083 case QUEUE_STRATEGY_RANDOM: 04084 tmp->metric = ast_random() % 1000; 04085 tmp->metric += mem->penalty * 1000000 * usepenalty; 04086 break; 04087 case QUEUE_STRATEGY_WRANDOM: 04088 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000); 04089 break; 04090 case QUEUE_STRATEGY_FEWESTCALLS: 04091 tmp->metric = mem->calls; 04092 tmp->metric += mem->penalty * 1000000 * usepenalty; 04093 break; 04094 case QUEUE_STRATEGY_LEASTRECENT: 04095 if (!mem->lastcall) 04096 tmp->metric = 0; 04097 else 04098 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 04099 tmp->metric += mem->penalty * 1000000 * usepenalty; 04100 break; 04101 default: 04102 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 04103 break; 04104 } 04105 return 0; 04106 }
static void callattempt_free | ( | struct callattempt * | doomed | ) | [static] |
Definition at line 2819 of file app_queue.c.
References ao2_ref, ast_free, ast_party_connected_line_free(), callattempt::connected, and callattempt::member.
Referenced by hangupcalls().
02820 { 02821 if (doomed->member) { 02822 ao2_ref(doomed->member, -1); 02823 } 02824 ast_party_connected_line_free(&doomed->connected); 02825 ast_free(doomed); 02826 }
static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 1735 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().
01736 { 01737 q->holdtime = 0; 01738 q->callscompleted = 0; 01739 q->callsabandoned = 0; 01740 q->callscompletedinsl = 0; 01741 q->talktime = 0; 01742 01743 if (q->members) { 01744 struct member *mem; 01745 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01746 while ((mem = ao2_iterator_next(&mem_iter))) { 01747 mem->calls = 0; 01748 mem->lastcall = 0; 01749 ao2_ref(mem, -1); 01750 } 01751 ao2_iterator_destroy(&mem_iter); 01752 } 01753 }
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 6823 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().
06824 { 06825 struct call_queue *q; 06826 struct ao2_iterator queue_iter; 06827 06828 queue_iter = ao2_iterator_init(queues, 0); 06829 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 06830 ao2_lock(q); 06831 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) 06832 clear_queue(q); 06833 ao2_unlock(q); 06834 queue_t_unref(q, "Done with iterator"); 06835 } 06836 ao2_iterator_destroy(&queue_iter); 06837 return 0; 06838 }
static int compare_weight | ( | struct call_queue * | rq, | |
struct member * | member | |||
) | [static] |
Definition at line 2899 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().
02900 { 02901 struct call_queue *q; 02902 struct member *mem; 02903 int found = 0; 02904 struct ao2_iterator queue_iter; 02905 02906 queue_iter = ao2_iterator_init(queues, 0); 02907 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 02908 if (q == rq) { /* don't check myself, could deadlock */ 02909 queue_t_unref(q, "Done with iterator"); 02910 continue; 02911 } 02912 ao2_lock(q); 02913 if (q->count && q->members) { 02914 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 02915 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 02916 if (q->weight > rq->weight && q->count >= num_available_members(q)) { 02917 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); 02918 found = 1; 02919 } 02920 ao2_ref(mem, -1); 02921 } 02922 } 02923 ao2_unlock(q); 02924 queue_t_unref(q, "Done with iterator"); 02925 if (found) { 02926 break; 02927 } 02928 } 02929 ao2_iterator_destroy(&queue_iter); 02930 return found; 02931 }
static char* complete_queue | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7015 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().
07016 { 07017 struct call_queue *q; 07018 char *ret = NULL; 07019 int which = 0; 07020 int wordlen = strlen(word); 07021 struct ao2_iterator queue_iter; 07022 07023 queue_iter = ao2_iterator_init(queues, 0); 07024 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07025 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 07026 ret = ast_strdup(q->name); 07027 queue_t_unref(q, "Done with iterator"); 07028 break; 07029 } 07030 queue_t_unref(q, "Done with iterator"); 07031 } 07032 ao2_iterator_destroy(&queue_iter); 07033 07034 return ret; 07035 }
static char* complete_queue_add_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7461 of file app_queue.c.
References ast_malloc, ast_strdup, and complete_queue().
Referenced by handle_queue_add_member().
07462 { 07463 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 07464 switch (pos) { 07465 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 07466 return NULL; 07467 case 4: /* only one possible match, "to" */ 07468 return state == 0 ? ast_strdup("to") : NULL; 07469 case 5: /* <queue> */ 07470 return complete_queue(line, word, pos, state); 07471 case 6: /* only one possible match, "penalty" */ 07472 return state == 0 ? ast_strdup("penalty") : NULL; 07473 case 7: 07474 if (state < 100) { /* 0-99 */ 07475 char *num; 07476 if ((num = ast_malloc(3))) { 07477 sprintf(num, "%d", state); 07478 } 07479 return num; 07480 } else { 07481 return NULL; 07482 } 07483 case 8: /* only one possible match, "as" */ 07484 return state == 0 ? ast_strdup("as") : NULL; 07485 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 07486 return NULL; 07487 default: 07488 return NULL; 07489 } 07490 }
static char* complete_queue_pause_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7682 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_pause_member().
07683 { 07684 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */ 07685 switch (pos) { 07686 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 07687 return NULL; 07688 case 4: /* only one possible match, "queue" */ 07689 return state == 0 ? ast_strdup("queue") : NULL; 07690 case 5: /* <queue> */ 07691 return complete_queue(line, word, pos, state); 07692 case 6: /* "reason" */ 07693 return state == 0 ? ast_strdup("reason") : NULL; 07694 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */ 07695 return NULL; 07696 default: 07697 return NULL; 07698 } 07699 }
static char* complete_queue_remove_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7591 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().
07592 { 07593 int which = 0; 07594 struct call_queue *q; 07595 struct member *m; 07596 struct ao2_iterator queue_iter; 07597 struct ao2_iterator mem_iter; 07598 int wordlen = strlen(word); 07599 07600 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 07601 if (pos > 5 || pos < 3) 07602 return NULL; 07603 if (pos == 4) /* only one possible match, 'from' */ 07604 return (state == 0 ? ast_strdup("from") : NULL); 07605 07606 if (pos == 5) /* No need to duplicate code */ 07607 return complete_queue(line, word, pos, state); 07608 07609 /* here is the case for 3, <member> */ 07610 queue_iter = ao2_iterator_init(queues, 0); 07611 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07612 ao2_lock(q); 07613 mem_iter = ao2_iterator_init(q->members, 0); 07614 while ((m = ao2_iterator_next(&mem_iter))) { 07615 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) { 07616 char *tmp; 07617 tmp = ast_strdup(m->interface); 07618 ao2_ref(m, -1); 07619 ao2_iterator_destroy(&mem_iter); 07620 ao2_unlock(q); 07621 queue_t_unref(q, "Done with iterator, returning interface name"); 07622 ao2_iterator_destroy(&queue_iter); 07623 return tmp; 07624 } 07625 ao2_ref(m, -1); 07626 } 07627 ao2_iterator_destroy(&mem_iter); 07628 ao2_unlock(q); 07629 queue_t_unref(q, "Done with iterator"); 07630 } 07631 ao2_iterator_destroy(&queue_iter); 07632 07633 return NULL; 07634 }
static char* complete_queue_rule_show | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7815 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, rule_list::list, and rule_list::name.
Referenced by handle_queue_rule_show().
07816 { 07817 int which = 0; 07818 struct rule_list *rl_iter; 07819 int wordlen = strlen(word); 07820 char *ret = NULL; 07821 if (pos != 3) /* Wha? */ { 07822 return NULL; 07823 } 07824 07825 AST_LIST_LOCK(&rule_lists); 07826 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 07827 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) { 07828 ret = ast_strdup(rl_iter->name); 07829 break; 07830 } 07831 } 07832 AST_LIST_UNLOCK(&rule_lists); 07833 07834 return ret; 07835 }
static char* complete_queue_set_member_penalty | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7752 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_set_member_penalty().
07753 { 07754 /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/ 07755 switch (pos) { 07756 case 4: 07757 if (state == 0) { 07758 return ast_strdup("on"); 07759 } else { 07760 return NULL; 07761 } 07762 case 6: 07763 if (state == 0) { 07764 return ast_strdup("in"); 07765 } else { 07766 return NULL; 07767 } 07768 case 7: 07769 return complete_queue(line, word, pos, state); 07770 default: 07771 return NULL; 07772 } 07773 }
static char* complete_queue_show | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 7037 of file app_queue.c.
References complete_queue().
Referenced by queue_show().
07038 { 07039 if (pos == 2) 07040 return complete_queue(line, word, pos, state); 07041 return NULL; 07042 }
static int compress_char | ( | const char | c | ) | [static] |
Definition at line 1627 of file app_queue.c.
Referenced by member_hash_fn().
01628 { 01629 if (c < 32) 01630 return 0; 01631 else if (c > 96) 01632 return c - 64; 01633 else 01634 return c - 32; 01635 }
static void copy_rules | ( | struct queue_ent * | qe, | |
const char * | rulename | |||
) | [static] |
Copy rule from global list into specified queue.
Definition at line 5748 of file app_queue.c.
References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), call_queue::defaultrule, penalty_rule::list, rule_list::list, LOG_ERROR, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, queue_ent::parent, queue_ent::qe_rules, rule_list::rules, and penalty_rule::time.
Referenced by queue_exec().
05749 { 05750 struct penalty_rule *pr_iter; 05751 struct rule_list *rl_iter; 05752 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename; 05753 AST_LIST_LOCK(&rule_lists); 05754 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 05755 if (!strcasecmp(rl_iter->name, tmp)) 05756 break; 05757 } 05758 if (rl_iter) { 05759 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 05760 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr)); 05761 if (!new_pr) { 05762 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n"); 05763 break; 05764 } 05765 new_pr->time = pr_iter->time; 05766 new_pr->max_value = pr_iter->max_value; 05767 new_pr->min_value = pr_iter->min_value; 05768 new_pr->max_relative = pr_iter->max_relative; 05769 new_pr->min_relative = pr_iter->min_relative; 05770 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list); 05771 } 05772 } 05773 AST_LIST_UNLOCK(&rule_lists); 05774 }
static struct member* create_queue_member | ( | const char * | interface, | |
const char * | membername, | |||
int | penalty, | |||
int | paused, | |||
const char * | state_interface | |||
) | [static] |
allocate space for new queue member and set fields based on parameters passed
Definition at line 1595 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(), LOG_WARNING, member::penalty, S_OR, and strsep().
Referenced by add_to_queue(), reload_single_member(), and rt_handle_member_record().
01596 { 01597 struct member *cur; 01598 01599 if ((cur = ao2_alloc(sizeof(*cur), NULL))) { 01600 cur->penalty = penalty; 01601 cur->paused = paused; 01602 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 01603 if (!ast_strlen_zero(state_interface)) 01604 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); 01605 else 01606 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface)); 01607 if (!ast_strlen_zero(membername)) 01608 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 01609 else 01610 ast_copy_string(cur->membername, interface, sizeof(cur->membername)); 01611 if (!strchr(cur->interface, '/')) 01612 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 01613 if (!strncmp(cur->state_interface, "hint:", 5)) { 01614 char *tmp = ast_strdupa(cur->state_interface), *context = tmp; 01615 char *exten = strsep(&context, "@") + 5; 01616 01617 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten)); 01618 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context)); 01619 } 01620 cur->status = get_queue_member_status(cur); 01621 } 01622 01623 return cur; 01624 }
static void destroy_queue | ( | void * | obj | ) | [static] |
Free queue's member list then its string fields.
Definition at line 2154 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().
02155 { 02156 struct call_queue *q = obj; 02157 int i; 02158 02159 free_members(q, 1); 02160 ast_string_field_free_memory(q); 02161 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 02162 if (q->sound_periodicannounce[i]) 02163 free(q->sound_periodicannounce[i]); 02164 } 02165 ao2_ref(q->members, -1); 02166 }
static void device_state_cb | ( | const struct ast_event * | event, | |
void * | unused | |||
) | [static] |
Definition at line 1493 of file app_queue.c.
References ast_calloc, ast_device_state(), 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, devicestate_tps, handle_statechange(), LOG_ERROR, and statechange::state.
Referenced by load_module(), and load_pbx().
01494 { 01495 enum ast_device_state state; 01496 const char *device; 01497 struct statechange *sc; 01498 size_t datapsize; 01499 01500 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE); 01501 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE); 01502 01503 if (ast_strlen_zero(device)) { 01504 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n"); 01505 return; 01506 } 01507 datapsize = sizeof(*sc) + strlen(device) + 1; 01508 if (!(sc = ast_calloc(1, datapsize))) { 01509 ast_log(LOG_ERROR, "failed to calloc a state change struct\n"); 01510 return; 01511 } 01512 sc->state = state; 01513 strcpy(sc->dev, device); 01514 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) { 01515 ast_free(sc); 01516 } 01517 }
static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 2934 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry().
02935 { 02936 o->stillgoing = 0; 02937 ast_hangup(o->chan); 02938 o->chan = NULL; 02939 }
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 6870 of file app_queue.c.
References ast_cli(), and astman_append().
Referenced by __queues_show().
06871 { 06872 if (s) 06873 astman_append(s, "%s\r\n", str); 06874 else 06875 ast_cli(fd, "%s\n", str); 06876 }
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 5124 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().
05125 { 05126 struct member *cur_member; 05127 char value[PM_MAX_LEN]; 05128 int value_len = 0; 05129 int res; 05130 struct ao2_iterator mem_iter; 05131 05132 memset(value, 0, sizeof(value)); 05133 05134 if (!pm_queue) 05135 return; 05136 05137 mem_iter = ao2_iterator_init(pm_queue->members, 0); 05138 while ((cur_member = ao2_iterator_next(&mem_iter))) { 05139 if (!cur_member->dynamic) { 05140 ao2_ref(cur_member, -1); 05141 continue; 05142 } 05143 05144 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s", 05145 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface); 05146 05147 ao2_ref(cur_member, -1); 05148 05149 if (res != strlen(value + value_len)) { 05150 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 05151 break; 05152 } 05153 value_len += res; 05154 } 05155 ao2_iterator_destroy(&mem_iter); 05156 05157 if (value_len && !cur_member) { 05158 if (ast_db_put(pm_family, pm_queue->name, value)) 05159 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 05160 } else 05161 /* Delete the entry if the queue is empty or there is an error */ 05162 ast_db_del(pm_family, pm_queue->name); 05163 }
static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 4259 of file app_queue.c.
References ao2_ref, queue_end_bridge::chan, queue_end_bridge::q, queue_t_unref, and set_queue_variables().
04260 { 04261 struct queue_end_bridge *qeb = data; 04262 struct call_queue *q = qeb->q; 04263 struct ast_channel *chan = qeb->chan; 04264 04265 if (ao2_ref(qeb, -1) == 1) { 04266 set_queue_variables(q, chan); 04267 /* This unrefs the reference we made in try_calling when we allocated qeb */ 04268 queue_t_unref(q, "Expire bridge_config reference"); 04269 } 04270 }
static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
struct ast_channel * | originator, | |||
struct ast_channel * | terminator | |||
) | [static] |
Definition at line 4252 of file app_queue.c.
References ao2_ref, queue_end_bridge::chan, and ast_bridge_config::end_bridge_callback_data.
04253 { 04254 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data; 04255 ao2_ref(qeb, +1); 04256 qeb->chan = originator; 04257 }
static int extension_state_cb | ( | char * | context, | |
char * | exten, | |||
enum ast_extension_states | state, | |||
void * | data | |||
) | [static] |
Definition at line 1551 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().
01552 { 01553 struct ao2_iterator miter, qiter; 01554 struct member *m; 01555 struct call_queue *q; 01556 int found = 0, device_state = extensionstate2devicestate(state); 01557 01558 qiter = ao2_iterator_init(queues, 0); 01559 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) { 01560 ao2_lock(q); 01561 01562 miter = ao2_iterator_init(q->members, 0); 01563 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) { 01564 if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) { 01565 update_status(q, m, device_state); 01566 ao2_ref(m, -1); 01567 found = 1; 01568 break; 01569 } 01570 } 01571 ao2_iterator_destroy(&miter); 01572 01573 ao2_unlock(q); 01574 queue_t_unref(q, "Done with iterator"); 01575 } 01576 ao2_iterator_destroy(&qiter); 01577 01578 if (found) { 01579 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state)); 01580 } else { 01581 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", 01582 exten, context, device_state, ast_devstate2str(device_state)); 01583 } 01584 01585 return 0; 01586 }
static int extensionstate2devicestate | ( | int | state | ) | [static] |
Helper function which converts from extension state to device state values.
Definition at line 1520 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().
01521 { 01522 switch (state) { 01523 case AST_EXTENSION_NOT_INUSE: 01524 state = AST_DEVICE_NOT_INUSE; 01525 break; 01526 case AST_EXTENSION_INUSE: 01527 state = AST_DEVICE_INUSE; 01528 break; 01529 case AST_EXTENSION_BUSY: 01530 state = AST_DEVICE_BUSY; 01531 break; 01532 case AST_EXTENSION_RINGING: 01533 state = AST_DEVICE_RINGING; 01534 break; 01535 case AST_EXTENSION_ONHOLD: 01536 state = AST_DEVICE_ONHOLD; 01537 break; 01538 case AST_EXTENSION_UNAVAILABLE: 01539 state = AST_DEVICE_UNAVAILABLE; 01540 break; 01541 case AST_EXTENSION_REMOVED: 01542 case AST_EXTENSION_DEACTIVATED: 01543 default: 01544 state = AST_DEVICE_INVALID; 01545 break; 01546 } 01547 01548 return state; 01549 }
static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static] |
find the entry with the best metric, or NULL
Definition at line 3174 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().
03175 { 03176 struct callattempt *best = NULL, *cur; 03177 03178 for (cur = outgoing; cur; cur = cur->q_next) { 03179 if (cur->stillgoing && /* Not already done */ 03180 !cur->chan && /* Isn't already going */ 03181 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 03182 best = cur; 03183 } 03184 } 03185 03186 return best; 03187 }
static struct call_queue* find_queue_by_name_rt | ( | const char * | queuename, | |
struct ast_variable * | queue_vars, | |||
struct ast_config * | member_config | |||
) | [static] |
Reload a single queue via realtime.
Check for statically defined queue first, check if deleted RT queue, check for new RT queue, if queue vars are not defined init them with defaults. reload RT queue vars, set RT queue members dead and reload them, return finished queue.
the | queue, | |
NULL | if it doesn't exist. |
Definition at line 2192 of file app_queue.c.
References alloc_queue(), ao2_lock, ao2_t_find, ao2_unlock, ast_debug, ast_log(), clear_queue(), call_queue::dead, LOG_WARNING, ast_variable::name, call_queue::name, ast_variable::next, OBJ_POINTER, QUEUE_STRATEGY_RINGALL, queue_t_unref, queues, queues_t_unlink, call_queue::realtime, strat2int(), call_queue::strategy, and ast_variable::value.
Referenced by load_realtime_queue().
02193 { 02194 struct ast_variable *v; 02195 struct call_queue *q, tmpq = { 02196 .name = queuename, 02197 }; 02198 struct member *m; 02199 struct ao2_iterator mem_iter; 02200 char *interface = NULL; 02201 const char *tmp_name; 02202 char *tmp; 02203 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 02204 02205 /* Static queues override realtime. */ 02206 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) { 02207 ao2_lock(q); 02208 if (!q->realtime) { 02209 if (q->dead) { 02210 ao2_unlock(q); 02211 queue_t_unref(q, "Queue is dead; can't return it"); 02212 return NULL; 02213 } else { 02214 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); 02215 ao2_unlock(q); 02216 return q; 02217 } 02218 } 02219 } else if (!member_config) 02220 /* Not found in the list, and it's not realtime ... */ 02221 return NULL; 02222 02223 /* Check if queue is defined in realtime. */ 02224 if (!queue_vars) { 02225 /* Delete queue from in-core list if it has been deleted in realtime. */ 02226 if (q) { 02227 /*! \note Hmm, can't seem to distinguish a DB failure from a not 02228 found condition... So we might delete an in-core queue 02229 in case of DB failure. */ 02230 ast_debug(1, "Queue %s not found in realtime.\n", queuename); 02231 02232 q->dead = 1; 02233 /* Delete if unused (else will be deleted when last caller leaves). */ 02234 queues_t_unlink(queues, q, "Unused; removing from container"); 02235 ao2_unlock(q); 02236 queue_t_unref(q, "Queue is dead; can't return it"); 02237 } 02238 return NULL; 02239 } 02240 02241 /* Create a new queue if an in-core entry does not exist yet. */ 02242 if (!q) { 02243 struct ast_variable *tmpvar = NULL; 02244 if (!(q = alloc_queue(queuename))) 02245 return NULL; 02246 ao2_lock(q); 02247 clear_queue(q); 02248 q->realtime = 1; 02249 /*Before we initialize the queue, we need to set the strategy, so that linear strategy 02250 * will allocate the members properly 02251 */ 02252 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) { 02253 if (!strcasecmp(tmpvar->name, "strategy")) { 02254 q->strategy = strat2int(tmpvar->value); 02255 if (q->strategy < 0) { 02256 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 02257 tmpvar->value, q->name); 02258 q->strategy = QUEUE_STRATEGY_RINGALL; 02259 } 02260 break; 02261 } 02262 } 02263 /* We traversed all variables and didn't find a strategy */ 02264 if (!tmpvar) 02265 q->strategy = QUEUE_STRATEGY_RINGALL; 02266 queues_t_link(queues, q, "Add queue to container"); 02267 } 02268 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 02269 02270 memset(tmpbuf, 0, sizeof(tmpbuf)); 02271 for (v = queue_vars; v; v = v->next) { 02272 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 02273 if ((tmp = strchr(v->name, '_'))) { 02274 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 02275 tmp_name = tmpbuf; 02276 tmp = tmpbuf; 02277 while ((tmp = strchr(tmp, '_'))) 02278 *tmp++ = '-'; 02279 } else 02280 tmp_name = v->name; 02281 02282 /* NULL values don't get returned from realtime; blank values should 02283 * still get set. If someone doesn't want a value to be set, they 02284 * should set the realtime column to NULL, not blank. */ 02285 queue_set_param(q, tmp_name, v->value, -1, 0); 02286 } 02287 02288 /* Temporarily set realtime members dead so we can detect deleted ones. */ 02289 mem_iter = ao2_iterator_init(q->members, 0); 02290 while ((m = ao2_iterator_next(&mem_iter))) { 02291 if (m->realtime) 02292 m->dead = 1; 02293 ao2_ref(m, -1); 02294 } 02295 ao2_iterator_destroy(&mem_iter); 02296 02297 while ((interface = ast_category_browse(member_config, interface))) { 02298 rt_handle_member_record(q, interface, 02299 ast_variable_retrieve(member_config, interface, "uniqueid"), 02300 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface), 02301 ast_variable_retrieve(member_config, interface, "penalty"), 02302 ast_variable_retrieve(member_config, interface, "paused"), 02303 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface)); 02304 } 02305 02306 /* Delete all realtime members that have been deleted in DB. */ 02307 mem_iter = ao2_iterator_init(q->members, 0); 02308 while ((m = ao2_iterator_next(&mem_iter))) { 02309 if (m->dead) { 02310 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 02311 ao2_unlink(q->members, m); 02312 } 02313 ao2_ref(m, -1); 02314 } 02315 ao2_iterator_destroy(&mem_iter); 02316 02317 ao2_unlock(q); 02318 02319 return q; 02320 }
static void free_members | ( | struct call_queue * | q, | |
int | all | |||
) | [static] |
Iterate through queue's member list and delete them.
Definition at line 2138 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().
02139 { 02140 /* Free non-dynamic members */ 02141 struct member *cur; 02142 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 02143 02144 while ((cur = ao2_iterator_next(&mem_iter))) { 02145 if (all || !cur->dynamic) { 02146 ao2_unlink(q->members, cur); 02147 } 02148 ao2_ref(cur, -1); 02149 } 02150 ao2_iterator_destroy(&mem_iter); 02151 }
static int get_member_penalty | ( | char * | queuename, | |
char * | interface | |||
) | [static] |
Definition at line 5396 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().
05397 { 05398 int foundqueue = 0, penalty; 05399 struct call_queue *q, tmpq = { 05400 .name = queuename, 05401 }; 05402 struct member *mem; 05403 05404 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) { 05405 foundqueue = 1; 05406 ao2_lock(q); 05407 if ((mem = interface_exists(q, interface))) { 05408 penalty = mem->penalty; 05409 ao2_ref(mem, -1); 05410 ao2_unlock(q); 05411 queue_t_unref(q, "Search complete"); 05412 return penalty; 05413 } 05414 ao2_unlock(q); 05415 queue_t_unref(q, "Search complete"); 05416 } 05417 05418 /* some useful debuging */ 05419 if (foundqueue) 05420 ast_log (LOG_ERROR, "Invalid queuename\n"); 05421 else 05422 ast_log (LOG_ERROR, "Invalid interface\n"); 05423 05424 return RESULT_FAILURE; 05425 }
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 1343 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().
01344 { 01345 struct member *member; 01346 struct ao2_iterator mem_iter; 01347 01348 ao2_lock(q); 01349 mem_iter = ao2_iterator_init(q->members, 0); 01350 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) { 01351 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) { 01352 if (conditions & QUEUE_EMPTY_PENALTY) { 01353 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty); 01354 continue; 01355 } 01356 } 01357 01358 switch (member->status) { 01359 case AST_DEVICE_INVALID: 01360 if (conditions & QUEUE_EMPTY_INVALID) { 01361 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername); 01362 break; 01363 } 01364 goto default_case; 01365 case AST_DEVICE_UNAVAILABLE: 01366 if (conditions & QUEUE_EMPTY_UNAVAILABLE) { 01367 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername); 01368 break; 01369 } 01370 goto default_case; 01371 case AST_DEVICE_INUSE: 01372 if (conditions & QUEUE_EMPTY_INUSE) { 01373 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername); 01374 break; 01375 } 01376 goto default_case; 01377 case AST_DEVICE_RINGING: 01378 if (conditions & QUEUE_EMPTY_RINGING) { 01379 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername); 01380 break; 01381 } 01382 goto default_case; 01383 case AST_DEVICE_UNKNOWN: 01384 if (conditions & QUEUE_EMPTY_UNKNOWN) { 01385 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername); 01386 break; 01387 } 01388 /* Fall-through */ 01389 default: 01390 default_case: 01391 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) { 01392 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername); 01393 break; 01394 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) { 01395 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); 01396 break; 01397 } else { 01398 ao2_ref(member, -1); 01399 ao2_iterator_destroy(&mem_iter); 01400 ao2_unlock(q); 01401 ast_debug(4, "%s is available.\n", member->membername); 01402 return 0; 01403 } 01404 break; 01405 } 01406 } 01407 ao2_iterator_destroy(&mem_iter); 01408 01409 ao2_unlock(q); 01410 return -1; 01411 }
static int get_queue_member_status | ( | struct member * | cur | ) | [static] |
Return the current state of a member.
Definition at line 1589 of file app_queue.c.
References ast_device_state(), 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().
01590 { 01591 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten)); 01592 }
static char* handle_queue_add_member | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7517 of file app_queue.c.
References add_to_queue(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_add_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, ast_cli_entry::usage, and ast_cli_args::word.
07518 { 07519 const char *queuename, *interface, *membername = NULL, *state_interface = NULL; 07520 int penalty; 07521 07522 switch ( cmd ) { 07523 case CLI_INIT: 07524 e->command = "queue add member"; 07525 e->usage = 07526 "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n" 07527 " Add a channel to a queue with optionally: a penalty, membername and a state_interface\n"; 07528 return NULL; 07529 case CLI_GENERATE: 07530 return complete_queue_add_member(a->line, a->word, a->pos, a->n); 07531 } 07532 07533 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) { 07534 return CLI_SHOWUSAGE; 07535 } else if (strcmp(a->argv[4], "to")) { 07536 return CLI_SHOWUSAGE; 07537 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) { 07538 return CLI_SHOWUSAGE; 07539 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) { 07540 return CLI_SHOWUSAGE; 07541 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) { 07542 return CLI_SHOWUSAGE; 07543 } 07544 07545 queuename = a->argv[5]; 07546 interface = a->argv[3]; 07547 if (a->argc >= 8) { 07548 if (sscanf(a->argv[7], "%30d", &penalty) == 1) { 07549 if (penalty < 0) { 07550 ast_cli(a->fd, "Penalty must be >= 0\n"); 07551 penalty = 0; 07552 } 07553 } else { 07554 ast_cli(a->fd, "Penalty must be an integer >= 0\n"); 07555 penalty = 0; 07556 } 07557 } else { 07558 penalty = 0; 07559 } 07560 07561 if (a->argc >= 10) { 07562 membername = a->argv[9]; 07563 } 07564 07565 if (a->argc >= 12) { 07566 state_interface = a->argv[11]; 07567 } 07568 07569 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { 07570 case RES_OKAY: 07571 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 07572 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 07573 return CLI_SUCCESS; 07574 case RES_EXISTS: 07575 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 07576 return CLI_FAILURE; 07577 case RES_NOSUCHQUEUE: 07578 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 07579 return CLI_FAILURE; 07580 case RES_OUTOFMEMORY: 07581 ast_cli(a->fd, "Out of memory\n"); 07582 return CLI_FAILURE; 07583 case RES_NOT_DYNAMIC: 07584 ast_cli(a->fd, "Member not dynamic\n"); 07585 return CLI_FAILURE; 07586 default: 07587 return CLI_FAILURE; 07588 } 07589 }
static char* handle_queue_pause_member | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7701 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_pause_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RESULT_SUCCESS, set_member_paused(), ast_cli_entry::usage, and word.
07702 { 07703 const char *queuename, *interface, *reason; 07704 int paused; 07705 07706 switch (cmd) { 07707 case CLI_INIT: 07708 e->command = "queue {pause|unpause} member"; 07709 e->usage = 07710 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n" 07711 " Pause or unpause a queue member. Not specifying a particular queue\n" 07712 " will pause or unpause a member across all queues to which the member\n" 07713 " belongs.\n"; 07714 return NULL; 07715 case CLI_GENERATE: 07716 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n); 07717 } 07718 07719 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) { 07720 return CLI_SHOWUSAGE; 07721 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) { 07722 return CLI_SHOWUSAGE; 07723 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) { 07724 return CLI_SHOWUSAGE; 07725 } 07726 07727 07728 interface = a->argv[3]; 07729 queuename = a->argc >= 6 ? a->argv[5] : NULL; 07730 reason = a->argc == 8 ? a->argv[7] : NULL; 07731 paused = !strcasecmp(a->argv[1], "pause"); 07732 07733 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) { 07734 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface); 07735 if (!ast_strlen_zero(queuename)) 07736 ast_cli(a->fd, " in queue '%s'", queuename); 07737 if (!ast_strlen_zero(reason)) 07738 ast_cli(a->fd, " for reason '%s'", reason); 07739 ast_cli(a->fd, "\n"); 07740 return CLI_SUCCESS; 07741 } else { 07742 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface); 07743 if (!ast_strlen_zero(queuename)) 07744 ast_cli(a->fd, " in queue '%s'", queuename); 07745 if (!ast_strlen_zero(reason)) 07746 ast_cli(a->fd, " for reason '%s'", reason); 07747 ast_cli(a->fd, "\n"); 07748 return CLI_FAILURE; 07749 } 07750 }
static char* handle_queue_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7910 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.
07911 { 07912 struct ast_flags mask = {0,}; 07913 int i; 07914 07915 switch (cmd) { 07916 case CLI_INIT: 07917 e->command = "queue reload {parameters|members|rules|all}"; 07918 e->usage = 07919 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n" 07920 "Reload queues. If <queuenames> are specified, only reload information pertaining\n" 07921 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n" 07922 "specified in order to know what information to reload. Below is an explanation\n" 07923 "of each of these qualifiers.\n" 07924 "\n" 07925 "\t'members' - reload queue members from queues.conf\n" 07926 "\t'parameters' - reload all queue options except for queue members\n" 07927 "\t'rules' - reload the queuerules.conf file\n" 07928 "\t'all' - reload queue rules, parameters, and members\n" 07929 "\n" 07930 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n" 07931 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n" 07932 "one queue is specified when using this command, reloading queue rules may cause\n" 07933 "other queues to be affected\n"; 07934 return NULL; 07935 case CLI_GENERATE: 07936 if (a->pos >= 3) { 07937 return complete_queue(a->line, a->word, a->pos, a->n); 07938 } else { 07939 return NULL; 07940 } 07941 } 07942 07943 if (a->argc < 3) 07944 return CLI_SHOWUSAGE; 07945 07946 if (!strcasecmp(a->argv[2], "rules")) { 07947 ast_set_flag(&mask, QUEUE_RELOAD_RULES); 07948 } else if (!strcasecmp(a->argv[2], "members")) { 07949 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER); 07950 } else if (!strcasecmp(a->argv[2], "parameters")) { 07951 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); 07952 } else if (!strcasecmp(a->argv[2], "all")) { 07953 ast_set_flag(&mask, AST_FLAGS_ALL); 07954 } 07955 07956 if (a->argc == 3) { 07957 reload_handler(1, &mask, NULL); 07958 return CLI_SUCCESS; 07959 } 07960 07961 for (i = 3; i < a->argc; ++i) { 07962 reload_handler(1, &mask, a->argv[i]); 07963 } 07964 07965 return CLI_SUCCESS; 07966 }
static char* handle_queue_remove_member | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7636 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_remove_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, ast_cli_entry::usage, and ast_cli_args::word.
07637 { 07638 const char *queuename, *interface; 07639 07640 switch (cmd) { 07641 case CLI_INIT: 07642 e->command = "queue remove member"; 07643 e->usage = 07644 "Usage: queue remove member <channel> from <queue>\n" 07645 " Remove a specific channel from a queue.\n"; 07646 return NULL; 07647 case CLI_GENERATE: 07648 return complete_queue_remove_member(a->line, a->word, a->pos, a->n); 07649 } 07650 07651 if (a->argc != 6) { 07652 return CLI_SHOWUSAGE; 07653 } else if (strcmp(a->argv[4], "from")) { 07654 return CLI_SHOWUSAGE; 07655 } 07656 07657 queuename = a->argv[5]; 07658 interface = a->argv[3]; 07659 07660 switch (remove_from_queue(queuename, interface)) { 07661 case RES_OKAY: 07662 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 07663 ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 07664 return CLI_SUCCESS; 07665 case RES_EXISTS: 07666 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 07667 return CLI_FAILURE; 07668 case RES_NOSUCHQUEUE: 07669 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 07670 return CLI_FAILURE; 07671 case RES_OUTOFMEMORY: 07672 ast_cli(a->fd, "Out of memory\n"); 07673 return CLI_FAILURE; 07674 case RES_NOT_DYNAMIC: 07675 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename); 07676 return CLI_FAILURE; 07677 default: 07678 return CLI_FAILURE; 07679 } 07680 }
static char* handle_queue_reset | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7871 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.
07872 { 07873 struct ast_flags mask = {QUEUE_RESET_STATS,}; 07874 int i; 07875 07876 switch (cmd) { 07877 case CLI_INIT: 07878 e->command = "queue reset stats"; 07879 e->usage = 07880 "Usage: queue reset stats [<queuenames>]\n" 07881 "\n" 07882 "Issuing this command will reset statistics for\n" 07883 "<queuenames>, or for all queues if no queue is\n" 07884 "specified.\n"; 07885 return NULL; 07886 case CLI_GENERATE: 07887 if (a->pos >= 3) { 07888 return complete_queue(a->line, a->word, a->pos, a->n); 07889 } else { 07890 return NULL; 07891 } 07892 } 07893 07894 if (a->argc < 3) { 07895 return CLI_SHOWUSAGE; 07896 } 07897 07898 if (a->argc == 3) { 07899 reload_handler(1, &mask, NULL); 07900 return CLI_SUCCESS; 07901 } 07902 07903 for (i = 3; i < a->argc; ++i) { 07904 reload_handler(1, &mask, a->argv[i]); 07905 } 07906 07907 return CLI_SUCCESS; 07908 }
static char* handle_queue_rule_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7837 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_rule_show(), ast_cli_args::fd, ast_cli_args::line, penalty_rule::list, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, ast_cli_args::n, rule_list::name, ast_cli_args::pos, rule_list::rules, penalty_rule::time, ast_cli_entry::usage, and ast_cli_args::word.
07838 { 07839 const char *rule; 07840 struct rule_list *rl_iter; 07841 struct penalty_rule *pr_iter; 07842 switch (cmd) { 07843 case CLI_INIT: 07844 e->command = "queue show rules"; 07845 e->usage = 07846 "Usage: queue show rules [rulename]\n" 07847 " Show the list of rules associated with rulename. If no\n" 07848 " rulename is specified, list all rules defined in queuerules.conf\n"; 07849 return NULL; 07850 case CLI_GENERATE: 07851 return complete_queue_rule_show(a->line, a->word, a->pos, a->n); 07852 } 07853 07854 if (a->argc != 3 && a->argc != 4) 07855 return CLI_SHOWUSAGE; 07856 07857 rule = a->argc == 4 ? a->argv[3] : ""; 07858 AST_LIST_LOCK(&rule_lists); 07859 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 07860 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) { 07861 ast_cli(a->fd, "Rule: %s\n", rl_iter->name); 07862 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 07863 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); 07864 } 07865 } 07866 } 07867 AST_LIST_UNLOCK(&rule_lists); 07868 return CLI_SUCCESS; 07869 }
static char* handle_queue_set_member_penalty | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7775 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_set_member_penalty(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RESULT_FAILURE, RESULT_SUCCESS, set_member_penalty(), ast_cli_entry::usage, and ast_cli_args::word.
07776 { 07777 const char *queuename = NULL, *interface; 07778 int penalty = 0; 07779 07780 switch (cmd) { 07781 case CLI_INIT: 07782 e->command = "queue set penalty"; 07783 e->usage = 07784 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n" 07785 " Set a member's penalty in the queue specified. If no queue is specified\n" 07786 " then that interface's penalty is set in all queues to which that interface is a member\n"; 07787 return NULL; 07788 case CLI_GENERATE: 07789 return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n); 07790 } 07791 07792 if (a->argc != 6 && a->argc != 8) { 07793 return CLI_SHOWUSAGE; 07794 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) { 07795 return CLI_SHOWUSAGE; 07796 } 07797 07798 if (a->argc == 8) 07799 queuename = a->argv[7]; 07800 interface = a->argv[5]; 07801 penalty = atoi(a->argv[3]); 07802 07803 switch (set_member_penalty(queuename, interface, penalty)) { 07804 case RESULT_SUCCESS: 07805 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename); 07806 return CLI_SUCCESS; 07807 case RESULT_FAILURE: 07808 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename); 07809 return CLI_FAILURE; 07810 default: 07811 return CLI_FAILURE; 07812 } 07813 }
static int handle_statechange | ( | void * | datap | ) | [static] |
set a member's status based on device state of that member's interface
Definition at line 1449 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().
01450 { 01451 struct statechange *sc = datap; 01452 struct ao2_iterator miter, qiter; 01453 struct member *m; 01454 struct call_queue *q; 01455 char interface[80], *slash_pos; 01456 int found = 0; 01457 01458 qiter = ao2_iterator_init(queues, 0); 01459 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) { 01460 ao2_lock(q); 01461 01462 miter = ao2_iterator_init(q->members, 0); 01463 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) { 01464 ast_copy_string(interface, m->state_interface, sizeof(interface)); 01465 01466 if ((slash_pos = strchr(interface, '/'))) 01467 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) 01468 *slash_pos = '\0'; 01469 01470 if (!strcasecmp(interface, sc->dev)) { 01471 found = 1; 01472 update_status(q, m, sc->state); 01473 ao2_ref(m, -1); 01474 break; 01475 } 01476 } 01477 ao2_iterator_destroy(&miter); 01478 01479 ao2_unlock(q); 01480 queue_t_unref(q, "Done with iterator"); 01481 } 01482 ao2_iterator_destroy(&qiter); 01483 01484 if (found) 01485 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state)); 01486 else 01487 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)); 01488 01489 ast_free(sc); 01490 return 0; 01491 }
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 2829 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.
02830 { 02831 struct callattempt *oo; 02832 02833 while (outgoing) { 02834 /* If someone else answered the call we should indicate this in the CANCEL */ 02835 /* Hangup any existing lines we have open */ 02836 if (outgoing->chan && (outgoing->chan != exception)) { 02837 if (exception || cancel_answered_elsewhere) 02838 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE); 02839 ast_hangup(outgoing->chan); 02840 } 02841 oo = outgoing; 02842 outgoing = outgoing->q_next; 02843 ast_aoc_destroy_decoded(oo->aoc_s_rate_list); 02844 callattempt_free(oo); 02845 } 02846 }
static void init_queue | ( | struct call_queue * | q | ) | [static] |
Initialize Queue default values.
Definition at line 1659 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::dead, DEFAULT_MIN_ANNOUNCE_FREQUENCY, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::eventwhencalled, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, penalty_rule::list, 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 reload_single_queue().
01660 { 01661 int i; 01662 struct penalty_rule *pr_iter; 01663 01664 q->dead = 0; 01665 q->retry = DEFAULT_RETRY; 01666 q->timeout = DEFAULT_TIMEOUT; 01667 q->maxlen = 0; 01668 q->announcefrequency = 0; 01669 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY; 01670 q->announceholdtime = 1; 01671 q->announcepositionlimit = 10; /* Default 10 positions */ 01672 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */ 01673 q->roundingseconds = 0; /* Default - don't announce seconds */ 01674 q->servicelevel = 0; 01675 q->ringinuse = 1; 01676 q->setinterfacevar = 0; 01677 q->setqueuevar = 0; 01678 q->setqueueentryvar = 0; 01679 q->autofill = autofill_default; 01680 q->montype = montype_default; 01681 q->monfmt[0] = '\0'; 01682 q->reportholdtime = 0; 01683 q->wrapuptime = 0; 01684 q->penaltymemberslimit = 0; 01685 q->joinempty = 0; 01686 q->leavewhenempty = 0; 01687 q->memberdelay = 0; 01688 q->maskmemberstatus = 0; 01689 q->eventwhencalled = 0; 01690 q->weight = 0; 01691 q->timeoutrestart = 0; 01692 q->periodicannouncefrequency = 0; 01693 q->randomperiodicannounce = 0; 01694 q->numperiodicannounce = 0; 01695 q->autopause = QUEUE_AUTOPAUSE_OFF; 01696 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 01697 if (!q->members) { 01698 if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) 01699 /* linear strategy depends on order, so we have to place all members in a single bucket */ 01700 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn); 01701 else 01702 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn); 01703 } 01704 q->found = 1; 01705 01706 ast_string_field_set(q, sound_next, "queue-youarenext"); 01707 ast_string_field_set(q, sound_thereare, "queue-thereare"); 01708 ast_string_field_set(q, sound_calls, "queue-callswaiting"); 01709 ast_string_field_set(q, queue_quantity1, "queue-quantity1"); 01710 ast_string_field_set(q, queue_quantity2, "queue-quantity2"); 01711 ast_string_field_set(q, sound_holdtime, "queue-holdtime"); 01712 ast_string_field_set(q, sound_minutes, "queue-minutes"); 01713 ast_string_field_set(q, sound_minute, "queue-minute"); 01714 ast_string_field_set(q, sound_seconds, "queue-seconds"); 01715 ast_string_field_set(q, sound_thanks, "queue-thankyou"); 01716 ast_string_field_set(q, sound_reporthold, "queue-reporthold"); 01717 01718 if (!q->sound_periodicannounce[0]) { 01719 q->sound_periodicannounce[0] = ast_str_create(32); 01720 } 01721 01722 if (q->sound_periodicannounce[0]) { 01723 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce"); 01724 } 01725 01726 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 01727 if (q->sound_periodicannounce[i]) 01728 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", ""); 01729 } 01730 01731 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) 01732 ast_free(pr_iter); 01733 }
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 1313 of file app_queue.c.
References call_queue::head, queue_ent::next, and queue_ref().
Referenced by join_queue().
01314 { 01315 struct queue_ent *cur; 01316 01317 if (!q || !new) 01318 return; 01319 if (prev) { 01320 cur = prev->next; 01321 prev->next = new; 01322 } else { 01323 cur = q->head; 01324 q->head = new; 01325 } 01326 new->next = cur; 01327 01328 /* every queue_ent must have a reference to it's parent call_queue, this 01329 * reference does not go away until the end of the queue_ent's life, meaning 01330 * that even when the queue_ent leaves the call_queue this ref must remain. */ 01331 queue_ref(q); 01332 new->parent = q; 01333 new->pos = ++(*pos); 01334 new->opos = *pos; 01335 }
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 1764 of file app_queue.c.
References ast_calloc, ast_free, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_strdupa, ast_strlen_zero(), rule_list::list, LOG_WARNING, rule_list::name, and rule_list::rules.
Referenced by reload_queue_rules().
01765 { 01766 char *timestr, *maxstr, *minstr, *contentdup; 01767 struct penalty_rule *rule = NULL, *rule_iter; 01768 struct rule_list *rl_iter; 01769 int penaltychangetime, inserted = 0; 01770 01771 if (!(rule = ast_calloc(1, sizeof(*rule)))) { 01772 return -1; 01773 } 01774 01775 contentdup = ast_strdupa(content); 01776 01777 if (!(maxstr = strchr(contentdup, ','))) { 01778 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum); 01779 ast_free(rule); 01780 return -1; 01781 } 01782 01783 *maxstr++ = '\0'; 01784 timestr = contentdup; 01785 01786 if ((penaltychangetime = atoi(timestr)) < 0) { 01787 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum); 01788 ast_free(rule); 01789 return -1; 01790 } 01791 01792 rule->time = penaltychangetime; 01793 01794 if ((minstr = strchr(maxstr,','))) 01795 *minstr++ = '\0'; 01796 01797 /* The last check will evaluate true if either no penalty change is indicated for a given rule 01798 * OR if a min penalty change is indicated but no max penalty change is */ 01799 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') { 01800 rule->max_relative = 1; 01801 } 01802 01803 rule->max_value = atoi(maxstr); 01804 01805 if (!ast_strlen_zero(minstr)) { 01806 if (*minstr == '+' || *minstr == '-') 01807 rule->min_relative = 1; 01808 rule->min_value = atoi(minstr); 01809 } else /*there was no minimum specified, so assume this means no change*/ 01810 rule->min_relative = 1; 01811 01812 /*We have the rule made, now we need to insert it where it belongs*/ 01813 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){ 01814 if (strcasecmp(rl_iter->name, list_name)) 01815 continue; 01816 01817 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) { 01818 if (rule->time < rule_iter->time) { 01819 AST_LIST_INSERT_BEFORE_CURRENT(rule, list); 01820 inserted = 1; 01821 break; 01822 } 01823 } 01824 AST_LIST_TRAVERSE_SAFE_END; 01825 01826 if (!inserted) { 01827 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list); 01828 } 01829 } 01830 01831 return 0; 01832 }
static const char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 1205 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().
01206 { 01207 int x; 01208 01209 for (x = 0; x < ARRAY_LEN(strategies); x++) { 01210 if (strategy == strategies[x].strategy) 01211 return strategies[x].name; 01212 } 01213 01214 return "<unknown>"; 01215 }
static struct member* interface_exists | ( | struct call_queue * | q, | |
const char * | interface | |||
) | [static] |
Definition at line 5098 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, member::interface, and call_queue::members.
Referenced by add_to_queue(), get_member_penalty(), set_member_paused(), and set_member_penalty().
05099 { 05100 struct member *mem; 05101 struct ao2_iterator mem_iter; 05102 05103 if (!q) 05104 return NULL; 05105 05106 mem_iter = ao2_iterator_init(q->members, 0); 05107 while ((mem = ao2_iterator_next(&mem_iter))) { 05108 if (!strcasecmp(interface, mem->interface)) { 05109 ao2_iterator_destroy(&mem_iter); 05110 return mem; 05111 } 05112 ao2_ref(mem, -1); 05113 } 05114 ao2_iterator_destroy(&mem_iter); 05115 05116 return NULL; 05117 }
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 3840 of file app_queue.c.
References ao2_lock, ao2_unlock, ast_debug, call_queue::autofill, queue_ent::chan, call_queue::head, ast_channel::name, queue_ent::next, num_available_members(), queue_ent::parent, queue_ent::pending, and queue_ent::pos.
Referenced by queue_exec(), and wait_our_turn().
03841 { 03842 struct queue_ent *ch; 03843 int res; 03844 int avl; 03845 int idx = 0; 03846 /* This needs a lock. How many members are available to be served? */ 03847 ao2_lock(qe->parent); 03848 03849 avl = num_available_members(qe->parent); 03850 03851 ch = qe->parent->head; 03852 03853 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member"); 03854 03855 while ((idx < avl) && (ch) && (ch != qe)) { 03856 if (!ch->pending) 03857 idx++; 03858 ch = ch->next; 03859 } 03860 03861 ao2_unlock(qe->parent); 03862 /* If the queue entry is within avl [the number of available members] calls from the top ... 03863 * Autofill and position check added to support autofill=no (as only calls 03864 * from the front of the queue are valid when autofill is disabled) 03865 */ 03866 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) { 03867 ast_debug(1, "It's our turn (%s).\n", qe->chan->name); 03868 res = 1; 03869 } else { 03870 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name); 03871 res = 0; 03872 } 03873 03874 return res; 03875 }
static int join_queue | ( | char * | queuename, | |
struct queue_ent * | qe, | |||
enum queue_result * | reason, | |||
int | position | |||
) | [static] |
Definition at line 2439 of file app_queue.c.
References queue_ent::announce, ao2_lock, ao2_unlock, ast_copy_string(), ast_debug, ast_log(), ast_manager_event, ast_channel::caller, queue_ent::chan, ast_channel::connected, queue_ent::context, call_queue::count, EVENT_FLAG_CALL, get_member_status(), call_queue::head, ast_party_connected_line::id, ast_party_caller::id, insert_entry(), call_queue::joinempty, load_realtime_queue(), LOG_NOTICE, queue_ent::max_penalty, call_queue::maxlen, queue_ent::min_penalty, queue_ent::moh, ast_party_id::name, ast_channel::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_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.
Referenced by queue_exec().
02440 { 02441 struct call_queue *q; 02442 struct queue_ent *cur, *prev = NULL; 02443 int res = -1; 02444 int pos = 0; 02445 int inserted = 0; 02446 02447 if (!(q = load_realtime_queue(queuename))) 02448 return res; 02449 02450 ao2_lock(q); 02451 02452 /* This is our one */ 02453 if (q->joinempty) { 02454 int status = 0; 02455 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) { 02456 *reason = QUEUE_JOINEMPTY; 02457 ao2_unlock(q); 02458 queue_t_unref(q, "Done with realtime queue"); 02459 return res; 02460 } 02461 } 02462 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) 02463 *reason = QUEUE_FULL; 02464 else if (*reason == QUEUE_UNKNOWN) { 02465 /* There's space for us, put us at the right position inside 02466 * the queue. 02467 * Take into account the priority of the calling user */ 02468 inserted = 0; 02469 prev = NULL; 02470 cur = q->head; 02471 while (cur) { 02472 /* We have higher priority than the current user, enter 02473 * before him, after all the other users with priority 02474 * higher or equal to our priority. */ 02475 if ((!inserted) && (qe->prio > cur->prio)) { 02476 insert_entry(q, prev, qe, &pos); 02477 inserted = 1; 02478 } 02479 /* <= is necessary for the position comparison because it may not be possible to enter 02480 * at our desired position since higher-priority callers may have taken the position we want 02481 */ 02482 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) { 02483 insert_entry(q, prev, qe, &pos); 02484 /*pos is incremented inside insert_entry, so don't need to add 1 here*/ 02485 if (position < pos) { 02486 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos); 02487 } 02488 inserted = 1; 02489 } 02490 cur->pos = ++pos; 02491 prev = cur; 02492 cur = cur->next; 02493 } 02494 /* No luck, join at the end of the queue */ 02495 if (!inserted) 02496 insert_entry(q, prev, qe, &pos); 02497 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 02498 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 02499 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 02500 q->count++; 02501 res = 0; 02502 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join", 02503 "Channel: %s\r\n" 02504 "CallerIDNum: %s\r\n" 02505 "CallerIDName: %s\r\n" 02506 "ConnectedLineNum: %s\r\n" 02507 "ConnectedLineName: %s\r\n" 02508 "Queue: %s\r\n" 02509 "Position: %d\r\n" 02510 "Count: %d\r\n" 02511 "Uniqueid: %s\r\n", 02512 qe->chan->name, 02513 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */ 02514 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 02515 S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */ 02516 S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), 02517 q->name, qe->pos, q->count, qe->chan->uniqueid ); 02518 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 02519 } 02520 ao2_unlock(q); 02521 queue_t_unref(q, "Done with realtime queue"); 02522 02523 return res; 02524 }
static int kill_dead_members | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6611 of file app_queue.c.
References CMP_MATCH, member::delme, get_queue_member_status(), and member::status.
06612 { 06613 struct member *member = obj; 06614 06615 if (!member->delme) { 06616 member->status = get_queue_member_status(member); 06617 return 0; 06618 } else { 06619 return CMP_MATCH; 06620 } 06621 }
static int kill_dead_queues | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6740 of file app_queue.c.
References ast_strlen_zero(), CMP_MATCH, call_queue::dead, and call_queue::name.
Referenced by reload_queues().
06741 { 06742 struct call_queue *q = obj; 06743 char *queuename = arg; 06744 if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) { 06745 return CMP_MATCH; 06746 } else { 06747 return 0; 06748 } 06749 }
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 2751 of file app_queue.c.
References ao2_lock, ao2_unlock, ast_debug, ast_free, AST_LIST_REMOVE_HEAD, ast_load_realtime(), ast_manager_event, ast_variables_destroy(), queue_ent::chan, call_queue::count, call_queue::dead, EVENT_FLAG_CALL, call_queue::head, penalty_rule::list, call_queue::name, ast_channel::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, ast_channel::uniqueid, and var.
Referenced by wait_our_turn().
02752 { 02753 struct call_queue *q; 02754 struct queue_ent *current, *prev = NULL; 02755 struct penalty_rule *pr_iter; 02756 int pos = 0; 02757 02758 if (!(q = qe->parent)) 02759 return; 02760 queue_t_ref(q, "Copy queue pointer from queue entry"); 02761 ao2_lock(q); 02762 02763 prev = NULL; 02764 for (current = q->head; current; current = current->next) { 02765 if (current == qe) { 02766 char posstr[20]; 02767 q->count--; 02768 02769 /* Take us out of the queue */ 02770 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave", 02771 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n", 02772 qe->chan->name, q->name, q->count, qe->pos, qe->chan->uniqueid); 02773 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 02774 /* Take us out of the queue */ 02775 if (prev) 02776 prev->next = current->next; 02777 else 02778 q->head = current->next; 02779 /* Free penalty rules */ 02780 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) 02781 ast_free(pr_iter); 02782 snprintf(posstr, sizeof(posstr), "%d", qe->pos); 02783 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr); 02784 } else { 02785 /* Renumber the people after us in the queue based on a new count */ 02786 current->pos = ++pos; 02787 prev = current; 02788 } 02789 } 02790 ao2_unlock(q); 02791 02792 /*If the queue is a realtime queue, check to see if it's still defined in real time*/ 02793 if (q->realtime) { 02794 struct ast_variable *var; 02795 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) { 02796 q->dead = 1; 02797 } else { 02798 ast_variables_destroy(var); 02799 } 02800 } 02801 02802 if (q->dead) { 02803 /* It's dead and nobody is in it, so kill it */ 02804 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container"); 02805 } 02806 /* unref the explicit ref earlier in the function */ 02807 queue_t_unref(q, "Expire copied reference"); 02808 }
static int load_module | ( | void | ) | [static] |
Definition at line 8313 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(), device_state_sub, devicestate_tps, 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().
08314 { 08315 int res; 08316 struct ast_context *con; 08317 struct ast_flags mask = {AST_FLAGS_ALL, }; 08318 08319 queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb); 08320 08321 use_weight = 0; 08322 08323 if (reload_handler(0, &mask, NULL)) 08324 return AST_MODULE_LOAD_DECLINE; 08325 08326 con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue"); 08327 if (!con) 08328 ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n"); 08329 else 08330 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue"); 08331 08332 if (queue_persistent_members) 08333 reload_queue_members(); 08334 08335 ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers)); 08336 08337 ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue)); 08338 res = ast_register_application_xml(app, queue_exec); 08339 res |= ast_register_application_xml(app_aqm, aqm_exec); 08340 res |= ast_register_application_xml(app_rqm, rqm_exec); 08341 res |= ast_register_application_xml(app_pqm, pqm_exec); 08342 res |= ast_register_application_xml(app_upqm, upqm_exec); 08343 res |= ast_register_application_xml(app_ql, ql_exec); 08344 res |= ast_manager_register_xml("Queues", 0, manager_queues_show); 08345 res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status); 08346 res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary); 08347 res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member); 08348 res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member); 08349 res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member); 08350 res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom); 08351 res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty); 08352 res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show); 08353 res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload); 08354 res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset); 08355 res |= ast_custom_function_register(&queuevar_function); 08356 res |= ast_custom_function_register(&queueexists_function); 08357 res |= ast_custom_function_register(&queuemembercount_function); 08358 res |= ast_custom_function_register(&queuemembercount_dep); 08359 res |= ast_custom_function_register(&queuememberlist_function); 08360 res |= ast_custom_function_register(&queuewaitingcount_function); 08361 res |= ast_custom_function_register(&queuememberpenalty_function); 08362 08363 if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) { 08364 ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n"); 08365 } 08366 08367 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */ 08368 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) { 08369 res = -1; 08370 } 08371 08372 ast_extension_state_add(NULL, NULL, extension_state_cb, NULL); 08373 08374 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL); 08375 08376 return res ? AST_MODULE_LOAD_DECLINE : 0; 08377 }
static struct call_queue* load_realtime_queue | ( | const char * | queuename | ) | [static] |
Definition at line 2323 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(), join_queue(), queue_function_exists(), queue_function_qac(), queue_function_qac_dep(), queues_data_provider_get(), and reload_queue_members().
02324 { 02325 struct ast_variable *queue_vars; 02326 struct ast_config *member_config = NULL; 02327 struct call_queue *q = NULL, tmpq = { 02328 .name = queuename, 02329 }; 02330 int prev_weight = 0; 02331 02332 /* Find the queue in the in-core list first. */ 02333 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first"); 02334 02335 if (!q || q->realtime) { 02336 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all 02337 queue operations while waiting for the DB. 02338 02339 This will be two separate database transactions, so we might 02340 see queue parameters as they were before another process 02341 changed the queue and member list as it was after the change. 02342 Thus we might see an empty member list when a queue is 02343 deleted. In practise, this is unlikely to cause a problem. */ 02344 02345 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL); 02346 if (queue_vars) { 02347 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL); 02348 if (!member_config) { 02349 ast_debug(1, "No queue_members defined in config extconfig.conf\n"); 02350 member_config = ast_config_new(); 02351 } 02352 } 02353 if (q) { 02354 prev_weight = q->weight ? 1 : 0; 02355 queue_t_unref(q, "Need to find realtime queue"); 02356 } 02357 02358 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 02359 ast_config_destroy(member_config); 02360 ast_variables_destroy(queue_vars); 02361 02362 /* update the use_weight value if the queue's has gained or lost a weight */ 02363 if (q) { 02364 if (!q->weight && prev_weight) { 02365 ast_atomic_fetchadd_int(&use_weight, -1); 02366 } 02367 if (q->weight && !prev_weight) { 02368 ast_atomic_fetchadd_int(&use_weight, +1); 02369 } 02370 } 02371 /* Other cases will end up with the proper value for use_weight */ 02372 } else { 02373 update_realtime_members(q); 02374 } 02375 return q; 02376 }
static int manager_add_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7284 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().
07285 { 07286 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; 07287 int paused, penalty = 0; 07288 07289 queuename = astman_get_header(m, "Queue"); 07290 interface = astman_get_header(m, "Interface"); 07291 penalty_s = astman_get_header(m, "Penalty"); 07292 paused_s = astman_get_header(m, "Paused"); 07293 membername = astman_get_header(m, "MemberName"); 07294 state_interface = astman_get_header(m, "StateInterface"); 07295 07296 if (ast_strlen_zero(queuename)) { 07297 astman_send_error(s, m, "'Queue' not specified."); 07298 return 0; 07299 } 07300 07301 if (ast_strlen_zero(interface)) { 07302 astman_send_error(s, m, "'Interface' not specified."); 07303 return 0; 07304 } 07305 07306 if (ast_strlen_zero(penalty_s)) 07307 penalty = 0; 07308 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) 07309 penalty = 0; 07310 07311 if (ast_strlen_zero(paused_s)) 07312 paused = 0; 07313 else 07314 paused = abs(ast_true(paused_s)); 07315 07316 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { 07317 case RES_OKAY: 07318 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); 07319 astman_send_ack(s, m, "Added interface to queue"); 07320 break; 07321 case RES_EXISTS: 07322 astman_send_error(s, m, "Unable to add interface: Already there"); 07323 break; 07324 case RES_NOSUCHQUEUE: 07325 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 07326 break; 07327 case RES_OUTOFMEMORY: 07328 astman_send_error(s, m, "Out of memory"); 07329 break; 07330 } 07331 07332 return 0; 07333 }
static int manager_pause_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7369 of file app_queue.c.
References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), and set_member_paused().
Referenced by load_module().
07370 { 07371 const char *queuename, *interface, *paused_s, *reason; 07372 int paused; 07373 07374 interface = astman_get_header(m, "Interface"); 07375 paused_s = astman_get_header(m, "Paused"); 07376 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 07377 reason = astman_get_header(m, "Reason"); /* Optional - Only used for logging purposes */ 07378 07379 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 07380 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 07381 return 0; 07382 } 07383 07384 paused = abs(ast_true(paused_s)); 07385 07386 if (set_member_paused(queuename, interface, reason, paused)) 07387 astman_send_error(s, m, "Interface not found"); 07388 else 07389 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 07390 return 0; 07391 }
static int manager_queue_log_custom | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7393 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and S_OR.
Referenced by load_module().
07394 { 07395 const char *queuename, *event, *message, *interface, *uniqueid; 07396 07397 queuename = astman_get_header(m, "Queue"); 07398 uniqueid = astman_get_header(m, "UniqueId"); 07399 interface = astman_get_header(m, "Interface"); 07400 event = astman_get_header(m, "Event"); 07401 message = astman_get_header(m, "Message"); 07402 07403 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) { 07404 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters."); 07405 return 0; 07406 } 07407 07408 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message); 07409 astman_send_ack(s, m, "Event added successfully"); 07410 07411 return 0; 07412 }
static int manager_queue_member_penalty | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7492 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().
07493 { 07494 const char *queuename, *interface, *penalty_s; 07495 int penalty; 07496 07497 interface = astman_get_header(m, "Interface"); 07498 penalty_s = astman_get_header(m, "Penalty"); 07499 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */ 07500 queuename = astman_get_header(m, "Queue"); 07501 07502 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) { 07503 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters."); 07504 return 0; 07505 } 07506 07507 penalty = atoi(penalty_s); 07508 07509 if (set_member_penalty((char *)queuename, (char *)interface, penalty)) 07510 astman_send_error(s, m, "Invalid interface, queuename or penalty"); 07511 else 07512 astman_send_ack(s, m, "Interface penalty set successfully"); 07513 07514 return 0; 07515 }
static int manager_queue_reload | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7414 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().
07415 { 07416 struct ast_flags mask = {0,}; 07417 const char *queuename = NULL; 07418 int header_found = 0; 07419 07420 queuename = astman_get_header(m, "Queue"); 07421 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) { 07422 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER); 07423 header_found = 1; 07424 } 07425 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) { 07426 ast_set_flag(&mask, QUEUE_RELOAD_RULES); 07427 header_found = 1; 07428 } 07429 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) { 07430 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); 07431 header_found = 1; 07432 } 07433 07434 if (!header_found) { 07435 ast_set_flag(&mask, AST_FLAGS_ALL); 07436 } 07437 07438 if (!reload_handler(1, &mask, queuename)) { 07439 astman_send_ack(s, m, "Queue reloaded successfully"); 07440 } else { 07441 astman_send_error(s, m, "Error encountered while reloading queue"); 07442 } 07443 return 0; 07444 }
static int manager_queue_reset | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7446 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().
07447 { 07448 const char *queuename = NULL; 07449 struct ast_flags mask = {QUEUE_RESET_STATS,}; 07450 07451 queuename = astman_get_header(m, "Queue"); 07452 07453 if (!reload_handler(1, &mask, queuename)) { 07454 astman_send_ack(s, m, "Queue stats reset successfully"); 07455 } else { 07456 astman_send_error(s, m, "Error encountered while resetting queue stats"); 07457 } 07458 return 0; 07459 }
static int manager_queue_rule_show | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7073 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), penalty_rule::list, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, RESULT_SUCCESS, rule_list::rules, and penalty_rule::time.
Referenced by load_module().
07074 { 07075 const char *rule = astman_get_header(m, "Rule"); 07076 const char *id = astman_get_header(m, "ActionID"); 07077 struct rule_list *rl_iter; 07078 struct penalty_rule *pr_iter; 07079 07080 astman_append(s, "Response: Success\r\n"); 07081 if (!ast_strlen_zero(id)) { 07082 astman_append(s, "ActionID: %s\r\n", id); 07083 } 07084 07085 AST_LIST_LOCK(&rule_lists); 07086 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 07087 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) { 07088 astman_append(s, "RuleList: %s\r\n", rl_iter->name); 07089 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 07090 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 ); 07091 } 07092 if (!ast_strlen_zero(rule)) 07093 break; 07094 } 07095 } 07096 AST_LIST_UNLOCK(&rule_lists); 07097 07098 /* 07099 * Two blank lines instead of one because the Response and 07100 * ActionID headers used to not be present. 07101 */ 07102 astman_append(s, "\r\n\r\n"); 07103 07104 return RESULT_SUCCESS; 07105 }
static int manager_queues_show | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7063 of file app_queue.c.
References __queues_show(), astman_append(), and RESULT_SUCCESS.
Referenced by load_module().
07064 { 07065 static const char * const a[] = { "queue", "show" }; 07066 07067 __queues_show(s, -1, 2, a); 07068 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 07069 07070 return RESULT_SUCCESS; 07071 }
static int manager_queues_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Queue status info via AMI.
Definition at line 7183 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), ast_channel::caller, member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, ast_channel::connected, call_queue::count, member::dynamic, call_queue::head, call_queue::holdtime, ast_party_connected_line::id, ast_party_caller::id, int2strat(), member::interface, member::lastcall, call_queue::maxlen, member::membername, call_queue::members, ast_party_id::name, ast_channel::name, call_queue::name, queue_ent::next, ast_party_id::number, member::paused, member::penalty, queue_t_unref, queues, RESULT_SUCCESS, S_COR, call_queue::servicelevel, queue_ent::start, member::status, ast_party_name::str, ast_party_number::str, call_queue::strategy, call_queue::talktime, ast_channel::uniqueid, ast_party_name::valid, ast_party_number::valid, and call_queue::weight.
Referenced by load_module().
07184 { 07185 time_t now; 07186 int pos; 07187 const char *id = astman_get_header(m,"ActionID"); 07188 const char *queuefilter = astman_get_header(m,"Queue"); 07189 const char *memberfilter = astman_get_header(m,"Member"); 07190 char idText[256] = ""; 07191 struct call_queue *q; 07192 struct queue_ent *qe; 07193 float sl = 0; 07194 struct member *mem; 07195 struct ao2_iterator queue_iter; 07196 struct ao2_iterator mem_iter; 07197 07198 astman_send_ack(s, m, "Queue status will follow"); 07199 time(&now); 07200 if (!ast_strlen_zero(id)) 07201 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 07202 07203 queue_iter = ao2_iterator_init(queues, 0); 07204 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07205 ao2_lock(q); 07206 07207 /* List queue properties */ 07208 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 07209 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 07210 astman_append(s, "Event: QueueParams\r\n" 07211 "Queue: %s\r\n" 07212 "Max: %d\r\n" 07213 "Strategy: %s\r\n" 07214 "Calls: %d\r\n" 07215 "Holdtime: %d\r\n" 07216 "TalkTime: %d\r\n" 07217 "Completed: %d\r\n" 07218 "Abandoned: %d\r\n" 07219 "ServiceLevel: %d\r\n" 07220 "ServicelevelPerf: %2.1f\r\n" 07221 "Weight: %d\r\n" 07222 "%s" 07223 "\r\n", 07224 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, 07225 q->callsabandoned, q->servicelevel, sl, q->weight, idText); 07226 /* List Queue Members */ 07227 mem_iter = ao2_iterator_init(q->members, 0); 07228 while ((mem = ao2_iterator_next(&mem_iter))) { 07229 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) { 07230 astman_append(s, "Event: QueueMember\r\n" 07231 "Queue: %s\r\n" 07232 "Name: %s\r\n" 07233 "Location: %s\r\n" 07234 "Membership: %s\r\n" 07235 "Penalty: %d\r\n" 07236 "CallsTaken: %d\r\n" 07237 "LastCall: %d\r\n" 07238 "Status: %d\r\n" 07239 "Paused: %d\r\n" 07240 "%s" 07241 "\r\n", 07242 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static", 07243 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 07244 } 07245 ao2_ref(mem, -1); 07246 } 07247 ao2_iterator_destroy(&mem_iter); 07248 /* List Queue Entries */ 07249 pos = 1; 07250 for (qe = q->head; qe; qe = qe->next) { 07251 astman_append(s, "Event: QueueEntry\r\n" 07252 "Queue: %s\r\n" 07253 "Position: %d\r\n" 07254 "Channel: %s\r\n" 07255 "Uniqueid: %s\r\n" 07256 "CallerIDNum: %s\r\n" 07257 "CallerIDName: %s\r\n" 07258 "ConnectedLineNum: %s\r\n" 07259 "ConnectedLineName: %s\r\n" 07260 "Wait: %ld\r\n" 07261 "%s" 07262 "\r\n", 07263 q->name, pos++, qe->chan->name, qe->chan->uniqueid, 07264 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"), 07265 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 07266 S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"), 07267 S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), 07268 (long) (now - qe->start), idText); 07269 } 07270 } 07271 ao2_unlock(q); 07272 queue_t_unref(q, "Done with iterator"); 07273 } 07274 ao2_iterator_destroy(&queue_iter); 07275 07276 astman_append(s, 07277 "Event: QueueStatusComplete\r\n" 07278 "%s" 07279 "\r\n",idText); 07280 07281 return RESULT_SUCCESS; 07282 }
static int manager_queues_summary | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Summary of queue info via the AMI.
Definition at line 7108 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().
07109 { 07110 time_t now; 07111 int qmemcount = 0; 07112 int qmemavail = 0; 07113 int qchancount = 0; 07114 int qlongestholdtime = 0; 07115 const char *id = astman_get_header(m, "ActionID"); 07116 const char *queuefilter = astman_get_header(m, "Queue"); 07117 char idText[256] = ""; 07118 struct call_queue *q; 07119 struct queue_ent *qe; 07120 struct member *mem; 07121 struct ao2_iterator queue_iter; 07122 struct ao2_iterator mem_iter; 07123 07124 astman_send_ack(s, m, "Queue summary will follow"); 07125 time(&now); 07126 if (!ast_strlen_zero(id)) 07127 snprintf(idText, 256, "ActionID: %s\r\n", id); 07128 queue_iter = ao2_iterator_init(queues, 0); 07129 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 07130 ao2_lock(q); 07131 07132 /* List queue properties */ 07133 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 07134 /* Reset the necessary local variables if no queuefilter is set*/ 07135 qmemcount = 0; 07136 qmemavail = 0; 07137 qchancount = 0; 07138 qlongestholdtime = 0; 07139 07140 /* List Queue Members */ 07141 mem_iter = ao2_iterator_init(q->members, 0); 07142 while ((mem = ao2_iterator_next(&mem_iter))) { 07143 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) { 07144 ++qmemcount; 07145 if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) { 07146 ++qmemavail; 07147 } 07148 } 07149 ao2_ref(mem, -1); 07150 } 07151 ao2_iterator_destroy(&mem_iter); 07152 for (qe = q->head; qe; qe = qe->next) { 07153 if ((now - qe->start) > qlongestholdtime) { 07154 qlongestholdtime = now - qe->start; 07155 } 07156 ++qchancount; 07157 } 07158 astman_append(s, "Event: QueueSummary\r\n" 07159 "Queue: %s\r\n" 07160 "LoggedIn: %d\r\n" 07161 "Available: %d\r\n" 07162 "Callers: %d\r\n" 07163 "HoldTime: %d\r\n" 07164 "TalkTime: %d\r\n" 07165 "LongestHoldTime: %d\r\n" 07166 "%s" 07167 "\r\n", 07168 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText); 07169 } 07170 ao2_unlock(q); 07171 queue_t_unref(q, "Done with iterator"); 07172 } 07173 ao2_iterator_destroy(&queue_iter); 07174 astman_append(s, 07175 "Event: QueueSummaryComplete\r\n" 07176 "%s" 07177 "\r\n", idText); 07178 07179 return RESULT_SUCCESS; 07180 }
static int manager_remove_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 7335 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and RES_OUTOFMEMORY.
Referenced by load_module().
07336 { 07337 const char *queuename, *interface; 07338 07339 queuename = astman_get_header(m, "Queue"); 07340 interface = astman_get_header(m, "Interface"); 07341 07342 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 07343 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 07344 return 0; 07345 } 07346 07347 switch (remove_from_queue(queuename, interface)) { 07348 case RES_OKAY: 07349 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 07350 astman_send_ack(s, m, "Removed interface from queue"); 07351 break; 07352 case RES_EXISTS: 07353 astman_send_error(s, m, "Unable to remove interface: Not there"); 07354 break; 07355 case RES_NOSUCHQUEUE: 07356 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 07357 break; 07358 case RES_OUTOFMEMORY: 07359 astman_send_error(s, m, "Out of memory"); 07360 break; 07361 case RES_NOT_DYNAMIC: 07362 astman_send_error(s, m, "Member not dynamic"); 07363 break; 07364 } 07365 07366 return 0; 07367 }
static int mark_dead_and_unfound | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6729 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().
06730 { 06731 struct call_queue *q = obj; 06732 char *queuename = arg; 06733 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) { 06734 q->dead = 1; 06735 q->found = 0; 06736 } 06737 return 0; 06738 }
static int mark_member_dead | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 6602 of file app_queue.c.
References member::delme, and member::dynamic.
Referenced by reload_single_queue().
06603 { 06604 struct member *member = obj; 06605 if (!member->dynamic) { 06606 member->delme = 1; 06607 } 06608 return 0; 06609 }
static int member_cmp_fn | ( | void * | obj1, | |
void * | obj2, | |||
int | flags | |||
) | [static] |
Definition at line 1649 of file app_queue.c.
References CMP_MATCH, CMP_STOP, and member::interface.
Referenced by init_queue().
01650 { 01651 struct member *mem1 = obj1, *mem2 = obj2; 01652 return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP; 01653 }
static int member_hash_fn | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 1637 of file app_queue.c.
References compress_char(), and member::interface.
Referenced by init_queue().
01638 { 01639 const struct member *mem = obj; 01640 const char *chname = strchr(mem->interface, '/'); 01641 int ret = 0, i; 01642 if (!chname) 01643 chname = mem->interface; 01644 for (i = 0; i < 5 && chname[i]; i++) 01645 ret += compress_char(chname[i]) << (i * 6); 01646 return ret; 01647 }
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 2856 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, call_queue::autofill, call_queue::members, member::paused, QUEUE_STRATEGY_RINGALL, call_queue::ringinuse, member::status, and call_queue::strategy.
Referenced by compare_weight(), and is_our_turn().
02857 { 02858 struct member *mem; 02859 int avl = 0; 02860 struct ao2_iterator mem_iter; 02861 02862 mem_iter = ao2_iterator_init(q->members, 0); 02863 while ((mem = ao2_iterator_next(&mem_iter))) { 02864 switch (mem->status) { 02865 case AST_DEVICE_INUSE: 02866 if (!q->ringinuse) 02867 break; 02868 /* else fall through */ 02869 case AST_DEVICE_NOT_INUSE: 02870 case AST_DEVICE_UNKNOWN: 02871 if (!mem->paused) { 02872 avl++; 02873 } 02874 break; 02875 } 02876 ao2_ref(mem, -1); 02877 02878 /* If autofill is not enabled or if the queue's strategy is ringall, then 02879 * we really don't care about the number of available members so much as we 02880 * do that there is at least one available. 02881 * 02882 * In fact, we purposely will return from this function stating that only 02883 * one member is available if either of those conditions hold. That way, 02884 * functions which determine what action to take based on the number of available 02885 * members will operate properly. The reasoning is that even if multiple 02886 * members are available, only the head caller can actually be serviced. 02887 */ 02888 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) { 02889 break; 02890 } 02891 } 02892 ao2_iterator_destroy(&mem_iter); 02893 02894 return avl; 02895 }
static void parse_empty_options | ( | const char * | value, | |
enum empty_conditions * | empty, | |||
int | joinempty | |||
) | [static] |
Definition at line 1834 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().
01835 { 01836 char *value_copy = ast_strdupa(value); 01837 char *option = NULL; 01838 while ((option = strsep(&value_copy, ","))) { 01839 if (!strcasecmp(option, "paused")) { 01840 *empty |= QUEUE_EMPTY_PAUSED; 01841 } else if (!strcasecmp(option, "penalty")) { 01842 *empty |= QUEUE_EMPTY_PENALTY; 01843 } else if (!strcasecmp(option, "inuse")) { 01844 *empty |= QUEUE_EMPTY_INUSE; 01845 } else if (!strcasecmp(option, "ringing")) { 01846 *empty |= QUEUE_EMPTY_RINGING; 01847 } else if (!strcasecmp(option, "invalid")) { 01848 *empty |= QUEUE_EMPTY_INVALID; 01849 } else if (!strcasecmp(option, "wrapup")) { 01850 *empty |= QUEUE_EMPTY_WRAPUP; 01851 } else if (!strcasecmp(option, "unavailable")) { 01852 *empty |= QUEUE_EMPTY_UNAVAILABLE; 01853 } else if (!strcasecmp(option, "unknown")) { 01854 *empty |= QUEUE_EMPTY_UNKNOWN; 01855 } else if (!strcasecmp(option, "loose")) { 01856 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID); 01857 } else if (!strcasecmp(option, "strict")) { 01858 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE); 01859 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) { 01860 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED); 01861 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) { 01862 *empty = 0; 01863 } else { 01864 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty"); 01865 } 01866 } 01867 }
static int play_file | ( | struct ast_channel * | chan, | |
const char * | filename | |||
) | [static] |
Definition at line 2526 of file app_queue.c.
References AST_DIGIT_ANY, ast_fileexists(), ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_waitstream(), queue_ent::chan, and ast_channel::language.
Referenced by say_periodic_announcement(), and say_position().
02527 { 02528 int res; 02529 02530 if (ast_strlen_zero(filename)) { 02531 return 0; 02532 } 02533 02534 if (!ast_fileexists(filename, NULL, chan->language)) { 02535 return 0; 02536 } 02537 02538 ast_stopstream(chan); 02539 02540 res = ast_streamfile(chan, filename, chan->language); 02541 if (!res) 02542 res = ast_waitstream(chan, AST_DIGIT_ANY); 02543 02544 ast_stopstream(chan); 02545 02546 return res; 02547 }
static int pqm_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
PauseQueueMember application.
Definition at line 5522 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().
05523 { 05524 char *parse; 05525 AST_DECLARE_APP_ARGS(args, 05526 AST_APP_ARG(queuename); 05527 AST_APP_ARG(interface); 05528 AST_APP_ARG(options); 05529 AST_APP_ARG(reason); 05530 ); 05531 05532 if (ast_strlen_zero(data)) { 05533 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n"); 05534 return -1; 05535 } 05536 05537 parse = ast_strdupa(data); 05538 05539 AST_STANDARD_APP_ARGS(args, parse); 05540 05541 if (ast_strlen_zero(args.interface)) { 05542 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 05543 return -1; 05544 } 05545 05546 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) { 05547 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 05548 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 05549 return 0; 05550 } 05551 05552 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 05553 05554 return 0; 05555 }
static int ql_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
QueueLog application.
Definition at line 5714 of file app_queue.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, and parse().
Referenced by load_module().
05715 { 05716 char *parse; 05717 05718 AST_DECLARE_APP_ARGS(args, 05719 AST_APP_ARG(queuename); 05720 AST_APP_ARG(uniqueid); 05721 AST_APP_ARG(membername); 05722 AST_APP_ARG(event); 05723 AST_APP_ARG(params); 05724 ); 05725 05726 if (ast_strlen_zero(data)) { 05727 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n"); 05728 return -1; 05729 } 05730 05731 parse = ast_strdupa(data); 05732 05733 AST_STANDARD_APP_ARGS(args, parse); 05734 05735 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 05736 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 05737 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n"); 05738 return -1; 05739 } 05740 05741 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 05742 "%s", args.params ? args.params : ""); 05743 05744 return 0; 05745 }
static int queue_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1256 of file app_queue.c.
References CMP_MATCH, CMP_STOP, and call_queue::name.
Referenced by load_module().
01257 { 01258 struct call_queue *q = obj, *q2 = arg; 01259 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0; 01260 }
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 5788 of file app_queue.c.
References call_queue::announcefrequency, ao2_container_count(), args, AST_APP_ARG, ast_channel_lock, ast_channel_unlock, AST_CONTROL_RINGING, ast_debug, AST_DECLARE_APP_ARGS, ast_indicate(), AST_LIST_FIRST, ast_log(), ast_moh_start(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::caller, queue_ent::chan, copy_rules(), queue_ent::expire, get_member_status(), 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, call_queue::leavewhenempty, LOG_WARNING, queue_ent::max_penalty, call_queue::members, queue_ent::min_penalty, queue_ent::moh, call_queue::name, ast_channel::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_LEAVEEMPTY, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), queue_ent::ring_when_ringing, S_COR, S_OR, say_periodic_announcement(), say_position(), set_queue_result(), queue_ent::start, status, stop, ast_party_number::str, penalty_rule::time, try_calling(), ast_channel::uniqueid, 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().
05789 { 05790 int res=-1; 05791 int ringing=0; 05792 const char *user_priority; 05793 const char *max_penalty_str; 05794 const char *min_penalty_str; 05795 int prio; 05796 int qcontinue = 0; 05797 int max_penalty, min_penalty; 05798 enum queue_result reason = QUEUE_UNKNOWN; 05799 /* whether to exit Queue application after the timeout hits */ 05800 int tries = 0; 05801 int noption = 0; 05802 char *parse; 05803 int makeannouncement = 0; 05804 int position = 0; 05805 AST_DECLARE_APP_ARGS(args, 05806 AST_APP_ARG(queuename); 05807 AST_APP_ARG(options); 05808 AST_APP_ARG(url); 05809 AST_APP_ARG(announceoverride); 05810 AST_APP_ARG(queuetimeoutstr); 05811 AST_APP_ARG(agi); 05812 AST_APP_ARG(macro); 05813 AST_APP_ARG(gosub); 05814 AST_APP_ARG(rule); 05815 AST_APP_ARG(position); 05816 ); 05817 /* Our queue entry */ 05818 struct queue_ent qe = { 0 }; 05819 05820 if (ast_strlen_zero(data)) { 05821 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n"); 05822 return -1; 05823 } 05824 05825 parse = ast_strdupa(data); 05826 AST_STANDARD_APP_ARGS(args, parse); 05827 05828 /* Setup our queue entry */ 05829 qe.start = time(NULL); 05830 05831 /* set the expire time based on the supplied timeout; */ 05832 if (!ast_strlen_zero(args.queuetimeoutstr)) 05833 qe.expire = qe.start + atoi(args.queuetimeoutstr); 05834 else 05835 qe.expire = 0; 05836 05837 /* Get the priority from the variable ${QUEUE_PRIO} */ 05838 ast_channel_lock(chan); 05839 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 05840 if (user_priority) { 05841 if (sscanf(user_priority, "%30d", &prio) == 1) { 05842 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio); 05843 } else { 05844 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 05845 user_priority, chan->name); 05846 prio = 0; 05847 } 05848 } else { 05849 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n"); 05850 prio = 0; 05851 } 05852 05853 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 05854 05855 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 05856 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) { 05857 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty); 05858 } else { 05859 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 05860 max_penalty_str, chan->name); 05861 max_penalty = 0; 05862 } 05863 } else { 05864 max_penalty = 0; 05865 } 05866 05867 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) { 05868 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) { 05869 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty); 05870 } else { 05871 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n", 05872 min_penalty_str, chan->name); 05873 min_penalty = 0; 05874 } 05875 } else { 05876 min_penalty = 0; 05877 } 05878 ast_channel_unlock(chan); 05879 05880 if (args.options && (strchr(args.options, 'r'))) 05881 ringing = 1; 05882 05883 if (ringing != 1 && args.options && (strchr(args.options, 'R'))) { 05884 qe.ring_when_ringing = 1; 05885 } 05886 05887 if (args.options && (strchr(args.options, 'c'))) 05888 qcontinue = 1; 05889 05890 if (args.position) { 05891 position = atoi(args.position); 05892 if (position < 0) { 05893 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename); 05894 position = 0; 05895 } 05896 } 05897 05898 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 05899 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 05900 05901 qe.chan = chan; 05902 qe.prio = prio; 05903 qe.max_penalty = max_penalty; 05904 qe.min_penalty = min_penalty; 05905 qe.last_pos_said = 0; 05906 qe.last_pos = 0; 05907 qe.last_periodic_announce_time = time(NULL); 05908 qe.last_periodic_announce_sound = 0; 05909 qe.valid_digits = 0; 05910 if (join_queue(args.queuename, &qe, &reason, position)) { 05911 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 05912 set_queue_result(chan, reason); 05913 return 0; 05914 } 05915 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d", 05916 S_OR(args.url, ""), 05917 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""), 05918 qe.opos); 05919 copy_rules(&qe, args.rule); 05920 qe.pr = AST_LIST_FIRST(&qe.qe_rules); 05921 check_turns: 05922 if (ringing) { 05923 ast_indicate(chan, AST_CONTROL_RINGING); 05924 } else { 05925 ast_moh_start(chan, qe.moh, NULL); 05926 } 05927 05928 /* This is the wait loop for callers 2 through maxlen */ 05929 res = wait_our_turn(&qe, ringing, &reason); 05930 if (res) { 05931 goto stop; 05932 } 05933 05934 makeannouncement = 0; 05935 05936 for (;;) { 05937 /* This is the wait loop for the head caller*/ 05938 /* To exit, they may get their call answered; */ 05939 /* they may dial a digit from the queue context; */ 05940 /* or, they may timeout. */ 05941 05942 /* Leave if we have exceeded our queuetimeout */ 05943 if (qe.expire && (time(NULL) >= qe.expire)) { 05944 record_abandoned(&qe); 05945 reason = QUEUE_TIMEOUT; 05946 res = 0; 05947 ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 05948 qe.pos, qe.opos, (long) time(NULL) - qe.start); 05949 break; 05950 } 05951 05952 if (makeannouncement) { 05953 /* Make a position announcement, if enabled */ 05954 if (qe.parent->announcefrequency) 05955 if ((res = say_position(&qe,ringing))) 05956 goto stop; 05957 } 05958 makeannouncement = 1; 05959 05960 /* Make a periodic announcement, if enabled */ 05961 if (qe.parent->periodicannouncefrequency) 05962 if ((res = say_periodic_announcement(&qe,ringing))) 05963 goto stop; 05964 05965 /* Leave if we have exceeded our queuetimeout */ 05966 if (qe.expire && (time(NULL) >= qe.expire)) { 05967 record_abandoned(&qe); 05968 reason = QUEUE_TIMEOUT; 05969 res = 0; 05970 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 05971 break; 05972 } 05973 05974 /* see if we need to move to the next penalty level for this queue */ 05975 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) { 05976 update_qe_rule(&qe); 05977 } 05978 05979 /* Try calling all queue members for 'timeout' seconds */ 05980 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing); 05981 if (res) { 05982 goto stop; 05983 } 05984 05985 if (qe.parent->leavewhenempty) { 05986 int status = 0; 05987 if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty))) { 05988 record_abandoned(&qe); 05989 reason = QUEUE_LEAVEEMPTY; 05990 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 05991 res = 0; 05992 break; 05993 } 05994 } 05995 05996 /* exit after 'timeout' cycle if 'n' option enabled */ 05997 if (noption && tries >= ao2_container_count(qe.parent->members)) { 05998 ast_verb(3, "Exiting on time-out cycle\n"); 05999 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 06000 record_abandoned(&qe); 06001 reason = QUEUE_TIMEOUT; 06002 res = 0; 06003 break; 06004 } 06005 06006 06007 /* Leave if we have exceeded our queuetimeout */ 06008 if (qe.expire && (time(NULL) >= qe.expire)) { 06009 record_abandoned(&qe); 06010 reason = QUEUE_TIMEOUT; 06011 res = 0; 06012 ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start); 06013 break; 06014 } 06015 06016 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 06017 update_realtime_members(qe.parent); 06018 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 06019 res = wait_a_bit(&qe); 06020 if (res) 06021 goto stop; 06022 06023 /* Since this is a priority queue and 06024 * it is not sure that we are still at the head 06025 * of the queue, go and check for our turn again. 06026 */ 06027 if (!is_our_turn(&qe)) { 06028 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name); 06029 goto check_turns; 06030 } 06031 } 06032 06033 stop: 06034 if (res) { 06035 if (res < 0) { 06036 if (!qe.handled) { 06037 record_abandoned(&qe); 06038 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 06039 "%d|%d|%ld", qe.pos, qe.opos, 06040 (long) time(NULL) - qe.start); 06041 res = -1; 06042 } else if (qcontinue) { 06043 reason = QUEUE_CONTINUE; 06044 res = 0; 06045 } 06046 } else if (qe.valid_digits) { 06047 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 06048 "%s|%d", qe.digits, qe.pos); 06049 } 06050 } 06051 06052 /* Don't allow return code > 0 */ 06053 if (res >= 0) { 06054 res = 0; 06055 if (ringing) { 06056 ast_indicate(chan, -1); 06057 } else { 06058 ast_moh_stop(chan); 06059 } 06060 ast_stopstream(chan); 06061 } 06062 06063 set_queue_variables(qe.parent, qe.chan); 06064 06065 leave_queue(&qe); 06066 if (reason != QUEUE_UNKNOWN) 06067 set_queue_result(chan, reason); 06068 06069 if (qe.parent) { 06070 /* every queue_ent is given a reference to it's parent call_queue when it joins the queue. 06071 * This ref must be taken away right before the queue_ent is destroyed. In this case 06072 * the queue_ent is about to be returned on the stack */ 06073 qe.parent = queue_unref(qe.parent); 06074 } 06075 06076 return res; 06077 }
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 6131 of file app_queue.c.
References ast_log(), ast_strlen_zero(), load_realtime_queue(), LOG_ERROR, and queue_t_unref.
06132 { 06133 struct call_queue *q; 06134 06135 buf[0] = '\0'; 06136 06137 if (ast_strlen_zero(data)) { 06138 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06139 return -1; 06140 } 06141 q = load_realtime_queue(data); 06142 snprintf(buf, len, "%d", q != NULL? 1 : 0); 06143 if (q) { 06144 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()"); 06145 } 06146 06147 return 0; 06148 }
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 6350 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.
06351 { 06352 int penalty; 06353 AST_DECLARE_APP_ARGS(args, 06354 AST_APP_ARG(queuename); 06355 AST_APP_ARG(interface); 06356 ); 06357 /* Make sure the returned value on error is NULL. */ 06358 buf[0] = '\0'; 06359 06360 if (ast_strlen_zero(data)) { 06361 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06362 return -1; 06363 } 06364 06365 AST_STANDARD_APP_ARGS(args, data); 06366 06367 if (args.argc < 2) { 06368 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06369 return -1; 06370 } 06371 06372 penalty = get_member_penalty (args.queuename, args.interface); 06373 06374 if (penalty >= 0) /* remember that buf is already '\0' */ 06375 snprintf (buf, len, "%d", penalty); 06376 06377 return 0; 06378 }
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 6381 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().
06382 { 06383 int penalty; 06384 AST_DECLARE_APP_ARGS(args, 06385 AST_APP_ARG(queuename); 06386 AST_APP_ARG(interface); 06387 ); 06388 06389 if (ast_strlen_zero(data)) { 06390 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06391 return -1; 06392 } 06393 06394 AST_STANDARD_APP_ARGS(args, data); 06395 06396 if (args.argc < 2) { 06397 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 06398 return -1; 06399 } 06400 06401 penalty = atoi(value); 06402 06403 if (ast_strlen_zero(args.interface)) { 06404 ast_log (LOG_ERROR, "<interface> parameter can't be null\n"); 06405 return -1; 06406 } 06407 06408 /* if queuename = NULL then penalty will be set for interface in all the queues. */ 06409 if (set_member_penalty(args.queuename, args.interface, penalty)) { 06410 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); 06411 return -1; 06412 } 06413 06414 return 0; 06415 }
static int queue_function_qac | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Get number either busy / free / ready or total members of a specific queue.
number | of members (busy / free / ready / total) | |
-1 | on error |
Definition at line 6155 of file app_queue.c.
References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_log(), ast_strlen_zero(), call_queue::count, member::lastcall, load_realtime_queue(), LOG_ERROR, LOG_WARNING, member::paused, queue_t_unref, and member::status.
06156 { 06157 int count = 0; 06158 struct member *m; 06159 struct ao2_iterator mem_iter; 06160 struct call_queue *q; 06161 char *option; 06162 06163 if (ast_strlen_zero(data)) { 06164 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06165 return -1; 06166 } 06167 06168 if ((option = strchr(data, ','))) 06169 *option++ = '\0'; 06170 else 06171 option = "logged"; 06172 if ((q = load_realtime_queue(data))) { 06173 ao2_lock(q); 06174 if (!strcasecmp(option, "logged")) { 06175 mem_iter = ao2_iterator_init(q->members, 0); 06176 while ((m = ao2_iterator_next(&mem_iter))) { 06177 /* Count the agents who are logged in and presently answering calls */ 06178 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 06179 count++; 06180 } 06181 ao2_ref(m, -1); 06182 } 06183 ao2_iterator_destroy(&mem_iter); 06184 } else if (!strcasecmp(option, "free")) { 06185 mem_iter = ao2_iterator_init(q->members, 0); 06186 while ((m = ao2_iterator_next(&mem_iter))) { 06187 /* Count the agents who are logged in and presently answering calls */ 06188 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) { 06189 count++; 06190 } 06191 ao2_ref(m, -1); 06192 } 06193 ao2_iterator_destroy(&mem_iter); 06194 } else if (!strcasecmp(option, "ready")) { 06195 time_t now; 06196 time(&now); 06197 mem_iter = ao2_iterator_init(q->members, 0); 06198 while ((m = ao2_iterator_next(&mem_iter))) { 06199 /* Count the agents who are logged in, not paused and not wrapping up */ 06200 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) && 06201 !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) { 06202 count++; 06203 } 06204 ao2_ref(m, -1); 06205 } 06206 ao2_iterator_destroy(&mem_iter); 06207 } else /* must be "count" */ 06208 count = ao2_container_count(q->members); 06209 ao2_unlock(q); 06210 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()"); 06211 } else 06212 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06213 06214 snprintf(buf, len, "%d", count); 06215 06216 return 0; 06217 }
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 6224 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, ast_log(), ast_strlen_zero(), call_queue::count, load_realtime_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, queue_t_unref, and member::status.
06225 { 06226 int count = 0; 06227 struct member *m; 06228 struct call_queue *q; 06229 struct ao2_iterator mem_iter; 06230 static int depflag = 1; 06231 06232 if (depflag) { 06233 depflag = 0; 06234 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"); 06235 } 06236 06237 if (ast_strlen_zero(data)) { 06238 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06239 return -1; 06240 } 06241 06242 if ((q = load_realtime_queue(data))) { 06243 ao2_lock(q); 06244 mem_iter = ao2_iterator_init(q->members, 0); 06245 while ((m = ao2_iterator_next(&mem_iter))) { 06246 /* Count the agents who are logged in and presently answering calls */ 06247 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 06248 count++; 06249 } 06250 ao2_ref(m, -1); 06251 } 06252 ao2_iterator_destroy(&mem_iter); 06253 ao2_unlock(q); 06254 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT"); 06255 } else 06256 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06257 06258 snprintf(buf, len, "%d", count); 06259 06260 return 0; 06261 }
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 6300 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.
06301 { 06302 struct call_queue *q, tmpq = { 06303 .name = data, 06304 }; 06305 struct member *m; 06306 06307 /* Ensure an otherwise empty list doesn't return garbage */ 06308 buf[0] = '\0'; 06309 06310 if (ast_strlen_zero(data)) { 06311 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 06312 return -1; 06313 } 06314 06315 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) { 06316 int buflen = 0, count = 0; 06317 struct ao2_iterator mem_iter; 06318 06319 ao2_lock(q); 06320 mem_iter = ao2_iterator_init(q->members, 0); 06321 while ((m = ao2_iterator_next(&mem_iter))) { 06322 /* strcat() is always faster than printf() */ 06323 if (count++) { 06324 strncat(buf + buflen, ",", len - buflen - 1); 06325 buflen++; 06326 } 06327 strncat(buf + buflen, m->interface, len - buflen - 1); 06328 buflen += strlen(m->interface); 06329 /* Safeguard against overflow (negative length) */ 06330 if (buflen >= len - 2) { 06331 ao2_ref(m, -1); 06332 ast_log(LOG_WARNING, "Truncating list\n"); 06333 break; 06334 } 06335 ao2_ref(m, -1); 06336 } 06337 ao2_iterator_destroy(&mem_iter); 06338 ao2_unlock(q); 06339 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()"); 06340 } else 06341 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06342 06343 /* We should already be terminated, but let's make sure. */ 06344 buf[len - 1] = '\0'; 06345 06346 return 0; 06347 }
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 6264 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.
06265 { 06266 int count = 0; 06267 struct call_queue *q, tmpq = { 06268 .name = data, 06269 }; 06270 struct ast_variable *var = NULL; 06271 06272 buf[0] = '\0'; 06273 06274 if (ast_strlen_zero(data)) { 06275 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n"); 06276 return -1; 06277 } 06278 06279 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) { 06280 ao2_lock(q); 06281 count = q->count; 06282 ao2_unlock(q); 06283 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()"); 06284 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) { 06285 /* if the queue is realtime but was not found in memory, this 06286 * means that the queue had been deleted from memory since it was 06287 * "dead." This means it has a 0 waiting count 06288 */ 06289 count = 0; 06290 ast_variables_destroy(var); 06291 } else 06292 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06293 06294 snprintf(buf, len, "%d", count); 06295 06296 return 0; 06297 }
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 6084 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.
06085 { 06086 int res = -1; 06087 struct call_queue *q, tmpq = { 06088 .name = data, 06089 }; 06090 06091 char interfacevar[256] = ""; 06092 float sl = 0; 06093 06094 if (ast_strlen_zero(data)) { 06095 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 06096 return -1; 06097 } 06098 06099 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) { 06100 ao2_lock(q); 06101 if (q->setqueuevar) { 06102 sl = 0; 06103 res = 0; 06104 06105 if (q->callscompleted > 0) { 06106 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 06107 } 06108 06109 snprintf(interfacevar, sizeof(interfacevar), 06110 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 06111 q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 06112 06113 pbx_builtin_setvar_multiple(chan, interfacevar); 06114 } 06115 06116 ao2_unlock(q); 06117 queue_t_unref(q, "Done with QUEUE() function"); 06118 } else { 06119 ast_log(LOG_WARNING, "queue %s was not found\n", data); 06120 } 06121 06122 snprintf(buf, len, "%d", res); 06123 06124 return 0; 06125 }
static int queue_hash_cb | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 1249 of file app_queue.c.
References ast_str_case_hash(), and call_queue::name.
Referenced by load_module().
01250 { 01251 const struct call_queue *q = obj; 01252 01253 return ast_str_case_hash(q->name); 01254 }
static struct call_queue* queue_ref | ( | struct call_queue * | q | ) | [inline, static] |
Definition at line 1274 of file app_queue.c.
References ao2_ref.
Referenced by insert_entry().
01275 { 01276 ao2_ref(q, 1); 01277 return q; 01278 }
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 6508 of file app_queue.c.
References ast_true(), and ast_variable_retrieve().
Referenced by reload_queues().
06509 { 06510 const char *general_val = NULL; 06511 queue_persistent_members = 0; 06512 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 06513 queue_persistent_members = ast_true(general_val); 06514 autofill_default = 0; 06515 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 06516 autofill_default = ast_true(general_val); 06517 montype_default = 0; 06518 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) { 06519 if (!strcasecmp(general_val, "mixmonitor")) 06520 montype_default = 1; 06521 } 06522 update_cdr = 0; 06523 if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr"))) 06524 update_cdr = ast_true(general_val); 06525 shared_lastcall = 0; 06526 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) 06527 shared_lastcall = ast_true(general_val); 06528 }
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 1877 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(), 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, 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 reload_single_queue().
01878 { 01879 if (!strcasecmp(param, "musicclass") || 01880 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 01881 ast_string_field_set(q, moh, val); 01882 } else if (!strcasecmp(param, "announce")) { 01883 ast_string_field_set(q, announce, val); 01884 } else if (!strcasecmp(param, "context")) { 01885 ast_string_field_set(q, context, val); 01886 } else if (!strcasecmp(param, "timeout")) { 01887 q->timeout = atoi(val); 01888 if (q->timeout < 0) 01889 q->timeout = DEFAULT_TIMEOUT; 01890 } else if (!strcasecmp(param, "ringinuse")) { 01891 q->ringinuse = ast_true(val); 01892 } else if (!strcasecmp(param, "setinterfacevar")) { 01893 q->setinterfacevar = ast_true(val); 01894 } else if (!strcasecmp(param, "setqueuevar")) { 01895 q->setqueuevar = ast_true(val); 01896 } else if (!strcasecmp(param, "setqueueentryvar")) { 01897 q->setqueueentryvar = ast_true(val); 01898 } else if (!strcasecmp(param, "monitor-format")) { 01899 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 01900 } else if (!strcasecmp(param, "membermacro")) { 01901 ast_string_field_set(q, membermacro, val); 01902 } else if (!strcasecmp(param, "membergosub")) { 01903 ast_string_field_set(q, membergosub, val); 01904 } else if (!strcasecmp(param, "queue-youarenext")) { 01905 ast_string_field_set(q, sound_next, val); 01906 } else if (!strcasecmp(param, "queue-thereare")) { 01907 ast_string_field_set(q, sound_thereare, val); 01908 } else if (!strcasecmp(param, "queue-callswaiting")) { 01909 ast_string_field_set(q, sound_calls, val); 01910 } else if (!strcasecmp(param, "queue-quantity1")) { 01911 ast_string_field_set(q, queue_quantity1, val); 01912 } else if (!strcasecmp(param, "queue-quantity2")) { 01913 ast_string_field_set(q, queue_quantity2, val); 01914 } else if (!strcasecmp(param, "queue-holdtime")) { 01915 ast_string_field_set(q, sound_holdtime, val); 01916 } else if (!strcasecmp(param, "queue-minutes")) { 01917 ast_string_field_set(q, sound_minutes, val); 01918 } else if (!strcasecmp(param, "queue-minute")) { 01919 ast_string_field_set(q, sound_minute, val); 01920 } else if (!strcasecmp(param, "queue-seconds")) { 01921 ast_string_field_set(q, sound_seconds, val); 01922 } else if (!strcasecmp(param, "queue-thankyou")) { 01923 ast_string_field_set(q, sound_thanks, val); 01924 } else if (!strcasecmp(param, "queue-callerannounce")) { 01925 ast_string_field_set(q, sound_callerannounce, val); 01926 } else if (!strcasecmp(param, "queue-reporthold")) { 01927 ast_string_field_set(q, sound_reporthold, val); 01928 } else if (!strcasecmp(param, "announce-frequency")) { 01929 q->announcefrequency = atoi(val); 01930 } else if (!strcasecmp(param, "min-announce-frequency")) { 01931 q->minannouncefrequency = atoi(val); 01932 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name); 01933 } else if (!strcasecmp(param, "announce-round-seconds")) { 01934 q->roundingseconds = atoi(val); 01935 /* Rounding to any other values just doesn't make sense... */ 01936 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10 01937 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) { 01938 if (linenum >= 0) { 01939 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01940 "using 0 instead for queue '%s' at line %d of queues.conf\n", 01941 val, param, q->name, linenum); 01942 } else { 01943 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01944 "using 0 instead for queue '%s'\n", val, param, q->name); 01945 } 01946 q->roundingseconds=0; 01947 } 01948 } else if (!strcasecmp(param, "announce-holdtime")) { 01949 if (!strcasecmp(val, "once")) 01950 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 01951 else if (ast_true(val)) 01952 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 01953 else 01954 q->announceholdtime = 0; 01955 } else if (!strcasecmp(param, "announce-position")) { 01956 if (!strcasecmp(val, "limit")) 01957 q->announceposition = ANNOUNCEPOSITION_LIMIT; 01958 else if (!strcasecmp(val, "more")) 01959 q->announceposition = ANNOUNCEPOSITION_MORE_THAN; 01960 else if (ast_true(val)) 01961 q->announceposition = ANNOUNCEPOSITION_YES; 01962 else 01963 q->announceposition = ANNOUNCEPOSITION_NO; 01964 } else if (!strcasecmp(param, "announce-position-limit")) { 01965 q->announcepositionlimit = atoi(val); 01966 } else if (!strcasecmp(param, "periodic-announce")) { 01967 if (strchr(val, ',')) { 01968 char *s, *buf = ast_strdupa(val); 01969 unsigned int i = 0; 01970 01971 while ((s = strsep(&buf, ",|"))) { 01972 if (!q->sound_periodicannounce[i]) 01973 q->sound_periodicannounce[i] = ast_str_create(16); 01974 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s); 01975 i++; 01976 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 01977 break; 01978 } 01979 q->numperiodicannounce = i; 01980 } else { 01981 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val); 01982 q->numperiodicannounce = 1; 01983 } 01984 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 01985 q->periodicannouncefrequency = atoi(val); 01986 } else if (!strcasecmp(param, "relative-periodic-announce")) { 01987 q->relativeperiodicannounce = ast_true(val); 01988 } else if (!strcasecmp(param, "random-periodic-announce")) { 01989 q->randomperiodicannounce = ast_true(val); 01990 } else if (!strcasecmp(param, "retry")) { 01991 q->retry = atoi(val); 01992 if (q->retry <= 0) 01993 q->retry = DEFAULT_RETRY; 01994 } else if (!strcasecmp(param, "wrapuptime")) { 01995 q->wrapuptime = atoi(val); 01996 } else if (!strcasecmp(param, "penaltymemberslimit")) { 01997 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) { 01998 q->penaltymemberslimit = 0; 01999 } 02000 } else if (!strcasecmp(param, "autofill")) { 02001 q->autofill = ast_true(val); 02002 } else if (!strcasecmp(param, "monitor-type")) { 02003 if (!strcasecmp(val, "mixmonitor")) 02004 q->montype = 1; 02005 } else if (!strcasecmp(param, "autopause")) { 02006 q->autopause = autopause2int(val); 02007 } else if (!strcasecmp(param, "maxlen")) { 02008 q->maxlen = atoi(val); 02009 if (q->maxlen < 0) 02010 q->maxlen = 0; 02011 } else if (!strcasecmp(param, "servicelevel")) { 02012 q->servicelevel= atoi(val); 02013 } else if (!strcasecmp(param, "strategy")) { 02014 int strategy; 02015 02016 /* We are a static queue and already have set this, no need to do it again */ 02017 if (failunknown) { 02018 return; 02019 } 02020 strategy = strat2int(val); 02021 if (strategy < 0) { 02022 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 02023 val, q->name); 02024 q->strategy = QUEUE_STRATEGY_RINGALL; 02025 } 02026 if (strategy == q->strategy) { 02027 return; 02028 } 02029 if (strategy == QUEUE_STRATEGY_LINEAR) { 02030 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n"); 02031 return; 02032 } 02033 q->strategy = strategy; 02034 } else if (!strcasecmp(param, "joinempty")) { 02035 parse_empty_options(val, &q->joinempty, 1); 02036 } else if (!strcasecmp(param, "leavewhenempty")) { 02037 parse_empty_options(val, &q->leavewhenempty, 0); 02038 } else if (!strcasecmp(param, "eventmemberstatus")) { 02039 q->maskmemberstatus = !ast_true(val); 02040 } else if (!strcasecmp(param, "eventwhencalled")) { 02041 if (!strcasecmp(val, "vars")) { 02042 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 02043 } else { 02044 q->eventwhencalled = ast_true(val) ? 1 : 0; 02045 } 02046 } else if (!strcasecmp(param, "reportholdtime")) { 02047 q->reportholdtime = ast_true(val); 02048 } else if (!strcasecmp(param, "memberdelay")) { 02049 q->memberdelay = atoi(val); 02050 } else if (!strcasecmp(param, "weight")) { 02051 q->weight = atoi(val); 02052 } else if (!strcasecmp(param, "timeoutrestart")) { 02053 q->timeoutrestart = ast_true(val); 02054 } else if (!strcasecmp(param, "defaultrule")) { 02055 ast_string_field_set(q, defaultrule, val); 02056 } else if (!strcasecmp(param, "timeoutpriority")) { 02057 if (!strcasecmp(val, "conf")) { 02058 q->timeoutpriority = TIMEOUT_PRIORITY_CONF; 02059 } else { 02060 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 02061 } 02062 } else if (failunknown) { 02063 if (linenum >= 0) { 02064 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 02065 q->name, param, linenum); 02066 } else { 02067 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 02068 } 02069 } 02070 }
static char* queue_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 7044 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.
07045 { 07046 switch ( cmd ) { 07047 case CLI_INIT: 07048 e->command = "queue show"; 07049 e->usage = 07050 "Usage: queue show\n" 07051 " Provides summary information on a specified queue.\n"; 07052 return NULL; 07053 case CLI_GENERATE: 07054 return complete_queue_show(a->line, a->word, a->pos, a->n); 07055 } 07056 07057 return __queues_show(NULL, a->fd, a->argc, a->argv); 07058 }
static void queue_transfer_destroy | ( | void * | data | ) | [static] |
Definition at line 4158 of file app_queue.c.
References ast_free.
04159 { 04160 struct queue_transfer_ds *qtds = data; 04161 ast_free(qtds); 04162 }
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 4181 of file app_queue.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_log(), ast_queue_log(), queue_transfer_ds::callcompletedinsl, queue_ent::chan, ast_channel::context, ast_channel::exten, LOG_WARNING, queue_transfer_ds::member, member::membername, call_queue::name, queue_ent::opos, queue_ent::parent, queue_transfer_ds::qe, queue_transfer_info, queue_ent::start, queue_transfer_ds::starttime, ast_channel::uniqueid, and update_queue().
04182 { 04183 struct queue_transfer_ds *qtds = data; 04184 struct queue_ent *qe = qtds->qe; 04185 struct member *member = qtds->member; 04186 time_t callstart = qtds->starttime; 04187 int callcompletedinsl = qtds->callcompletedinsl; 04188 struct ast_datastore *datastore; 04189 04190 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 04191 new_chan->exten, new_chan->context, (long) (callstart - qe->start), 04192 (long) (time(NULL) - callstart), qe->opos); 04193 04194 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart)); 04195 04196 /* No need to lock the channels because they are already locked in ast_do_masquerade */ 04197 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) { 04198 ast_channel_datastore_remove(old_chan, datastore); 04199 } else { 04200 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n"); 04201 } 04202 }
static struct call_queue* queue_unref | ( | struct call_queue * | q | ) | [inline, static] |
Definition at line 1280 of file app_queue.c.
References ao2_ref.
Referenced by queues_data_provider_get().
01281 { 01282 ao2_ref(q, -1); 01283 return NULL; 01284 }
static int queues_data_provider_get | ( | const struct ast_data_search * | search, | |
struct ast_data * | data_root | |||
) | [static] |
Definition at line 8205 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, ast_category_browse(), ast_config_destroy(), ast_load_realtime_multientry(), ast_strlen_zero(), load_realtime_queue(), queue_unref(), queues, queues_data_provider_get_helper(), and SENTINEL.
08207 { 08208 struct ao2_iterator i; 08209 struct call_queue *queue, *queue_realtime = NULL; 08210 struct ast_config *cfg; 08211 char *queuename; 08212 08213 /* load realtime queues. */ 08214 cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 08215 if (cfg) { 08216 for (queuename = ast_category_browse(cfg, NULL); 08217 !ast_strlen_zero(queuename); 08218 queuename = ast_category_browse(cfg, queuename)) { 08219 if ((queue = load_realtime_queue(queuename))) { 08220 queue_unref(queue); 08221 } 08222 } 08223 ast_config_destroy(cfg); 08224 } 08225 08226 /* static queues. */ 08227 i = ao2_iterator_init(queues, 0); 08228 while ((queue = ao2_iterator_next(&i))) { 08229 ao2_lock(queue); 08230 if (queue->realtime) { 08231 queue_realtime = load_realtime_queue(queue->name); 08232 if (!queue_realtime) { 08233 ao2_unlock(queue); 08234 queue_unref(queue); 08235 continue; 08236 } 08237 queue_unref(queue_realtime); 08238 } 08239 08240 queues_data_provider_get_helper(search, data_root, queue); 08241 ao2_unlock(queue); 08242 queue_unref(queue); 08243 } 08244 ao2_iterator_destroy(&i); 08245 08246 return 0; 08247 }
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 8099 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().
08101 { 08102 struct ao2_iterator im; 08103 struct member *member; 08104 struct queue_ent *qe; 08105 struct ast_data *data_queue, *data_members = NULL, *enum_node; 08106 struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel; 08107 08108 data_queue = ast_data_add_node(data_root, "queue"); 08109 if (!data_queue) { 08110 return; 08111 } 08112 08113 ast_data_add_structure(call_queue, data_queue, queue); 08114 08115 ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy)); 08116 ast_data_add_int(data_queue, "membercount", ao2_container_count(queue->members)); 08117 08118 /* announce position */ 08119 enum_node = ast_data_add_node(data_queue, "announceposition"); 08120 if (!enum_node) { 08121 return; 08122 } 08123 switch (queue->announceposition) { 08124 case ANNOUNCEPOSITION_LIMIT: 08125 ast_data_add_str(enum_node, "text", "limit"); 08126 break; 08127 case ANNOUNCEPOSITION_MORE_THAN: 08128 ast_data_add_str(enum_node, "text", "more"); 08129 break; 08130 case ANNOUNCEPOSITION_YES: 08131 ast_data_add_str(enum_node, "text", "yes"); 08132 break; 08133 case ANNOUNCEPOSITION_NO: 08134 ast_data_add_str(enum_node, "text", "no"); 08135 break; 08136 default: 08137 ast_data_add_str(enum_node, "text", "unknown"); 08138 break; 08139 } 08140 ast_data_add_int(enum_node, "value", queue->announceposition); 08141 08142 /* add queue members */ 08143 im = ao2_iterator_init(queue->members, 0); 08144 while ((member = ao2_iterator_next(&im))) { 08145 if (!data_members) { 08146 data_members = ast_data_add_node(data_queue, "members"); 08147 if (!data_members) { 08148 ao2_ref(member, -1); 08149 continue; 08150 } 08151 } 08152 08153 data_member = ast_data_add_node(data_members, "member"); 08154 if (!data_member) { 08155 ao2_ref(member, -1); 08156 continue; 08157 } 08158 08159 ast_data_add_structure(member, data_member, member); 08160 08161 ao2_ref(member, -1); 08162 } 08163 ao2_iterator_destroy(&im); 08164 08165 /* include the callers inside the result. */ 08166 if (queue->head) { 08167 for (qe = queue->head; qe; qe = qe->next) { 08168 if (!data_callers) { 08169 data_callers = ast_data_add_node(data_queue, "callers"); 08170 if (!data_callers) { 08171 continue; 08172 } 08173 } 08174 08175 data_caller = ast_data_add_node(data_callers, "caller"); 08176 if (!data_caller) { 08177 continue; 08178 } 08179 08180 ast_data_add_structure(queue_ent, data_caller, qe); 08181 08182 /* add the caller channel. */ 08183 data_caller_channel = ast_data_add_node(data_caller, "channel"); 08184 if (!data_caller_channel) { 08185 continue; 08186 } 08187 08188 ast_channel_data_add_structure(data_caller_channel, qe->chan, 1); 08189 } 08190 } 08191 08192 /* if this queue doesn't match remove the added queue. */ 08193 if (!ast_data_search_match(search, data_queue)) { 08194 ast_data_remove_node(data_root, data_queue); 08195 } 08196 }
static void recalc_holdtime | ( | struct queue_ent * | qe, | |
int | newholdtime | |||
) | [static] |
Definition at line 2732 of file app_queue.c.
References ao2_lock, ao2_unlock, call_queue::holdtime, and queue_ent::parent.
02733 { 02734 int oldvalue; 02735 02736 /* Calculate holdtime using an exponential average */ 02737 /* Thanks to SRT for this contribution */ 02738 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 02739 02740 ao2_lock(qe->parent); 02741 oldvalue = qe->parent->holdtime; 02742 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 02743 ao2_unlock(qe->parent); 02744 }
static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Record that a caller gave up on waiting in queue.
Definition at line 3340 of file app_queue.c.
References ao2_lock, ao2_unlock, 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(), queue_ent::start, and ast_channel::uniqueid.
Referenced by queue_exec().
03341 { 03342 set_queue_variables(qe->parent, qe->chan); 03343 ao2_lock(qe->parent); 03344 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 03345 "Queue: %s\r\n" 03346 "Uniqueid: %s\r\n" 03347 "Position: %d\r\n" 03348 "OriginalPosition: %d\r\n" 03349 "HoldTime: %d\r\n", 03350 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 03351 03352 qe->parent->callsabandoned++; 03353 ao2_unlock(qe->parent); 03354 }
static int reload | ( | void | ) | [static] |
Definition at line 8379 of file app_queue.c.
References AST_FLAGS_ALL, ast_unload_realtime(), QUEUE_RESET_STATS, and reload_handler().
08380 { 08381 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,}; 08382 ast_unload_realtime("queue_members"); 08383 reload_handler(1, &mask, NULL); 08384 return 0; 08385 }
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 6853 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().
06854 { 06855 int res = 0; 06856 06857 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) { 06858 res |= reload_queue_rules(reload); 06859 } 06860 if (ast_test_flag(mask, QUEUE_RESET_STATS)) { 06861 res |= clear_stats(queuename); 06862 } 06863 if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) { 06864 res |= reload_queues(reload, mask, queuename); 06865 } 06866 return res; 06867 }
static void reload_queue_members | ( | void | ) | [static] |
Reload dynamic queue members persisted into the astdb.
Definition at line 5428 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(), errno, member::interface, ast_db_entry::key, load_realtime_queue(), 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().
05429 { 05430 char *cur_ptr; 05431 const char *queue_name; 05432 char *member; 05433 char *interface; 05434 char *membername = NULL; 05435 char *state_interface; 05436 char *penalty_tok; 05437 int penalty = 0; 05438 char *paused_tok; 05439 int paused = 0; 05440 struct ast_db_entry *db_tree; 05441 struct ast_db_entry *entry; 05442 struct call_queue *cur_queue; 05443 char queue_data[PM_MAX_LEN]; 05444 05445 /* Each key in 'pm_family' is the name of a queue */ 05446 db_tree = ast_db_gettree(pm_family, NULL); 05447 for (entry = db_tree; entry; entry = entry->next) { 05448 05449 queue_name = entry->key + strlen(pm_family) + 2; 05450 05451 { 05452 struct call_queue tmpq = { 05453 .name = queue_name, 05454 }; 05455 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members"); 05456 } 05457 05458 if (!cur_queue) 05459 cur_queue = load_realtime_queue(queue_name); 05460 05461 if (!cur_queue) { 05462 /* If the queue no longer exists, remove it from the 05463 * database */ 05464 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 05465 ast_db_del(pm_family, queue_name); 05466 continue; 05467 } 05468 05469 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) { 05470 queue_t_unref(cur_queue, "Expire reload reference"); 05471 continue; 05472 } 05473 05474 cur_ptr = queue_data; 05475 while ((member = strsep(&cur_ptr, ",|"))) { 05476 if (ast_strlen_zero(member)) 05477 continue; 05478 05479 interface = strsep(&member, ";"); 05480 penalty_tok = strsep(&member, ";"); 05481 paused_tok = strsep(&member, ";"); 05482 membername = strsep(&member, ";"); 05483 state_interface = strsep(&member, ";"); 05484 05485 if (!penalty_tok) { 05486 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 05487 break; 05488 } 05489 penalty = strtol(penalty_tok, NULL, 10); 05490 if (errno == ERANGE) { 05491 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 05492 break; 05493 } 05494 05495 if (!paused_tok) { 05496 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 05497 break; 05498 } 05499 paused = strtol(paused_tok, NULL, 10); 05500 if ((errno == ERANGE) || paused < 0 || paused > 1) { 05501 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 05502 break; 05503 } 05504 05505 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 05506 05507 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { 05508 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 05509 break; 05510 } 05511 } 05512 queue_t_unref(cur_queue, "Expire reload reference"); 05513 } 05514 05515 if (db_tree) { 05516 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 05517 ast_db_freetree(db_tree); 05518 } 05519 }
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 6459 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_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, insert_penaltychange(), ast_variable::lineno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, rule_list::rules, and ast_variable::value.
Referenced by reload_handler().
06460 { 06461 struct ast_config *cfg; 06462 struct rule_list *rl_iter, *new_rl; 06463 struct penalty_rule *pr_iter; 06464 char *rulecat = NULL; 06465 struct ast_variable *rulevar = NULL; 06466 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06467 06468 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) { 06469 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n"); 06470 return AST_MODULE_LOAD_SUCCESS; 06471 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06472 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n"); 06473 return AST_MODULE_LOAD_SUCCESS; 06474 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 06475 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n"); 06476 return AST_MODULE_LOAD_SUCCESS; 06477 } 06478 06479 AST_LIST_LOCK(&rule_lists); 06480 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) { 06481 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list))) 06482 ast_free(pr_iter); 06483 ast_free(rl_iter); 06484 } 06485 while ((rulecat = ast_category_browse(cfg, rulecat))) { 06486 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) { 06487 AST_LIST_UNLOCK(&rule_lists); 06488 ast_config_destroy(cfg); 06489 return AST_MODULE_LOAD_FAILURE; 06490 } else { 06491 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name)); 06492 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list); 06493 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next) 06494 if(!strcasecmp(rulevar->name, "penaltychange")) 06495 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno); 06496 else 06497 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno); 06498 } 06499 } 06500 AST_LIST_UNLOCK(&rule_lists); 06501 06502 ast_config_destroy(cfg); 06503 06504 return AST_MODULE_LOAD_SUCCESS; 06505 }
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 6763 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_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, kill_dead_queues(), LOG_ERROR, LOG_NOTICE, mark_dead_and_unfound(), OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, QUEUE_RELOAD_PARAMETERS, queue_set_global_params(), queues, and reload_single_queue().
Referenced by reload_handler().
06764 { 06765 struct ast_config *cfg; 06766 char *cat; 06767 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06768 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); 06769 06770 if (!(cfg = ast_config_load("queues.conf", config_flags))) { 06771 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 06772 return -1; 06773 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06774 return 0; 06775 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 06776 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n"); 06777 return -1; 06778 } 06779 06780 /* We've made it here, so it looks like we're doing operations on all queues. */ 06781 ao2_lock(queues); 06782 06783 /* Mark all queues as dead for the moment if we're reloading queues. 06784 * For clarity, we could just be reloading members, in which case we don't want to mess 06785 * with the other queue parameters at all*/ 06786 if (queue_reload) { 06787 ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename); 06788 } 06789 06790 /* Chug through config file */ 06791 cat = NULL; 06792 while ((cat = ast_category_browse(cfg, cat)) ) { 06793 if (!strcasecmp(cat, "general") && queue_reload) { 06794 queue_set_global_params(cfg); 06795 continue; 06796 } 06797 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename)) 06798 reload_single_queue(cfg, mask, cat); 06799 } 06800 06801 ast_config_destroy(cfg); 06802 /* Unref all the dead queues if we were reloading queues */ 06803 if (queue_reload) { 06804 ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename); 06805 } 06806 ao2_unlock(queues); 06807 return 0; 06808 }
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 6538 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().
06539 { 06540 char *membername, *interface, *state_interface, *tmp; 06541 char *parse; 06542 struct member *cur, *newm; 06543 struct member tmpmem; 06544 int penalty; 06545 AST_DECLARE_APP_ARGS(args, 06546 AST_APP_ARG(interface); 06547 AST_APP_ARG(penalty); 06548 AST_APP_ARG(membername); 06549 AST_APP_ARG(state_interface); 06550 ); 06551 06552 if (ast_strlen_zero(memberdata)) { 06553 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n"); 06554 return; 06555 } 06556 06557 /* Add a new member */ 06558 parse = ast_strdupa(memberdata); 06559 06560 AST_STANDARD_APP_ARGS(args, parse); 06561 06562 interface = args.interface; 06563 if (!ast_strlen_zero(args.penalty)) { 06564 tmp = args.penalty; 06565 ast_strip(tmp); 06566 penalty = atoi(tmp); 06567 if (penalty < 0) { 06568 penalty = 0; 06569 } 06570 } else { 06571 penalty = 0; 06572 } 06573 06574 if (!ast_strlen_zero(args.membername)) { 06575 membername = args.membername; 06576 ast_strip(membername); 06577 } else { 06578 membername = interface; 06579 } 06580 06581 if (!ast_strlen_zero(args.state_interface)) { 06582 state_interface = args.state_interface; 06583 ast_strip(state_interface); 06584 } else { 06585 state_interface = interface; 06586 } 06587 06588 /* Find the old position in the list */ 06589 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 06590 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); 06591 if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) { 06592 ao2_link(q->members, newm); 06593 ao2_ref(newm, -1); 06594 } 06595 newm = NULL; 06596 06597 if (cur) { 06598 ao2_ref(cur, -1); 06599 } 06600 }
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 6634 of file app_queue.c.
References alloc_queue(), ao2_callback, ao2_lock, ao2_t_find, ao2_unlock, ast_log(), ast_test_flag, ast_variable_browse(), ast_variable_retrieve(), call_queue::found, init_queue(), LOG_WARNING, mark_member_dead(), call_queue::members, call_queue::name, OBJ_NODATA, OBJ_POINTER, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_t_unref, queues, reload_single_member(), strat2int(), call_queue::strategy, and var.
Referenced by reload_queues().
06635 { 06636 int new; 06637 struct call_queue *q = NULL; 06638 /*We're defining a queue*/ 06639 struct call_queue tmpq = { 06640 .name = queuename, 06641 }; 06642 const char *tmpvar; 06643 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); 06644 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER); 06645 int prev_weight = 0; 06646 struct ast_variable *var; 06647 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) { 06648 if (queue_reload) { 06649 /* Make one then */ 06650 if (!(q = alloc_queue(queuename))) { 06651 return; 06652 } 06653 } else { 06654 /* Since we're not reloading queues, this means that we found a queue 06655 * in the configuration file which we don't know about yet. Just return. 06656 */ 06657 return; 06658 } 06659 new = 1; 06660 } else { 06661 new = 0; 06662 } 06663 06664 if (!new) { 06665 ao2_lock(q); 06666 prev_weight = q->weight ? 1 : 0; 06667 } 06668 /* Check if we already found a queue with this name in the config file */ 06669 if (q->found) { 06670 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename); 06671 if (!new) { 06672 /* It should be impossible to *not* hit this case*/ 06673 ao2_unlock(q); 06674 } 06675 queue_t_unref(q, "We exist! Expiring temporary pointer"); 06676 return; 06677 } 06678 /* Due to the fact that the "linear" strategy will have a different allocation 06679 * scheme for queue members, we must devise the queue's strategy before other initializations. 06680 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2 06681 * container used will have only a single bucket instead of the typical number. 06682 */ 06683 if (queue_reload) { 06684 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) { 06685 q->strategy = strat2int(tmpvar); 06686 if (q->strategy < 0) { 06687 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 06688 tmpvar, q->name); 06689 q->strategy = QUEUE_STRATEGY_RINGALL; 06690 } 06691 } else { 06692 q->strategy = QUEUE_STRATEGY_RINGALL; 06693 } 06694 init_queue(q); 06695 } 06696 if (member_reload) { 06697 ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL); 06698 } 06699 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) { 06700 if (member_reload && !strcasecmp(var->name, "member")) { 06701 reload_single_member(var->value, q); 06702 } else if (queue_reload) { 06703 queue_set_param(q, var->name, var->value, var->lineno, 1); 06704 } 06705 } 06706 /* At this point, we've determined if the queue has a weight, so update use_weight 06707 * as appropriate 06708 */ 06709 if (!q->weight && prev_weight) { 06710 ast_atomic_fetchadd_int(&use_weight, -1); 06711 } 06712 else if (q->weight && !prev_weight) { 06713 ast_atomic_fetchadd_int(&use_weight, +1); 06714 } 06715 06716 /* Free remaining members marked as delme */ 06717 if (member_reload) { 06718 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q); 06719 } 06720 06721 if (new) { 06722 queues_t_link(queues, q, "Add queue to container"); 06723 } else { 06724 ao2_unlock(q); 06725 } 06726 queue_t_unref(q, "Expiring creation reference"); 06727 }
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 5171 of file app_queue.c.
References ao2_find, ao2_lock, ao2_ref, ao2_t_find, ao2_unlink, ao2_unlock, ast_copy_string(), 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, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, and RES_OKAY.
Referenced by attempt_thread(), handle_queue_remove_member(), manager_remove_queue_member(), rqm_exec(), and scan_service().
05172 { 05173 struct call_queue *q, tmpq = { 05174 .name = queuename, 05175 }; 05176 struct member *mem, tmpmem; 05177 int res = RES_NOSUCHQUEUE; 05178 05179 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 05180 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) { 05181 ao2_lock(q); 05182 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 05183 /* XXX future changes should beware of this assumption!! */ 05184 if (!mem->dynamic) { 05185 ao2_ref(mem, -1); 05186 ao2_unlock(q); 05187 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference"); 05188 return RES_NOT_DYNAMIC; 05189 } 05190 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 05191 "Queue: %s\r\n" 05192 "Location: %s\r\n" 05193 "MemberName: %s\r\n", 05194 q->name, mem->interface, mem->membername); 05195 ao2_unlink(q->members, mem); 05196 ao2_ref(mem, -1); 05197 05198 if (queue_persistent_members) 05199 dump_queue_members(q); 05200 05201 res = RES_OKAY; 05202 } else { 05203 res = RES_EXISTS; 05204 } 05205 ao2_unlock(q); 05206 queue_t_unref(q, "Expiring temporary reference"); 05207 } 05208 05209 return res; 05210 }
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 2993 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_set_caller_event(), ast_channel_unlock, ast_connected_line_copy_from_caller(), ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, AST_FLAG_ANSWERED_ELSEWHERE, ast_party_caller_set_init(), ast_party_redirecting_copy(), ast_request(), ast_set_callerid(), ast_set_flag, ast_string_field_set, ast_strlen_zero(), ast_verb, 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, dialcontext, 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, callattempt::interface, ast_cdr::lastapp, callattempt::lastcall, ast_cdr::lastdata, callattempt::lastqueue, queue_ent::linpos, ast_channel::macroexten, manager_event, callattempt::member, member::membername, ast_party_id::name, ast_channel::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, ast_channel::uniqueid, 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().
02994 { 02995 int res; 02996 int status; 02997 char tech[256]; 02998 char *location; 02999 const char *macrocontext, *macroexten; 03000 03001 /* on entry here, we know that tmp->chan == NULL */ 03002 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) || 03003 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) { 03004 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 03005 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface); 03006 if (qe->chan->cdr) 03007 ast_cdr_busy(qe->chan->cdr); 03008 tmp->stillgoing = 0; 03009 (*busies)++; 03010 return 0; 03011 } 03012 03013 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 03014 ast_debug(1, "%s in use, can't receive call\n", tmp->interface); 03015 if (qe->chan->cdr) 03016 ast_cdr_busy(qe->chan->cdr); 03017 tmp->stillgoing = 0; 03018 return 0; 03019 } 03020 03021 if (tmp->member->paused) { 03022 ast_debug(1, "%s paused, can't receive call\n", tmp->interface); 03023 if (qe->chan->cdr) 03024 ast_cdr_busy(qe->chan->cdr); 03025 tmp->stillgoing = 0; 03026 return 0; 03027 } 03028 if (use_weight && compare_weight(qe->parent,tmp->member)) { 03029 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 03030 if (qe->chan->cdr) 03031 ast_cdr_busy(qe->chan->cdr); 03032 tmp->stillgoing = 0; 03033 (*busies)++; 03034 return 0; 03035 } 03036 03037 ast_copy_string(tech, tmp->interface, sizeof(tech)); 03038 if ((location = strchr(tech, '/'))) 03039 *location++ = '\0'; 03040 else 03041 location = ""; 03042 03043 /* Request the peer */ 03044 tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status); 03045 if (!tmp->chan) { /* If we can't, just go on to the next call */ 03046 if (qe->chan->cdr) 03047 ast_cdr_busy(qe->chan->cdr); 03048 tmp->stillgoing = 0; 03049 03050 ao2_lock(qe->parent); 03051 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member)); 03052 qe->parent->rrpos++; 03053 qe->linpos++; 03054 ao2_unlock(qe->parent); 03055 03056 (*busies)++; 03057 return 0; 03058 } 03059 03060 ast_channel_lock_both(tmp->chan, qe->chan); 03061 03062 if (qe->cancel_answered_elsewhere) { 03063 ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE); 03064 } 03065 tmp->chan->appl = "AppQueue"; 03066 tmp->chan->data = "(Outgoing Line)"; 03067 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup)); 03068 03069 /* If the new channel has no callerid, try to guess what it should be */ 03070 if (!tmp->chan->caller.id.number.valid) { 03071 if (qe->chan->connected.id.number.valid) { 03072 struct ast_party_caller caller; 03073 03074 ast_party_caller_set_init(&caller, &tmp->chan->caller); 03075 caller.id = qe->chan->connected.id; 03076 caller.ani = qe->chan->connected.ani; 03077 ast_channel_set_caller_event(tmp->chan, &caller, NULL); 03078 } else if (!ast_strlen_zero(qe->chan->dialed.number.str)) { 03079 ast_set_callerid(tmp->chan, qe->chan->dialed.number.str, NULL, NULL); 03080 } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) { 03081 ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL); 03082 } 03083 tmp->dial_callerid_absent = 1; 03084 } 03085 03086 ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting); 03087 03088 tmp->chan->dialed.transit_network_select = qe->chan->dialed.transit_network_select; 03089 03090 ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->caller); 03091 03092 /* Inherit specially named variables from parent channel */ 03093 ast_channel_inherit_variables(qe->chan, tmp->chan); 03094 ast_channel_datastore_inherit(qe->chan, tmp->chan); 03095 03096 /* Presense of ADSI CPE on outgoing channel follows ours */ 03097 tmp->chan->adsicpe = qe->chan->adsicpe; 03098 03099 /* Inherit context and extension */ 03100 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 03101 ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext); 03102 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 03103 if (!ast_strlen_zero(macroexten)) 03104 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 03105 else 03106 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 03107 if (ast_cdr_isset_unanswered()) { 03108 /* they want to see the unanswered dial attempts! */ 03109 /* set up the CDR fields on all the CDRs to give sensical information */ 03110 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name); 03111 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid); 03112 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel); 03113 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src); 03114 strcpy(tmp->chan->cdr->dst, qe->chan->exten); 03115 strcpy(tmp->chan->cdr->dcontext, qe->chan->context); 03116 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp); 03117 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata); 03118 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags; 03119 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode); 03120 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); 03121 } 03122 03123 ast_channel_unlock(tmp->chan); 03124 ast_channel_unlock(qe->chan); 03125 03126 /* Place the call, but don't wait on the answer */ 03127 if ((res = ast_call(tmp->chan, location, 0))) { 03128 /* Again, keep going even if there's an error */ 03129 ast_debug(1, "ast call on peer returned %d\n", res); 03130 ast_verb(3, "Couldn't call %s\n", tmp->interface); 03131 do_hang(tmp); 03132 (*busies)++; 03133 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member)); 03134 return 0; 03135 } else if (qe->parent->eventwhencalled) { 03136 char vars[2048]; 03137 03138 ast_channel_lock_both(tmp->chan, qe->chan); 03139 03140 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 03141 "Queue: %s\r\n" 03142 "AgentCalled: %s\r\n" 03143 "AgentName: %s\r\n" 03144 "ChannelCalling: %s\r\n" 03145 "DestinationChannel: %s\r\n" 03146 "CallerIDNum: %s\r\n" 03147 "CallerIDName: %s\r\n" 03148 "ConnectedLineNum: %s\r\n" 03149 "ConnectedLineName: %s\r\n" 03150 "Context: %s\r\n" 03151 "Extension: %s\r\n" 03152 "Priority: %d\r\n" 03153 "Uniqueid: %s\r\n" 03154 "%s", 03155 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name, 03156 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"), 03157 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"), 03158 S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"), 03159 S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"), 03160 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid, 03161 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03162 03163 ast_channel_unlock(tmp->chan); 03164 ast_channel_unlock(qe->chan); 03165 03166 ast_verb(3, "Called %s\n", tmp->interface); 03167 } 03168 03169 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member)); 03170 return 1; 03171 }
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 3199 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 wait_for_answer().
03200 { 03201 int ret = 0; 03202 03203 while (ret == 0) { 03204 struct callattempt *best = find_best(outgoing); 03205 if (!best) { 03206 ast_debug(1, "Nobody left to try ringing in queue\n"); 03207 break; 03208 } 03209 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 03210 struct callattempt *cur; 03211 /* Ring everyone who shares this best metric (for ringall) */ 03212 for (cur = outgoing; cur; cur = cur->q_next) { 03213 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 03214 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 03215 ret |= ring_entry(qe, cur, busies); 03216 } 03217 } 03218 } else { 03219 /* Ring just the best channel */ 03220 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric); 03221 ret = ring_entry(qe, best, busies); 03222 } 03223 03224 /* If we have timed out, break out */ 03225 if (qe->expire && (time(NULL) >= qe->expire)) { 03226 ast_debug(1, "Queue timed out while ringing members.\n"); 03227 ret = 0; 03228 break; 03229 } 03230 } 03231 03232 return ret; 03233 }
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 3357 of file app_queue.c.
References ast_indicate(), ast_moh_start(), ast_queue_log(), ast_verb, call_queue::autopause, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, manager_event, queue_ent::moh, ast_channel::name, call_queue::name, queue_ent::parent, QUEUE_AUTOPAUSE_OFF, QUEUE_AUTOPAUSE_ON, QUEUE_EVENT_VARIABLES, queue_ent::ring_when_ringing, set_member_paused(), ast_channel::uniqueid, and vars2manager().
03358 { 03359 ast_verb(3, "Nobody picked up in %d ms\n", rnatime); 03360 03361 /* Stop ringing, and resume MOH if specified */ 03362 if (qe->ring_when_ringing) { 03363 ast_indicate(qe->chan, -1); 03364 ast_moh_start(qe->chan, qe->moh, NULL); 03365 } 03366 03367 if (qe->parent->eventwhencalled) { 03368 char vars[2048]; 03369 03370 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer", 03371 "Queue: %s\r\n" 03372 "Uniqueid: %s\r\n" 03373 "Channel: %s\r\n" 03374 "Member: %s\r\n" 03375 "MemberName: %s\r\n" 03376 "Ringtime: %d\r\n" 03377 "%s", 03378 qe->parent->name, 03379 qe->chan->uniqueid, 03380 qe->chan->name, 03381 interface, 03382 membername, 03383 rnatime, 03384 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03385 } 03386 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 03387 if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) { 03388 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) { 03389 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) { 03390 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", 03391 interface, qe->parent->name); 03392 } else { 03393 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 03394 } 03395 } else { 03396 /* If queue autopause is mode all, just don't send any queue to stop. 03397 * the function will stop in all queues */ 03398 if (!set_member_paused("", interface, "Auto-Pause", 1)) { 03399 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n", 03400 interface, qe->parent->name); 03401 } else { 03402 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface); 03403 } 03404 } 03405 } 03406 return; 03407 }
static int rqm_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
RemoveQueueMember application.
Definition at line 5594 of file app_queue.c.
References args, AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_NOTICE, LOG_WARNING, ast_channel::name, parse(), pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and ast_channel::uniqueid.
Referenced by load_module().
05595 { 05596 int res=-1; 05597 char *parse, *temppos = NULL; 05598 AST_DECLARE_APP_ARGS(args, 05599 AST_APP_ARG(queuename); 05600 AST_APP_ARG(interface); 05601 AST_APP_ARG(options); 05602 ); 05603 05604 05605 if (ast_strlen_zero(data)) { 05606 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n"); 05607 return -1; 05608 } 05609 05610 parse = ast_strdupa(data); 05611 05612 AST_STANDARD_APP_ARGS(args, parse); 05613 05614 if (ast_strlen_zero(args.interface)) { 05615 args.interface = ast_strdupa(chan->name); 05616 temppos = strrchr(args.interface, '-'); 05617 if (temppos) 05618 *temppos = '\0'; 05619 } 05620 05621 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface); 05622 05623 switch (remove_from_queue(args.queuename, args.interface)) { 05624 case RES_OKAY: 05625 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 05626 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 05627 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 05628 res = 0; 05629 break; 05630 case RES_EXISTS: 05631 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 05632 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 05633 res = 0; 05634 break; 05635 case RES_NOSUCHQUEUE: 05636 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 05637 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 05638 res = 0; 05639 break; 05640 case RES_NOT_DYNAMIC: 05641 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 05642 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 05643 res = 0; 05644 break; 05645 } 05646 05647 return res; 05648 }
static void rt_handle_member_record | ( | struct call_queue * | q, | |
char * | interface, | |||
const char * | rt_uniqueid, | |||
const char * | membername, | |||
const char * | penalty_str, | |||
const char * | paused_str, | |||
const char * | state_interface | |||
) | [static] |
Find rt member record to update otherwise create one.
Search for member in queue, if found update penalty/paused state, if no member exists create one flag it as a RT member and add to queue member list.
Definition at line 2078 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(), create_queue_member(), member::dead, member::interface, LOG_WARNING, call_queue::members, call_queue::name, member::paused, member::penalty, member::realtime, member::rt_uniqueid, S_OR, and member::state_interface.
Referenced by update_realtime_members().
02079 { 02080 struct member *m; 02081 struct ao2_iterator mem_iter; 02082 int penalty = 0; 02083 int paused = 0; 02084 int found = 0; 02085 02086 if (ast_strlen_zero(rt_uniqueid)) { 02087 ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL")); 02088 return; 02089 } 02090 02091 if (penalty_str) { 02092 penalty = atoi(penalty_str); 02093 if (penalty < 0) 02094 penalty = 0; 02095 } 02096 02097 if (paused_str) { 02098 paused = atoi(paused_str); 02099 if (paused < 0) 02100 paused = 0; 02101 } 02102 02103 /* Find member by realtime uniqueid and update */ 02104 mem_iter = ao2_iterator_init(q->members, 0); 02105 while ((m = ao2_iterator_next(&mem_iter))) { 02106 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) { 02107 m->dead = 0; /* Do not delete this one. */ 02108 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 02109 if (paused_str) 02110 m->paused = paused; 02111 if (strcasecmp(state_interface, m->state_interface)) { 02112 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); 02113 } 02114 m->penalty = penalty; 02115 found = 1; 02116 ao2_ref(m, -1); 02117 break; 02118 } 02119 ao2_ref(m, -1); 02120 } 02121 ao2_iterator_destroy(&mem_iter); 02122 02123 /* Create a new member */ 02124 if (!found) { 02125 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { 02126 m->dead = 0; 02127 m->realtime = 1; 02128 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 02129 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : ""); 02130 ao2_link(q->members, m); 02131 ao2_ref(m, -1); 02132 m = NULL; 02133 } 02134 } 02135 }
static int say_periodic_announcement | ( | struct queue_ent * | qe, | |
int | ringing | |||
) | [static] |
Playback announcement to queued members if period has elapsed.
Definition at line 3284 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().
03285 { 03286 int res = 0; 03287 time_t now; 03288 03289 /* Get the current time */ 03290 time(&now); 03291 03292 /* Check to see if it is time to announce */ 03293 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 03294 return 0; 03295 03296 /* Stop the music on hold so we can play our own file */ 03297 if (ringing) 03298 ast_indicate(qe->chan,-1); 03299 else 03300 ast_moh_stop(qe->chan); 03301 03302 ast_verb(3, "Playing periodic announcement\n"); 03303 03304 if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) { 03305 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce; 03306 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce || 03307 ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) { 03308 qe->last_periodic_announce_sound = 0; 03309 } 03310 03311 /* play the announcement */ 03312 res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])); 03313 03314 if (res > 0 && !valid_exit(qe, res)) 03315 res = 0; 03316 03317 /* Resume Music on Hold if the caller is going to stay in the queue */ 03318 if (!res) { 03319 if (ringing) 03320 ast_indicate(qe->chan, AST_CONTROL_RINGING); 03321 else 03322 ast_moh_start(qe->chan, qe->moh, NULL); 03323 } 03324 03325 /* update last_periodic_announce_time */ 03326 if (qe->parent->relativeperiodicannounce) 03327 time(&qe->last_periodic_announce_time); 03328 else 03329 qe->last_periodic_announce_time = now; 03330 03331 /* Update the current periodic announcement to the next announcement */ 03332 if (!qe->parent->randomperiodicannounce) { 03333 qe->last_periodic_announce_sound++; 03334 } 03335 03336 return res; 03337 }
static int say_position | ( | struct queue_ent * | qe, | |
int | ringing | |||
) | [static] |
Definition at line 2588 of file app_queue.c.
References call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, AST_CONTROL_RINGING, AST_DIGIT_ANY, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_say_number(), ast_verb, queue_ent::chan, call_queue::holdtime, ast_channel::language, queue_ent::last_pos, queue_ent::last_pos_said, call_queue::minannouncefrequency, queue_ent::moh, ast_channel::name, 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().
02589 { 02590 int res = 0, avgholdmins, avgholdsecs, announceposition = 0; 02591 int say_thanks = 1; 02592 time_t now; 02593 02594 /* Let minannouncefrequency seconds pass between the start of each position announcement */ 02595 time(&now); 02596 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) 02597 return 0; 02598 02599 /* If either our position has changed, or we are over the freq timer, say position */ 02600 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 02601 return 0; 02602 02603 if (ringing) { 02604 ast_indicate(qe->chan,-1); 02605 } else { 02606 ast_moh_stop(qe->chan); 02607 } 02608 02609 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES || 02610 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN || 02611 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT && 02612 qe->pos <= qe->parent->announcepositionlimit)) 02613 announceposition = 1; 02614 02615 02616 if (announceposition == 1) { 02617 /* Say we're next, if we are */ 02618 if (qe->pos == 1) { 02619 res = play_file(qe->chan, qe->parent->sound_next); 02620 if (res) 02621 goto playout; 02622 else 02623 goto posout; 02624 } else { 02625 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 02626 /* More than Case*/ 02627 res = play_file(qe->chan, qe->parent->queue_quantity1); 02628 if (res) 02629 goto playout; 02630 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 02631 if (res) 02632 goto playout; 02633 } else { 02634 /* Normal Case */ 02635 res = play_file(qe->chan, qe->parent->sound_thereare); 02636 if (res) 02637 goto playout; 02638 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 02639 if (res) 02640 goto playout; 02641 } 02642 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 02643 /* More than Case*/ 02644 res = play_file(qe->chan, qe->parent->queue_quantity2); 02645 if (res) 02646 goto playout; 02647 } else { 02648 res = play_file(qe->chan, qe->parent->sound_calls); 02649 if (res) 02650 goto playout; 02651 } 02652 } 02653 } 02654 /* Round hold time to nearest minute */ 02655 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 02656 02657 /* If they have specified a rounding then round the seconds as well */ 02658 if (qe->parent->roundingseconds) { 02659 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 02660 avgholdsecs *= qe->parent->roundingseconds; 02661 } else { 02662 avgholdsecs = 0; 02663 } 02664 02665 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 02666 02667 /* If the hold time is >1 min, if it's enabled, and if it's not 02668 supposed to be only once and we have already said it, say it */ 02669 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime && 02670 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) || 02671 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) { 02672 res = play_file(qe->chan, qe->parent->sound_holdtime); 02673 if (res) 02674 goto playout; 02675 02676 if (avgholdmins >= 1) { 02677 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL); 02678 if (res) 02679 goto playout; 02680 02681 if (avgholdmins == 1) { 02682 res = play_file(qe->chan, qe->parent->sound_minute); 02683 if (res) 02684 goto playout; 02685 } else { 02686 res = play_file(qe->chan, qe->parent->sound_minutes); 02687 if (res) 02688 goto playout; 02689 } 02690 } 02691 if (avgholdsecs >= 1) { 02692 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL); 02693 if (res) 02694 goto playout; 02695 02696 res = play_file(qe->chan, qe->parent->sound_seconds); 02697 if (res) 02698 goto playout; 02699 } 02700 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) { 02701 say_thanks = 0; 02702 } 02703 02704 posout: 02705 if (qe->parent->announceposition) { 02706 ast_verb(3, "Told %s in %s their queue position (which was %d)\n", 02707 qe->chan->name, qe->parent->name, qe->pos); 02708 } 02709 if (say_thanks) { 02710 res = play_file(qe->chan, qe->parent->sound_thanks); 02711 } 02712 playout: 02713 02714 if ((res > 0 && !valid_exit(qe, res))) 02715 res = 0; 02716 02717 /* Set our last_pos indicators */ 02718 qe->last_pos = now; 02719 qe->last_pos_said = qe->pos; 02720 02721 /* Don't restart music on hold if we're about to exit the caller from the queue */ 02722 if (!res) { 02723 if (ringing) { 02724 ast_indicate(qe->chan, AST_CONTROL_RINGING); 02725 } else { 02726 ast_moh_start(qe->chan, qe->moh, NULL); 02727 } 02728 } 02729 return res; 02730 }
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 4115 of file app_queue.c.
References AGENT, CALLER, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, member::interface, manager_event, member::membername, ast_channel::name, queue_ent::parent, QUEUE_EVENT_VARIABLES, queue_ent::start, ast_channel::uniqueid, and vars2manager().
04118 { 04119 const char *reason = NULL; /* silence dumb compilers */ 04120 04121 if (!qe->parent->eventwhencalled) 04122 return; 04123 04124 switch (rsn) { 04125 case CALLER: 04126 reason = "caller"; 04127 break; 04128 case AGENT: 04129 reason = "agent"; 04130 break; 04131 case TRANSFER: 04132 reason = "transfer"; 04133 break; 04134 } 04135 04136 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 04137 "Queue: %s\r\n" 04138 "Uniqueid: %s\r\n" 04139 "Channel: %s\r\n" 04140 "Member: %s\r\n" 04141 "MemberName: %s\r\n" 04142 "HoldTime: %ld\r\n" 04143 "TalkTime: %ld\r\n" 04144 "Reason: %s\r\n" 04145 "%s", 04146 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 04147 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason, 04148 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : ""); 04149 }
static int set_member_paused | ( | const char * | queuename, | |
const char * | interface, | |||
const char * | reason, | |||
int | paused | |||
) | [static] |
Definition at line 5270 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().
05271 { 05272 int found = 0; 05273 struct call_queue *q; 05274 struct member *mem; 05275 struct ao2_iterator queue_iter; 05276 int failed; 05277 05278 /* Special event for when all queues are paused - individual events still generated */ 05279 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 05280 if (ast_strlen_zero(queuename)) 05281 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 05282 05283 queue_iter = ao2_iterator_init(queues, 0); 05284 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) { 05285 ao2_lock(q); 05286 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 05287 if ((mem = interface_exists(q, interface))) { 05288 if (mem->paused == paused) { 05289 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 05290 } 05291 05292 failed = 0; 05293 if (mem->realtime) { 05294 failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); 05295 } 05296 05297 if (failed) { 05298 ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface); 05299 ao2_ref(mem, -1); 05300 ao2_unlock(q); 05301 queue_t_unref(q, "Done with iterator"); 05302 continue; 05303 } 05304 found++; 05305 mem->paused = paused; 05306 05307 if (queue_persistent_members) 05308 dump_queue_members(q); 05309 05310 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, "")); 05311 05312 if (!ast_strlen_zero(reason)) { 05313 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 05314 "Queue: %s\r\n" 05315 "Location: %s\r\n" 05316 "MemberName: %s\r\n" 05317 "Paused: %d\r\n" 05318 "Reason: %s\r\n", 05319 q->name, mem->interface, mem->membername, paused, reason); 05320 } else { 05321 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 05322 "Queue: %s\r\n" 05323 "Location: %s\r\n" 05324 "MemberName: %s\r\n" 05325 "Paused: %d\r\n", 05326 q->name, mem->interface, mem->membername, paused); 05327 } 05328 ao2_ref(mem, -1); 05329 } 05330 } 05331 05332 if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) { 05333 ao2_unlock(q); 05334 queue_t_unref(q, "Done with iterator"); 05335 break; 05336 } 05337 05338 ao2_unlock(q); 05339 queue_t_unref(q, "Done with iterator"); 05340 } 05341 ao2_iterator_destroy(&queue_iter); 05342 05343 return found ? RESULT_SUCCESS : RESULT_FAILURE; 05344 }
static int set_member_penalty | ( | const char * | queuename, | |
const char * | interface, | |||
int | penalty | |||
) | [static] |
Definition at line 5347 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_log(), ast_queue_log(), ast_strlen_zero(), EVENT_FLAG_AGENT, member::interface, interface_exists(), LOG_ERROR, manager_event, call_queue::name, member::penalty, queue_t_unref, queues, RESULT_FAILURE, and RESULT_SUCCESS.
Referenced by handle_queue_set_member_penalty(), manager_queue_member_penalty(), and queue_function_memberpenalty_write().
05348 { 05349 int foundinterface = 0, foundqueue = 0; 05350 struct call_queue *q; 05351 struct member *mem; 05352 struct ao2_iterator queue_iter; 05353 05354 if (penalty < 0) { 05355 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty); 05356 return RESULT_FAILURE; 05357 } 05358 05359 queue_iter = ao2_iterator_init(queues, 0); 05360 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 05361 ao2_lock(q); 05362 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 05363 foundqueue++; 05364 if ((mem = interface_exists(q, interface))) { 05365 foundinterface++; 05366 mem->penalty = penalty; 05367 05368 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty); 05369 manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty", 05370 "Queue: %s\r\n" 05371 "Location: %s\r\n" 05372 "Penalty: %d\r\n", 05373 q->name, mem->interface, penalty); 05374 ao2_ref(mem, -1); 05375 } 05376 } 05377 ao2_unlock(q); 05378 queue_t_unref(q, "Done with iterator"); 05379 } 05380 ao2_iterator_destroy(&queue_iter); 05381 05382 if (foundinterface) { 05383 return RESULT_SUCCESS; 05384 } else if (!foundqueue) { 05385 ast_log (LOG_ERROR, "Invalid queuename\n"); 05386 } else { 05387 ast_log (LOG_ERROR, "Invalid interface\n"); 05388 } 05389 05390 return RESULT_FAILURE; 05391 }
static void set_queue_result | ( | struct ast_channel * | chan, | |
enum queue_result | res | |||
) | [static] |
sets the QUEUESTATUS channel variable
Definition at line 1193 of file app_queue.c.
References ARRAY_LEN, pbx_builtin_setvar_helper(), queue_results, and text.
Referenced by queue_exec().
01194 { 01195 int i; 01196 01197 for (i = 0; i < ARRAY_LEN(queue_results); i++) { 01198 if (queue_results[i].id == res) { 01199 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 01200 return; 01201 } 01202 } 01203 }
static void set_queue_variables | ( | struct call_queue * | q, | |
struct ast_channel * | chan | |||
) | [static] |
Set variables of queue.
Definition at line 1288 of file app_queue.c.
References ao2_lock, ao2_unlock, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, 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(), and record_abandoned().
01289 { 01290 char interfacevar[256]=""; 01291 float sl = 0; 01292 01293 ao2_lock(q); 01294 01295 if (q->setqueuevar) { 01296 sl = 0; 01297 if (q->callscompleted > 0) 01298 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 01299 01300 snprintf(interfacevar, sizeof(interfacevar), 01301 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 01302 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 01303 01304 ao2_unlock(q); 01305 01306 pbx_builtin_setvar_multiple(chan, interfacevar); 01307 } else { 01308 ao2_unlock(q); 01309 } 01310 }
static struct ast_datastore* setup_transfer_datastore | ( | struct queue_ent * | qe, | |
struct member * | member, | |||
time_t | starttime, | |||
int | callcompletedinsl | |||
) | [static] |
create a datastore for storing relevant info to log attended transfers in the queue_log
Definition at line 4219 of file app_queue.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_log(), queue_ent::chan, ast_datastore::data, LOG_WARNING, queue_transfer_ds::member, queue_transfer_ds::qe, and queue_transfer_info.
04220 { 04221 struct ast_datastore *ds; 04222 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds)); 04223 04224 if (!qtds) { 04225 ast_log(LOG_WARNING, "Memory allocation error!\n"); 04226 return NULL; 04227 } 04228 04229 ast_channel_lock(qe->chan); 04230 if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) { 04231 ast_channel_unlock(qe->chan); 04232 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n"); 04233 return NULL; 04234 } 04235 04236 qtds->qe = qe; 04237 /* This member is refcounted in try_calling, so no need to add it here, too */ 04238 qtds->member = member; 04239 qtds->starttime = starttime; 04240 qtds->callcompletedinsl = callcompletedinsl; 04241 ds->data = qtds; 04242 ast_channel_datastore_add(qe->chan, ds); 04243 ast_channel_unlock(qe->chan); 04244 return ds; 04245 }
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 3260 of file app_queue.c.
References ast_debug, find_best(), callattempt::interface, queue_ent::linpos, queue_ent::linwrapped, and callattempt::metric.
03261 { 03262 struct callattempt *best = find_best(outgoing); 03263 03264 if (best) { 03265 /* Ring just the best channel */ 03266 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 03267 qe->linpos = best->metric % 1000; 03268 } else { 03269 /* Just increment rrpos */ 03270 if (qe->linwrapped) { 03271 /* No more channels, start over */ 03272 qe->linpos = 0; 03273 } else { 03274 /* Prioritize next entry */ 03275 qe->linpos++; 03276 } 03277 } 03278 qe->linwrapped = 0; 03279 03280 return 0; 03281 }
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 3236 of file app_queue.c.
References ast_debug, find_best(), callattempt::interface, callattempt::metric, queue_ent::parent, call_queue::rrpos, and call_queue::wrapped.
03237 { 03238 struct callattempt *best = find_best(outgoing); 03239 03240 if (best) { 03241 /* Ring just the best channel */ 03242 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 03243 qe->parent->rrpos = best->metric % 1000; 03244 } else { 03245 /* Just increment rrpos */ 03246 if (qe->parent->wrapped) { 03247 /* No more channels, start over */ 03248 qe->parent->rrpos = 0; 03249 } else { 03250 /* Prioritize next entry */ 03251 qe->parent->rrpos++; 03252 } 03253 } 03254 qe->parent->wrapped = 0; 03255 03256 return 0; 03257 }
static int strat2int | ( | const char * | strategy | ) | [static] |
Definition at line 1217 of file app_queue.c.
References ARRAY_LEN, strategies, and strategy::strategy.
Referenced by find_queue_by_name_rt(), queue_set_param(), and reload_single_queue().
01218 { 01219 int x; 01220 01221 for (x = 0; x < ARRAY_LEN(strategies); x++) { 01222 if (!strcasecmp(strategy, strategies[x].name)) 01223 return strategies[x].strategy; 01224 } 01225 01226 return -1; 01227 }
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 4299 of file app_queue.c.
References ao2_container_count(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, 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_MAX_CONTEXT, AST_MAX_EXTENSION, ast_set_flag, ast_test_flag, queue_ent::cancel_answered_elsewhere, queue_ent::chan, dialed_interface_info, queue_ent::expire, call_queue::members, queue_ent::parent, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, and call_queue::strategy.
Referenced by queue_exec().
04300 { 04301 struct member *cur; 04302 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 04303 int to, orig; 04304 char oldexten[AST_MAX_EXTENSION]=""; 04305 char oldcontext[AST_MAX_CONTEXT]=""; 04306 char queuename[256]=""; 04307 char interfacevar[256]=""; 04308 struct ast_channel *peer; 04309 struct ast_channel *which; 04310 struct callattempt *lpeer; 04311 struct member *member; 04312 struct ast_app *application; 04313 int res = 0, bridge = 0; 04314 int numbusies = 0; 04315 int x=0; 04316 char *announce = NULL; 04317 char digit = 0; 04318 time_t callstart; 04319 time_t now = time(NULL); 04320 struct ast_bridge_config bridge_config; 04321 char nondataquality = 1; 04322 char *agiexec = NULL; 04323 char *macroexec = NULL; 04324 char *gosubexec = NULL; 04325 const char *monitorfilename; 04326 const char *monitor_exec; 04327 const char *monitor_options; 04328 char tmpid[256], tmpid2[256]; 04329 char meid[1024], meid2[1024]; 04330 char mixmonargs[1512]; 04331 struct ast_app *mixmonapp = NULL; 04332 char *p; 04333 char vars[2048]; 04334 int forwardsallowed = 1; 04335 int update_connectedline = 1; 04336 int callcompletedinsl; 04337 struct ao2_iterator memi; 04338 struct ast_datastore *datastore, *transfer_ds; 04339 struct queue_end_bridge *queue_end_bridge = NULL; 04340 04341 ast_channel_lock(qe->chan); 04342 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL); 04343 ast_channel_unlock(qe->chan); 04344 04345 memset(&bridge_config, 0, sizeof(bridge_config)); 04346 tmpid[0] = 0; 04347 meid[0] = 0; 04348 time(&now); 04349 04350 /* If we've already exceeded our timeout, then just stop 04351 * This should be extremely rare. queue_exec will take care 04352 * of removing the caller and reporting the timeout as the reason. 04353 */ 04354 if (qe->expire && now >= qe->expire) { 04355 res = 0; 04356 goto out; 04357 } 04358 04359 for (; options && *options; options++) 04360 switch (*options) { 04361 case 't': 04362 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 04363 break; 04364 case 'T': 04365 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 04366 break; 04367 case 'w': 04368 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 04369 break; 04370 case 'W': 04371 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 04372 break; 04373 case 'c': 04374 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN); 04375 break; 04376 case 'd': 04377 nondataquality = 0; 04378 break; 04379 case 'h': 04380 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 04381 break; 04382 case 'H': 04383 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 04384 break; 04385 case 'k': 04386 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL); 04387 break; 04388 case 'K': 04389 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL); 04390 break; 04391 case 'n': 04392 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) 04393 (*tries)++; 04394 else 04395 *tries = ao2_container_count(qe->parent->members); 04396 *noption = 1; 04397 break; 04398 case 'i': 04399 forwardsallowed = 0; 04400 break; 04401 case 'I': 04402 update_connectedline = 0; 04403 break; 04404 case 'x': 04405 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON); 04406 break; 04407 case 'X': 04408 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON); 04409 break; 04410 case 'C': 04411 qe->cancel_answered_elsewhere = 1; 04412 break; 04413 } 04414 04415 /* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited. 04416 (this is mainly to support chan_local) 04417 */ 04418 if (ast_test_flag(qe->chan, AST_FLAG_ANSWERED_ELSEWHERE)) { 04419 qe->cancel_answered_elsewhere = 1; 04420 } 04421 04422 ao2_lock(qe->parent); 04423 ast_debug(1, "%s is trying to call a queue member.\n", 04424 qe->chan->name); 04425 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 04426 if (!ast_strlen_zero(qe->announce)) 04427 announce = qe->announce; 04428 if (!ast_strlen_zero(announceoverride)) 04429 announce = announceoverride; 04430 04431 memi = ao2_iterator_init(qe->parent->members, 0); 04432 while ((cur = ao2_iterator_next(&memi))) { 04433 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 04434 struct ast_dialed_interface *di; 04435 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 04436 if (!tmp) { 04437 ao2_ref(cur, -1); 04438 ao2_iterator_destroy(&memi); 04439 ao2_unlock(qe->parent); 04440 goto out; 04441 } 04442 if (!datastore) { 04443 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) { 04444 callattempt_free(tmp); 04445 ao2_ref(cur, -1); 04446 ao2_iterator_destroy(&memi); 04447 ao2_unlock(qe->parent); 04448 goto out; 04449 } 04450 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 04451 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 04452 callattempt_free(tmp); 04453 ao2_ref(cur, -1); 04454 ao2_iterator_destroy(&memi); 04455 ao2_unlock(&qe->parent); 04456 goto out; 04457 } 04458 datastore->data = dialed_interfaces; 04459 AST_LIST_HEAD_INIT(dialed_interfaces); 04460 04461 ast_channel_lock(qe->chan); 04462 ast_channel_datastore_add(qe->chan, datastore); 04463 ast_channel_unlock(qe->chan); 04464 } else 04465 dialed_interfaces = datastore->data; 04466 04467 AST_LIST_LOCK(dialed_interfaces); 04468 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 04469 if (!strcasecmp(cur->interface, di->interface)) { 04470 ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n", 04471 di->interface); 04472 break; 04473 } 04474 } 04475 AST_LIST_UNLOCK(dialed_interfaces); 04476 04477 if (di) { 04478 callattempt_free(tmp); 04479 ao2_ref(cur, -1); 04480 continue; 04481 } 04482 04483 /* It is always ok to dial a Local interface. We only keep track of 04484 * which "real" interfaces have been dialed. The Local channel will 04485 * inherit this list so that if it ends up dialing a real interface, 04486 * it won't call one that has already been called. */ 04487 if (strncasecmp(cur->interface, "Local/", 6)) { 04488 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) { 04489 callattempt_free(tmp); 04490 ao2_ref(cur, -1); 04491 ao2_iterator_destroy(&memi); 04492 ao2_unlock(qe->parent); 04493 goto out; 04494 } 04495 strcpy(di->interface, cur->interface); 04496 04497 AST_LIST_LOCK(dialed_interfaces); 04498 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 04499 AST_LIST_UNLOCK(dialed_interfaces); 04500 } 04501 04502 ast_channel_lock(qe->chan); 04503 /* 04504 * Seed the callattempt's connected line information with previously 04505 * acquired connected line info from the queued channel. The 04506 * previously acquired connected line info could have been set 04507 * through the CONNECTED_LINE dialplan function. 04508 */ 04509 ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected); 04510 ast_channel_unlock(qe->chan); 04511 04512 tmp->stillgoing = -1; 04513 tmp->member = cur;/* Place the reference for cur into callattempt. */ 04514 tmp->lastcall = cur->lastcall; 04515 tmp->lastqueue = cur->lastqueue; 04516 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 04517 /* Special case: If we ring everyone, go ahead and ring them, otherwise 04518 just calculate their metric for the appropriate strategy */ 04519 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 04520 /* Put them in the list of outgoing thingies... We're ready now. 04521 XXX If we're forcibly removed, these outgoing calls won't get 04522 hung up XXX */ 04523 tmp->q_next = outgoing; 04524 outgoing = tmp; 04525 /* If this line is up, don't try anybody else */ 04526 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 04527 break; 04528 } else { 04529 callattempt_free(tmp); 04530 } 04531 } 04532 ao2_iterator_destroy(&memi); 04533 04534 if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) { 04535 /* Application arguments have higher timeout priority (behaviour for <=1.6) */ 04536 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 04537 to = (qe->expire - now) * 1000; 04538 else 04539 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 04540 } else { 04541 /* Config timeout is higher priority thatn application timeout */ 04542 if (qe->expire && qe->expire<=now) { 04543 to = 0; 04544 } else if (qe->parent->timeout) { 04545 to = qe->parent->timeout * 1000; 04546 } else { 04547 to = -1; 04548 } 04549 } 04550 orig = to; 04551 ++qe->pending; 04552 ao2_unlock(qe->parent); 04553 ring_one(qe, outgoing, &numbusies); 04554 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline); 04555 /* The ast_channel_datastore_remove() function could fail here if the 04556 * datastore was moved to another channel during a masquerade. If this is 04557 * the case, don't free the datastore here because later, when the channel 04558 * to which the datastore was moved hangs up, it will attempt to free this 04559 * datastore again, causing a crash 04560 */ 04561 ast_channel_lock(qe->chan); 04562 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) { 04563 ast_datastore_free(datastore); 04564 } 04565 ast_channel_unlock(qe->chan); 04566 ao2_lock(qe->parent); 04567 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) { 04568 store_next_rr(qe, outgoing); 04569 04570 } 04571 if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) { 04572 store_next_lin(qe, outgoing); 04573 } 04574 ao2_unlock(qe->parent); 04575 peer = lpeer ? lpeer->chan : NULL; 04576 if (!peer) { 04577 qe->pending = 0; 04578 if (to) { 04579 /* Must gotten hung up */ 04580 res = -1; 04581 } else { 04582 /* User exited by pressing a digit */ 04583 res = digit; 04584 } 04585 if (res == -1) 04586 ast_debug(1, "%s: Nobody answered.\n", qe->chan->name); 04587 if (ast_cdr_isset_unanswered()) { 04588 /* channel contains the name of one of the outgoing channels 04589 in its CDR; zero out this CDR to avoid a dual-posting */ 04590 struct callattempt *o; 04591 for (o = outgoing; o; o = o->q_next) { 04592 if (!o->chan) { 04593 continue; 04594 } 04595 if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) { 04596 ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED); 04597 break; 04598 } 04599 } 04600 } 04601 } else { /* peer is valid */ 04602 /* Ah ha! Someone answered within the desired timeframe. Of course after this 04603 we will always return with -1 so that it is hung up properly after the 04604 conversation. */ 04605 if (!strcmp(qe->chan->tech->type, "DAHDI")) 04606 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 04607 if (!strcmp(peer->tech->type, "DAHDI")) 04608 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 04609 /* Update parameters for the queue */ 04610 time(&now); 04611 recalc_holdtime(qe, (now - qe->start)); 04612 ao2_lock(qe->parent); 04613 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 04614 ao2_unlock(qe->parent); 04615 member = lpeer->member; 04616 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ 04617 ao2_ref(member, 1); 04618 hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere); 04619 outgoing = NULL; 04620 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 04621 int res2; 04622 04623 res2 = ast_autoservice_start(qe->chan); 04624 if (!res2) { 04625 if (qe->parent->memberdelay) { 04626 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 04627 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 04628 } 04629 if (!res2 && announce) { 04630 play_file(peer, announce); 04631 } 04632 if (!res2 && qe->parent->reportholdtime) { 04633 if (!play_file(peer, qe->parent->sound_reporthold)) { 04634 int holdtime, holdtimesecs; 04635 04636 time(&now); 04637 holdtime = abs((now - qe->start) / 60); 04638 holdtimesecs = abs((now - qe->start) % 60); 04639 if (holdtime > 0) { 04640 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 04641 play_file(peer, qe->parent->sound_minutes); 04642 } 04643 if (holdtimesecs > 1) { 04644 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL); 04645 play_file(peer, qe->parent->sound_seconds); 04646 } 04647 } 04648 } 04649 } 04650 res2 |= ast_autoservice_stop(qe->chan); 04651 if (ast_check_hangup(peer)) { 04652 /* Agent must have hung up */ 04653 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name); 04654 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", ""); 04655 if (qe->parent->eventwhencalled) 04656 manager_event(EVENT_FLAG_AGENT, "AgentDump", 04657 "Queue: %s\r\n" 04658 "Uniqueid: %s\r\n" 04659 "Channel: %s\r\n" 04660 "Member: %s\r\n" 04661 "MemberName: %s\r\n" 04662 "%s", 04663 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 04664 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 04665 ast_hangup(peer); 04666 ao2_ref(member, -1); 04667 goto out; 04668 } else if (res2) { 04669 /* Caller must have hung up just before being connected*/ 04670 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 04671 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 04672 record_abandoned(qe); 04673 ast_hangup(peer); 04674 ao2_ref(member, -1); 04675 return -1; 04676 } 04677 } 04678 /* Stop music on hold */ 04679 if (ringing) 04680 ast_indicate(qe->chan,-1); 04681 else 04682 ast_moh_stop(qe->chan); 04683 /* If appropriate, log that we have a destination channel */ 04684 if (qe->chan->cdr) 04685 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 04686 /* Make sure channels are compatible */ 04687 res = ast_channel_make_compatible(qe->chan, peer); 04688 if (res < 0) { 04689 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", ""); 04690 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 04691 record_abandoned(qe); 04692 ast_cdr_failed(qe->chan->cdr); 04693 ast_hangup(peer); 04694 ao2_ref(member, -1); 04695 return -1; 04696 } 04697 04698 /* Play announcement to the caller telling it's his turn if defined */ 04699 if (!ast_strlen_zero(qe->parent->sound_callerannounce)) { 04700 if (play_file(qe->chan, qe->parent->sound_callerannounce)) 04701 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce); 04702 } 04703 04704 ao2_lock(qe->parent); 04705 /* if setinterfacevar is defined, make member variables available to the channel */ 04706 /* use pbx_builtin_setvar to set a load of variables with one call */ 04707 if (qe->parent->setinterfacevar) { 04708 snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d", 04709 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime); 04710 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 04711 pbx_builtin_setvar_multiple(peer, interfacevar); 04712 } 04713 04714 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */ 04715 /* use pbx_builtin_setvar to set a load of variables with one call */ 04716 if (qe->parent->setqueueentryvar) { 04717 snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d", 04718 (long) time(NULL) - qe->start, qe->opos); 04719 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 04720 pbx_builtin_setvar_multiple(peer, interfacevar); 04721 } 04722 04723 ao2_unlock(qe->parent); 04724 04725 /* try to set queue variables if configured to do so*/ 04726 set_queue_variables(qe->parent, qe->chan); 04727 set_queue_variables(qe->parent, peer); 04728 04729 ast_channel_lock(qe->chan); 04730 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) { 04731 monitorfilename = ast_strdupa(monitorfilename); 04732 } 04733 ast_channel_unlock(qe->chan); 04734 /* Begin Monitoring */ 04735 if (qe->parent->monfmt && *qe->parent->monfmt) { 04736 if (!qe->parent->montype) { 04737 const char *monexec, *monargs; 04738 ast_debug(1, "Starting Monitor as requested.\n"); 04739 ast_channel_lock(qe->chan); 04740 if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || (monargs = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))) { 04741 which = qe->chan; 04742 monexec = monexec ? ast_strdupa(monexec) : NULL; 04743 } 04744 else 04745 which = peer; 04746 ast_channel_unlock(qe->chan); 04747 if (monitorfilename) { 04748 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT); 04749 } else if (qe->chan->cdr) { 04750 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT); 04751 } else { 04752 /* Last ditch effort -- no CDR, make up something */ 04753 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 04754 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT); 04755 } 04756 if (!ast_strlen_zero(monexec)) { 04757 ast_monitor_setjoinfiles(which, 1); 04758 } 04759 } else { 04760 mixmonapp = pbx_findapp("MixMonitor"); 04761 04762 if (mixmonapp) { 04763 ast_debug(1, "Starting MixMonitor as requested.\n"); 04764 if (!monitorfilename) { 04765 if (qe->chan->cdr) 04766 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)); 04767 else 04768 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 04769 } else { 04770 const char *m = monitorfilename; 04771 for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) { 04772 switch (*m) { 04773 case '^': 04774 if (*(m + 1) == '{') 04775 *p = '$'; 04776 break; 04777 case ',': 04778 *p++ = '\\'; 04779 /* Fall through */ 04780 default: 04781 *p = *m; 04782 } 04783 if (*m == '\0') 04784 break; 04785 } 04786 if (p == tmpid2 + sizeof(tmpid2)) 04787 tmpid2[sizeof(tmpid2) - 1] = '\0'; 04788 04789 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 04790 } 04791 04792 ast_channel_lock(qe->chan); 04793 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) { 04794 monitor_exec = ast_strdupa(monitor_exec); 04795 } 04796 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) { 04797 monitor_options = ast_strdupa(monitor_options); 04798 } else { 04799 monitor_options = ""; 04800 } 04801 ast_channel_unlock(qe->chan); 04802 04803 if (monitor_exec) { 04804 const char *m = monitor_exec; 04805 for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) { 04806 switch (*m) { 04807 case '^': 04808 if (*(m + 1) == '{') 04809 *p = '$'; 04810 break; 04811 case ',': 04812 *p++ = '\\'; 04813 /* Fall through */ 04814 default: 04815 *p = *m; 04816 } 04817 if (*m == '\0') 04818 break; 04819 } 04820 if (p == meid2 + sizeof(meid2)) 04821 meid2[sizeof(meid2) - 1] = '\0'; 04822 04823 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 04824 } 04825 04826 snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt); 04827 04828 if (!ast_strlen_zero(monitor_exec)) 04829 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec); 04830 else 04831 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options); 04832 04833 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 04834 /* We purposely lock the CDR so that pbx_exec does not update the application data */ 04835 if (qe->chan->cdr) 04836 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 04837 pbx_exec(qe->chan, mixmonapp, mixmonargs); 04838 if (qe->chan->cdr) 04839 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 04840 04841 } else { 04842 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 04843 } 04844 } 04845 } 04846 /* Drop out of the queue at this point, to prepare for next caller */ 04847 leave_queue(qe); 04848 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 04849 ast_debug(1, "app_queue: sendurl=%s.\n", url); 04850 ast_channel_sendurl(peer, url); 04851 } 04852 04853 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */ 04854 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */ 04855 if (!ast_strlen_zero(macro)) { 04856 macroexec = ast_strdupa(macro); 04857 } else { 04858 if (qe->parent->membermacro) 04859 macroexec = ast_strdupa(qe->parent->membermacro); 04860 } 04861 04862 if (!ast_strlen_zero(macroexec)) { 04863 ast_debug(1, "app_queue: macro=%s.\n", macroexec); 04864 04865 res = ast_autoservice_start(qe->chan); 04866 if (res) { 04867 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 04868 res = -1; 04869 } 04870 04871 application = pbx_findapp("Macro"); 04872 04873 if (application) { 04874 res = pbx_exec(peer, application, macroexec); 04875 ast_debug(1, "Macro exited with status %d\n", res); 04876 res = 0; 04877 } else { 04878 ast_log(LOG_ERROR, "Could not find application Macro\n"); 04879 res = -1; 04880 } 04881 04882 if (ast_autoservice_stop(qe->chan) < 0) { 04883 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 04884 res = -1; 04885 } 04886 } 04887 04888 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */ 04889 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */ 04890 if (!ast_strlen_zero(gosub)) { 04891 gosubexec = ast_strdupa(gosub); 04892 } else { 04893 if (qe->parent->membergosub) 04894 gosubexec = ast_strdupa(qe->parent->membergosub); 04895 } 04896 04897 if (!ast_strlen_zero(gosubexec)) { 04898 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec); 04899 04900 res = ast_autoservice_start(qe->chan); 04901 if (res) { 04902 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 04903 res = -1; 04904 } 04905 04906 application = pbx_findapp("Gosub"); 04907 04908 if (application) { 04909 char *gosub_args, *gosub_argstart; 04910 04911 /* Set where we came from */ 04912 ast_copy_string(peer->context, "app_queue_gosub_virtual_context", sizeof(peer->context)); 04913 ast_copy_string(peer->exten, "s", sizeof(peer->exten)); 04914 peer->priority = 0; 04915 04916 gosub_argstart = strchr(gosubexec, ','); 04917 if (gosub_argstart) { 04918 const char *what_is_s = "s"; 04919 *gosub_argstart = 0; 04920 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) && 04921 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) { 04922 what_is_s = "~~s~~"; 04923 } 04924 if (asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) { 04925 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 04926 gosub_args = NULL; 04927 } 04928 *gosub_argstart = ','; 04929 } else { 04930 const char *what_is_s = "s"; 04931 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) && 04932 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) { 04933 what_is_s = "~~s~~"; 04934 } 04935 if (asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) { 04936 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 04937 gosub_args = NULL; 04938 } 04939 } 04940 if (gosub_args) { 04941 res = pbx_exec(peer, application, gosub_args); 04942 if (!res) { 04943 struct ast_pbx_args args; 04944 memset(&args, 0, sizeof(args)); 04945 args.no_hangup_chan = 1; 04946 ast_pbx_run_args(peer, &args); 04947 } 04948 ast_free(gosub_args); 04949 ast_debug(1, "Gosub exited with status %d\n", res); 04950 } else { 04951 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n"); 04952 } 04953 } else { 04954 ast_log(LOG_ERROR, "Could not find application Gosub\n"); 04955 res = -1; 04956 } 04957 04958 if (ast_autoservice_stop(qe->chan) < 0) { 04959 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 04960 res = -1; 04961 } 04962 } 04963 04964 if (!ast_strlen_zero(agi)) { 04965 ast_debug(1, "app_queue: agi=%s.\n", agi); 04966 application = pbx_findapp("agi"); 04967 if (application) { 04968 agiexec = ast_strdupa(agi); 04969 pbx_exec(qe->chan, application, agiexec); 04970 } else 04971 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 04972 } 04973 qe->handled++; 04974 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid, 04975 (long)(orig - to > 0 ? (orig - to) / 1000 : 0)); 04976 04977 if (qe->chan->cdr) { 04978 struct ast_cdr *cdr; 04979 struct ast_cdr *newcdr; 04980 04981 /* Only work with the last CDR in the stack*/ 04982 cdr = qe->chan->cdr; 04983 while (cdr->next) { 04984 cdr = cdr->next; 04985 } 04986 04987 /* If this CDR is not related to us add new one*/ 04988 if ((strcasecmp(cdr->uniqueid, qe->chan->uniqueid)) && 04989 (strcasecmp(cdr->linkedid, qe->chan->uniqueid)) && 04990 (newcdr = ast_cdr_dup(cdr))) { 04991 ast_channel_lock(qe->chan); 04992 ast_cdr_init(newcdr, qe->chan); 04993 ast_cdr_reset(newcdr, 0); 04994 cdr = ast_cdr_append(cdr, newcdr); 04995 cdr = cdr->next; 04996 ast_channel_unlock(qe->chan); 04997 } 04998 04999 if (update_cdr) { 05000 ast_copy_string(cdr->dstchannel, member->membername, sizeof(cdr->dstchannel)); 05001 } 05002 } 05003 05004 if (qe->parent->eventwhencalled) 05005 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 05006 "Queue: %s\r\n" 05007 "Uniqueid: %s\r\n" 05008 "Channel: %s\r\n" 05009 "Member: %s\r\n" 05010 "MemberName: %s\r\n" 05011 "Holdtime: %ld\r\n" 05012 "BridgedChannel: %s\r\n" 05013 "Ringtime: %ld\r\n" 05014 "%s", 05015 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 05016 (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0), 05017 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 05018 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 05019 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 05020 05021 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) { 05022 queue_end_bridge->q = qe->parent; 05023 queue_end_bridge->chan = qe->chan; 05024 bridge_config.end_bridge_callback = end_bridge_callback; 05025 bridge_config.end_bridge_callback_data = queue_end_bridge; 05026 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 05027 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need 05028 * to make sure to increase the refcount of this queue so it cannot be freed until we 05029 * are done with it. We remove this reference in end_bridge_callback. 05030 */ 05031 queue_t_ref(qe->parent, "For bridge_config reference"); 05032 } 05033 05034 time(&callstart); 05035 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl); 05036 bridge = ast_bridge_call(qe->chan,peer, &bridge_config); 05037 05038 /* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log 05039 * when the masquerade occurred. These other "ending" queue_log messages are unnecessary, except for 05040 * the AgentComplete manager event 05041 */ 05042 ast_channel_lock(qe->chan); 05043 if (!attended_transfer_occurred(qe->chan)) { 05044 struct ast_datastore *tds; 05045 05046 /* detect a blind transfer */ 05047 if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) { 05048 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 05049 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 05050 (long) (time(NULL) - callstart), qe->opos); 05051 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER); 05052 } else if (ast_check_hangup(qe->chan)) { 05053 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d", 05054 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 05055 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER); 05056 } else { 05057 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 05058 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 05059 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT); 05060 } 05061 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) { 05062 ast_channel_datastore_remove(qe->chan, tds); 05063 } 05064 ast_channel_unlock(qe->chan); 05065 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart)); 05066 } else { 05067 ast_channel_unlock(qe->chan); 05068 05069 /* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */ 05070 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER); 05071 } 05072 05073 if (transfer_ds) { 05074 ast_datastore_free(transfer_ds); 05075 } 05076 ast_hangup(peer); 05077 res = bridge ? bridge : 1; 05078 ao2_ref(member, -1); 05079 } 05080 out: 05081 hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere); 05082 05083 return res; 05084 }
static int unload_module | ( | void | ) | [static] |
Definition at line 8258 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, device_state_sub, devicestate_tps, 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.
08259 { 08260 int res; 08261 struct ast_context *con; 08262 struct ao2_iterator q_iter; 08263 struct call_queue *q = NULL; 08264 08265 ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue)); 08266 res = ast_manager_unregister("QueueStatus"); 08267 res |= ast_manager_unregister("Queues"); 08268 res |= ast_manager_unregister("QueueRule"); 08269 res |= ast_manager_unregister("QueueSummary"); 08270 res |= ast_manager_unregister("QueueAdd"); 08271 res |= ast_manager_unregister("QueueRemove"); 08272 res |= ast_manager_unregister("QueuePause"); 08273 res |= ast_manager_unregister("QueueLog"); 08274 res |= ast_manager_unregister("QueuePenalty"); 08275 res |= ast_unregister_application(app_aqm); 08276 res |= ast_unregister_application(app_rqm); 08277 res |= ast_unregister_application(app_pqm); 08278 res |= ast_unregister_application(app_upqm); 08279 res |= ast_unregister_application(app_ql); 08280 res |= ast_unregister_application(app); 08281 res |= ast_custom_function_unregister(&queueexists_function); 08282 res |= ast_custom_function_unregister(&queuevar_function); 08283 res |= ast_custom_function_unregister(&queuemembercount_function); 08284 res |= ast_custom_function_unregister(&queuemembercount_dep); 08285 res |= ast_custom_function_unregister(&queuememberlist_function); 08286 res |= ast_custom_function_unregister(&queuewaitingcount_function); 08287 res |= ast_custom_function_unregister(&queuememberpenalty_function); 08288 08289 res |= ast_data_unregister(NULL); 08290 08291 if (device_state_sub) 08292 ast_event_unsubscribe(device_state_sub); 08293 08294 ast_extension_state_del(0, extension_state_cb); 08295 08296 if ((con = ast_context_find("app_queue_gosub_virtual_context"))) { 08297 ast_context_remove_extension2(con, "s", 1, NULL, 0); 08298 ast_context_destroy(con, "app_queue"); /* leave no trace */ 08299 } 08300 08301 q_iter = ao2_iterator_init(queues, 0); 08302 while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) { 08303 queues_t_unlink(queues, q, "Remove queue from container due to unload"); 08304 queue_t_unref(q, "Done with iterator"); 08305 } 08306 ao2_iterator_destroy(&q_iter); 08307 ao2_ref(queues, -1); 08308 devicestate_tps = ast_taskprocessor_unreference(devicestate_tps); 08309 ast_unload_realtime("queue_members"); 08310 return res; 08311 }
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 3883 of file app_queue.c.
References 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, ast_channel::name, pbx_builtin_setvar_helper(), queue_ent::pr, and penalty_rule::time.
Referenced by queue_exec().
03884 { 03885 int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value; 03886 int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value; 03887 char max_penalty_str[20], min_penalty_str[20]; 03888 /* a relative change to the penalty could put it below 0 */ 03889 if (max_penalty < 0) 03890 max_penalty = 0; 03891 if (min_penalty < 0) 03892 min_penalty = 0; 03893 if (min_penalty > max_penalty) 03894 min_penalty = max_penalty; 03895 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty); 03896 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty); 03897 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str); 03898 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str); 03899 qe->max_penalty = max_penalty; 03900 qe->min_penalty = min_penalty; 03901 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, qe->chan->name, qe->pr->time); 03902 qe->pr = AST_LIST_NEXT(qe->pr, list); 03903 }
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 3991 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().
03992 { 03993 int oldtalktime; 03994 03995 struct member *mem; 03996 struct call_queue *qtmp; 03997 struct ao2_iterator queue_iter; 03998 03999 if (shared_lastcall) { 04000 queue_iter = ao2_iterator_init(queues, 0); 04001 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 04002 ao2_lock(qtmp); 04003 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) { 04004 time(&mem->lastcall); 04005 mem->calls++; 04006 mem->lastqueue = q; 04007 ao2_ref(mem, -1); 04008 } 04009 ao2_unlock(qtmp); 04010 queue_t_unref(qtmp, "Done with iterator"); 04011 } 04012 ao2_iterator_destroy(&queue_iter); 04013 } else { 04014 ao2_lock(q); 04015 time(&member->lastcall); 04016 member->calls++; 04017 member->lastqueue = q; 04018 ao2_unlock(q); 04019 } 04020 ao2_lock(q); 04021 q->callscompleted++; 04022 if (callcompletedinsl) 04023 q->callscompletedinsl++; 04024 /* Calculate talktime using the same exponential average as holdtime code*/ 04025 oldtalktime = q->talktime; 04026 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2; 04027 ao2_unlock(q); 04028 return 0; 04029 }
static int update_realtime_member_field | ( | struct member * | mem, | |
const char * | queue_name, | |||
const char * | field, | |||
const char * | value | |||
) | [static] |
Definition at line 2378 of file app_queue.c.
References ast_strlen_zero(), ast_update_realtime(), member::rt_uniqueid, and SENTINEL.
Referenced by set_member_paused().
02379 { 02380 int ret = -1; 02381 02382 if (ast_strlen_zero(mem->rt_uniqueid)) 02383 return ret; 02384 02385 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0) 02386 ret = 0; 02387 02388 return ret; 02389 }
static void update_realtime_members | ( | struct call_queue * | q | ) | [static] |
Definition at line 2392 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_variable_retrieve(), member::dead, member::interface, call_queue::members, call_queue::name, member::realtime, rt_handle_member_record(), S_OR, and SENTINEL.
Referenced by load_realtime_queue(), and queue_exec().
02393 { 02394 struct ast_config *member_config = NULL; 02395 struct member *m; 02396 char *interface = NULL; 02397 struct ao2_iterator mem_iter; 02398 02399 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) { 02400 /*This queue doesn't have realtime members*/ 02401 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name); 02402 return; 02403 } 02404 02405 ao2_lock(q); 02406 02407 /* Temporarily set realtime members dead so we can detect deleted ones.*/ 02408 mem_iter = ao2_iterator_init(q->members, 0); 02409 while ((m = ao2_iterator_next(&mem_iter))) { 02410 if (m->realtime) 02411 m->dead = 1; 02412 ao2_ref(m, -1); 02413 } 02414 ao2_iterator_destroy(&mem_iter); 02415 02416 while ((interface = ast_category_browse(member_config, interface))) { 02417 rt_handle_member_record(q, interface, 02418 ast_variable_retrieve(member_config, interface, "uniqueid"), 02419 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), 02420 ast_variable_retrieve(member_config, interface, "penalty"), 02421 ast_variable_retrieve(member_config, interface, "paused"), 02422 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface)); 02423 } 02424 02425 /* Delete all realtime members that have been deleted in DB. */ 02426 mem_iter = ao2_iterator_init(q->members, 0); 02427 while ((m = ao2_iterator_next(&mem_iter))) { 02428 if (m->dead) { 02429 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 02430 ao2_unlink(q->members, m); 02431 } 02432 ao2_ref(m, -1); 02433 } 02434 ao2_iterator_destroy(&mem_iter); 02435 ao2_unlock(q); 02436 ast_config_destroy(member_config); 02437 }
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 1424 of file app_queue.c.
References EVENT_FLAG_AGENT, and manager_event.
Referenced by extension_state_cb(), handle_statechange(), and ring_entry().
01425 { 01426 m->status = status; 01427 01428 if (q->maskmemberstatus) 01429 return 0; 01430 01431 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 01432 "Queue: %s\r\n" 01433 "Location: %s\r\n" 01434 "MemberName: %s\r\n" 01435 "Membership: %s\r\n" 01436 "Penalty: %d\r\n" 01437 "CallsTaken: %d\r\n" 01438 "LastCall: %d\r\n" 01439 "Status: %d\r\n" 01440 "Paused: %d\r\n", 01441 q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static", 01442 m->penalty, m->calls, (int)m->lastcall, m->status, m->paused 01443 ); 01444 01445 return 0; 01446 }
static int upqm_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
UnPauseQueueMember application.
Definition at line 5558 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().
05559 { 05560 char *parse; 05561 AST_DECLARE_APP_ARGS(args, 05562 AST_APP_ARG(queuename); 05563 AST_APP_ARG(interface); 05564 AST_APP_ARG(options); 05565 AST_APP_ARG(reason); 05566 ); 05567 05568 if (ast_strlen_zero(data)) { 05569 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n"); 05570 return -1; 05571 } 05572 05573 parse = ast_strdupa(data); 05574 05575 AST_STANDARD_APP_ARGS(args, parse); 05576 05577 if (ast_strlen_zero(args.interface)) { 05578 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 05579 return -1; 05580 } 05581 05582 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) { 05583 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 05584 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 05585 return 0; 05586 } 05587 05588 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 05589 05590 return 0; 05591 }
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 2554 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(), and wait_a_bit().
02555 { 02556 int digitlen = strlen(qe->digits); 02557 02558 /* Prevent possible buffer overflow */ 02559 if (digitlen < sizeof(qe->digits) - 2) { 02560 qe->digits[digitlen] = digit; 02561 qe->digits[digitlen + 1] = '\0'; 02562 } else { 02563 qe->digits[0] = '\0'; 02564 return 0; 02565 } 02566 02567 /* If there's no context to goto, short-circuit */ 02568 if (ast_strlen_zero(qe->context)) 02569 return 0; 02570 02571 /* If the extension is bad, then reset the digits to blank */ 02572 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, 02573 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, NULL))) { 02574 qe->digits[0] = '\0'; 02575 return 0; 02576 } 02577 02578 /* We have an exact match */ 02579 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 02580 qe->valid_digits = 1; 02581 /* Return 1 on a successful goto */ 02582 return 1; 02583 } 02584 02585 return 0; 02586 }
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 2942 of file app_queue.c.
References ast_copy_string(), ast_str_buffer(), ast_str_thread_get(), queue_ent::chan, and pbx_builtin_serialize_variables().
Referenced by ring_entry(), rna(), and send_agent_complete().
02943 { 02944 struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1); 02945 const char *tmp; 02946 02947 if (pbx_builtin_serialize_variables(chan, &buf)) { 02948 int i, j; 02949 02950 /* convert "\n" to "\nVariable: " */ 02951 strcpy(vars, "Variable: "); 02952 tmp = ast_str_buffer(buf); 02953 02954 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 02955 vars[j] = tmp[i]; 02956 02957 if (tmp[i + 1] == '\0') 02958 break; 02959 if (tmp[i] == '\n') { 02960 vars[j++] = '\r'; 02961 vars[j++] = '\n'; 02962 02963 ast_copy_string(&(vars[j]), "Variable: ", len - j); 02964 j += 9; 02965 } 02966 } 02967 if (j > len - 3) 02968 j = len - 3; 02969 vars[j++] = '\r'; 02970 vars[j++] = '\n'; 02971 vars[j] = '\0'; 02972 } else { 02973 /* there are no channel variables; leave it blank */ 02974 *vars = '\0'; 02975 } 02976 return vars; 02977 }
static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 5086 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
05087 { 05088 /* Don't need to hold the lock while we setup the outgoing calls */ 05089 int retrywait = qe->parent->retry * 1000; 05090 05091 int res = ast_waitfordigit(qe->chan, retrywait); 05092 if (res > 0 && !valid_exit(qe, res)) 05093 res = 0; 05094 05095 return res; 05096 }
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] |
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 3424 of file app_queue.c.
References ast_channel_lock, ast_channel_unlock, AST_MAX_WATCHERS, ast_party_connected_line_init(), ast_poll_channel_add(), ast_strdupa, callattempt::call_next, callattempt::chan, queue_ent::chan, f, ast_channel::name, call_queue::name, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), starttime, status, callattempt::stillgoing, and call_queue::strategy.
03425 { 03426 const char *queue = qe->parent->name; 03427 struct callattempt *o, *start = NULL, *prev = NULL; 03428 int res; 03429 int status; 03430 int numbusies = prebusies; 03431 int numnochan = 0; 03432 int stillgoing = 0; 03433 int orig = *to; 03434 struct ast_frame *f; 03435 struct callattempt *peer = NULL; 03436 struct ast_channel *winner; 03437 struct ast_channel *in = qe->chan; 03438 char on[80] = ""; 03439 char membername[80] = ""; 03440 long starttime = 0; 03441 long endtime = 0; 03442 #ifdef HAVE_EPOLL 03443 struct callattempt *epollo; 03444 #endif 03445 struct ast_party_connected_line connected_caller; 03446 char *inchan_name; 03447 03448 ast_party_connected_line_init(&connected_caller); 03449 03450 ast_channel_lock(qe->chan); 03451 inchan_name = ast_strdupa(qe->chan->name); 03452 ast_channel_unlock(qe->chan); 03453 03454 starttime = (long) time(NULL); 03455 #ifdef HAVE_EPOLL 03456 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 03457 if (epollo->chan) 03458 ast_poll_channel_add(in, epollo->chan); 03459 } 03460 #endif 03461 03462 while (*to && !peer) { 03463 int numlines, retry, pos = 1; 03464 struct ast_channel *watchers[AST_MAX_WATCHERS]; 03465 watchers[0] = in; 03466 start = NULL; 03467 03468 for (retry = 0; retry < 2; retry++) { 03469 numlines = 0; 03470 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 03471 if (o->stillgoing) { /* Keep track of important channels */ 03472 stillgoing = 1; 03473 if (o->chan) { 03474 if (pos < AST_MAX_WATCHERS) { 03475 watchers[pos++] = o->chan; 03476 } 03477 if (!start) 03478 start = o; 03479 else 03480 prev->call_next = o; 03481 prev = o; 03482 } 03483 } 03484 numlines++; 03485 } 03486 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 03487 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 03488 break; 03489 /* On "ringall" strategy we only move to the next penalty level 03490 when *all* ringing phones are done in the current penalty level */ 03491 ring_one(qe, outgoing, &numbusies); 03492 /* and retry... */ 03493 } 03494 if (pos == 1 /* not found */) { 03495 if (numlines == (numbusies + numnochan)) { 03496 ast_debug(1, "Everyone is busy at this time\n"); 03497 } else { 03498 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan); 03499 } 03500 *to = 0; 03501 return NULL; 03502 } 03503 03504 /* Poll for events from both the incoming channel as well as any outgoing channels */ 03505 winner = ast_waitfor_n(watchers, pos, to); 03506 03507 /* Service all of the outgoing channels */ 03508 for (o = start; o; o = o->call_next) { 03509 /* We go with a static buffer here instead of using ast_strdupa. Using 03510 * ast_strdupa in a loop like this one can cause a stack overflow 03511 */ 03512 char ochan_name[AST_CHANNEL_NAME]; 03513 if (o->chan) { 03514 ast_channel_lock(o->chan); 03515 ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name)); 03516 ast_channel_unlock(o->chan); 03517 } 03518 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 03519 if (!peer) { 03520 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); 03521 if (update_connectedline) { 03522 if (o->pending_connected_update) { 03523 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { 03524 ast_channel_update_connected_line(in, &o->connected, NULL); 03525 } 03526 } else if (!o->dial_callerid_absent) { 03527 ast_channel_lock(o->chan); 03528 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller); 03529 ast_channel_unlock(o->chan); 03530 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 03531 ast_channel_update_connected_line(in, &connected_caller, NULL); 03532 ast_party_connected_line_free(&connected_caller); 03533 } 03534 } 03535 if (o->aoc_s_rate_list) { 03536 size_t encoded_size; 03537 struct ast_aoc_encoded *encoded; 03538 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) { 03539 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size); 03540 ast_aoc_destroy_encoded(encoded); 03541 } 03542 } 03543 peer = o; 03544 } 03545 } else if (o->chan && (o->chan == winner)) { 03546 03547 ast_copy_string(on, o->member->interface, sizeof(on)); 03548 ast_copy_string(membername, o->member->membername, sizeof(membername)); 03549 03550 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { 03551 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward); 03552 numnochan++; 03553 do_hang(o); 03554 winner = NULL; 03555 continue; 03556 } else if (!ast_strlen_zero(o->chan->call_forward)) { 03557 struct ast_channel *original = o->chan; 03558 char tmpchan[256]; 03559 char *stuff; 03560 char *tech; 03561 03562 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 03563 if ((stuff = strchr(tmpchan, '/'))) { 03564 *stuff++ = '\0'; 03565 tech = tmpchan; 03566 } else { 03567 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 03568 stuff = tmpchan; 03569 tech = "Local"; 03570 } 03571 03572 ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL); 03573 03574 /* Before processing channel, go ahead and check for forwarding */ 03575 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name); 03576 /* Setup parameters */ 03577 o->chan = ast_request(tech, in->nativeformats, in, stuff, &status); 03578 if (!o->chan) { 03579 ast_log(LOG_NOTICE, 03580 "Forwarding failed to create channel to dial '%s/%s'\n", 03581 tech, stuff); 03582 o->stillgoing = 0; 03583 numnochan++; 03584 } else { 03585 struct ast_party_redirecting redirecting; 03586 03587 ast_channel_lock_both(o->chan, in); 03588 ast_channel_inherit_variables(in, o->chan); 03589 ast_channel_datastore_inherit(in, o->chan); 03590 03591 ast_string_field_set(o->chan, accountcode, in->accountcode); 03592 03593 ast_channel_set_redirecting(o->chan, &original->redirecting, NULL); 03594 if (!o->chan->redirecting.from.number.valid 03595 || ast_strlen_zero(o->chan->redirecting.from.number.str)) { 03596 /* 03597 * The call was not previously redirected so it is 03598 * now redirected from this number. 03599 */ 03600 ast_party_number_free(&o->chan->redirecting.from.number); 03601 ast_party_number_init(&o->chan->redirecting.from.number); 03602 o->chan->redirecting.from.number.valid = 1; 03603 o->chan->redirecting.from.number.str = 03604 ast_strdup(S_OR(in->macroexten, in->exten)); 03605 } 03606 03607 o->chan->dialed.transit_network_select = in->dialed.transit_network_select; 03608 03609 ast_party_caller_copy(&o->chan->caller, &in->caller); 03610 ast_party_connected_line_copy(&o->chan->connected, &original->connected); 03611 03612 /* 03613 * We must unlock o->chan before calling 03614 * ast_channel_redirecting_macro, because we put o->chan into 03615 * autoservice there. That is pretty much a guaranteed 03616 * deadlock. This is why the handling of o->chan's lock may 03617 * seem a bit unusual here. 03618 */ 03619 ast_party_redirecting_init(&redirecting); 03620 ast_party_redirecting_copy(&redirecting, &o->chan->redirecting); 03621 ast_channel_unlock(o->chan); 03622 res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0); 03623 if (res) { 03624 ast_channel_update_redirecting(in, &redirecting, NULL); 03625 } 03626 ast_party_redirecting_free(&redirecting); 03627 ast_channel_unlock(in); 03628 03629 update_connectedline = 1; 03630 03631 if (ast_call(o->chan, stuff, 0)) { 03632 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n", 03633 tech, stuff); 03634 do_hang(o); 03635 numnochan++; 03636 } 03637 } 03638 /* Hangup the original channel now, in case we needed it */ 03639 ast_hangup(winner); 03640 continue; 03641 } 03642 f = ast_read(winner); 03643 if (f) { 03644 if (f->frametype == AST_FRAME_CONTROL) { 03645 switch (f->subclass.integer) { 03646 case AST_CONTROL_ANSWER: 03647 /* This is our guy if someone answered. */ 03648 if (!peer) { 03649 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name); 03650 if (update_connectedline) { 03651 if (o->pending_connected_update) { 03652 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) { 03653 ast_channel_update_connected_line(in, &o->connected, NULL); 03654 } 03655 } else if (!o->dial_callerid_absent) { 03656 ast_channel_lock(o->chan); 03657 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller); 03658 ast_channel_unlock(o->chan); 03659 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 03660 ast_channel_update_connected_line(in, &connected_caller, NULL); 03661 ast_party_connected_line_free(&connected_caller); 03662 } 03663 } 03664 if (o->aoc_s_rate_list) { 03665 size_t encoded_size; 03666 struct ast_aoc_encoded *encoded; 03667 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) { 03668 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size); 03669 ast_aoc_destroy_encoded(encoded); 03670 } 03671 } 03672 peer = o; 03673 } 03674 break; 03675 case AST_CONTROL_BUSY: 03676 ast_verb(3, "%s is busy\n", ochan_name); 03677 if (in->cdr) 03678 ast_cdr_busy(in->cdr); 03679 do_hang(o); 03680 endtime = (long) time(NULL); 03681 endtime -= starttime; 03682 rna(endtime * 1000, qe, on, membername, 0); 03683 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03684 if (qe->parent->timeoutrestart) 03685 *to = orig; 03686 /* Have enough time for a queue member to answer? */ 03687 if (*to > 500) { 03688 ring_one(qe, outgoing, &numbusies); 03689 starttime = (long) time(NULL); 03690 } 03691 } 03692 numbusies++; 03693 break; 03694 case AST_CONTROL_CONGESTION: 03695 ast_verb(3, "%s is circuit-busy\n", ochan_name); 03696 if (in->cdr) 03697 ast_cdr_busy(in->cdr); 03698 endtime = (long) time(NULL); 03699 endtime -= starttime; 03700 rna(endtime * 1000, qe, on, membername, 0); 03701 do_hang(o); 03702 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03703 if (qe->parent->timeoutrestart) 03704 *to = orig; 03705 if (*to > 500) { 03706 ring_one(qe, outgoing, &numbusies); 03707 starttime = (long) time(NULL); 03708 } 03709 } 03710 numbusies++; 03711 break; 03712 case AST_CONTROL_RINGING: 03713 ast_verb(3, "%s is ringing\n", ochan_name); 03714 03715 /* Start ring indication when the channel is ringing, if specified */ 03716 if (qe->ring_when_ringing) { 03717 ast_moh_stop(qe->chan); 03718 ast_indicate(qe->chan, AST_CONTROL_RINGING); 03719 } 03720 break; 03721 case AST_CONTROL_OFFHOOK: 03722 /* Ignore going off hook */ 03723 break; 03724 case AST_CONTROL_CONNECTED_LINE: 03725 if (!update_connectedline) { 03726 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name); 03727 } else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 03728 struct ast_party_connected_line connected; 03729 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name); 03730 ast_party_connected_line_set_init(&connected, &o->connected); 03731 ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected); 03732 ast_party_connected_line_set(&o->connected, &connected, NULL); 03733 ast_party_connected_line_free(&connected); 03734 o->pending_connected_update = 1; 03735 } else { 03736 if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) { 03737 ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); 03738 } 03739 } 03740 break; 03741 case AST_CONTROL_AOC: 03742 { 03743 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan); 03744 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) { 03745 ast_aoc_destroy_decoded(o->aoc_s_rate_list); 03746 o->aoc_s_rate_list = decoded; 03747 } else { 03748 ast_aoc_destroy_decoded(decoded); 03749 } 03750 } 03751 break; 03752 case AST_CONTROL_REDIRECTING: 03753 if (!update_connectedline) { 03754 ast_verb(3, "Redirecting update to %s prevented\n", inchan_name); 03755 } else if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03756 ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name); 03757 if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) { 03758 ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); 03759 } 03760 } 03761 break; 03762 default: 03763 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer); 03764 break; 03765 } 03766 } 03767 ast_frfree(f); 03768 } else { /* ast_read() returned NULL */ 03769 endtime = (long) time(NULL) - starttime; 03770 rna(endtime * 1000, qe, on, membername, 1); 03771 do_hang(o); 03772 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 03773 if (qe->parent->timeoutrestart) 03774 *to = orig; 03775 if (*to > 500) { 03776 ring_one(qe, outgoing, &numbusies); 03777 starttime = (long) time(NULL); 03778 } 03779 } 03780 } 03781 } 03782 } 03783 03784 /* If we received an event from the caller, deal with it. */ 03785 if (winner == in) { 03786 f = ast_read(in); 03787 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) { 03788 /* Got hung up */ 03789 *to = -1; 03790 if (f) { 03791 if (f->data.uint32) { 03792 in->hangupcause = f->data.uint32; 03793 } 03794 ast_frfree(f); 03795 } 03796 return NULL; 03797 } 03798 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) { 03799 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer); 03800 *to = 0; 03801 ast_frfree(f); 03802 return NULL; 03803 } 03804 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) { 03805 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer); 03806 *to = 0; 03807 *digit = f->subclass.integer; 03808 ast_frfree(f); 03809 return NULL; 03810 } 03811 ast_frfree(f); 03812 } 03813 if (!*to) { 03814 for (o = start; o; o = o->call_next) 03815 rna(orig, qe, o->interface, o->member->membername, 1); 03816 } 03817 } 03818 03819 #ifdef HAVE_EPOLL 03820 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 03821 if (epollo->chan) 03822 ast_poll_channel_del(in, epollo->chan); 03823 } 03824 #endif 03825 03826 return peer; 03827 }
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 3915 of file app_queue.c.
References ast_queue_log(), queue_ent::chan, 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, queue_ent::pos, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, queue_ent::start, status, and ast_channel::uniqueid.
Referenced by queue_exec().
03916 { 03917 int res = 0; 03918 03919 /* This is the holding pen for callers 2 through maxlen */ 03920 for (;;) { 03921 03922 if (is_our_turn(qe)) 03923 break; 03924 03925 /* If we have timed out, break out */ 03926 if (qe->expire && (time(NULL) >= qe->expire)) { 03927 *reason = QUEUE_TIMEOUT; 03928 break; 03929 } 03930 03931 if (qe->parent->leavewhenempty) { 03932 int status = 0; 03933 03934 if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty))) { 03935 *reason = QUEUE_LEAVEEMPTY; 03936 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 03937 leave_queue(qe); 03938 break; 03939 } 03940 } 03941 03942 /* Make a position announcement, if enabled */ 03943 if (qe->parent->announcefrequency && 03944 (res = say_position(qe,ringing))) 03945 break; 03946 03947 /* If we have timed out, break out */ 03948 if (qe->expire && (time(NULL) >= qe->expire)) { 03949 *reason = QUEUE_TIMEOUT; 03950 break; 03951 } 03952 03953 /* Make a periodic announcement, if enabled */ 03954 if (qe->parent->periodicannouncefrequency && 03955 (res = say_periodic_announcement(qe,ringing))) 03956 break; 03957 03958 /* see if we need to move to the next penalty level for this queue */ 03959 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) { 03960 update_qe_rule(qe); 03961 } 03962 03963 /* If we have timed out, break out */ 03964 if (qe->expire && (time(NULL) >= qe->expire)) { 03965 *reason = QUEUE_TIMEOUT; 03966 break; 03967 } 03968 03969 /* Wait a second before checking again */ 03970 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 03971 if (res > 0 && !valid_exit(qe, res)) 03972 res = 0; 03973 else 03974 break; 03975 } 03976 03977 /* If we have timed out, break out */ 03978 if (qe->expire && (time(NULL) >= qe->expire)) { 03979 *reason = QUEUE_TIMEOUT; 03980 break; 03981 } 03982 } 03983 03984 return res; 03985 }
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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, .nonoptreq = "res_monitor", } [static] |
Definition at line 8393 of file app_queue.c.
char* app = "Queue" [static] |
Definition at line 901 of file app_queue.c.
char* app_aqm = "AddQueueMember" [static] |
Definition at line 903 of file app_queue.c.
char* app_pqm = "PauseQueueMember" [static] |
Definition at line 907 of file app_queue.c.
char* app_ql = "QueueLog" [static] |
Definition at line 911 of file app_queue.c.
char* app_rqm = "RemoveQueueMember" [static] |
Definition at line 905 of file app_queue.c.
char* app_upqm = "UnpauseQueueMember" [static] |
Definition at line 909 of file app_queue.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 8393 of file app_queue.c.
int autofill_default = 1 [static] |
struct autopause autopausesmodes[] [static] |
Referenced by autopause2int().
struct ast_cli_entry cli_queue[] [static] |
struct ast_event_sub* device_state_sub [static] |
Subscription to device state change events.
Definition at line 934 of file app_queue.c.
Referenced by aji_init_event_distribution(), load_module(), load_pbx(), and unload_module().
struct ast_taskprocessor* devicestate_tps [static] |
Definition at line 885 of file app_queue.c.
Referenced by device_state_cb(), load_module(), and unload_module().
enum queue_result id |
Definition at line 951 of file app_queue.c.
Referenced by _sip_show_peers(), _skinny_show_devices(), _skinny_show_lines(), amixer_max(), ast_cc_extension_monitor_add_dialstring(), ast_party_id_presentation(), frame_trace_helper(), idemodulator(), misdn_queue_connected_line_update(), misdn_update_caller_id(), party_id_build_data(), party_id_read(), party_id_write(), pidf_validate_tuple(), and setamixer().
int montype_default = 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 7968 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 7974 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 8254 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 4166 of file app_queue.c.
Referenced by attended_transfer_occurred(), queue_transfer_fixup(), and setup_transfer_datastore().
struct ast_custom_function queueexists_function [static] |
Initial value:
{ .name = "QUEUE_EXISTS", .read = queue_function_exists, }
Definition at line 6417 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 6432 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_qac, }
Definition at line 6427 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 6442 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 6447 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ao2_container* queues [static] |
Definition at line 1186 of file app_queue.c.
Referenced by __queues_show(), clear_stats(), compare_weight(), complete_queue(), complete_queue_remove_member(), extension_state_cb(), find_queue_by_name_rt(), get_member_penalty(), handle_statechange(), leave_queue(), load_module(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), queues_data_provider_get(), reload_queue_members(), reload_queues(), reload_single_queue(), remove_from_queue(), set_member_paused(), set_member_penalty(), unload_module(), and update_queue().
struct ast_data_handler queues_data_provider [static] |
Initial value:
{ .version = AST_DATA_HANDLER_VERSION, .get = queues_data_provider_get }
Definition at line 8249 of file app_queue.c.
struct ast_custom_function queuevar_function [static] |
Initial value:
{ .name = "QUEUE_VARIABLES", .read = queue_function_var, }
Definition at line 6422 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 6437 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 7971 of file app_queue.c.
int shared_lastcall = 1 [static] |
struct strategy strategies[] [static] |
Referenced by int2strat(), and strat2int().
char* text |
Definition at line 952 of file app_queue.c.
Referenced by festival_exec(), iconv_read(), method_match(), parse_sip_options(), process_sdp(), reqprep(), set_queue_result(), and sip_new().
int update_cdr = 0 [static] |
queues.conf [general] option
Definition at line 937 of file app_queue.c.
Referenced by login_exec().
int use_weight = 0 [static] |