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