#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"
Go to the source code of this file.
Data Structures | |
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 | interfaces |
struct | member |
struct | member_interface |
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 | 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_EMPTY_LOOSE 3 |
#define | QUEUE_EMPTY_NORMAL 1 |
#define | QUEUE_EMPTY_STRICT 2 |
#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 } |
enum | agent_complete_reason { CALLER, AGENT, TRANSFER } |
enum | queue_member_status { QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, QUEUE_NORMAL } |
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, char **argv) |
Show queue(s) status and statistics. | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | add_to_interfaces (const char *interface) |
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, void *data) |
AddQueueMember application. | |
static int | attended_transfer_occurred (struct ast_channel *chan) |
mechanism to tell if a queue caller was atxferred by a queue member. | |
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 | clear_and_free_interfaces (void) |
static void | clear_queue (struct call_queue *q) |
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 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 enum queue_member_status | get_member_status (struct call_queue *q, int max_penalty, int min_penalty) |
Check if members are available. | |
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_remove_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_queue_rule_reload (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) |
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 | interface_exists_global (const char *interface, int lock_queue_container) |
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, const char *overriding_rule) |
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_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 | 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 int | play_file (struct ast_channel *chan, const char *filename) |
static int | pqm_exec (struct ast_channel *chan, void *data) |
PauseQueueMember application. | |
static int | ql_exec (struct ast_channel *chan, void *data) |
QueueLog application. | |
static int | queue_cmp_cb (void *obj, void *arg, int flags) |
static int | queue_exec (struct ast_channel *chan, void *data) |
The starting point for all queue calls. | |
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 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_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 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 void | reload_queue_members (void) |
Reload dynamic queue members persisted into the astdb. | |
static int | reload_queue_rules (int reload) |
static int | reload_queues (int reload) |
static int | remove_from_interfaces (const char *interface, int lock_queue_container) |
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, void *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 peroid 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 (char *queuename, 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) |
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 (const char *interface, 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, void *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_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } |
static char * | app = "Queue" |
static char * | app_aqm = "AddQueueMember" |
static char * | app_aqm_descrip |
static char * | app_aqm_synopsis = "Dynamically adds queue members" |
static char * | app_pqm = "PauseQueueMember" |
static char * | app_pqm_descrip |
static char * | app_pqm_synopsis = "Pauses a queue member" |
static char * | app_ql = "QueueLog" |
static char * | app_ql_descrip |
static char * | app_ql_synopsis = "Writes to the queue_log" |
static char * | app_rqm = "RemoveQueueMember" |
static char * | app_rqm_descrip |
static char * | app_rqm_synopsis = "Dynamically removes queue members" |
static char * | app_upqm = "UnpauseQueueMember" |
static char * | app_upqm_descrip |
static char * | app_upqm_synopsis = "Unpauses a queue member" |
static struct ast_module_info * | ast_module_info = &__mod_info |
static int | autofill_default = 0 |
queues.conf [general] option | |
static struct ast_cli_entry | cli_queue [] |
static char * | descrip |
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 * | pm_family = "Queue/PersistentMembers" |
Persistent Members astdb family. | |
static const char | qpm_cmd_usage [] |
static const char | qsmp_cmd_usage [] |
static int | queue_keep_stats = 0 |
queues.conf [general] option | |
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 | 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_custom_function | queuevar_function |
static struct ast_custom_function | queuewaitingcount_function |
static const char | qum_cmd_usage [] |
static int | shared_lastcall = 0 |
queues.conf [general] option | |
static struct strategy | strategies [] |
static char * | synopsis = "Queue a call for a call queue" |
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 436 of file app_queue.c.
Referenced by queue_set_param(), and say_position().
#define ANNOUNCEPOSITION_MORE_THAN 3 |
We say "Currently there are more than <limit>"
Definition at line 435 of file app_queue.c.
Referenced by queue_set_param(), and say_position().
#define ANNOUNCEPOSITION_NO 2 |
We don't announce position
Definition at line 434 of file app_queue.c.
Referenced by queue_set_param().
#define ANNOUNCEPOSITION_YES 1 |
We announce position
Definition at line 433 of file app_queue.c.
Referenced by init_queue(), queue_set_param(), and say_position().
#define AST_MAX_WATCHERS 256 |
Definition at line 2615 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 144 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 143 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 282 of file app_queue.c.
Referenced by dump_queue_members(), and reload_queue_members().
#define QUEUE_EMPTY_LOOSE 3 |
Definition at line 419 of file app_queue.c.
Referenced by join_queue(), queue_exec(), queue_set_param(), and wait_our_turn().
#define QUEUE_EMPTY_NORMAL 1 |
#define QUEUE_EMPTY_STRICT 2 |
Definition at line 418 of file app_queue.c.
Referenced by join_queue(), queue_exec(), queue_set_param(), and wait_our_turn().
#define QUEUE_EVENT_VARIABLES 3 |
Definition at line 422 of file app_queue.c.
Referenced by queue_set_param(), ring_entry(), 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 614 of file app_queue.c.
Referenced by __queues_show(), compare_weight(), complete_queue(), complete_queue_remove_member(), end_bridge_callback(), find_queue_by_name_rt(), get_member_penalty(), interface_exists_global(), leave_queue(), manager_queues_status(), manager_queues_summary(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), reload_queue_members(), reload_queues(), remove_from_queue(), set_member_paused(), set_member_penalty(), unload_module(), and update_status().
#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) |
Definition at line 616 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 142 of file app_queue.c.
Referenced by wait_our_turn().
#define RES_EXISTS (-1) |
Entry already exists
Definition at line 149 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 151 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 152 of file app_queue.c.
Referenced by handle_queue_add_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
#define RES_OKAY 0 |
Action completed
Definition at line 148 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 150 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 |
Definition at line 114 of file app_queue.c.
00114 { 00115 QUEUE_STRATEGY_RINGALL = 0, 00116 QUEUE_STRATEGY_LEASTRECENT, 00117 QUEUE_STRATEGY_FEWESTCALLS, 00118 QUEUE_STRATEGY_RANDOM, 00119 QUEUE_STRATEGY_RRMEMORY, 00120 QUEUE_STRATEGY_LINEAR, 00121 QUEUE_STRATEGY_WRANDOM 00122 };
enum queue_member_status |
QUEUE_NO_MEMBERS | |
QUEUE_NO_REACHABLE_MEMBERS | |
QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS | |
QUEUE_NORMAL |
Definition at line 674 of file app_queue.c.
00674 { 00675 QUEUE_NO_MEMBERS, 00676 QUEUE_NO_REACHABLE_MEMBERS, 00677 QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, 00678 QUEUE_NORMAL 00679 };
enum queue_result |
QUEUE_UNKNOWN | |
QUEUE_TIMEOUT | |
QUEUE_JOINEMPTY | |
QUEUE_LEAVEEMPTY | |
QUEUE_JOINUNAVAIL | |
QUEUE_LEAVEUNAVAIL | |
QUEUE_FULL | |
QUEUE_CONTINUE |
Definition at line 308 of file app_queue.c.
00308 { 00309 QUEUE_UNKNOWN = 0, 00310 QUEUE_TIMEOUT = 1, 00311 QUEUE_JOINEMPTY = 2, 00312 QUEUE_LEAVEEMPTY = 3, 00313 QUEUE_JOINUNAVAIL = 4, 00314 QUEUE_LEAVEUNAVAIL = 5, 00315 QUEUE_FULL = 6, 00316 QUEUE_CONTINUE = 7, 00317 };
Definition at line 333 of file app_queue.c.
00333 { 00334 TIMEOUT_PRIORITY_APP, 00335 TIMEOUT_PRIORITY_CONF, 00336 };
static char* __queues_show | ( | struct mansession * | s, | |
int | fd, | |||
int | argc, | |||
char ** | 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 5798 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_load_realtime_multientry(), ast_str_alloca, ast_str_append(), 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, devstate2str(), 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, s, SENTINEL, call_queue::servicelevel, queue_ent::start, member::status, ast_str::str, call_queue::strategy, and call_queue::weight.
Referenced by manager_queues_show(), and queue_show().
05799 { 05800 struct call_queue *q; 05801 struct ast_str *out = ast_str_alloca(240); 05802 int found = 0; 05803 time_t now = time(NULL); 05804 struct ao2_iterator queue_iter; 05805 struct ao2_iterator mem_iter; 05806 05807 if (argc != 2 && argc != 3) 05808 return CLI_SHOWUSAGE; 05809 05810 if (argc == 3) { /* specific queue */ 05811 if ((q = load_realtime_queue(argv[2]))) { 05812 queue_t_unref(q, "Expiring queue loaded from realtime"); 05813 } 05814 } else if (ast_check_realtime("queues")) { 05815 /* This block is to find any queues which are defined in realtime but 05816 * which have not yet been added to the in-core container 05817 */ 05818 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 05819 char *queuename; 05820 if (cfg) { 05821 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { 05822 if ((q = load_realtime_queue(queuename))) { 05823 queue_t_unref(q, "Expiring queue loaded from realtime"); 05824 } 05825 } 05826 ast_config_destroy(cfg); 05827 } 05828 } 05829 05830 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); 05831 ao2_lock(queues); 05832 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 05833 float sl; 05834 struct call_queue *realtime_queue = NULL; 05835 05836 ao2_lock(q); 05837 /* This check is to make sure we don't print information for realtime 05838 * queues which have been deleted from realtime but which have not yet 05839 * been deleted from the in-core container 05840 */ 05841 if (q->realtime && !(realtime_queue = load_realtime_queue(q->name))) { 05842 ao2_unlock(q); 05843 queue_t_unref(q, "Done with iterator"); 05844 continue; 05845 } else if (q->realtime) { 05846 queue_t_unref(realtime_queue, "Expire queue loaded from realtime"); 05847 } 05848 if (argc == 3 && strcasecmp(q->name, argv[2])) { 05849 ao2_unlock(q); 05850 queue_t_unref(q, "Done with iterator"); 05851 continue; 05852 } 05853 found = 1; 05854 05855 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count); 05856 if (q->maxlen) 05857 ast_str_append(&out, 0, "%d", q->maxlen); 05858 else 05859 ast_str_append(&out, 0, "unlimited"); 05860 sl = 0; 05861 if (q->callscompleted > 0) 05862 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 05863 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds", 05864 int2strat(q->strategy), q->holdtime, q->weight, 05865 q->callscompleted, q->callsabandoned,sl,q->servicelevel); 05866 do_print(s, fd, out->str); 05867 if (!ao2_container_count(q->members)) 05868 do_print(s, fd, " No Members"); 05869 else { 05870 struct member *mem; 05871 05872 do_print(s, fd, " Members: "); 05873 mem_iter = ao2_iterator_init(q->members, 0); 05874 while ((mem = ao2_iterator_next(&mem_iter))) { 05875 ast_str_set(&out, 0, " %s", mem->membername); 05876 if (strcasecmp(mem->membername, mem->interface)) { 05877 ast_str_append(&out, 0, " (%s)", mem->interface); 05878 } 05879 if (mem->penalty) 05880 ast_str_append(&out, 0, " with penalty %d", mem->penalty); 05881 ast_str_append(&out, 0, "%s%s%s (%s)", 05882 mem->dynamic ? " (dynamic)" : "", 05883 mem->realtime ? " (realtime)" : "", 05884 mem->paused ? " (paused)" : "", 05885 devstate2str(mem->status)); 05886 if (mem->calls) 05887 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)", 05888 mem->calls, (long) (time(NULL) - mem->lastcall)); 05889 else 05890 ast_str_append(&out, 0, " has taken no calls yet"); 05891 do_print(s, fd, out->str); 05892 ao2_ref(mem, -1); 05893 } 05894 ao2_iterator_destroy(&mem_iter); 05895 } 05896 if (!q->head) 05897 do_print(s, fd, " No Callers"); 05898 else { 05899 struct queue_ent *qe; 05900 int pos = 1; 05901 05902 do_print(s, fd, " Callers: "); 05903 for (qe = q->head; qe; qe = qe->next) { 05904 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)", 05905 pos++, qe->chan->name, (long) (now - qe->start) / 60, 05906 (long) (now - qe->start) % 60, qe->prio); 05907 do_print(s, fd, out->str); 05908 } 05909 } 05910 do_print(s, fd, ""); /* blank line between entries */ 05911 ao2_unlock(q); 05912 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */ 05913 } 05914 ao2_iterator_destroy(&queue_iter); 05915 ao2_unlock(queues); 05916 if (!found) { 05917 if (argc == 3) 05918 ast_str_set(&out, 0, "No such queue: %s.", argv[2]); 05919 else 05920 ast_str_set(&out, 0, "No queues."); 05921 do_print(s, fd, out->str); 05922 } 05923 return CLI_SUCCESS; 05924 }
static void __reg_module | ( | void | ) | [static] |
Definition at line 6868 of file app_queue.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 6868 of file app_queue.c.
static int add_to_interfaces | ( | const char * | interface | ) | [static] |
Definition at line 983 of file app_queue.c.
References ast_calloc, ast_copy_string(), ast_debug, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, member_interface::interface, and member_interface::list.
Referenced by add_to_queue(), reload_queues(), and rt_handle_member_record().
00984 { 00985 struct member_interface *curint; 00986 00987 AST_LIST_LOCK(&interfaces); 00988 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00989 if (!strcasecmp(curint->interface, interface)) 00990 break; 00991 } 00992 00993 if (curint) { 00994 AST_LIST_UNLOCK(&interfaces); 00995 return 0; 00996 } 00997 00998 ast_debug(1, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface); 00999 01000 if ((curint = ast_calloc(1, sizeof(*curint)))) { 01001 ast_copy_string(curint->interface, interface, sizeof(curint->interface)); 01002 AST_LIST_INSERT_HEAD(&interfaces, curint, list); 01003 } 01004 AST_LIST_UNLOCK(&interfaces); 01005 01006 return 0; 01007 }
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 4255 of file app_queue.c.
References add_to_interfaces(), 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, call_queue::membercount, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, queues, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, member::state_interface, and member::status.
Referenced by aqm_exec(), handle_queue_add_member(), manager_add_queue_member(), and reload_queue_members().
04256 { 04257 struct call_queue *q; 04258 struct member *new_member, *old_member; 04259 int res = RES_NOSUCHQUEUE; 04260 04261 /*! \note Ensure the appropriate realtime queue is loaded. Note that this 04262 * short-circuits if the queue is already in memory. */ 04263 if (!(q = load_realtime_queue(queuename))) 04264 return res; 04265 04266 ao2_lock(queues); 04267 04268 ao2_lock(q); 04269 if ((old_member = interface_exists(q, interface)) == NULL) { 04270 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { 04271 add_to_interfaces(new_member->state_interface); 04272 new_member->dynamic = 1; 04273 ao2_link(q->members, new_member); 04274 q->membercount++; 04275 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 04276 "Queue: %s\r\n" 04277 "Location: %s\r\n" 04278 "MemberName: %s\r\n" 04279 "Membership: %s\r\n" 04280 "Penalty: %d\r\n" 04281 "CallsTaken: %d\r\n" 04282 "LastCall: %d\r\n" 04283 "Status: %d\r\n" 04284 "Paused: %d\r\n", 04285 q->name, new_member->interface, new_member->membername, 04286 "dynamic", 04287 new_member->penalty, new_member->calls, (int) new_member->lastcall, 04288 new_member->status, new_member->paused); 04289 04290 ao2_ref(new_member, -1); 04291 new_member = NULL; 04292 04293 if (dump) 04294 dump_queue_members(q); 04295 04296 res = RES_OKAY; 04297 } else { 04298 res = RES_OUTOFMEMORY; 04299 } 04300 } else { 04301 ao2_ref(old_member, -1); 04302 res = RES_EXISTS; 04303 } 04304 ao2_unlock(q); 04305 ao2_unlock(queues); 04306 04307 return res; 04308 }
static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static] |
Definition at line 1466 of file app_queue.c.
References ao2_t_alloc, ao2_t_ref, ast_string_field_init, ast_string_field_set, and destroy_queue().
Referenced by find_queue_by_name_rt(), and reload_queues().
01467 { 01468 struct call_queue *q; 01469 01470 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) { 01471 if (ast_string_field_init(q, 64)) { 01472 ao2_t_ref(q, -1, "String field allocation failed"); 01473 return NULL; 01474 } 01475 ast_string_field_set(q, name, queuename); 01476 } 01477 return q; 01478 }
static int aqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
AddQueueMember application.
Definition at line 4692 of file app_queue.c.
References add_to_queue(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), chan, 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().
04693 { 04694 int res=-1; 04695 char *parse, *temppos = NULL; 04696 AST_DECLARE_APP_ARGS(args, 04697 AST_APP_ARG(queuename); 04698 AST_APP_ARG(interface); 04699 AST_APP_ARG(penalty); 04700 AST_APP_ARG(options); 04701 AST_APP_ARG(membername); 04702 AST_APP_ARG(state_interface); 04703 ); 04704 int penalty = 0; 04705 04706 if (ast_strlen_zero(data)) { 04707 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n"); 04708 return -1; 04709 } 04710 04711 parse = ast_strdupa(data); 04712 04713 AST_STANDARD_APP_ARGS(args, parse); 04714 04715 if (ast_strlen_zero(args.interface)) { 04716 args.interface = ast_strdupa(chan->name); 04717 temppos = strrchr(args.interface, '-'); 04718 if (temppos) 04719 *temppos = '\0'; 04720 } 04721 04722 if (!ast_strlen_zero(args.penalty)) { 04723 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) { 04724 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 04725 penalty = 0; 04726 } 04727 } 04728 04729 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { 04730 case RES_OKAY: 04731 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 04732 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 04733 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 04734 res = 0; 04735 break; 04736 case RES_EXISTS: 04737 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 04738 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 04739 res = 0; 04740 break; 04741 case RES_NOSUCHQUEUE: 04742 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 04743 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 04744 res = 0; 04745 break; 04746 case RES_OUTOFMEMORY: 04747 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 04748 break; 04749 } 04750 04751 return res; 04752 }
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 3289 of file app_queue.c.
References ast_channel_datastore_find(), chan, and queue_transfer_info.
03290 { 03291 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1; 03292 }
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 3128 of file app_queue.c.
References ast_log(), ast_random(), member::calls, member::lastcall, queue_ent::linpos, queue_ent::linwrapped, LOG_WARNING, queue_ent::max_penalty, callattempt::metric, queue_ent::min_penalty, member::penalty, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_RRMEMORY, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.
Referenced by try_calling().
03129 { 03130 if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || (qe->min_penalty && (mem->penalty < qe->min_penalty))) 03131 return -1; 03132 03133 switch (q->strategy) { 03134 case QUEUE_STRATEGY_RINGALL: 03135 /* Everyone equal, except for penalty */ 03136 tmp->metric = mem->penalty * 1000000; 03137 break; 03138 case QUEUE_STRATEGY_LINEAR: 03139 if (pos < qe->linpos) { 03140 tmp->metric = 1000 + pos; 03141 } else { 03142 if (pos > qe->linpos) 03143 /* Indicate there is another priority */ 03144 qe->linwrapped = 1; 03145 tmp->metric = pos; 03146 } 03147 tmp->metric += mem->penalty * 1000000; 03148 break; 03149 case QUEUE_STRATEGY_RRMEMORY: 03150 if (pos < q->rrpos) { 03151 tmp->metric = 1000 + pos; 03152 } else { 03153 if (pos > q->rrpos) 03154 /* Indicate there is another priority */ 03155 q->wrapped = 1; 03156 tmp->metric = pos; 03157 } 03158 tmp->metric += mem->penalty * 1000000; 03159 break; 03160 case QUEUE_STRATEGY_RANDOM: 03161 tmp->metric = ast_random() % 1000; 03162 tmp->metric += mem->penalty * 1000000; 03163 break; 03164 case QUEUE_STRATEGY_WRANDOM: 03165 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000); 03166 break; 03167 case QUEUE_STRATEGY_FEWESTCALLS: 03168 tmp->metric = mem->calls; 03169 tmp->metric += mem->penalty * 1000000; 03170 break; 03171 case QUEUE_STRATEGY_LEASTRECENT: 03172 if (!mem->lastcall) 03173 tmp->metric = 0; 03174 else 03175 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 03176 tmp->metric += mem->penalty * 1000000; 03177 break; 03178 default: 03179 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 03180 break; 03181 } 03182 return 0; 03183 }
static void clear_and_free_interfaces | ( | void | ) | [static] |
Definition at line 1059 of file app_queue.c.
References ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and member_interface::list.
Referenced by unload_module().
01060 { 01061 struct member_interface *curint; 01062 01063 AST_LIST_LOCK(&interfaces); 01064 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list))) 01065 ast_free(curint); 01066 AST_LIST_UNLOCK(&interfaces); 01067 }
static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 974 of file app_queue.c.
References call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::holdtime, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_queues().
00975 { 00976 q->holdtime = 0; 00977 q->callscompleted = 0; 00978 q->callsabandoned = 0; 00979 q->callscompletedinsl = 0; 00980 q->wrapuptime = 0; 00981 }
static int compare_weight | ( | struct call_queue * | rq, | |
struct member * | member | |||
) | [static] |
Definition at line 2158 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().
02159 { 02160 struct call_queue *q; 02161 struct member *mem; 02162 int found = 0; 02163 struct ao2_iterator queue_iter; 02164 02165 /* q's lock and rq's lock already set by try_calling() 02166 * to solve deadlock */ 02167 queue_iter = ao2_iterator_init(queues, 0); 02168 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 02169 if (q == rq) { /* don't check myself, could deadlock */ 02170 queue_t_unref(q, "Done with iterator"); 02171 continue; 02172 } 02173 ao2_lock(q); 02174 if (q->count && q->members) { 02175 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 02176 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 02177 if (q->weight > rq->weight && q->count >= num_available_members(q)) { 02178 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); 02179 found = 1; 02180 } 02181 ao2_ref(mem, -1); 02182 } 02183 } 02184 ao2_unlock(q); 02185 queue_t_unref(q, "Done with iterator"); 02186 if (found) { 02187 break; 02188 } 02189 } 02190 ao2_iterator_destroy(&queue_iter); 02191 return found; 02192 }
static char* complete_queue | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5926 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(), and complete_queue_show().
05927 { 05928 struct call_queue *q; 05929 char *ret = NULL; 05930 int which = 0; 05931 int wordlen = strlen(word); 05932 struct ao2_iterator queue_iter; 05933 05934 queue_iter = ao2_iterator_init(queues, 0); 05935 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 05936 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 05937 ret = ast_strdup(q->name); 05938 queue_t_unref(q, "Done with iterator"); 05939 break; 05940 } 05941 queue_t_unref(q, "Done with iterator"); 05942 } 05943 ao2_iterator_destroy(&queue_iter); 05944 05945 return ret; 05946 }
static char* complete_queue_add_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 6308 of file app_queue.c.
References ast_malloc, ast_strdup, complete_queue(), and num.
Referenced by handle_queue_add_member().
06309 { 06310 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 06311 switch (pos) { 06312 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 06313 return NULL; 06314 case 4: /* only one possible match, "to" */ 06315 return state == 0 ? ast_strdup("to") : NULL; 06316 case 5: /* <queue> */ 06317 return complete_queue(line, word, pos, state); 06318 case 6: /* only one possible match, "penalty" */ 06319 return state == 0 ? ast_strdup("penalty") : NULL; 06320 case 7: 06321 if (state < 100) { /* 0-99 */ 06322 char *num; 06323 if ((num = ast_malloc(3))) { 06324 sprintf(num, "%d", state); 06325 } 06326 return num; 06327 } else { 06328 return NULL; 06329 } 06330 case 8: /* only one possible match, "as" */ 06331 return state == 0 ? ast_strdup("as") : NULL; 06332 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 06333 return NULL; 06334 default: 06335 return NULL; 06336 } 06337 }
static char* complete_queue_pause_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 6526 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_pause_member().
06527 { 06528 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */ 06529 switch (pos) { 06530 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 06531 return NULL; 06532 case 4: /* only one possible match, "queue" */ 06533 return state == 0 ? ast_strdup("queue") : NULL; 06534 case 5: /* <queue> */ 06535 return complete_queue(line, word, pos, state); 06536 case 6: /* "reason" */ 06537 return state == 0 ? ast_strdup("reason") : NULL; 06538 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */ 06539 return NULL; 06540 default: 06541 return NULL; 06542 } 06543 }
static char* complete_queue_remove_member | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 6438 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().
06439 { 06440 int which = 0; 06441 struct call_queue *q; 06442 struct member *m; 06443 struct ao2_iterator queue_iter; 06444 struct ao2_iterator mem_iter; 06445 int wordlen = strlen(word); 06446 06447 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 06448 if (pos > 5 || pos < 3) 06449 return NULL; 06450 if (pos == 4) /* only one possible match, 'from' */ 06451 return (state == 0 ? ast_strdup("from") : NULL); 06452 06453 if (pos == 5) /* No need to duplicate code */ 06454 return complete_queue(line, word, pos, state); 06455 06456 /* here is the case for 3, <member> */ 06457 queue_iter = ao2_iterator_init(queues, 0); 06458 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 06459 ao2_lock(q); 06460 mem_iter = ao2_iterator_init(q->members, 0); 06461 while ((m = ao2_iterator_next(&mem_iter))) { 06462 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) { 06463 char *tmp; 06464 ao2_unlock(q); 06465 tmp = ast_strdup(m->interface); 06466 ao2_ref(m, -1); 06467 queue_t_unref(q, "Done with iterator"); 06468 ao2_iterator_destroy(&mem_iter); 06469 ao2_iterator_destroy(&queue_iter); 06470 return tmp; 06471 } 06472 ao2_ref(m, -1); 06473 } 06474 ao2_iterator_destroy(&mem_iter); 06475 ao2_unlock(q); 06476 queue_t_unref(q, "Done with iterator"); 06477 } 06478 ao2_iterator_destroy(&queue_iter); 06479 06480 return NULL; 06481 }
static char* complete_queue_rule_show | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 6659 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().
06660 { 06661 int which = 0; 06662 struct rule_list *rl_iter; 06663 int wordlen = strlen(word); 06664 char *ret = NULL; 06665 if (pos != 3) /* Wha? */ { 06666 return NULL; 06667 } 06668 06669 AST_LIST_LOCK(&rule_lists); 06670 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 06671 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) { 06672 ret = ast_strdup(rl_iter->name); 06673 break; 06674 } 06675 } 06676 AST_LIST_UNLOCK(&rule_lists); 06677 06678 return ret; 06679 }
static char* complete_queue_set_member_penalty | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 6596 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_set_member_penalty().
06597 { 06598 /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/ 06599 switch (pos) { 06600 case 4: 06601 if (state == 0) { 06602 return ast_strdup("on"); 06603 } else { 06604 return NULL; 06605 } 06606 case 6: 06607 if (state == 0) { 06608 return ast_strdup("in"); 06609 } else { 06610 return NULL; 06611 } 06612 case 7: 06613 return complete_queue(line, word, pos, state); 06614 default: 06615 return NULL; 06616 } 06617 }
static char* complete_queue_show | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 5948 of file app_queue.c.
References complete_queue().
Referenced by queue_show().
05949 { 05950 if (pos == 2) 05951 return complete_queue(line, word, pos, state); 05952 return NULL; 05953 }
static int compress_char | ( | const char | c | ) | [static] |
Definition at line 872 of file app_queue.c.
00873 { 00874 if (c < 32) 00875 return 0; 00876 else if (c > 96) 00877 return c - 64; 00878 else 00879 return c - 32; 00880 }
static void copy_rules | ( | struct queue_ent * | qe, | |
const char * | rulename | |||
) | [static] |
Copy rule from global list into specified queue.
Definition at line 4789 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(), 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::qe_rules, rule_list::rules, and penalty_rule::time.
Referenced by join_queue().
04790 { 04791 struct penalty_rule *pr_iter; 04792 struct rule_list *rl_iter; 04793 const char *tmp = rulename; 04794 if (ast_strlen_zero(tmp)) { 04795 return; 04796 } 04797 AST_LIST_LOCK(&rule_lists); 04798 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 04799 if (!strcasecmp(rl_iter->name, tmp)) 04800 break; 04801 } 04802 if (rl_iter) { 04803 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 04804 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr)); 04805 if (!new_pr) { 04806 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n"); 04807 AST_LIST_UNLOCK(&rule_lists); 04808 break; 04809 } 04810 new_pr->time = pr_iter->time; 04811 new_pr->max_value = pr_iter->max_value; 04812 new_pr->min_value = pr_iter->min_value; 04813 new_pr->max_relative = pr_iter->max_relative; 04814 new_pr->min_relative = pr_iter->min_relative; 04815 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list); 04816 } 04817 } 04818 AST_LIST_UNLOCK(&rule_lists); 04819 }
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 847 of file app_queue.c.
References ao2_alloc, ast_copy_string(), ast_device_state(), ast_log(), ast_strlen_zero(), LOG_WARNING, and member::penalty.
Referenced by add_to_queue(), reload_queues(), and rt_handle_member_record().
00848 { 00849 struct member *cur; 00850 00851 if ((cur = ao2_alloc(sizeof(*cur), NULL))) { 00852 cur->penalty = penalty; 00853 cur->paused = paused; 00854 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 00855 if (!ast_strlen_zero(state_interface)) 00856 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); 00857 else 00858 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface)); 00859 if (!ast_strlen_zero(membername)) 00860 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 00861 else 00862 ast_copy_string(cur->membername, interface, sizeof(cur->membername)); 00863 if (!strchr(cur->interface, '/')) 00864 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 00865 cur->status = ast_device_state(cur->state_interface); 00866 } 00867 00868 return cur; 00869 }
static void destroy_queue | ( | void * | obj | ) | [static] |
Free queue's member list then its string fields.
Definition at line 1452 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().
01453 { 01454 struct call_queue *q = obj; 01455 int i; 01456 01457 free_members(q, 1); 01458 ast_string_field_free_memory(q); 01459 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 01460 if (q->sound_periodicannounce[i]) 01461 free(q->sound_periodicannounce[i]); 01462 } 01463 ao2_ref(q->members, -1); 01464 }
static void device_state_cb | ( | const struct ast_event * | event, | |
void * | unused | |||
) | [static] |
Definition at line 820 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.
00821 { 00822 enum ast_device_state state; 00823 const char *device; 00824 struct statechange *sc; 00825 size_t datapsize; 00826 00827 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE); 00828 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE); 00829 00830 if (ast_strlen_zero(device)) { 00831 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n"); 00832 return; 00833 } 00834 datapsize = sizeof(*sc) + strlen(device) + 1; 00835 if (!(sc = ast_calloc(1, datapsize))) { 00836 ast_log(LOG_ERROR, "failed to calloc a state change struct\n"); 00837 return; 00838 } 00839 sc->state = state; 00840 strcpy(sc->dev, device); 00841 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) { 00842 ast_free(sc); 00843 } 00844 }
static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 2195 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry().
02196 { 02197 o->stillgoing = 0; 02198 ast_hangup(o->chan); 02199 o->chan = NULL; 02200 }
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 5784 of file app_queue.c.
References ast_cli(), astman_append(), and s.
Referenced by __queues_show().
05785 { 05786 if (s) 05787 astman_append(s, "%s\r\n", str); 05788 else 05789 ast_cli(fd, "%s\n", str); 05790 }
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 4155 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, and member::state_interface.
Referenced by add_to_queue(), remove_from_queue(), and set_member_paused().
04156 { 04157 struct member *cur_member; 04158 char value[PM_MAX_LEN]; 04159 int value_len = 0; 04160 int res; 04161 struct ao2_iterator mem_iter; 04162 04163 memset(value, 0, sizeof(value)); 04164 04165 if (!pm_queue) 04166 return; 04167 04168 mem_iter = ao2_iterator_init(pm_queue->members, 0); 04169 while ((cur_member = ao2_iterator_next(&mem_iter))) { 04170 if (!cur_member->dynamic) { 04171 ao2_ref(cur_member, -1); 04172 continue; 04173 } 04174 04175 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s", 04176 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface); 04177 04178 ao2_ref(cur_member, -1); 04179 04180 if (res != strlen(value + value_len)) { 04181 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 04182 break; 04183 } 04184 value_len += res; 04185 } 04186 ao2_iterator_destroy(&mem_iter); 04187 04188 if (value_len && !cur_member) { 04189 if (ast_db_put(pm_family, pm_queue->name, value)) 04190 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 04191 } else 04192 /* Delete the entry if the queue is empty or there is an error */ 04193 ast_db_del(pm_family, pm_queue->name); 04194 }
static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 3336 of file app_queue.c.
References ao2_lock(), ao2_ref, ao2_unlock(), queue_end_bridge::chan, chan, queue_end_bridge::q, queue_t_unref, and set_queue_variables().
03337 { 03338 struct queue_end_bridge *qeb = data; 03339 struct call_queue *q = qeb->q; 03340 struct ast_channel *chan = qeb->chan; 03341 03342 if (ao2_ref(qeb, -1) == 1) { 03343 ao2_lock(q); 03344 set_queue_variables(q, chan); 03345 ao2_unlock(q); 03346 /* This unrefs the reference we made in try_calling when we allocated qeb */ 03347 queue_t_unref(q, "Expire bridge_config reference"); 03348 } 03349 }
static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
struct ast_channel * | originator, | |||
struct ast_channel * | terminator | |||
) | [static] |
Definition at line 3329 of file app_queue.c.
References ao2_ref, queue_end_bridge::chan, and ast_bridge_config::end_bridge_callback_data.
03330 { 03331 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data; 03332 ao2_ref(qeb, +1); 03333 qeb->chan = originator; 03334 }
static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static] |
find the entry with the best metric, or NULL
Definition at line 2407 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
02408 { 02409 struct callattempt *best = NULL, *cur; 02410 02411 for (cur = outgoing; cur; cur = cur->q_next) { 02412 if (cur->stillgoing && /* Not already done */ 02413 !cur->chan && /* Isn't already going */ 02414 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 02415 best = cur; 02416 } 02417 } 02418 02419 return best; 02420 }
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 1490 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().
01491 { 01492 struct ast_variable *v; 01493 struct call_queue *q, tmpq = { 01494 .name = queuename, 01495 }; 01496 struct member *m; 01497 struct ao2_iterator mem_iter; 01498 char *interface = NULL; 01499 const char *tmp_name; 01500 char *tmp; 01501 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 01502 01503 /* Static queues override realtime. */ 01504 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) { 01505 ao2_lock(q); 01506 if (!q->realtime) { 01507 if (q->dead) { 01508 ao2_unlock(q); 01509 queue_t_unref(q, "Queue is dead; can't return it"); 01510 return NULL; 01511 } else { 01512 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); 01513 ao2_unlock(q); 01514 return q; 01515 } 01516 } 01517 } else if (!member_config) 01518 /* Not found in the list, and it's not realtime ... */ 01519 return NULL; 01520 01521 /* Check if queue is defined in realtime. */ 01522 if (!queue_vars) { 01523 /* Delete queue from in-core list if it has been deleted in realtime. */ 01524 if (q) { 01525 /*! \note Hmm, can't seem to distinguish a DB failure from a not 01526 found condition... So we might delete an in-core queue 01527 in case of DB failure. */ 01528 ast_debug(1, "Queue %s not found in realtime.\n", queuename); 01529 01530 q->dead = 1; 01531 /* Delete if unused (else will be deleted when last caller leaves). */ 01532 queues_t_unlink(queues, q, "Unused, removing from container"); 01533 ao2_unlock(q); 01534 queue_t_unref(q, "Queue is dead; can't return it"); 01535 } 01536 return NULL; 01537 } 01538 01539 /* Create a new queue if an in-core entry does not exist yet. */ 01540 if (!q) { 01541 struct ast_variable *tmpvar = NULL; 01542 if (!(q = alloc_queue(queuename))) 01543 return NULL; 01544 ao2_lock(q); 01545 clear_queue(q); 01546 q->realtime = 1; 01547 /*Before we initialize the queue, we need to set the strategy, so that linear strategy 01548 * will allocate the members properly 01549 */ 01550 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) { 01551 if (!strcasecmp(tmpvar->name, "strategy")) { 01552 q->strategy = strat2int(tmpvar->value); 01553 if (q->strategy < 0) { 01554 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 01555 tmpvar->value, q->name); 01556 q->strategy = QUEUE_STRATEGY_RINGALL; 01557 } 01558 break; 01559 } 01560 } 01561 /* We traversed all variables and didn't find a strategy */ 01562 if (!tmpvar) 01563 q->strategy = QUEUE_STRATEGY_RINGALL; 01564 queues_t_link(queues, q, "Add queue to container"); 01565 } 01566 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 01567 01568 memset(tmpbuf, 0, sizeof(tmpbuf)); 01569 for (v = queue_vars; v; v = v->next) { 01570 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 01571 if ((tmp = strchr(v->name, '_'))) { 01572 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 01573 tmp_name = tmpbuf; 01574 tmp = tmpbuf; 01575 while ((tmp = strchr(tmp, '_'))) 01576 *tmp++ = '-'; 01577 } else 01578 tmp_name = v->name; 01579 01580 if (!ast_strlen_zero(v->value)) { 01581 /* Don't want to try to set the option if the value is empty */ 01582 queue_set_param(q, tmp_name, v->value, -1, 0); 01583 } 01584 } 01585 01586 /* Temporarily set realtime members dead so we can detect deleted ones. 01587 * Also set the membercount correctly for realtime*/ 01588 mem_iter = ao2_iterator_init(q->members, 0); 01589 while ((m = ao2_iterator_next(&mem_iter))) { 01590 q->membercount++; 01591 if (m->realtime) 01592 m->dead = 1; 01593 ao2_ref(m, -1); 01594 } 01595 ao2_iterator_destroy(&mem_iter); 01596 01597 while ((interface = ast_category_browse(member_config, interface))) { 01598 rt_handle_member_record(q, interface, 01599 ast_variable_retrieve(member_config, interface, "uniqueid"), 01600 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface), 01601 ast_variable_retrieve(member_config, interface, "penalty"), 01602 ast_variable_retrieve(member_config, interface, "paused"), 01603 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface)); 01604 } 01605 01606 /* Delete all realtime members that have been deleted in DB. */ 01607 mem_iter = ao2_iterator_init(q->members, 0); 01608 while ((m = ao2_iterator_next(&mem_iter))) { 01609 if (m->dead) { 01610 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 01611 ao2_unlink(q->members, m); 01612 remove_from_interfaces(m->state_interface, 0); 01613 q->membercount--; 01614 } 01615 ao2_ref(m, -1); 01616 } 01617 ao2_iterator_destroy(&mem_iter); 01618 01619 ao2_unlock(q); 01620 01621 return q; 01622 }
static void free_members | ( | struct call_queue * | q, | |
int | all | |||
) | [static] |
Iterate through queue's member list and delete them.
Definition at line 1434 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ao2_unlink, member::dynamic, call_queue::membercount, call_queue::members, remove_from_interfaces(), and member::state_interface.
Referenced by destroy_queue().
01435 { 01436 /* Free non-dynamic members */ 01437 struct member *cur; 01438 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01439 01440 while ((cur = ao2_iterator_next(&mem_iter))) { 01441 if (all || !cur->dynamic) { 01442 ao2_unlink(q->members, cur); 01443 remove_from_interfaces(cur->state_interface, 1); 01444 q->membercount--; 01445 } 01446 ao2_ref(cur, -1); 01447 } 01448 ao2_iterator_destroy(&mem_iter); 01449 }
static int get_member_penalty | ( | char * | queuename, | |
char * | interface | |||
) | [static] |
Definition at line 4436 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().
04437 { 04438 int foundqueue = 0, penalty; 04439 struct call_queue *q, tmpq = { 04440 .name = queuename, 04441 }; 04442 struct member *mem; 04443 04444 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) { 04445 foundqueue = 1; 04446 ao2_lock(q); 04447 if ((mem = interface_exists(q, interface))) { 04448 penalty = mem->penalty; 04449 ao2_ref(mem, -1); 04450 ao2_unlock(q); 04451 queue_t_unref(q, "Search complete"); 04452 return penalty; 04453 } 04454 ao2_unlock(q); 04455 queue_t_unref(q, "Search complete"); 04456 } 04457 04458 /* some useful debuging */ 04459 if (foundqueue) 04460 ast_log (LOG_ERROR, "Invalid queuename\n"); 04461 else 04462 ast_log (LOG_ERROR, "Invalid interface\n"); 04463 04464 return RESULT_FAILURE; 04465 }
static enum queue_member_status get_member_status | ( | struct call_queue * | q, | |
int | max_penalty, | |||
int | min_penalty | |||
) | [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 QUEUE_NORMAL. If no members are available, the appropriate reason why is returned
Definition at line 687 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, call_queue::members, member::paused, member::penalty, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, and member::status.
Referenced by join_queue(), queue_exec(), and wait_our_turn().
00688 { 00689 struct member *member; 00690 struct ao2_iterator mem_iter; 00691 enum queue_member_status result = QUEUE_NO_MEMBERS; 00692 00693 ao2_lock(q); 00694 mem_iter = ao2_iterator_init(q->members, 0); 00695 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) { 00696 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) 00697 continue; 00698 00699 switch (member->status) { 00700 case AST_DEVICE_INVALID: 00701 /* nothing to do */ 00702 break; 00703 case AST_DEVICE_UNAVAILABLE: 00704 if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS) 00705 result = QUEUE_NO_REACHABLE_MEMBERS; 00706 break; 00707 default: 00708 if (member->paused) { 00709 result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS; 00710 } else { 00711 ao2_unlock(q); 00712 ao2_ref(member, -1); 00713 ao2_iterator_destroy(&mem_iter); 00714 return QUEUE_NORMAL; 00715 } 00716 break; 00717 } 00718 } 00719 ao2_iterator_destroy(&mem_iter); 00720 00721 ao2_unlock(q); 00722 return result; 00723 }
static char* handle_queue_add_member | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 6364 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.
06365 { 06366 char *queuename, *interface, *membername = NULL, *state_interface = NULL; 06367 int penalty; 06368 06369 switch ( cmd ) { 06370 case CLI_INIT: 06371 e->command = "queue add member"; 06372 e->usage = 06373 "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n" 06374 " Add a channel to a queue with optionally: a penalty, membername and a state_interface\n"; 06375 return NULL; 06376 case CLI_GENERATE: 06377 return complete_queue_add_member(a->line, a->word, a->pos, a->n); 06378 } 06379 06380 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) { 06381 return CLI_SHOWUSAGE; 06382 } else if (strcmp(a->argv[4], "to")) { 06383 return CLI_SHOWUSAGE; 06384 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) { 06385 return CLI_SHOWUSAGE; 06386 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) { 06387 return CLI_SHOWUSAGE; 06388 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) { 06389 return CLI_SHOWUSAGE; 06390 } 06391 06392 queuename = a->argv[5]; 06393 interface = a->argv[3]; 06394 if (a->argc >= 8) { 06395 if (sscanf(a->argv[7], "%30d", &penalty) == 1) { 06396 if (penalty < 0) { 06397 ast_cli(a->fd, "Penalty must be >= 0\n"); 06398 penalty = 0; 06399 } 06400 } else { 06401 ast_cli(a->fd, "Penalty must be an integer >= 0\n"); 06402 penalty = 0; 06403 } 06404 } else { 06405 penalty = 0; 06406 } 06407 06408 if (a->argc >= 10) { 06409 membername = a->argv[9]; 06410 } 06411 06412 if (a->argc >= 12) { 06413 state_interface = a->argv[11]; 06414 } 06415 06416 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { 06417 case RES_OKAY: 06418 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 06419 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 06420 return CLI_SUCCESS; 06421 case RES_EXISTS: 06422 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 06423 return CLI_FAILURE; 06424 case RES_NOSUCHQUEUE: 06425 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 06426 return CLI_FAILURE; 06427 case RES_OUTOFMEMORY: 06428 ast_cli(a->fd, "Out of memory\n"); 06429 return CLI_FAILURE; 06430 case RES_NOT_DYNAMIC: 06431 ast_cli(a->fd, "Member not dynamic\n"); 06432 return CLI_FAILURE; 06433 default: 06434 return CLI_FAILURE; 06435 } 06436 }
static char* handle_queue_pause_member | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 6545 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(), and ast_cli_entry::usage.
06546 { 06547 char *queuename, *interface, *reason; 06548 int paused; 06549 06550 switch (cmd) { 06551 case CLI_INIT: 06552 e->command = "queue {pause|unpause} member"; 06553 e->usage = 06554 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n" 06555 " Pause or unpause a queue member. Not specifying a particular queue\n" 06556 " will pause or unpause a member across all queues to which the member\n" 06557 " belongs.\n"; 06558 return NULL; 06559 case CLI_GENERATE: 06560 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n); 06561 } 06562 06563 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) { 06564 return CLI_SHOWUSAGE; 06565 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) { 06566 return CLI_SHOWUSAGE; 06567 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) { 06568 return CLI_SHOWUSAGE; 06569 } 06570 06571 06572 interface = a->argv[3]; 06573 queuename = a->argc >= 6 ? a->argv[5] : NULL; 06574 reason = a->argc == 8 ? a->argv[7] : NULL; 06575 paused = !strcasecmp(a->argv[1], "pause"); 06576 06577 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) { 06578 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface); 06579 if (!ast_strlen_zero(queuename)) 06580 ast_cli(a->fd, " in queue '%s'", queuename); 06581 if (!ast_strlen_zero(reason)) 06582 ast_cli(a->fd, " for reason '%s'", reason); 06583 ast_cli(a->fd, "\n"); 06584 return CLI_SUCCESS; 06585 } else { 06586 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface); 06587 if (!ast_strlen_zero(queuename)) 06588 ast_cli(a->fd, " in queue '%s'", queuename); 06589 if (!ast_strlen_zero(reason)) 06590 ast_cli(a->fd, " for reason '%s'", reason); 06591 ast_cli(a->fd, "\n"); 06592 return CLI_FAILURE; 06593 } 06594 }
static char* handle_queue_remove_member | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 6483 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_OKAY, RES_OUTOFMEMORY, ast_cli_entry::usage, and ast_cli_args::word.
06484 { 06485 char *queuename, *interface; 06486 06487 switch (cmd) { 06488 case CLI_INIT: 06489 e->command = "queue remove member"; 06490 e->usage = 06491 "Usage: queue remove member <channel> from <queue>\n" 06492 " Remove a specific channel from a queue.\n"; 06493 return NULL; 06494 case CLI_GENERATE: 06495 return complete_queue_remove_member(a->line, a->word, a->pos, a->n); 06496 } 06497 06498 if (a->argc != 6) { 06499 return CLI_SHOWUSAGE; 06500 } else if (strcmp(a->argv[4], "from")) { 06501 return CLI_SHOWUSAGE; 06502 } 06503 06504 queuename = a->argv[5]; 06505 interface = a->argv[3]; 06506 06507 switch (remove_from_queue(queuename, interface)) { 06508 case RES_OKAY: 06509 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 06510 ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 06511 return CLI_SUCCESS; 06512 case RES_EXISTS: 06513 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 06514 return CLI_FAILURE; 06515 case RES_NOSUCHQUEUE: 06516 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 06517 return CLI_FAILURE; 06518 case RES_OUTOFMEMORY: 06519 ast_cli(a->fd, "Out of memory\n"); 06520 return CLI_FAILURE; 06521 default: 06522 return CLI_FAILURE; 06523 } 06524 }
static char* handle_queue_rule_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 6715 of file app_queue.c.
References CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, reload_queue_rules(), and ast_cli_entry::usage.
06716 { 06717 switch (cmd) { 06718 case CLI_INIT: 06719 e->command = "queue rules reload"; 06720 e->usage = 06721 "Usage: queue rules reload\n" 06722 " Reloads rules defined in queuerules.conf\n"; 06723 return NULL; 06724 case CLI_GENERATE: 06725 return NULL; 06726 } 06727 reload_queue_rules(1); 06728 return CLI_SUCCESS; 06729 }
static char* handle_queue_rule_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 6681 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.
06682 { 06683 char *rule; 06684 struct rule_list *rl_iter; 06685 struct penalty_rule *pr_iter; 06686 switch (cmd) { 06687 case CLI_INIT: 06688 e->command = "queue rules show"; 06689 e->usage = 06690 "Usage: queue rules show [rulename]\n" 06691 " Show the list of rules associated with rulename. If no\n" 06692 " rulename is specified, list all rules defined in queuerules.conf\n"; 06693 return NULL; 06694 case CLI_GENERATE: 06695 return complete_queue_rule_show(a->line, a->word, a->pos, a->n); 06696 } 06697 06698 if (a->argc != 3 && a->argc != 4) 06699 return CLI_SHOWUSAGE; 06700 06701 rule = a->argc == 4 ? a->argv[3] : ""; 06702 AST_LIST_LOCK(&rule_lists); 06703 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 06704 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) { 06705 ast_cli(a->fd, "Rule: %s\n", rl_iter->name); 06706 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 06707 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); 06708 } 06709 } 06710 } 06711 AST_LIST_UNLOCK(&rule_lists); 06712 return CLI_SUCCESS; 06713 }
static char* handle_queue_set_member_penalty | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 6619 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.
06620 { 06621 char *queuename = NULL, *interface; 06622 int penalty = 0; 06623 06624 switch (cmd) { 06625 case CLI_INIT: 06626 e->command = "queue set penalty"; 06627 e->usage = 06628 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n" 06629 " Set a member's penalty in the queue specified. If no queue is specified\n" 06630 " then that interface's penalty is set in all queues to which that interface is a member\n"; 06631 return NULL; 06632 case CLI_GENERATE: 06633 return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n); 06634 } 06635 06636 if (a->argc != 6 && a->argc != 8) { 06637 return CLI_SHOWUSAGE; 06638 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) { 06639 return CLI_SHOWUSAGE; 06640 } 06641 06642 if (a->argc == 8) 06643 queuename = a->argv[7]; 06644 interface = a->argv[5]; 06645 penalty = atoi(a->argv[3]); 06646 06647 switch (set_member_penalty(queuename, interface, penalty)) { 06648 case RESULT_SUCCESS: 06649 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename); 06650 return CLI_SUCCESS; 06651 case RESULT_FAILURE: 06652 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename); 06653 return CLI_FAILURE; 06654 default: 06655 return CLI_FAILURE; 06656 } 06657 }
static int handle_statechange | ( | void * | datap | ) | [static] |
set a member's status based on device state of that member's interface
Definition at line 789 of file app_queue.c.
References ast_copy_string(), ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, statechange::dev, devstate2str(), member_interface::interface, statechange::state, and update_status().
00790 { 00791 struct member_interface *curint; 00792 struct statechange *sc = datap; 00793 char interface[80]; 00794 00795 AST_LIST_LOCK(&interfaces); 00796 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00797 char *slash_pos; 00798 ast_copy_string(interface, curint->interface, sizeof(interface)); 00799 if ((slash_pos = strchr(interface, '/'))) 00800 if ((slash_pos = strchr(slash_pos + 1, '/'))) 00801 *slash_pos = '\0'; 00802 if (!strcasecmp(interface, sc->dev)) 00803 break; 00804 } 00805 AST_LIST_UNLOCK(&interfaces); 00806 00807 if (!curint) { 00808 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, devstate2str(sc->state)); 00809 ast_free(sc); 00810 return 0; 00811 } 00812 00813 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, devstate2str(sc->state)); 00814 00815 update_status(sc->dev, sc->state); 00816 ast_free(sc); 00817 return 0; 00818 }
static void hangupcalls | ( | struct callattempt * | outgoing, | |
struct ast_channel * | exception | |||
) | [static] |
Hang up a list of outgoing calls.
Definition at line 2091 of file app_queue.c.
References ao2_ref, ast_free, ast_hangup(), callattempt::chan, callattempt::member, and callattempt::q_next.
02092 { 02093 struct callattempt *oo; 02094 02095 while (outgoing) { 02096 /* Hangup any existing lines we have open */ 02097 if (outgoing->chan && (outgoing->chan != exception)) 02098 ast_hangup(outgoing->chan); 02099 oo = outgoing; 02100 outgoing = outgoing->q_next; 02101 if (oo->member) 02102 ao2_ref(oo->member, -1); 02103 ast_free(oo); 02104 } 02105 }
static void init_queue | ( | struct call_queue * | q | ) | [static] |
Initialize Queue default values.
Definition at line 904 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::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::membercount, call_queue::memberdelay, call_queue::members, call_queue::minannouncefrequency, call_queue::monfmt, call_queue::montype, call_queue::numperiodicannounce, call_queue::periodicannouncefrequency, QUEUE_STRATEGY_LINEAR, 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_queues().
00905 { 00906 int i; 00907 struct penalty_rule *pr_iter; 00908 00909 q->dead = 0; 00910 q->retry = DEFAULT_RETRY; 00911 q->timeout = DEFAULT_TIMEOUT; 00912 q->maxlen = 0; 00913 q->announcefrequency = 0; 00914 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY; 00915 q->announceholdtime = 1; 00916 q->announcepositionlimit = 10; /* Default 10 positions */ 00917 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */ 00918 q->roundingseconds = 0; /* Default - don't announce seconds */ 00919 q->servicelevel = 0; 00920 q->ringinuse = 1; 00921 q->setinterfacevar = 0; 00922 q->setqueuevar = 0; 00923 q->setqueueentryvar = 0; 00924 q->autofill = autofill_default; 00925 q->montype = montype_default; 00926 q->monfmt[0] = '\0'; 00927 q->reportholdtime = 0; 00928 q->wrapuptime = 0; 00929 q->joinempty = 0; 00930 q->leavewhenempty = 0; 00931 q->memberdelay = 0; 00932 q->maskmemberstatus = 0; 00933 q->eventwhencalled = 0; 00934 q->weight = 0; 00935 q->timeoutrestart = 0; 00936 q->periodicannouncefrequency = 0; 00937 q->randomperiodicannounce = 0; 00938 q->numperiodicannounce = 0; 00939 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 00940 if (!q->members) { 00941 if (q->strategy == QUEUE_STRATEGY_LINEAR) 00942 /* linear strategy depends on order, so we have to place all members in a single bucket */ 00943 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn); 00944 else 00945 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn); 00946 } 00947 q->membercount = 0; 00948 q->found = 1; 00949 00950 ast_string_field_set(q, sound_next, "queue-youarenext"); 00951 ast_string_field_set(q, sound_thereare, "queue-thereare"); 00952 ast_string_field_set(q, sound_calls, "queue-callswaiting"); 00953 ast_string_field_set(q, queue_quantity1, "queue-quantity1"); 00954 ast_string_field_set(q, queue_quantity2, "queue-quantity2"); 00955 ast_string_field_set(q, sound_holdtime, "queue-holdtime"); 00956 ast_string_field_set(q, sound_minutes, "queue-minutes"); 00957 ast_string_field_set(q, sound_minute, "queue-minute"); 00958 ast_string_field_set(q, sound_seconds, "queue-seconds"); 00959 ast_string_field_set(q, sound_thanks, "queue-thankyou"); 00960 ast_string_field_set(q, sound_reporthold, "queue-reporthold"); 00961 00962 if ((q->sound_periodicannounce[0] = ast_str_create(32))) 00963 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce"); 00964 00965 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 00966 if (q->sound_periodicannounce[i]) 00967 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", ""); 00968 } 00969 00970 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) 00971 ast_free(pr_iter); 00972 }
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 650 of file app_queue.c.
References call_queue::head, queue_ent::next, and queue_ref().
Referenced by join_queue().
00651 { 00652 struct queue_ent *cur; 00653 00654 if (!q || !new) 00655 return; 00656 if (prev) { 00657 cur = prev->next; 00658 prev->next = new; 00659 } else { 00660 cur = q->head; 00661 q->head = new; 00662 } 00663 new->next = cur; 00664 00665 /* every queue_ent must have a reference to it's parent call_queue, this 00666 * reference does not go away until the end of the queue_ent's life, meaning 00667 * that even when the queue_ent leaves the call_queue this ref must remain. */ 00668 queue_ref(q); 00669 new->parent = q; 00670 new->pos = ++(*pos); 00671 new->opos = *pos; 00672 }
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 1078 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_ERROR, LOG_WARNING, rule_list::name, and rule_list::rules.
Referenced by reload_queue_rules().
01079 { 01080 char *timestr, *maxstr, *minstr, *contentdup; 01081 struct penalty_rule *rule = NULL, *rule_iter; 01082 struct rule_list *rl_iter; 01083 int penaltychangetime, inserted = 0; 01084 01085 if (!(rule = ast_calloc(1, sizeof(*rule)))) { 01086 ast_log(LOG_ERROR, "Cannot allocate memory for penaltychange rule at line %d!\n", linenum); 01087 return -1; 01088 } 01089 01090 contentdup = ast_strdupa(content); 01091 01092 if (!(maxstr = strchr(contentdup, ','))) { 01093 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum); 01094 ast_free(rule); 01095 return -1; 01096 } 01097 01098 *maxstr++ = '\0'; 01099 timestr = contentdup; 01100 01101 if ((penaltychangetime = atoi(timestr)) < 0) { 01102 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum); 01103 ast_free(rule); 01104 return -1; 01105 } 01106 01107 rule->time = penaltychangetime; 01108 01109 if ((minstr = strchr(maxstr,','))) 01110 *minstr++ = '\0'; 01111 01112 /* The last check will evaluate true if either no penalty change is indicated for a given rule 01113 * OR if a min penalty change is indicated but no max penalty change is */ 01114 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') { 01115 rule->max_relative = 1; 01116 } 01117 01118 rule->max_value = atoi(maxstr); 01119 01120 if (!ast_strlen_zero(minstr)) { 01121 if (*minstr == '+' || *minstr == '-') 01122 rule->min_relative = 1; 01123 rule->min_value = atoi(minstr); 01124 } else /*there was no minimum specified, so assume this means no change*/ 01125 rule->min_relative = 1; 01126 01127 /*We have the rule made, now we need to insert it where it belongs*/ 01128 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){ 01129 if (strcasecmp(rl_iter->name, list_name)) 01130 continue; 01131 01132 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) { 01133 if (rule->time < rule_iter->time) { 01134 AST_LIST_INSERT_BEFORE_CURRENT(rule, list); 01135 inserted = 1; 01136 break; 01137 } 01138 } 01139 AST_LIST_TRAVERSE_SAFE_END; 01140 01141 if (!inserted) { 01142 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list); 01143 } 01144 } 01145 01146 return 0; 01147 }
static const char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 568 of file app_queue.c.
References ARRAY_LEN, strategy::name, and strategies.
Referenced by __queues_show(), manager_queues_status(), queue_function_var(), and set_queue_variables().
00569 { 00570 int x; 00571 00572 for (x = 0; x < ARRAY_LEN(strategies); x++) { 00573 if (strategy == strategies[x].strategy) 00574 return strategies[x].name; 00575 } 00576 00577 return "<unknown>"; 00578 }
static struct member* interface_exists | ( | struct call_queue * | q, | |
const char * | interface | |||
) | [static] |
Definition at line 4129 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().
04130 { 04131 struct member *mem; 04132 struct ao2_iterator mem_iter; 04133 04134 if (!q) 04135 return NULL; 04136 04137 mem_iter = ao2_iterator_init(q->members, 0); 04138 while ((mem = ao2_iterator_next(&mem_iter))) { 04139 if (!strcasecmp(interface, mem->interface)) { 04140 ao2_iterator_destroy(&mem_iter); 04141 return mem; 04142 } 04143 ao2_ref(mem, -1); 04144 } 04145 ao2_iterator_destroy(&mem_iter); 04146 04147 return NULL; 04148 }
static int interface_exists_global | ( | const char * | interface, | |
int | lock_queue_container | |||
) | [static] |
Definition at line 1009 of file app_queue.c.
References ao2_iterator_destroy(), AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_t_iterator_next, ao2_unlock(), ast_copy_string(), member::interface, call_queue::members, queue_t_unref, queues, and member::state_interface.
Referenced by remove_from_interfaces().
01010 { 01011 struct call_queue *q; 01012 struct member *mem, tmpmem; 01013 struct ao2_iterator queue_iter, mem_iter; 01014 int ret = 0; 01015 01016 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 01017 queue_iter = ao2_iterator_init(queues, lock_queue_container ? 0 : AO2_ITERATOR_DONTLOCK); 01018 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 01019 ao2_lock(q); 01020 mem_iter = ao2_iterator_init(q->members, 0); 01021 while ((mem = ao2_iterator_next(&mem_iter))) { 01022 if (!strcasecmp(mem->state_interface, interface)) { 01023 ao2_ref(mem, -1); 01024 ret = 1; 01025 break; 01026 } 01027 } 01028 ao2_iterator_destroy(&mem_iter); 01029 ao2_unlock(q); 01030 queue_t_unref(q, "Done with iterator"); 01031 } 01032 ao2_iterator_destroy(&queue_iter); 01033 01034 return ret; 01035 }
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 2901 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().
02902 { 02903 struct queue_ent *ch; 02904 int res; 02905 int avl; 02906 int idx = 0; 02907 /* This needs a lock. How many members are available to be served? */ 02908 ao2_lock(qe->parent); 02909 02910 avl = num_available_members(qe->parent); 02911 02912 ch = qe->parent->head; 02913 02914 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member"); 02915 02916 while ((idx < avl) && (ch) && (ch != qe)) { 02917 if (!ch->pending) 02918 idx++; 02919 ch = ch->next; 02920 } 02921 02922 ao2_unlock(qe->parent); 02923 /* If the queue entry is within avl [the number of available members] calls from the top ... 02924 * Autofill and position check added to support autofill=no (as only calls 02925 * from the front of the queue are valid when autofill is disabled) 02926 */ 02927 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) { 02928 ast_debug(1, "It's our turn (%s).\n", qe->chan->name); 02929 res = 1; 02930 } else { 02931 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name); 02932 res = 0; 02933 } 02934 02935 return res; 02936 }
static int join_queue | ( | char * | queuename, | |
struct queue_ent * | qe, | |||
enum queue_result * | reason, | |||
const char * | overriding_rule | |||
) | [static] |
Definition at line 1734 of file app_queue.c.
References queue_ent::announce, ao2_lock(), ao2_unlock(), ast_copy_string(), ast_debug, AST_LIST_FIRST, queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, queue_ent::context, copy_rules(), call_queue::count, call_queue::defaultrule, EVENT_FLAG_CALL, get_member_status(), call_queue::head, insert_entry(), call_queue::joinempty, load_realtime_queue(), manager_event, queue_ent::max_penalty, call_queue::maxlen, queue_ent::min_penalty, queue_ent::moh, ast_channel::name, queue_ent::next, queue_ent::pos, queue_ent::pr, queue_ent::prio, queue_ent::qe_rules, QUEUE_EMPTY_LOOSE, QUEUE_EMPTY_STRICT, QUEUE_FULL, QUEUE_JOINEMPTY, QUEUE_JOINUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, queues, S_OR, status, ast_channel::uniqueid, and update_qe_rule().
Referenced by queue_exec().
01735 { 01736 struct call_queue *q; 01737 struct queue_ent *cur, *prev = NULL; 01738 int res = -1; 01739 int pos = 0; 01740 int inserted = 0; 01741 enum queue_member_status status; 01742 int exit = 0; 01743 01744 if (!(q = load_realtime_queue(queuename))) 01745 return res; 01746 01747 ao2_lock(queues); 01748 ao2_lock(q); 01749 01750 copy_rules(qe, S_OR(overriding_rule, q->defaultrule)); 01751 qe->pr = AST_LIST_FIRST(&qe->qe_rules); 01752 01753 /* This is our one */ 01754 while (!exit) { 01755 status = get_member_status(q, qe->max_penalty, qe->min_penalty); 01756 if (!q->joinempty && (status == QUEUE_NO_MEMBERS)) 01757 *reason = QUEUE_JOINEMPTY; 01758 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS || status == QUEUE_NO_MEMBERS)) 01759 *reason = QUEUE_JOINUNAVAIL; 01760 else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_MEMBERS)) 01761 *reason = QUEUE_JOINUNAVAIL; 01762 else if (q->maxlen && (q->count >= q->maxlen)) 01763 *reason = QUEUE_FULL; 01764 else { 01765 /* There's space for us, put us at the right position inside 01766 * the queue. 01767 * Take into account the priority of the calling user */ 01768 inserted = 0; 01769 prev = NULL; 01770 cur = q->head; 01771 while (cur) { 01772 /* We have higher priority than the current user, enter 01773 * before him, after all the other users with priority 01774 * higher or equal to our priority. */ 01775 if ((!inserted) && (qe->prio > cur->prio)) { 01776 insert_entry(q, prev, qe, &pos); 01777 inserted = 1; 01778 } 01779 cur->pos = ++pos; 01780 prev = cur; 01781 cur = cur->next; 01782 } 01783 /* No luck, join at the end of the queue */ 01784 if (!inserted) 01785 insert_entry(q, prev, qe, &pos); 01786 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 01787 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 01788 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 01789 q->count++; 01790 res = 0; 01791 manager_event(EVENT_FLAG_CALL, "Join", 01792 "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n", 01793 qe->chan->name, 01794 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */ 01795 S_OR(qe->chan->cid.cid_name, "unknown"), 01796 q->name, qe->pos, q->count, qe->chan->uniqueid ); 01797 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 01798 } 01799 if (!exit && qe->pr && res) { 01800 /* We failed to join the queue, but perhaps we can join if we move 01801 * to the next defined penalty rule 01802 */ 01803 update_qe_rule(qe); 01804 } else { 01805 exit = 1; 01806 } 01807 } 01808 ao2_unlock(q); 01809 ao2_unlock(queues); 01810 01811 return res; 01812 }
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 2034 of file app_queue.c.
References ao2_lock(), ao2_unlock(), ast_debug, ast_free, AST_LIST_REMOVE_HEAD, ast_load_realtime(), ast_variables_destroy(), queue_ent::chan, call_queue::count, call_queue::dead, EVENT_FLAG_CALL, call_queue::head, penalty_rule::list, manager_event, call_queue::name, ast_channel::name, queue_ent::next, queue_ent::parent, 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().
02035 { 02036 struct call_queue *q; 02037 struct queue_ent *current, *prev = NULL; 02038 struct penalty_rule *pr_iter; 02039 int pos = 0; 02040 02041 if (!(q = qe->parent)) 02042 return; 02043 queue_t_ref(q, "Copy queue pointer from queue entry"); 02044 ao2_lock(q); 02045 02046 prev = NULL; 02047 for (current = q->head; current; current = current->next) { 02048 if (current == qe) { 02049 q->count--; 02050 02051 /* Take us out of the queue */ 02052 manager_event(EVENT_FLAG_CALL, "Leave", 02053 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n", 02054 qe->chan->name, q->name, q->count, qe->chan->uniqueid); 02055 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 02056 /* Take us out of the queue */ 02057 if (prev) 02058 prev->next = current->next; 02059 else 02060 q->head = current->next; 02061 /* Free penalty rules */ 02062 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) 02063 ast_free(pr_iter); 02064 } else { 02065 /* Renumber the people after us in the queue based on a new count */ 02066 current->pos = ++pos; 02067 prev = current; 02068 } 02069 } 02070 ao2_unlock(q); 02071 02072 /*If the queue is a realtime queue, check to see if it's still defined in real time*/ 02073 if (q->realtime) { 02074 struct ast_variable *var; 02075 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) { 02076 q->dead = 1; 02077 } else { 02078 ast_variables_destroy(var); 02079 } 02080 } 02081 02082 if (q->dead) { 02083 /* It's dead and nobody is in it, so kill it */ 02084 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container"); 02085 } 02086 /* unref the explicit ref earlier in the function */ 02087 queue_t_unref(q, "Expire copied reference"); 02088 }
static int load_module | ( | void | ) | [static] |
Definition at line 6802 of file app_queue.c.
References ao2_container_alloc, aqm_exec(), ast_add_extension2(), ast_cli_register_multiple(), ast_context_find_or_create(), ast_custom_function_register, AST_EVENT_DEVICE_STATE, AST_EVENT_IE_END, ast_event_subscribe(), ast_free_ptr, ast_log(), ast_manager_register, AST_MODULE_LOAD_DECLINE, ast_realtime_require_field(), ast_register_application, ast_strdup, ast_taskprocessor_get(), cli_queue, device_state_cb(), device_state_sub, devicestate_tps, EVENT_FLAG_AGENT, LOG_ERROR, LOG_WARNING, manager_add_queue_member(), manager_pause_queue_member(), manager_queue_log_custom(), manager_queue_member_penalty(), manager_queue_rule_show(), manager_queues_show(), manager_queues_status(), manager_queues_summary(), manager_remove_queue_member(), MAX_QUEUE_BUCKETS, pqm_exec(), ql_exec(), queue_cmp_cb(), queue_exec(), queue_hash_cb(), queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queuevar_function, queuewaitingcount_function, reload_queue_members(), reload_queues(), RQ_INTEGER1, RQ_UINTEGER2, rqm_exec(), SENTINEL, and upqm_exec().
06803 { 06804 int res; 06805 struct ast_context *con; 06806 06807 queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb); 06808 06809 if (!reload_queues(0)) 06810 return AST_MODULE_LOAD_DECLINE; 06811 06812 con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue"); 06813 if (!con) 06814 ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n"); 06815 else 06816 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue"); 06817 06818 if (queue_persistent_members) 06819 reload_queue_members(); 06820 06821 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 06822 res = ast_register_application(app, queue_exec, synopsis, descrip); 06823 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip); 06824 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip); 06825 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip); 06826 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip); 06827 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip); 06828 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues"); 06829 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status"); 06830 res |= ast_manager_register("QueueSummary", 0, manager_queues_summary, "Queue Summary"); 06831 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue."); 06832 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue."); 06833 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable"); 06834 res |= ast_manager_register("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom, "Adds custom entry in queue_log"); 06835 res |= ast_manager_register("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty, "Set the penalty for a queue member"); 06836 res |= ast_manager_register("QueueRule", 0, manager_queue_rule_show, "Queue Rules"); 06837 res |= ast_custom_function_register(&queuevar_function); 06838 res |= ast_custom_function_register(&queuemembercount_function); 06839 res |= ast_custom_function_register(&queuemembercount_dep); 06840 res |= ast_custom_function_register(&queuememberlist_function); 06841 res |= ast_custom_function_register(&queuewaitingcount_function); 06842 res |= ast_custom_function_register(&queuememberpenalty_function); 06843 06844 if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) { 06845 ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n"); 06846 } 06847 06848 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL, AST_EVENT_IE_END))) { 06849 res = -1; 06850 } 06851 06852 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL); 06853 06854 return res ? AST_MODULE_LOAD_DECLINE : 0; 06855 }
static struct call_queue* load_realtime_queue | ( | const char * | queuename | ) | [static] |
Definition at line 1624 of file app_queue.c.
References ao2_lock(), ao2_t_find, ao2_unlock(), ast_config_destroy(), ast_load_realtime(), ast_load_realtime_multientry(), ast_log(), ast_variables_destroy(), find_queue_by_name_rt(), LOG_ERROR, call_queue::name, OBJ_POINTER, queues, call_queue::realtime, SENTINEL, and update_realtime_members().
Referenced by __queues_show(), add_to_queue(), join_queue(), queue_function_qac(), queue_function_qac_dep(), and reload_queue_members().
01625 { 01626 struct ast_variable *queue_vars; 01627 struct ast_config *member_config = NULL; 01628 struct call_queue *q = NULL, tmpq = { 01629 .name = queuename, 01630 }; 01631 01632 /* Find the queue in the in-core list first. */ 01633 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first"); 01634 01635 if (!q || q->realtime) { 01636 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all 01637 queue operations while waiting for the DB. 01638 01639 This will be two separate database transactions, so we might 01640 see queue parameters as they were before another process 01641 changed the queue and member list as it was after the change. 01642 Thus we might see an empty member list when a queue is 01643 deleted. In practise, this is unlikely to cause a problem. */ 01644 01645 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL); 01646 if (queue_vars) { 01647 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL); 01648 if (!member_config) { 01649 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n"); 01650 ast_variables_destroy(queue_vars); 01651 return NULL; 01652 } 01653 } 01654 01655 ao2_lock(queues); 01656 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 01657 if (member_config) 01658 ast_config_destroy(member_config); 01659 if (queue_vars) 01660 ast_variables_destroy(queue_vars); 01661 ao2_unlock(queues); 01662 01663 } else { 01664 update_realtime_members(q); 01665 } 01666 return q; 01667 }
static int manager_add_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 6178 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, RES_OUTOFMEMORY, and s.
Referenced by load_module().
06179 { 06180 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; 06181 int paused, penalty = 0; 06182 06183 queuename = astman_get_header(m, "Queue"); 06184 interface = astman_get_header(m, "Interface"); 06185 penalty_s = astman_get_header(m, "Penalty"); 06186 paused_s = astman_get_header(m, "Paused"); 06187 membername = astman_get_header(m, "MemberName"); 06188 state_interface = astman_get_header(m, "StateInterface"); 06189 06190 if (ast_strlen_zero(queuename)) { 06191 astman_send_error(s, m, "'Queue' not specified."); 06192 return 0; 06193 } 06194 06195 if (ast_strlen_zero(interface)) { 06196 astman_send_error(s, m, "'Interface' not specified."); 06197 return 0; 06198 } 06199 06200 if (ast_strlen_zero(penalty_s)) 06201 penalty = 0; 06202 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) 06203 penalty = 0; 06204 06205 if (ast_strlen_zero(paused_s)) 06206 paused = 0; 06207 else 06208 paused = abs(ast_true(paused_s)); 06209 06210 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { 06211 case RES_OKAY: 06212 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", ""); 06213 astman_send_ack(s, m, "Added interface to queue"); 06214 break; 06215 case RES_EXISTS: 06216 astman_send_error(s, m, "Unable to add interface: Already there"); 06217 break; 06218 case RES_NOSUCHQUEUE: 06219 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 06220 break; 06221 case RES_OUTOFMEMORY: 06222 astman_send_error(s, m, "Out of memory"); 06223 break; 06224 } 06225 06226 return 0; 06227 }
static int manager_pause_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 6263 of file app_queue.c.
References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), s, and set_member_paused().
Referenced by load_module().
06264 { 06265 const char *queuename, *interface, *paused_s, *reason; 06266 int paused; 06267 06268 interface = astman_get_header(m, "Interface"); 06269 paused_s = astman_get_header(m, "Paused"); 06270 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 06271 reason = astman_get_header(m, "Reason"); /* Optional - Only used for logging purposes */ 06272 06273 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 06274 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 06275 return 0; 06276 } 06277 06278 paused = abs(ast_true(paused_s)); 06279 06280 if (set_member_paused(queuename, interface, reason, paused)) 06281 astman_send_error(s, m, "Interface not found"); 06282 else 06283 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 06284 return 0; 06285 }
static int manager_queue_log_custom | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 6287 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), s, and S_OR.
Referenced by load_module().
06288 { 06289 const char *queuename, *event, *message, *interface, *uniqueid; 06290 06291 queuename = astman_get_header(m, "Queue"); 06292 uniqueid = astman_get_header(m, "UniqueId"); 06293 interface = astman_get_header(m, "Interface"); 06294 event = astman_get_header(m, "Event"); 06295 message = astman_get_header(m, "Message"); 06296 06297 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) { 06298 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters."); 06299 return 0; 06300 } 06301 06302 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message); 06303 astman_send_ack(s, m, "Event added successfully"); 06304 06305 return 0; 06306 }
static int manager_queue_member_penalty | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 6339 of file app_queue.c.
References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), s, and set_member_penalty().
Referenced by load_module().
06340 { 06341 const char *queuename, *interface, *penalty_s; 06342 int penalty; 06343 06344 interface = astman_get_header(m, "Interface"); 06345 penalty_s = astman_get_header(m, "Penalty"); 06346 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */ 06347 queuename = astman_get_header(m, "Queue"); 06348 06349 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) { 06350 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters."); 06351 return 0; 06352 } 06353 06354 penalty = atoi(penalty_s); 06355 06356 if (set_member_penalty((char *)queuename, (char *)interface, penalty)) 06357 astman_send_error(s, m, "Invalid interface, queuename or penalty"); 06358 else 06359 astman_send_ack(s, m, "Interface penalty set successfully"); 06360 06361 return 0; 06362 }
static int manager_queue_rule_show | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5984 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, s, and penalty_rule::time.
Referenced by load_module().
05985 { 05986 const char *rule = astman_get_header(m, "Rule"); 05987 struct rule_list *rl_iter; 05988 struct penalty_rule *pr_iter; 05989 05990 AST_LIST_LOCK(&rule_lists); 05991 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 05992 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) { 05993 astman_append(s, "RuleList: %s\r\n", rl_iter->name); 05994 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 05995 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 ); 05996 } 05997 if (!ast_strlen_zero(rule)) 05998 break; 05999 } 06000 } 06001 AST_LIST_UNLOCK(&rule_lists); 06002 06003 astman_append(s, "\r\n\r\n"); 06004 06005 return RESULT_SUCCESS; 06006 }
static int manager_queues_show | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 5974 of file app_queue.c.
References __queues_show(), astman_append(), RESULT_SUCCESS, and s.
Referenced by load_module().
05975 { 05976 char *a[] = { "queue", "show" }; 05977 05978 __queues_show(s, -1, 2, a); 05979 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 05980 05981 return RESULT_SUCCESS; 05982 }
static int manager_queues_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Queue status info via AMI.
Definition at line 6083 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(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, call_queue::count, member::dynamic, call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, call_queue::maxlen, member::membername, call_queue::members, ast_channel::name, call_queue::name, queue_ent::next, member::paused, member::penalty, queue_t_unref, queues, RESULT_SUCCESS, s, S_OR, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, and call_queue::weight.
Referenced by load_module().
06084 { 06085 time_t now; 06086 int pos; 06087 const char *id = astman_get_header(m,"ActionID"); 06088 const char *queuefilter = astman_get_header(m,"Queue"); 06089 const char *memberfilter = astman_get_header(m,"Member"); 06090 char idText[256] = ""; 06091 struct call_queue *q; 06092 struct queue_ent *qe; 06093 float sl = 0; 06094 struct member *mem; 06095 struct ao2_iterator queue_iter; 06096 struct ao2_iterator mem_iter; 06097 06098 astman_send_ack(s, m, "Queue status will follow"); 06099 time(&now); 06100 if (!ast_strlen_zero(id)) 06101 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 06102 06103 queue_iter = ao2_iterator_init(queues, 0); 06104 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 06105 ao2_lock(q); 06106 06107 /* List queue properties */ 06108 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 06109 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 06110 astman_append(s, "Event: QueueParams\r\n" 06111 "Queue: %s\r\n" 06112 "Max: %d\r\n" 06113 "Strategy: %s\r\n" 06114 "Calls: %d\r\n" 06115 "Holdtime: %d\r\n" 06116 "Completed: %d\r\n" 06117 "Abandoned: %d\r\n" 06118 "ServiceLevel: %d\r\n" 06119 "ServicelevelPerf: %2.1f\r\n" 06120 "Weight: %d\r\n" 06121 "%s" 06122 "\r\n", 06123 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, 06124 q->callsabandoned, q->servicelevel, sl, q->weight, idText); 06125 /* List Queue Members */ 06126 mem_iter = ao2_iterator_init(q->members, 0); 06127 while ((mem = ao2_iterator_next(&mem_iter))) { 06128 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) { 06129 astman_append(s, "Event: QueueMember\r\n" 06130 "Queue: %s\r\n" 06131 "Name: %s\r\n" 06132 "Location: %s\r\n" 06133 "Membership: %s\r\n" 06134 "Penalty: %d\r\n" 06135 "CallsTaken: %d\r\n" 06136 "LastCall: %d\r\n" 06137 "Status: %d\r\n" 06138 "Paused: %d\r\n" 06139 "%s" 06140 "\r\n", 06141 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static", 06142 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 06143 } 06144 ao2_ref(mem, -1); 06145 } 06146 ao2_iterator_destroy(&mem_iter); 06147 /* List Queue Entries */ 06148 pos = 1; 06149 for (qe = q->head; qe; qe = qe->next) { 06150 astman_append(s, "Event: QueueEntry\r\n" 06151 "Queue: %s\r\n" 06152 "Position: %d\r\n" 06153 "Channel: %s\r\n" 06154 "CallerIDNum: %s\r\n" 06155 "CallerIDName: %s\r\n" 06156 "Wait: %ld\r\n" 06157 "%s" 06158 "\r\n", 06159 q->name, pos++, qe->chan->name, 06160 S_OR(qe->chan->cid.cid_num, "unknown"), 06161 S_OR(qe->chan->cid.cid_name, "unknown"), 06162 (long) (now - qe->start), idText); 06163 } 06164 } 06165 ao2_unlock(q); 06166 queue_t_unref(q, "Done with iterator"); 06167 } 06168 ao2_iterator_destroy(&queue_iter); 06169 06170 astman_append(s, 06171 "Event: QueueStatusComplete\r\n" 06172 "%s" 06173 "\r\n",idText); 06174 06175 return RESULT_SUCCESS; 06176 }
static int manager_queues_summary | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Summary of queue info via the AMI.
Definition at line 6009 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, s, queue_ent::start, and member::status.
Referenced by load_module().
06010 { 06011 time_t now; 06012 int qmemcount = 0; 06013 int qmemavail = 0; 06014 int qchancount = 0; 06015 int qlongestholdtime = 0; 06016 const char *id = astman_get_header(m, "ActionID"); 06017 const char *queuefilter = astman_get_header(m, "Queue"); 06018 char idText[256] = ""; 06019 struct call_queue *q; 06020 struct queue_ent *qe; 06021 struct member *mem; 06022 struct ao2_iterator queue_iter; 06023 struct ao2_iterator mem_iter; 06024 06025 astman_send_ack(s, m, "Queue summary will follow"); 06026 time(&now); 06027 if (!ast_strlen_zero(id)) 06028 snprintf(idText, 256, "ActionID: %s\r\n", id); 06029 queue_iter = ao2_iterator_init(queues, 0); 06030 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 06031 ao2_lock(q); 06032 06033 /* List queue properties */ 06034 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 06035 /* Reset the necessary local variables if no queuefilter is set*/ 06036 qmemcount = 0; 06037 qmemavail = 0; 06038 qchancount = 0; 06039 qlongestholdtime = 0; 06040 06041 /* List Queue Members */ 06042 mem_iter = ao2_iterator_init(q->members, 0); 06043 while ((mem = ao2_iterator_next(&mem_iter))) { 06044 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) { 06045 ++qmemcount; 06046 if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) { 06047 ++qmemavail; 06048 } 06049 } 06050 ao2_ref(mem, -1); 06051 } 06052 ao2_iterator_destroy(&mem_iter); 06053 for (qe = q->head; qe; qe = qe->next) { 06054 if ((now - qe->start) > qlongestholdtime) { 06055 qlongestholdtime = now - qe->start; 06056 } 06057 ++qchancount; 06058 } 06059 astman_append(s, "Event: QueueSummary\r\n" 06060 "Queue: %s\r\n" 06061 "LoggedIn: %d\r\n" 06062 "Available: %d\r\n" 06063 "Callers: %d\r\n" 06064 "HoldTime: %d\r\n" 06065 "LongestHoldTime: %d\r\n" 06066 "%s" 06067 "\r\n", 06068 q->name, qmemcount, qmemavail, qchancount, q->holdtime, qlongestholdtime, idText); 06069 } 06070 ao2_unlock(q); 06071 queue_t_unref(q, "Done with iterator"); 06072 } 06073 ao2_iterator_destroy(&queue_iter); 06074 astman_append(s, 06075 "Event: QueueSummaryComplete\r\n" 06076 "%s" 06077 "\r\n", idText); 06078 06079 return RESULT_SUCCESS; 06080 }
static int manager_remove_queue_member | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 6229 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, RES_OUTOFMEMORY, and s.
Referenced by load_module().
06230 { 06231 const char *queuename, *interface; 06232 06233 queuename = astman_get_header(m, "Queue"); 06234 interface = astman_get_header(m, "Interface"); 06235 06236 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 06237 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 06238 return 0; 06239 } 06240 06241 switch (remove_from_queue(queuename, interface)) { 06242 case RES_OKAY: 06243 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 06244 astman_send_ack(s, m, "Removed interface from queue"); 06245 break; 06246 case RES_EXISTS: 06247 astman_send_error(s, m, "Unable to remove interface: Not there"); 06248 break; 06249 case RES_NOSUCHQUEUE: 06250 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 06251 break; 06252 case RES_OUTOFMEMORY: 06253 astman_send_error(s, m, "Out of memory"); 06254 break; 06255 case RES_NOT_DYNAMIC: 06256 astman_send_error(s, m, "Member not dynamic"); 06257 break; 06258 } 06259 06260 return 0; 06261 }
static int member_cmp_fn | ( | void * | obj1, | |
void * | obj2, | |||
int | flags | |||
) | [static] |
Definition at line 894 of file app_queue.c.
References CMP_MATCH, CMP_STOP, and member::interface.
Referenced by init_queue().
00895 { 00896 struct member *mem1 = obj1, *mem2 = obj2; 00897 return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP; 00898 }
static int member_hash_fn | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 882 of file app_queue.c.
References compress_char(), and member::interface.
Referenced by init_queue().
00883 { 00884 const struct member *mem = obj; 00885 const char *chname = strchr(mem->interface, '/'); 00886 int ret = 0, i; 00887 if (!chname) 00888 chname = mem->interface; 00889 for (i = 0; i < 5 && chname[i]; i++) 00890 ret += compress_char(chname[i]) << (i * 6); 00891 return ret; 00892 }
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 2115 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().
02116 { 02117 struct member *mem; 02118 int avl = 0; 02119 struct ao2_iterator mem_iter; 02120 02121 mem_iter = ao2_iterator_init(q->members, 0); 02122 while ((mem = ao2_iterator_next(&mem_iter))) { 02123 switch (mem->status) { 02124 case AST_DEVICE_INUSE: 02125 if (!q->ringinuse) 02126 break; 02127 /* else fall through */ 02128 case AST_DEVICE_NOT_INUSE: 02129 case AST_DEVICE_UNKNOWN: 02130 if (!mem->paused) { 02131 avl++; 02132 } 02133 break; 02134 } 02135 ao2_ref(mem, -1); 02136 02137 /* If autofill is not enabled or if the queue's strategy is ringall, then 02138 * we really don't care about the number of available members so much as we 02139 * do that there is at least one available. 02140 * 02141 * In fact, we purposely will return from this function stating that only 02142 * one member is available if either of those conditions hold. That way, 02143 * functions which determine what action to take based on the number of available 02144 * members will operate properly. The reasoning is that even if multiple 02145 * members are available, only the head caller can actually be serviced. 02146 */ 02147 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) { 02148 break; 02149 } 02150 } 02151 ao2_iterator_destroy(&mem_iter); 02152 02153 return avl; 02154 }
static int play_file | ( | struct ast_channel * | chan, | |
const char * | filename | |||
) | [static] |
Definition at line 1814 of file app_queue.c.
References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_waitstream(), queue_ent::chan, and ast_channel::language.
Referenced by say_periodic_announcement(), and say_position().
01815 { 01816 int res; 01817 01818 if (ast_strlen_zero(filename)) { 01819 return 0; 01820 } 01821 01822 ast_stopstream(chan); 01823 01824 res = ast_streamfile(chan, filename, chan->language); 01825 if (!res) 01826 res = ast_waitstream(chan, AST_DIGIT_ANY); 01827 01828 ast_stopstream(chan); 01829 01830 return res; 01831 }
static int pqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
PauseQueueMember application.
Definition at line 4565 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), chan, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), and set_member_paused().
Referenced by load_module().
04566 { 04567 char *parse; 04568 AST_DECLARE_APP_ARGS(args, 04569 AST_APP_ARG(queuename); 04570 AST_APP_ARG(interface); 04571 AST_APP_ARG(options); 04572 AST_APP_ARG(reason); 04573 ); 04574 04575 if (ast_strlen_zero(data)) { 04576 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n"); 04577 return -1; 04578 } 04579 04580 parse = ast_strdupa(data); 04581 04582 AST_STANDARD_APP_ARGS(args, parse); 04583 04584 if (ast_strlen_zero(args.interface)) { 04585 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 04586 return -1; 04587 } 04588 04589 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) { 04590 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 04591 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 04592 return 0; 04593 } 04594 04595 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 04596 04597 return 0; 04598 }
static int ql_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
QueueLog application.
Definition at line 4755 of file app_queue.c.
References 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().
04756 { 04757 char *parse; 04758 04759 AST_DECLARE_APP_ARGS(args, 04760 AST_APP_ARG(queuename); 04761 AST_APP_ARG(uniqueid); 04762 AST_APP_ARG(membername); 04763 AST_APP_ARG(event); 04764 AST_APP_ARG(params); 04765 ); 04766 04767 if (ast_strlen_zero(data)) { 04768 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n"); 04769 return -1; 04770 } 04771 04772 parse = ast_strdupa(data); 04773 04774 AST_STANDARD_APP_ARGS(args, parse); 04775 04776 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 04777 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 04778 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n"); 04779 return -1; 04780 } 04781 04782 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 04783 "%s", args.params ? args.params : ""); 04784 04785 return 0; 04786 }
static int queue_cmp_cb | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 599 of file app_queue.c.
References CMP_MATCH, CMP_STOP, and call_queue::name.
Referenced by load_module().
00600 { 00601 struct call_queue *q = obj, *q2 = arg; 00602 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0; 00603 }
static int queue_exec | ( | struct ast_channel * | chan, | |
void * | 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 4833 of file app_queue.c.
References call_queue::announcefrequency, AST_APP_ARG, ast_cdr_noanswer(), ast_channel_lock, ast_channel_unlock, AST_CONTROL_RINGING, ast_debug, AST_DECLARE_APP_ARGS, ast_indicate(), ast_log(), ast_moh_start(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::cdr, queue_ent::chan, chan, ast_channel::cid, ast_callerid::cid_num, queue_ent::expire, get_member_status(), 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::membercount, queue_ent::min_penalty, queue_ent::moh, call_queue::name, ast_channel::name, queue_ent::opos, queue_ent::parent, parse(), pbx_builtin_getvar_helper(), call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::pr, queue_ent::prio, QUEUE_EMPTY_LOOSE, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), S_OR, say_periodic_announcement(), say_position(), set_queue_result(), queue_ent::start, status, stop, penalty_rule::time, try_calling(), ast_channel::uniqueid, update_qe_rule(), update_realtime_members(), url, queue_ent::valid_digits, wait_a_bit(), and wait_our_turn().
Referenced by load_module().
04834 { 04835 int res=-1; 04836 int ringing=0; 04837 const char *user_priority; 04838 const char *max_penalty_str; 04839 const char *min_penalty_str; 04840 int prio; 04841 int qcontinue = 0; 04842 int max_penalty, min_penalty; 04843 enum queue_result reason = QUEUE_UNKNOWN; 04844 /* whether to exit Queue application after the timeout hits */ 04845 int tries = 0; 04846 int noption = 0; 04847 char *parse; 04848 int makeannouncement = 0; 04849 AST_DECLARE_APP_ARGS(args, 04850 AST_APP_ARG(queuename); 04851 AST_APP_ARG(options); 04852 AST_APP_ARG(url); 04853 AST_APP_ARG(announceoverride); 04854 AST_APP_ARG(queuetimeoutstr); 04855 AST_APP_ARG(agi); 04856 AST_APP_ARG(macro); 04857 AST_APP_ARG(gosub); 04858 AST_APP_ARG(rule); 04859 ); 04860 /* Our queue entry */ 04861 struct queue_ent qe = { 0 }; 04862 04863 if (ast_strlen_zero(data)) { 04864 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule]]]]]]]]\n"); 04865 return -1; 04866 } 04867 04868 parse = ast_strdupa(data); 04869 AST_STANDARD_APP_ARGS(args, parse); 04870 04871 /* Setup our queue entry */ 04872 qe.start = time(NULL); 04873 04874 /* set the expire time based on the supplied timeout; */ 04875 if (!ast_strlen_zero(args.queuetimeoutstr)) 04876 qe.expire = qe.start + atoi(args.queuetimeoutstr); 04877 else 04878 qe.expire = 0; 04879 04880 /* Get the priority from the variable ${QUEUE_PRIO} */ 04881 ast_channel_lock(chan); 04882 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 04883 if (user_priority) { 04884 if (sscanf(user_priority, "%30d", &prio) == 1) { 04885 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio); 04886 } else { 04887 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 04888 user_priority, chan->name); 04889 prio = 0; 04890 } 04891 } else { 04892 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n"); 04893 prio = 0; 04894 } 04895 04896 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 04897 04898 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 04899 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) { 04900 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty); 04901 } else { 04902 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 04903 max_penalty_str, chan->name); 04904 max_penalty = 0; 04905 } 04906 } else { 04907 max_penalty = 0; 04908 } 04909 04910 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) { 04911 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) { 04912 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty); 04913 } else { 04914 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n", 04915 min_penalty_str, chan->name); 04916 min_penalty = 0; 04917 } 04918 } else { 04919 min_penalty = 0; 04920 } 04921 ast_channel_unlock(chan); 04922 04923 if (args.options && (strchr(args.options, 'r'))) 04924 ringing = 1; 04925 04926 if (args.options && (strchr(args.options, 'c'))) 04927 qcontinue = 1; 04928 04929 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 04930 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 04931 04932 qe.chan = chan; 04933 qe.prio = prio; 04934 qe.max_penalty = max_penalty; 04935 qe.min_penalty = min_penalty; 04936 qe.last_pos_said = 0; 04937 qe.last_pos = 0; 04938 qe.last_periodic_announce_time = time(NULL); 04939 qe.last_periodic_announce_sound = 0; 04940 qe.valid_digits = 0; 04941 if (join_queue(args.queuename, &qe, &reason, args.rule)) { 04942 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 04943 set_queue_result(chan, reason); 04944 return 0; 04945 } 04946 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""), 04947 S_OR(chan->cid.cid_num, "")); 04948 check_turns: 04949 if (ringing) { 04950 ast_indicate(chan, AST_CONTROL_RINGING); 04951 } else { 04952 ast_moh_start(chan, qe.moh, NULL); 04953 } 04954 04955 /* This is the wait loop for callers 2 through maxlen */ 04956 res = wait_our_turn(&qe, ringing, &reason); 04957 if (res) { 04958 goto stop; 04959 } 04960 04961 makeannouncement = 0; 04962 04963 for (;;) { 04964 /* This is the wait loop for the head caller*/ 04965 /* To exit, they may get their call answered; */ 04966 /* they may dial a digit from the queue context; */ 04967 /* or, they may timeout. */ 04968 04969 enum queue_member_status status = QUEUE_NORMAL; 04970 int exit = 0; 04971 04972 /* Leave if we have exceeded our queuetimeout */ 04973 if (qe.expire && (time(NULL) >= qe.expire)) { 04974 record_abandoned(&qe); 04975 ast_cdr_noanswer(qe.chan->cdr); 04976 reason = QUEUE_TIMEOUT; 04977 res = 0; 04978 ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 04979 qe.pos, qe.opos, (long) time(NULL) - qe.start); 04980 break; 04981 } 04982 04983 if (makeannouncement) { 04984 /* Make a position announcement, if enabled */ 04985 if (qe.parent->announcefrequency) 04986 if ((res = say_position(&qe,ringing))) 04987 goto stop; 04988 } 04989 makeannouncement = 1; 04990 04991 /* Make a periodic announcement, if enabled */ 04992 if (qe.parent->periodicannouncefrequency) 04993 if ((res = say_periodic_announcement(&qe,ringing))) 04994 goto stop; 04995 04996 /* Leave if we have exceeded our queuetimeout */ 04997 if (qe.expire && (time(NULL) >= qe.expire)) { 04998 record_abandoned(&qe); 04999 ast_cdr_noanswer(qe.chan->cdr); 05000 reason = QUEUE_TIMEOUT; 05001 res = 0; 05002 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 05003 break; 05004 } 05005 05006 /* see if we need to move to the next penalty level for this queue */ 05007 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) { 05008 update_qe_rule(&qe); 05009 } 05010 05011 /* Try calling all queue members for 'timeout' seconds */ 05012 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing); 05013 if (res) { 05014 goto stop; 05015 } 05016 05017 /* exit after 'timeout' cycle if 'n' option enabled */ 05018 if (noption && tries >= qe.parent->membercount) { 05019 ast_verb(3, "Exiting on time-out cycle\n"); 05020 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 05021 record_abandoned(&qe); 05022 ast_cdr_noanswer(qe.chan->cdr); 05023 reason = QUEUE_TIMEOUT; 05024 res = 0; 05025 break; 05026 } 05027 05028 for (; !exit || qe.pr; update_qe_rule(&qe)) { 05029 status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty); 05030 05031 if (!qe.pr || status == QUEUE_NORMAL) { 05032 break; 05033 } 05034 05035 if ((qe.parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) || 05036 ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) || 05037 ((qe.parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS))) { 05038 continue; 05039 } else { 05040 exit = 1; 05041 } 05042 } 05043 05044 /* leave the queue if no agents, if enabled */ 05045 if (qe.parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) { 05046 record_abandoned(&qe); 05047 ast_cdr_noanswer(qe.chan->cdr); 05048 reason = QUEUE_LEAVEEMPTY; 05049 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 05050 res = 0; 05051 break; 05052 } 05053 05054 /* leave the queue if no reachable agents, if enabled */ 05055 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) { 05056 record_abandoned(&qe); 05057 reason = QUEUE_LEAVEUNAVAIL; 05058 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 05059 res = 0; 05060 break; 05061 } 05062 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS)) { 05063 record_abandoned(&qe); 05064 reason = QUEUE_LEAVEUNAVAIL; 05065 res = 0; 05066 break; 05067 } 05068 05069 /* Leave if we have exceeded our queuetimeout */ 05070 if (qe.expire && (time(NULL) >= qe.expire)) { 05071 record_abandoned(&qe); 05072 reason = QUEUE_TIMEOUT; 05073 res = 0; 05074 ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start); 05075 break; 05076 } 05077 05078 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 05079 update_realtime_members(qe.parent); 05080 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 05081 res = wait_a_bit(&qe); 05082 if (res) 05083 goto stop; 05084 05085 /* Since this is a priority queue and 05086 * it is not sure that we are still at the head 05087 * of the queue, go and check for our turn again. 05088 */ 05089 if (!is_our_turn(&qe)) { 05090 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name); 05091 goto check_turns; 05092 } 05093 } 05094 05095 stop: 05096 if (res) { 05097 if (res < 0) { 05098 if (!qe.handled) { 05099 record_abandoned(&qe); 05100 ast_cdr_noanswer(qe.chan->cdr); 05101 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 05102 "%d|%d|%ld", qe.pos, qe.opos, 05103 (long) time(NULL) - qe.start); 05104 res = -1; 05105 } else if (qcontinue) { 05106 reason = QUEUE_CONTINUE; 05107 res = 0; 05108 } 05109 } else if (qe.valid_digits) { 05110 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 05111 "%s|%d", qe.digits, qe.pos); 05112 } 05113 } 05114 05115 /* Don't allow return code > 0 */ 05116 if (res >= 0) { 05117 res = 0; 05118 if (ringing) { 05119 ast_indicate(chan, -1); 05120 } else { 05121 ast_moh_stop(chan); 05122 } 05123 ast_stopstream(chan); 05124 } 05125 05126 set_queue_variables(qe.parent, qe.chan); 05127 05128 leave_queue(&qe); 05129 if (reason != QUEUE_UNKNOWN) 05130 set_queue_result(chan, reason); 05131 05132 if (qe.parent) { 05133 /* every queue_ent is given a reference to it's parent call_queue when it joins the queue. 05134 * This ref must be taken away right before the queue_ent is destroyed. In this case 05135 * the queue_ent is about to be returned on the stack */ 05136 qe.parent = queue_unref(qe.parent); 05137 } 05138 05139 return res; 05140 }
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 5376 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), get_member_penalty(), and LOG_ERROR.
05377 { 05378 int penalty; 05379 AST_DECLARE_APP_ARGS(args, 05380 AST_APP_ARG(queuename); 05381 AST_APP_ARG(interface); 05382 ); 05383 /* Make sure the returned value on error is NULL. */ 05384 buf[0] = '\0'; 05385 05386 if (ast_strlen_zero(data)) { 05387 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05388 return -1; 05389 } 05390 05391 AST_STANDARD_APP_ARGS(args, data); 05392 05393 if (args.argc < 2) { 05394 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05395 return -1; 05396 } 05397 05398 penalty = get_member_penalty (args.queuename, args.interface); 05399 05400 if (penalty >= 0) /* remember that buf is already '\0' */ 05401 snprintf (buf, len, "%d", penalty); 05402 05403 return 0; 05404 }
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 5407 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), LOG_ERROR, and set_member_penalty().
05408 { 05409 int penalty; 05410 AST_DECLARE_APP_ARGS(args, 05411 AST_APP_ARG(queuename); 05412 AST_APP_ARG(interface); 05413 ); 05414 05415 if (ast_strlen_zero(data)) { 05416 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05417 return -1; 05418 } 05419 05420 AST_STANDARD_APP_ARGS(args, data); 05421 05422 if (args.argc < 2) { 05423 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05424 return -1; 05425 } 05426 05427 penalty = atoi(value); 05428 05429 if (ast_strlen_zero(args.interface)) { 05430 ast_log (LOG_ERROR, "<interface> parameter can't be null\n"); 05431 return -1; 05432 } 05433 05434 /* if queuename = NULL then penalty will be set for interface in all the queues. */ 05435 if (set_member_penalty(args.queuename, args.interface, penalty)) { 05436 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); 05437 return -1; 05438 } 05439 05440 return 0; 05441 }
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 or total members of a specific queue.
number | of members (busy / free / total) | |
-1 | on error |
Definition at line 5195 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_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_log(), ast_strlen_zero(), call_queue::count, load_realtime_queue(), LOG_ERROR, LOG_WARNING, member::paused, queue_t_unref, and member::status.
05196 { 05197 int count = 0; 05198 struct member *m; 05199 struct ao2_iterator mem_iter; 05200 struct call_queue *q; 05201 char *option; 05202 05203 if (ast_strlen_zero(data)) { 05204 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 05205 return -1; 05206 } 05207 05208 if ((option = strchr(data, ','))) 05209 *option++ = '\0'; 05210 else 05211 option = "logged"; 05212 if ((q = load_realtime_queue(data))) { 05213 ao2_lock(q); 05214 if (!strcasecmp(option, "logged")) { 05215 mem_iter = ao2_iterator_init(q->members, 0); 05216 while ((m = ao2_iterator_next(&mem_iter))) { 05217 /* Count the agents who are logged in and presently answering calls */ 05218 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05219 count++; 05220 } 05221 ao2_ref(m, -1); 05222 } 05223 ao2_iterator_destroy(&mem_iter); 05224 } else if (!strcasecmp(option, "free")) { 05225 mem_iter = ao2_iterator_init(q->members, 0); 05226 while ((m = ao2_iterator_next(&mem_iter))) { 05227 /* Count the agents who are logged in and presently answering calls */ 05228 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) { 05229 count++; 05230 } 05231 ao2_ref(m, -1); 05232 } 05233 ao2_iterator_destroy(&mem_iter); 05234 } else /* must be "count" */ 05235 count = q->membercount; 05236 ao2_unlock(q); 05237 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()"); 05238 } else 05239 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05240 05241 snprintf(buf, len, "%d", count); 05242 05243 return 0; 05244 }
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 5251 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.
05252 { 05253 int count = 0; 05254 struct member *m; 05255 struct call_queue *q; 05256 struct ao2_iterator mem_iter; 05257 static int depflag = 1; 05258 05259 if (depflag) { 05260 depflag = 0; 05261 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"); 05262 } 05263 05264 if (ast_strlen_zero(data)) { 05265 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 05266 return -1; 05267 } 05268 05269 if ((q = load_realtime_queue(data))) { 05270 ao2_lock(q); 05271 mem_iter = ao2_iterator_init(q->members, 0); 05272 while ((m = ao2_iterator_next(&mem_iter))) { 05273 /* Count the agents who are logged in and presently answering calls */ 05274 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05275 count++; 05276 } 05277 ao2_ref(m, -1); 05278 } 05279 ao2_iterator_destroy(&mem_iter); 05280 ao2_unlock(q); 05281 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT"); 05282 } else 05283 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05284 05285 snprintf(buf, len, "%d", count); 05286 05287 return 0; 05288 }
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 5327 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.
05328 { 05329 struct call_queue *q, tmpq = { 05330 .name = data, 05331 }; 05332 struct member *m; 05333 05334 /* Ensure an otherwise empty list doesn't return garbage */ 05335 buf[0] = '\0'; 05336 05337 if (ast_strlen_zero(data)) { 05338 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 05339 return -1; 05340 } 05341 05342 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) { 05343 int buflen = 0, count = 0; 05344 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 05345 05346 ao2_lock(q); 05347 while ((m = ao2_iterator_next(&mem_iter))) { 05348 /* strcat() is always faster than printf() */ 05349 if (count++) { 05350 strncat(buf + buflen, ",", len - buflen - 1); 05351 buflen++; 05352 } 05353 strncat(buf + buflen, m->interface, len - buflen - 1); 05354 buflen += strlen(m->interface); 05355 /* Safeguard against overflow (negative length) */ 05356 if (buflen >= len - 2) { 05357 ao2_ref(m, -1); 05358 ast_log(LOG_WARNING, "Truncating list\n"); 05359 break; 05360 } 05361 ao2_ref(m, -1); 05362 } 05363 ao2_iterator_destroy(&mem_iter); 05364 ao2_unlock(q); 05365 queue_t_unref(q, "Done with find for QUEUE_MEMBER_LIST()"); 05366 } else 05367 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05368 05369 /* We should already be terminated, but let's make sure. */ 05370 buf[len - 1] = '\0'; 05371 05372 return 0; 05373 }
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 5291 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.
05292 { 05293 int count = 0; 05294 struct call_queue *q, tmpq = { 05295 .name = data, 05296 }; 05297 struct ast_variable *var = NULL; 05298 05299 buf[0] = '\0'; 05300 05301 if (ast_strlen_zero(data)) { 05302 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n"); 05303 return -1; 05304 } 05305 05306 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) { 05307 ao2_lock(q); 05308 count = q->count; 05309 ao2_unlock(q); 05310 queue_t_unref(q, "Done with find for QUEUE_WAITING_COUNT"); 05311 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) { 05312 /* if the queue is realtime but was not found in memory, this 05313 * means that the queue had been deleted from memory since it was 05314 * "dead." This means it has a 0 waiting count 05315 */ 05316 count = 0; 05317 ast_variables_destroy(var); 05318 } else 05319 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05320 05321 snprintf(buf, len, "%d", count); 05322 05323 return 0; 05324 }
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 5147 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, chan, 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, and call_queue::strategy.
05148 { 05149 int res = -1; 05150 struct call_queue *q, tmpq = { 05151 .name = data, 05152 }; 05153 05154 char interfacevar[256] = ""; 05155 float sl = 0; 05156 05157 if (ast_strlen_zero(data)) { 05158 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 05159 return -1; 05160 } 05161 05162 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) { 05163 ao2_lock(q); 05164 if (q->setqueuevar) { 05165 sl = 0; 05166 res = 0; 05167 05168 if (q->callscompleted > 0) { 05169 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 05170 } 05171 05172 snprintf(interfacevar, sizeof(interfacevar), 05173 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 05174 q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 05175 05176 pbx_builtin_setvar_multiple(chan, interfacevar); 05177 } 05178 05179 ao2_unlock(q); 05180 queue_t_unref(q, "Done with temporary reference in QUEUE() function"); 05181 } else { 05182 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05183 } 05184 05185 snprintf(buf, len, "%d", res); 05186 05187 return 0; 05188 }
static int queue_hash_cb | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 592 of file app_queue.c.
References ast_str_case_hash(), and call_queue::name.
Referenced by load_module().
00593 { 00594 const struct call_queue *q = obj; 00595 00596 return ast_str_case_hash(q->name); 00597 }
static struct call_queue* queue_ref | ( | struct call_queue * | q | ) | [inline, static] |
Definition at line 617 of file app_queue.c.
References ao2_ref.
Referenced by insert_entry().
00618 { 00619 ao2_ref(q, 1); 00620 return q; 00621 }
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 1157 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, buf, 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, call_queue::periodicannouncefrequency, QUEUE_EMPTY_LOOSE, QUEUE_EMPTY_NORMAL, QUEUE_EMPTY_STRICT, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RINGALL, call_queue::randomperiodicannounce, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::roundingseconds, s, 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_queues().
01158 { 01159 if (!strcasecmp(param, "musicclass") || 01160 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 01161 ast_string_field_set(q, moh, val); 01162 } else if (!strcasecmp(param, "announce")) { 01163 ast_string_field_set(q, announce, val); 01164 } else if (!strcasecmp(param, "context")) { 01165 ast_string_field_set(q, context, val); 01166 } else if (!strcasecmp(param, "timeout")) { 01167 q->timeout = atoi(val); 01168 if (q->timeout < 0) 01169 q->timeout = DEFAULT_TIMEOUT; 01170 } else if (!strcasecmp(param, "ringinuse")) { 01171 q->ringinuse = ast_true(val); 01172 } else if (!strcasecmp(param, "setinterfacevar")) { 01173 q->setinterfacevar = ast_true(val); 01174 } else if (!strcasecmp(param, "setqueuevar")) { 01175 q->setqueuevar = ast_true(val); 01176 } else if (!strcasecmp(param, "setqueueentryvar")) { 01177 q->setqueueentryvar = ast_true(val); 01178 } else if (!strcasecmp(param, "monitor-format")) { 01179 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 01180 } else if (!strcasecmp(param, "membermacro")) { 01181 ast_string_field_set(q, membermacro, val); 01182 } else if (!strcasecmp(param, "membergosub")) { 01183 ast_string_field_set(q, membergosub, val); 01184 } else if (!strcasecmp(param, "queue-youarenext")) { 01185 ast_string_field_set(q, sound_next, val); 01186 } else if (!strcasecmp(param, "queue-thereare")) { 01187 ast_string_field_set(q, sound_thereare, val); 01188 } else if (!strcasecmp(param, "queue-callswaiting")) { 01189 ast_string_field_set(q, sound_calls, val); 01190 } else if (!strcasecmp(param, "queue-quantity1")) { 01191 ast_string_field_set(q, queue_quantity1, val); 01192 } else if (!strcasecmp(param, "queue-quantity2")) { 01193 ast_string_field_set(q, queue_quantity2, val); 01194 } else if (!strcasecmp(param, "queue-holdtime")) { 01195 ast_string_field_set(q, sound_holdtime, val); 01196 } else if (!strcasecmp(param, "queue-minutes")) { 01197 ast_string_field_set(q, sound_minutes, val); 01198 } else if (!strcasecmp(param, "queue-minute")) { 01199 ast_string_field_set(q, sound_minute, val); 01200 } else if (!strcasecmp(param, "queue-seconds")) { 01201 ast_string_field_set(q, sound_seconds, val); 01202 } else if (!strcasecmp(param, "queue-thankyou")) { 01203 ast_string_field_set(q, sound_thanks, val); 01204 } else if (!strcasecmp(param, "queue-callerannounce")) { 01205 ast_string_field_set(q, sound_callerannounce, val); 01206 } else if (!strcasecmp(param, "queue-reporthold")) { 01207 ast_string_field_set(q, sound_reporthold, val); 01208 } else if (!strcasecmp(param, "announce-frequency")) { 01209 q->announcefrequency = atoi(val); 01210 } else if (!strcasecmp(param, "min-announce-frequency")) { 01211 q->minannouncefrequency = atoi(val); 01212 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name); 01213 } else if (!strcasecmp(param, "announce-round-seconds")) { 01214 q->roundingseconds = atoi(val); 01215 /* Rounding to any other values just doesn't make sense... */ 01216 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10 01217 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) { 01218 if (linenum >= 0) { 01219 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01220 "using 0 instead for queue '%s' at line %d of queues.conf\n", 01221 val, param, q->name, linenum); 01222 } else { 01223 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01224 "using 0 instead for queue '%s'\n", val, param, q->name); 01225 } 01226 q->roundingseconds=0; 01227 } 01228 } else if (!strcasecmp(param, "announce-holdtime")) { 01229 if (!strcasecmp(val, "once")) 01230 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 01231 else if (ast_true(val)) 01232 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 01233 else 01234 q->announceholdtime = 0; 01235 } else if (!strcasecmp(param, "announce-position")) { 01236 if (!strcasecmp(val, "limit")) 01237 q->announceposition = ANNOUNCEPOSITION_LIMIT; 01238 else if (!strcasecmp(val, "more")) 01239 q->announceposition = ANNOUNCEPOSITION_MORE_THAN; 01240 else if (ast_true(val)) 01241 q->announceposition = ANNOUNCEPOSITION_YES; 01242 else 01243 q->announceposition = ANNOUNCEPOSITION_NO; 01244 } else if (!strcasecmp(param, "announce-position-limit")) { 01245 q->announcepositionlimit = atoi(val); 01246 } else if (!strcasecmp(param, "periodic-announce")) { 01247 if (strchr(val, ',')) { 01248 char *s, *buf = ast_strdupa(val); 01249 unsigned int i = 0; 01250 01251 while ((s = strsep(&buf, ",|"))) { 01252 if (!q->sound_periodicannounce[i]) 01253 q->sound_periodicannounce[i] = ast_str_create(16); 01254 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s); 01255 i++; 01256 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 01257 break; 01258 } 01259 q->numperiodicannounce = i; 01260 } else { 01261 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val); 01262 q->numperiodicannounce = 1; 01263 } 01264 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 01265 q->periodicannouncefrequency = atoi(val); 01266 } else if (!strcasecmp(param, "random-periodic-announce")) { 01267 q->randomperiodicannounce = ast_true(val); 01268 } else if (!strcasecmp(param, "retry")) { 01269 q->retry = atoi(val); 01270 if (q->retry <= 0) 01271 q->retry = DEFAULT_RETRY; 01272 } else if (!strcasecmp(param, "wrapuptime")) { 01273 q->wrapuptime = atoi(val); 01274 } else if (!strcasecmp(param, "autofill")) { 01275 q->autofill = ast_true(val); 01276 } else if (!strcasecmp(param, "monitor-type")) { 01277 if (!strcasecmp(val, "mixmonitor")) 01278 q->montype = 1; 01279 } else if (!strcasecmp(param, "autopause")) { 01280 q->autopause = ast_true(val); 01281 } else if (!strcasecmp(param, "maxlen")) { 01282 q->maxlen = atoi(val); 01283 if (q->maxlen < 0) 01284 q->maxlen = 0; 01285 } else if (!strcasecmp(param, "servicelevel")) { 01286 q->servicelevel= atoi(val); 01287 } else if (!strcasecmp(param, "strategy")) { 01288 int strategy; 01289 01290 /* We are a static queue and already have set this, no need to do it again */ 01291 if (failunknown) { 01292 return; 01293 } 01294 strategy = strat2int(val); 01295 if (strategy < 0) { 01296 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 01297 val, q->name); 01298 q->strategy = QUEUE_STRATEGY_RINGALL; 01299 } 01300 if (strategy == q->strategy) { 01301 return; 01302 } 01303 if (strategy == QUEUE_STRATEGY_LINEAR) { 01304 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n"); 01305 return; 01306 } 01307 q->strategy = strategy; 01308 } else if (!strcasecmp(param, "joinempty")) { 01309 if (!strcasecmp(val, "loose")) 01310 q->joinempty = QUEUE_EMPTY_LOOSE; 01311 else if (!strcasecmp(val, "strict")) 01312 q->joinempty = QUEUE_EMPTY_STRICT; 01313 else if (ast_true(val)) 01314 q->joinempty = QUEUE_EMPTY_NORMAL; 01315 else 01316 q->joinempty = 0; 01317 } else if (!strcasecmp(param, "leavewhenempty")) { 01318 if (!strcasecmp(val, "loose")) 01319 q->leavewhenempty = QUEUE_EMPTY_LOOSE; 01320 else if (!strcasecmp(val, "strict")) 01321 q->leavewhenempty = QUEUE_EMPTY_STRICT; 01322 else if (ast_true(val)) 01323 q->leavewhenempty = QUEUE_EMPTY_NORMAL; 01324 else 01325 q->leavewhenempty = 0; 01326 } else if (!strcasecmp(param, "eventmemberstatus")) { 01327 q->maskmemberstatus = !ast_true(val); 01328 } else if (!strcasecmp(param, "eventwhencalled")) { 01329 if (!strcasecmp(val, "vars")) { 01330 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 01331 } else { 01332 q->eventwhencalled = ast_true(val) ? 1 : 0; 01333 } 01334 } else if (!strcasecmp(param, "reportholdtime")) { 01335 q->reportholdtime = ast_true(val); 01336 } else if (!strcasecmp(param, "memberdelay")) { 01337 q->memberdelay = atoi(val); 01338 } else if (!strcasecmp(param, "weight")) { 01339 q->weight = atoi(val); 01340 if (q->weight) 01341 use_weight++; 01342 /* With Realtime queues, if the last queue using weights is deleted in realtime, 01343 we will not see any effect on use_weight until next reload. */ 01344 } else if (!strcasecmp(param, "timeoutrestart")) { 01345 q->timeoutrestart = ast_true(val); 01346 } else if (!strcasecmp(param, "defaultrule")) { 01347 ast_string_field_set(q, defaultrule, val); 01348 } else if (!strcasecmp(param, "timeoutpriority")) { 01349 if (!strcasecmp(val, "conf")) { 01350 q->timeoutpriority = TIMEOUT_PRIORITY_CONF; 01351 } else { 01352 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 01353 } 01354 } else if (failunknown) { 01355 if (linenum >= 0) { 01356 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 01357 q->name, param, linenum); 01358 } else { 01359 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 01360 } 01361 } 01362 }
static char* queue_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 5955 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.
05956 { 05957 switch ( cmd ) { 05958 case CLI_INIT: 05959 e->command = "queue show"; 05960 e->usage = 05961 "Usage: queue show\n" 05962 " Provides summary information on a specified queue.\n"; 05963 return NULL; 05964 case CLI_GENERATE: 05965 return complete_queue_show(a->line, a->word, a->pos, a->n); 05966 } 05967 05968 return __queues_show(NULL, a->fd, a->argc, a->argv); 05969 }
static void queue_transfer_destroy | ( | void * | data | ) | [static] |
Definition at line 3235 of file app_queue.c.
References ast_free.
03236 { 03237 struct queue_transfer_ds *qtds = data; 03238 ast_free(qtds); 03239 }
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 3258 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().
03259 { 03260 struct queue_transfer_ds *qtds = data; 03261 struct queue_ent *qe = qtds->qe; 03262 struct member *member = qtds->member; 03263 time_t callstart = qtds->starttime; 03264 int callcompletedinsl = qtds->callcompletedinsl; 03265 struct ast_datastore *datastore; 03266 03267 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 03268 new_chan->exten, new_chan->context, (long) (callstart - qe->start), 03269 (long) (time(NULL) - callstart), qe->opos); 03270 03271 update_queue(qe->parent, member, callcompletedinsl); 03272 03273 /* No need to lock the channels because they are already locked in ast_do_masquerade */ 03274 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) { 03275 ast_channel_datastore_remove(old_chan, datastore); 03276 } else { 03277 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n"); 03278 } 03279 }
static struct call_queue* queue_unref | ( | struct call_queue * | q | ) | [inline, static] |
Definition at line 623 of file app_queue.c.
References ao2_ref.
00624 { 00625 ao2_ref(q, -1); 00626 return q; 00627 }
static void recalc_holdtime | ( | struct queue_ent * | qe, | |
int | newholdtime | |||
) | [static] |
Definition at line 2015 of file app_queue.c.
References ao2_lock(), ao2_unlock(), call_queue::holdtime, and queue_ent::parent.
02016 { 02017 int oldvalue; 02018 02019 /* Calculate holdtime using an exponential average */ 02020 /* Thanks to SRT for this contribution */ 02021 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 02022 02023 ao2_lock(qe->parent); 02024 oldvalue = qe->parent->holdtime; 02025 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 02026 ao2_unlock(qe->parent); 02027 }
static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Record that a caller gave up on waiting in queue.
Definition at line 2570 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().
02571 { 02572 ao2_lock(qe->parent); 02573 set_queue_variables(qe->parent, qe->chan); 02574 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 02575 "Queue: %s\r\n" 02576 "Uniqueid: %s\r\n" 02577 "Position: %d\r\n" 02578 "OriginalPosition: %d\r\n" 02579 "HoldTime: %d\r\n", 02580 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 02581 02582 qe->parent->callsabandoned++; 02583 ao2_unlock(qe->parent); 02584 }
static int reload | ( | void | ) | [static] |
Definition at line 6857 of file app_queue.c.
References ast_unload_realtime(), and reload_queues().
06858 { 06859 ast_unload_realtime("queue_members"); 06860 reload_queues(1); 06861 return 0; 06862 }
static void reload_queue_members | ( | void | ) | [static] |
Reload dynamic queue members persisted into the astdb.
Definition at line 4468 of file app_queue.c.
References add_to_queue(), ao2_lock(), ao2_t_find, ao2_unlock(), 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, 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().
04469 { 04470 char *cur_ptr; 04471 const char *queue_name; 04472 char *member; 04473 char *interface; 04474 char *membername = NULL; 04475 char *state_interface; 04476 char *penalty_tok; 04477 int penalty = 0; 04478 char *paused_tok; 04479 int paused = 0; 04480 struct ast_db_entry *db_tree; 04481 struct ast_db_entry *entry; 04482 struct call_queue *cur_queue; 04483 char queue_data[PM_MAX_LEN]; 04484 04485 ao2_lock(queues); 04486 04487 /* Each key in 'pm_family' is the name of a queue */ 04488 db_tree = ast_db_gettree(pm_family, NULL); 04489 for (entry = db_tree; entry; entry = entry->next) { 04490 04491 queue_name = entry->key + strlen(pm_family) + 2; 04492 04493 { 04494 struct call_queue tmpq = { 04495 .name = queue_name, 04496 }; 04497 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members"); 04498 } 04499 04500 if (!cur_queue) 04501 cur_queue = load_realtime_queue(queue_name); 04502 04503 if (!cur_queue) { 04504 /* If the queue no longer exists, remove it from the 04505 * database */ 04506 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 04507 ast_db_del(pm_family, queue_name); 04508 continue; 04509 } 04510 04511 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) { 04512 queue_t_unref(cur_queue, "Expire reload reference"); 04513 continue; 04514 } 04515 04516 cur_ptr = queue_data; 04517 while ((member = strsep(&cur_ptr, ",|"))) { 04518 if (ast_strlen_zero(member)) 04519 continue; 04520 04521 interface = strsep(&member, ";"); 04522 penalty_tok = strsep(&member, ";"); 04523 paused_tok = strsep(&member, ";"); 04524 membername = strsep(&member, ";"); 04525 state_interface = strsep(&member, ";"); 04526 04527 if (!penalty_tok) { 04528 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 04529 break; 04530 } 04531 penalty = strtol(penalty_tok, NULL, 10); 04532 if (errno == ERANGE) { 04533 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 04534 break; 04535 } 04536 04537 if (!paused_tok) { 04538 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 04539 break; 04540 } 04541 paused = strtol(paused_tok, NULL, 10); 04542 if ((errno == ERANGE) || paused < 0 || paused > 1) { 04543 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 04544 break; 04545 } 04546 04547 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 04548 04549 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { 04550 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 04551 break; 04552 } 04553 } 04554 queue_t_unref(cur_queue, "Expire reload reference"); 04555 } 04556 04557 ao2_unlock(queues); 04558 if (db_tree) { 04559 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 04560 ast_db_freetree(db_tree); 04561 } 04562 }
static int reload_queue_rules | ( | int | reload | ) | [static] |
Definition at line 5512 of file app_queue.c.
References ast_calloc, ast_category_browse(), ast_config_load, ast_copy_string(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_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 handle_queue_rule_reload(), and reload_queues().
05513 { 05514 struct ast_config *cfg; 05515 struct rule_list *rl_iter, *new_rl; 05516 struct penalty_rule *pr_iter; 05517 char *rulecat = NULL; 05518 struct ast_variable *rulevar = NULL; 05519 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 05520 05521 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) { 05522 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n"); 05523 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 05524 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n"); 05525 return AST_MODULE_LOAD_SUCCESS; 05526 } else { 05527 AST_LIST_LOCK(&rule_lists); 05528 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) { 05529 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list))) 05530 ast_free(pr_iter); 05531 ast_free(rl_iter); 05532 } 05533 while ((rulecat = ast_category_browse(cfg, rulecat))) { 05534 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) { 05535 ast_log(LOG_ERROR, "Memory allocation error while loading queuerules.conf! Aborting!\n"); 05536 AST_LIST_UNLOCK(&rule_lists); 05537 return AST_MODULE_LOAD_FAILURE; 05538 } else { 05539 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name)); 05540 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list); 05541 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next) 05542 if(!strcasecmp(rulevar->name, "penaltychange")) { 05543 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno); 05544 } else { 05545 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno); 05546 } 05547 } 05548 } 05549 AST_LIST_UNLOCK(&rule_lists); 05550 } 05551 05552 ast_config_destroy(cfg); 05553 05554 return AST_MODULE_LOAD_SUCCESS; 05555 }
static int reload_queues | ( | int | reload | ) | [static] |
Definition at line 5558 of file app_queue.c.
References add_to_interfaces(), alloc_queue(), ao2_find, AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_lock(), ao2_ref, ao2_t_find, ao2_t_iterator_next, ao2_unlink, ao2_unlock(), AST_APP_ARG, ast_category_browse(), ast_config_load, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_free, ast_log(), AST_MODULE_LOAD_FAILURE, AST_STANDARD_APP_ARGS, ast_strdup, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), clear_queue(), CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEUNCHANGED, create_queue_member(), call_queue::dead, member::delme, member::dynamic, call_queue::found, init_queue(), member::interface, LOG_NOTICE, LOG_WARNING, call_queue::membercount, call_queue::members, call_queue::name, OBJ_POINTER, OBJ_UNLINK, parse(), member::paused, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_t_unref, queues, queues_t_link, call_queue::realtime, reload_queue_rules(), remove_from_interfaces(), member::state_interface, strat2int(), and var.
Referenced by load_module(), and reload().
05559 { 05560 struct call_queue *q; 05561 struct ast_config *cfg; 05562 char *cat, *tmp; 05563 struct ast_variable *var; 05564 struct member *cur, *newm; 05565 struct ao2_iterator mem_iter; 05566 int new; 05567 const char *general_val = NULL; 05568 char *parse; 05569 char *interface, *state_interface; 05570 char *membername = NULL; 05571 int penalty; 05572 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 05573 struct ao2_iterator queue_iter; 05574 AST_DECLARE_APP_ARGS(args, 05575 AST_APP_ARG(interface); 05576 AST_APP_ARG(penalty); 05577 AST_APP_ARG(membername); 05578 AST_APP_ARG(state_interface); 05579 ); 05580 05581 /*First things first. Let's load queuerules.conf*/ 05582 if (reload_queue_rules(reload) == AST_MODULE_LOAD_FAILURE) 05583 return AST_MODULE_LOAD_FAILURE; 05584 05585 if (!(cfg = ast_config_load("queues.conf", config_flags))) { 05586 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 05587 return 0; 05588 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 05589 return 0; 05590 ao2_lock(queues); 05591 use_weight=0; 05592 /* Mark all queues as dead for the moment */ 05593 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); 05594 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 05595 if (!q->realtime) { 05596 q->dead = 1; 05597 q->found = 0; 05598 } 05599 queue_t_unref(q, "Done with iterator"); 05600 } 05601 05602 /* Chug through config file */ 05603 cat = NULL; 05604 while ((cat = ast_category_browse(cfg, cat)) ) { 05605 if (!strcasecmp(cat, "general")) { 05606 /* Initialize global settings */ 05607 queue_keep_stats = 0; 05608 if ((general_val = ast_variable_retrieve(cfg, "general", "keepstats"))) 05609 queue_keep_stats = ast_true(general_val); 05610 queue_persistent_members = 0; 05611 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 05612 queue_persistent_members = ast_true(general_val); 05613 autofill_default = 0; 05614 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 05615 autofill_default = ast_true(general_val); 05616 montype_default = 0; 05617 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) { 05618 if (!strcasecmp(general_val, "mixmonitor")) 05619 montype_default = 1; 05620 } 05621 update_cdr = 0; 05622 if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr"))) 05623 update_cdr = ast_true(general_val); 05624 shared_lastcall = 0; 05625 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) 05626 shared_lastcall = ast_true(general_val); 05627 } else { /* Define queue */ 05628 /* Look for an existing one */ 05629 struct call_queue tmpq = { 05630 .name = cat, 05631 }; 05632 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Verify whether we exist or not"))) { 05633 /* Make one then */ 05634 if (!(q = alloc_queue(cat))) { 05635 /* TODO: Handle memory allocation failure */ 05636 } 05637 new = 1; 05638 } else 05639 new = 0; 05640 if (q) { 05641 const char *tmpvar = NULL; 05642 if (!new) 05643 ao2_lock(q); 05644 /* Check if a queue with this name already exists */ 05645 if (q->found) { 05646 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat); 05647 if (!new) { 05648 ao2_unlock(q); 05649 queue_t_unref(q, "We exist! Expiring temporary pointer"); 05650 } 05651 continue; 05652 } 05653 /* Due to the fact that the "linear" strategy will have a different allocation 05654 * scheme for queue members, we must devise the queue's strategy before other initializations 05655 */ 05656 if ((tmpvar = ast_variable_retrieve(cfg, cat, "strategy"))) { 05657 q->strategy = strat2int(tmpvar); 05658 if (q->strategy < 0) { 05659 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 05660 tmpvar, q->name); 05661 q->strategy = QUEUE_STRATEGY_RINGALL; 05662 } 05663 } else 05664 q->strategy = QUEUE_STRATEGY_RINGALL; 05665 /* Re-initialize the queue, and clear statistics */ 05666 init_queue(q); 05667 if (!queue_keep_stats) 05668 clear_queue(q); 05669 mem_iter = ao2_iterator_init(q->members, 0); 05670 while ((cur = ao2_iterator_next(&mem_iter))) { 05671 if (!cur->dynamic) { 05672 cur->delme = 1; 05673 } 05674 ao2_ref(cur, -1); 05675 } 05676 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 05677 if (!strcasecmp(var->name, "member")) { 05678 struct member tmpmem; 05679 membername = NULL; 05680 05681 if (ast_strlen_zero(var->value)) { 05682 ast_log(LOG_WARNING, "Empty queue member definition at line %d. Moving on!\n", var->lineno); 05683 continue; 05684 } 05685 05686 /* Add a new member */ 05687 if (!(parse = ast_strdup(var->value))) { 05688 continue; 05689 } 05690 05691 AST_STANDARD_APP_ARGS(args, parse); 05692 05693 interface = args.interface; 05694 if (!ast_strlen_zero(args.penalty)) { 05695 tmp = args.penalty; 05696 while (*tmp && *tmp < 33) tmp++; 05697 penalty = atoi(tmp); 05698 if (penalty < 0) { 05699 penalty = 0; 05700 } 05701 } else 05702 penalty = 0; 05703 05704 if (!ast_strlen_zero(args.membername)) { 05705 membername = args.membername; 05706 while (*membername && *membername < 33) membername++; 05707 } 05708 05709 if (!ast_strlen_zero(args.state_interface)) { 05710 state_interface = args.state_interface; 05711 while (*state_interface && *state_interface < 33) state_interface++; 05712 } else 05713 state_interface = interface; 05714 05715 /* Find the old position in the list */ 05716 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 05717 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); 05718 /* Only attempt removing from interfaces list if the new state_interface is different than the old one */ 05719 if (cur && strcasecmp(cur->state_interface, state_interface)) { 05720 remove_from_interfaces(cur->state_interface, 0); 05721 } 05722 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface); 05723 if (!cur || (cur && strcasecmp(cur->state_interface, state_interface))) 05724 add_to_interfaces(state_interface); 05725 ao2_link(q->members, newm); 05726 ao2_ref(newm, -1); 05727 newm = NULL; 05728 05729 if (cur) 05730 ao2_ref(cur, -1); 05731 else { 05732 q->membercount++; 05733 } 05734 ast_free(parse); 05735 } else { 05736 queue_set_param(q, var->name, var->value, var->lineno, 1); 05737 } 05738 } 05739 05740 /* Free remaining members marked as delme */ 05741 mem_iter = ao2_iterator_init(q->members, 0); 05742 while ((cur = ao2_iterator_next(&mem_iter))) { 05743 if (! cur->delme) { 05744 ao2_ref(cur, -1); 05745 continue; 05746 } 05747 q->membercount--; 05748 ao2_unlink(q->members, cur); 05749 remove_from_interfaces(cur->interface, 0); 05750 ao2_ref(cur, -1); 05751 } 05752 05753 if (new) { 05754 queues_t_link(queues, q, "Add queue to container"); 05755 } else 05756 ao2_unlock(q); 05757 queue_t_unref(q, "Added queue to container, deleting creation pointer"); 05758 } 05759 } 05760 } 05761 ast_config_destroy(cfg); 05762 queue_iter = ao2_iterator_init(queues, 0); 05763 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 05764 if (q->dead) { 05765 queues_t_unlink(queues, q, "Remove queue from container because marked as dead"); 05766 } else { 05767 ao2_lock(q); 05768 mem_iter = ao2_iterator_init(q->members, 0); 05769 while ((cur = ao2_iterator_next(&mem_iter))) { 05770 if (cur->dynamic) 05771 q->membercount++; 05772 cur->status = ast_device_state(cur->state_interface); 05773 ao2_ref(cur, -1); 05774 } 05775 ao2_unlock(q); 05776 } 05777 queue_t_unref(q, "Done with iterator"); 05778 } 05779 ao2_unlock(queues); 05780 return 1; 05781 }
static int remove_from_interfaces | ( | const char * | interface, | |
int | lock_queue_container | |||
) | [static] |
Definition at line 1037 of file app_queue.c.
References ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, member_interface::interface, interface_exists_global(), and member_interface::list.
Referenced by free_members(), reload_queues(), remove_from_queue(), rt_handle_member_record(), and update_realtime_members().
01038 { 01039 struct member_interface *curint; 01040 01041 if (interface_exists_global(interface, lock_queue_container)) 01042 return 0; 01043 01044 AST_LIST_LOCK(&interfaces); 01045 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) { 01046 if (!strcasecmp(curint->interface, interface)) { 01047 ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface); 01048 AST_LIST_REMOVE_CURRENT(list); 01049 ast_free(curint); 01050 break; 01051 } 01052 } 01053 AST_LIST_TRAVERSE_SAFE_END; 01054 AST_LIST_UNLOCK(&interfaces); 01055 01056 return 0; 01057 }
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 4202 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, call_queue::membercount, member::membername, call_queue::members, call_queue::name, OBJ_POINTER, queue_t_unref, queues, remove_from_interfaces(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and member::state_interface.
Referenced by attempt_thread(), handle_queue_remove_member(), manager_remove_queue_member(), rqm_exec(), and scan_service().
04203 { 04204 struct call_queue *q, tmpq = { 04205 .name = queuename, 04206 }; 04207 struct member *mem, tmpmem; 04208 int res = RES_NOSUCHQUEUE; 04209 04210 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 04211 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) { 04212 ao2_lock(queues); 04213 ao2_lock(q); 04214 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 04215 /* XXX future changes should beware of this assumption!! */ 04216 if (!mem->dynamic) { 04217 ao2_ref(mem, -1); 04218 ao2_unlock(q); 04219 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference"); 04220 ao2_unlock(queues); 04221 return RES_NOT_DYNAMIC; 04222 } 04223 q->membercount--; 04224 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 04225 "Queue: %s\r\n" 04226 "Location: %s\r\n" 04227 "MemberName: %s\r\n", 04228 q->name, mem->interface, mem->membername); 04229 ao2_unlink(q->members, mem); 04230 remove_from_interfaces(mem->state_interface, 0); 04231 ao2_ref(mem, -1); 04232 04233 if (queue_persistent_members) 04234 dump_queue_members(q); 04235 04236 res = RES_OKAY; 04237 } else { 04238 res = RES_EXISTS; 04239 } 04240 ao2_unlock(q); 04241 ao2_unlock(queues); 04242 queue_t_unref(q, "Expiring temporary reference"); 04243 } 04244 04245 return res; 04246 }
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 2254 of file app_queue.c.
References ast_cdr::accountcode, ast_channel::adsicpe, ast_cdr::amaflags, 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, ast_channel_unlock, ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, ast_device_state(), AST_DEVICE_UNKNOWN, ast_free, ast_request(), ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_verb, ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_cdr::clid, compare_weight(), ast_channel::context, ast_channel::data, ast_cdr::dcontext, dialcontext, do_hang(), ast_cdr::dst, EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, callattempt::interface, ast_cdr::lastapp, callattempt::lastcall, ast_cdr::lastdata, callattempt::lastqueue, queue_ent::linpos, manager_event, callattempt::member, member::membername, ast_channel::name, call_queue::name, ast_channel::nativeformats, queue_ent::parent, member::paused, pbx_builtin_getvar_helper(), ast_channel::priority, QUEUE_EVENT_VARIABLES, call_queue::ringinuse, call_queue::rrpos, ast_cdr::src, member::state_interface, member::status, status, callattempt::stillgoing, ast_channel::uniqueid, update_status(), ast_cdr::userfield, vars2manager(), ast_channel::whentohangup, and call_queue::wrapuptime.
Referenced by ring_one().
02255 { 02256 int res; 02257 int status; 02258 char tech[256]; 02259 char *location; 02260 const char *macrocontext, *macroexten; 02261 02262 /* on entry here, we know that tmp->chan == NULL */ 02263 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) || 02264 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) { 02265 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 02266 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface); 02267 if (qe->chan->cdr) 02268 ast_cdr_busy(qe->chan->cdr); 02269 tmp->stillgoing = 0; 02270 (*busies)++; 02271 return 0; 02272 } 02273 02274 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 02275 ast_debug(1, "%s in use, can't receive call\n", tmp->interface); 02276 if (qe->chan->cdr) 02277 ast_cdr_busy(qe->chan->cdr); 02278 tmp->stillgoing = 0; 02279 return 0; 02280 } 02281 02282 if (tmp->member->paused) { 02283 ast_debug(1, "%s paused, can't receive call\n", tmp->interface); 02284 if (qe->chan->cdr) 02285 ast_cdr_busy(qe->chan->cdr); 02286 tmp->stillgoing = 0; 02287 return 0; 02288 } 02289 if (use_weight && compare_weight(qe->parent,tmp->member)) { 02290 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 02291 if (qe->chan->cdr) 02292 ast_cdr_busy(qe->chan->cdr); 02293 tmp->stillgoing = 0; 02294 (*busies)++; 02295 return 0; 02296 } 02297 02298 ast_copy_string(tech, tmp->interface, sizeof(tech)); 02299 if ((location = strchr(tech, '/'))) 02300 *location++ = '\0'; 02301 else 02302 location = ""; 02303 02304 /* Request the peer */ 02305 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status); 02306 if (!tmp->chan) { /* If we can't, just go on to the next call */ 02307 if (qe->chan->cdr) 02308 ast_cdr_busy(qe->chan->cdr); 02309 tmp->stillgoing = 0; 02310 02311 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02312 02313 ao2_lock(qe->parent); 02314 qe->parent->rrpos++; 02315 qe->linpos++; 02316 ao2_unlock(qe->parent); 02317 02318 02319 (*busies)++; 02320 return 0; 02321 } 02322 02323 tmp->chan->appl = "AppQueue"; 02324 tmp->chan->data = "(Outgoing Line)"; 02325 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup)); 02326 if (tmp->chan->cid.cid_num) 02327 ast_free(tmp->chan->cid.cid_num); 02328 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num); 02329 if (tmp->chan->cid.cid_name) 02330 ast_free(tmp->chan->cid.cid_name); 02331 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name); 02332 if (tmp->chan->cid.cid_ani) 02333 ast_free(tmp->chan->cid.cid_ani); 02334 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani); 02335 02336 /* Inherit specially named variables from parent channel */ 02337 ast_channel_inherit_variables(qe->chan, tmp->chan); 02338 ast_channel_datastore_inherit(qe->chan, tmp->chan); 02339 02340 /* Presense of ADSI CPE on outgoing channel follows ours */ 02341 tmp->chan->adsicpe = qe->chan->adsicpe; 02342 02343 /* Inherit context and extension */ 02344 ast_channel_lock(qe->chan); 02345 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 02346 ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext); 02347 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 02348 if (!ast_strlen_zero(macroexten)) 02349 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 02350 else 02351 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 02352 if (ast_cdr_isset_unanswered()) { 02353 /* they want to see the unanswered dial attempts! */ 02354 /* set up the CDR fields on all the CDRs to give sensical information */ 02355 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name); 02356 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid); 02357 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel); 02358 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src); 02359 strcpy(tmp->chan->cdr->dst, qe->chan->exten); 02360 strcpy(tmp->chan->cdr->dcontext, qe->chan->context); 02361 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp); 02362 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata); 02363 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags; 02364 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode); 02365 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); 02366 } 02367 ast_channel_unlock(qe->chan); 02368 02369 /* Place the call, but don't wait on the answer */ 02370 if ((res = ast_call(tmp->chan, location, 0))) { 02371 /* Again, keep going even if there's an error */ 02372 ast_debug(1, "ast call on peer returned %d\n", res); 02373 ast_verb(3, "Couldn't call %s\n", tmp->interface); 02374 do_hang(tmp); 02375 (*busies)++; 02376 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02377 return 0; 02378 } else if (qe->parent->eventwhencalled) { 02379 char vars[2048]; 02380 02381 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 02382 "Queue: %s\r\n" 02383 "AgentCalled: %s\r\n" 02384 "AgentName: %s\r\n" 02385 "ChannelCalling: %s\r\n" 02386 "DestinationChannel: %s\r\n" 02387 "CallerIDNum: %s\r\n" 02388 "CallerIDName: %s\r\n" 02389 "Context: %s\r\n" 02390 "Extension: %s\r\n" 02391 "Priority: %d\r\n" 02392 "Uniqueid: %s\r\n" 02393 "%s", 02394 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name, 02395 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown", 02396 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown", 02397 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid, 02398 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02399 ast_verb(3, "Called %s\n", tmp->interface); 02400 } 02401 02402 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02403 return 1; 02404 }
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 2432 of file app_queue.c.
References ast_debug, callattempt::chan, queue_ent::expire, find_best(), callattempt::interface, callattempt::metric, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_entry(), callattempt::stillgoing, and call_queue::strategy.
Referenced by try_calling(), and wait_for_answer().
02433 { 02434 int ret = 0; 02435 02436 while (ret == 0) { 02437 struct callattempt *best = find_best(outgoing); 02438 if (!best) { 02439 ast_debug(1, "Nobody left to try ringing in queue\n"); 02440 break; 02441 } 02442 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 02443 struct callattempt *cur; 02444 /* Ring everyone who shares this best metric (for ringall) */ 02445 for (cur = outgoing; cur; cur = cur->q_next) { 02446 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 02447 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 02448 ret |= ring_entry(qe, cur, busies); 02449 } 02450 } 02451 } else { 02452 /* Ring just the best channel */ 02453 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric); 02454 ret = ring_entry(qe, best, busies); 02455 } 02456 02457 /* If we have timed out, break out */ 02458 if (qe->expire && (time(NULL) >= qe->expire)) { 02459 ast_debug(1, "Queue timed out while ringing members.\n"); 02460 ret = 0; 02461 break; 02462 } 02463 } 02464 02465 return ret; 02466 }
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 2587 of file app_queue.c.
References ast_queue_log(), ast_verb, call_queue::autopause, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, manager_event, ast_channel::name, call_queue::name, queue_ent::parent, set_member_paused(), and ast_channel::uniqueid.
02588 { 02589 ast_verb(3, "Nobody picked up in %d ms\n", rnatime); 02590 if (qe->parent->eventwhencalled) 02591 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer", 02592 "Queue: %s\r\n" 02593 "Uniqueid: %s\r\n" 02594 "Channel: %s\r\n" 02595 "Member: %s\r\n" 02596 "MemberName: %s\r\n" 02597 "Ringtime: %d\r\n", 02598 qe->parent->name, 02599 qe->chan->uniqueid, 02600 qe->chan->name, 02601 interface, 02602 membername, 02603 rnatime); 02604 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 02605 if (qe->parent->autopause && pause) { 02606 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) { 02607 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name); 02608 } else { 02609 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 02610 } 02611 } 02612 return; 02613 }
static int rqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
RemoveQueueMember application.
Definition at line 4637 of file app_queue.c.
References AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), chan, 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().
04638 { 04639 int res=-1; 04640 char *parse, *temppos = NULL; 04641 AST_DECLARE_APP_ARGS(args, 04642 AST_APP_ARG(queuename); 04643 AST_APP_ARG(interface); 04644 AST_APP_ARG(options); 04645 ); 04646 04647 04648 if (ast_strlen_zero(data)) { 04649 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n"); 04650 return -1; 04651 } 04652 04653 parse = ast_strdupa(data); 04654 04655 AST_STANDARD_APP_ARGS(args, parse); 04656 04657 if (ast_strlen_zero(args.interface)) { 04658 args.interface = ast_strdupa(chan->name); 04659 temppos = strrchr(args.interface, '-'); 04660 if (temppos) 04661 *temppos = '\0'; 04662 } 04663 04664 switch (remove_from_queue(args.queuename, args.interface)) { 04665 case RES_OKAY: 04666 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 04667 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 04668 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 04669 res = 0; 04670 break; 04671 case RES_EXISTS: 04672 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 04673 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 04674 res = 0; 04675 break; 04676 case RES_NOSUCHQUEUE: 04677 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 04678 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 04679 res = 0; 04680 break; 04681 case RES_NOT_DYNAMIC: 04682 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 04683 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 04684 res = 0; 04685 break; 04686 } 04687 04688 return res; 04689 }
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 1370 of file app_queue.c.
References add_to_interfaces(), 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::membercount, call_queue::members, call_queue::name, member::paused, member::penalty, member::realtime, remove_from_interfaces(), member::rt_uniqueid, S_OR, and member::state_interface.
Referenced by update_realtime_members().
01371 { 01372 struct member *m; 01373 struct ao2_iterator mem_iter; 01374 int penalty = 0; 01375 int paused = 0; 01376 int found = 0; 01377 01378 if (ast_strlen_zero(rt_uniqueid)) { 01379 ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL")); 01380 return; 01381 } 01382 01383 if (penalty_str) { 01384 penalty = atoi(penalty_str); 01385 if (penalty < 0) 01386 penalty = 0; 01387 } 01388 01389 if (paused_str) { 01390 paused = atoi(paused_str); 01391 if (paused < 0) 01392 paused = 0; 01393 } 01394 01395 /* Find member by realtime uniqueid and update */ 01396 mem_iter = ao2_iterator_init(q->members, 0); 01397 while ((m = ao2_iterator_next(&mem_iter))) { 01398 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) { 01399 m->dead = 0; /* Do not delete this one. */ 01400 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 01401 if (paused_str) 01402 m->paused = paused; 01403 if (strcasecmp(state_interface, m->state_interface)) { 01404 remove_from_interfaces(m->state_interface, 0); 01405 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); 01406 add_to_interfaces(m->state_interface); 01407 } 01408 m->penalty = penalty; 01409 found = 1; 01410 ao2_ref(m, -1); 01411 break; 01412 } 01413 ao2_ref(m, -1); 01414 } 01415 ao2_iterator_destroy(&mem_iter); 01416 01417 /* Create a new member */ 01418 if (!found) { 01419 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { 01420 m->dead = 0; 01421 m->realtime = 1; 01422 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 01423 add_to_interfaces(m->state_interface); 01424 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", ""); 01425 ao2_link(q->members, m); 01426 ao2_ref(m, -1); 01427 m = NULL; 01428 q->membercount++; 01429 } 01430 } 01431 }
static int say_periodic_announcement | ( | struct queue_ent * | qe, | |
int | ringing | |||
) | [static] |
Playback announcement to queued members if peroid has elapsed.
Definition at line 2517 of file app_queue.c.
References AST_CONTROL_RINGING, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_random(), ast_strlen_zero(), 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::sound_periodicannounce, and valid_exit().
Referenced by queue_exec(), and wait_our_turn().
02518 { 02519 int res = 0; 02520 time_t now; 02521 02522 /* Get the current time */ 02523 time(&now); 02524 02525 /* Check to see if it is time to announce */ 02526 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 02527 return 0; 02528 02529 /* Stop the music on hold so we can play our own file */ 02530 if (ringing) 02531 ast_indicate(qe->chan,-1); 02532 else 02533 ast_moh_stop(qe->chan); 02534 02535 ast_verb(3, "Playing periodic announcement\n"); 02536 02537 if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) { 02538 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce; 02539 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce || 02540 ast_strlen_zero(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str)) { 02541 qe->last_periodic_announce_sound = 0; 02542 } 02543 02544 /* play the announcement */ 02545 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str); 02546 02547 if (res > 0 && !valid_exit(qe, res)) 02548 res = 0; 02549 02550 /* Resume Music on Hold if the caller is going to stay in the queue */ 02551 if (!res) { 02552 if (ringing) 02553 ast_indicate(qe->chan, AST_CONTROL_RINGING); 02554 else 02555 ast_moh_start(qe->chan, qe->moh, NULL); 02556 } 02557 02558 /* update last_periodic_announce_time */ 02559 qe->last_periodic_announce_time = now; 02560 02561 /* Update the current periodic announcement to the next announcement */ 02562 if (!qe->parent->randomperiodicannounce) { 02563 qe->last_periodic_announce_sound++; 02564 } 02565 02566 return res; 02567 }
static int say_position | ( | struct queue_ent * | qe, | |
int | ringing | |||
) | [static] |
Definition at line 1871 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(), and wait_our_turn().
01872 { 01873 int res = 0, avgholdmins, avgholdsecs, announceposition = 0; 01874 int say_thanks = 1; 01875 time_t now; 01876 01877 /* Let minannouncefrequency seconds pass between the start of each position announcement */ 01878 time(&now); 01879 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) 01880 return 0; 01881 01882 /* If either our position has changed, or we are over the freq timer, say position */ 01883 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 01884 return 0; 01885 01886 if (ringing) { 01887 ast_indicate(qe->chan,-1); 01888 } else { 01889 ast_moh_stop(qe->chan); 01890 } 01891 01892 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES || 01893 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN || 01894 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT && 01895 qe->pos <= qe->parent->announcepositionlimit)) 01896 announceposition = 1; 01897 01898 01899 if (announceposition == 1) { 01900 /* Say we're next, if we are */ 01901 if (qe->pos == 1) { 01902 res = play_file(qe->chan, qe->parent->sound_next); 01903 if (res) 01904 goto playout; 01905 else 01906 goto posout; 01907 } else { 01908 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 01909 /* More than Case*/ 01910 res = play_file(qe->chan, qe->parent->queue_quantity1); 01911 if (res) 01912 goto playout; 01913 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 01914 if (res) 01915 goto playout; 01916 } else { 01917 /* Normal Case */ 01918 res = play_file(qe->chan, qe->parent->sound_thereare); 01919 if (res) 01920 goto playout; 01921 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 01922 if (res) 01923 goto playout; 01924 } 01925 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 01926 /* More than Case*/ 01927 res = play_file(qe->chan, qe->parent->queue_quantity2); 01928 if (res) 01929 goto playout; 01930 } else { 01931 res = play_file(qe->chan, qe->parent->sound_calls); 01932 if (res) 01933 goto playout; 01934 } 01935 } 01936 } 01937 /* Round hold time to nearest minute */ 01938 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 01939 01940 /* If they have specified a rounding then round the seconds as well */ 01941 if (qe->parent->roundingseconds) { 01942 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 01943 avgholdsecs *= qe->parent->roundingseconds; 01944 } else { 01945 avgholdsecs = 0; 01946 } 01947 01948 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 01949 01950 /* If the hold time is >1 min, if it's enabled, and if it's not 01951 supposed to be only once and we have already said it, say it */ 01952 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime && 01953 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) || 01954 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) { 01955 res = play_file(qe->chan, qe->parent->sound_holdtime); 01956 if (res) 01957 goto playout; 01958 01959 if (avgholdmins >= 1) { 01960 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL); 01961 if (res) 01962 goto playout; 01963 01964 if (avgholdmins == 1) { 01965 res = play_file(qe->chan, qe->parent->sound_minute); 01966 if (res) 01967 goto playout; 01968 } else { 01969 res = play_file(qe->chan, qe->parent->sound_minutes); 01970 if (res) 01971 goto playout; 01972 } 01973 } 01974 if (avgholdsecs >= 1) { 01975 res = ast_say_number(qe->chan, avgholdmins > 1 ? avgholdsecs : avgholdmins * 60 + avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL); 01976 if (res) 01977 goto playout; 01978 01979 res = play_file(qe->chan, qe->parent->sound_seconds); 01980 if (res) 01981 goto playout; 01982 } 01983 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) { 01984 say_thanks = 0; 01985 } 01986 01987 posout: 01988 if (qe->parent->announceposition) { 01989 ast_verb(3, "Told %s in %s their queue position (which was %d)\n", 01990 qe->chan->name, qe->parent->name, qe->pos); 01991 } 01992 if (say_thanks) { 01993 res = play_file(qe->chan, qe->parent->sound_thanks); 01994 } 01995 playout: 01996 01997 if ((res > 0 && !valid_exit(qe, res))) 01998 res = 0; 01999 02000 /* Set our last_pos indicators */ 02001 qe->last_pos = now; 02002 qe->last_pos_said = qe->pos; 02003 02004 /* Don't restart music on hold if we're about to exit the caller from the queue */ 02005 if (!res) { 02006 if (ringing) { 02007 ast_indicate(qe->chan, AST_CONTROL_RINGING); 02008 } else { 02009 ast_moh_start(qe->chan, qe->moh, NULL); 02010 } 02011 } 02012 return res; 02013 }
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 3192 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().
03195 { 03196 const char *reason = NULL; /* silence dumb compilers */ 03197 03198 if (!qe->parent->eventwhencalled) 03199 return; 03200 03201 switch (rsn) { 03202 case CALLER: 03203 reason = "caller"; 03204 break; 03205 case AGENT: 03206 reason = "agent"; 03207 break; 03208 case TRANSFER: 03209 reason = "transfer"; 03210 break; 03211 } 03212 03213 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03214 "Queue: %s\r\n" 03215 "Uniqueid: %s\r\n" 03216 "Channel: %s\r\n" 03217 "Member: %s\r\n" 03218 "MemberName: %s\r\n" 03219 "HoldTime: %ld\r\n" 03220 "TalkTime: %ld\r\n" 03221 "Reason: %s\r\n" 03222 "%s", 03223 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03224 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason, 03225 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : ""); 03226 }
static int set_member_paused | ( | const char * | queuename, | |
const char * | interface, | |||
const char * | reason, | |||
int | paused | |||
) | [static] |
Definition at line 4310 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().
04311 { 04312 int found = 0; 04313 struct call_queue *q; 04314 struct member *mem; 04315 struct ao2_iterator queue_iter; 04316 int failed; 04317 04318 /* Special event for when all queues are paused - individual events still generated */ 04319 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 04320 if (ast_strlen_zero(queuename)) 04321 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 04322 04323 queue_iter = ao2_iterator_init(queues, 0); 04324 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 04325 ao2_lock(q); 04326 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 04327 if ((mem = interface_exists(q, interface))) { 04328 if (mem->paused == paused) { 04329 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 04330 } 04331 04332 failed = 0; 04333 if (mem->realtime) { 04334 failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); 04335 } 04336 04337 if (failed) { 04338 ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface); 04339 ao2_ref(mem, -1); 04340 ao2_unlock(q); 04341 queue_t_unref(q, "Done with iterator"); 04342 continue; 04343 } 04344 found++; 04345 mem->paused = paused; 04346 04347 if (queue_persistent_members) 04348 dump_queue_members(q); 04349 04350 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, "")); 04351 04352 if (!ast_strlen_zero(reason)) { 04353 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 04354 "Queue: %s\r\n" 04355 "Location: %s\r\n" 04356 "MemberName: %s\r\n" 04357 "Paused: %d\r\n" 04358 "Reason: %s\r\n", 04359 q->name, mem->interface, mem->membername, paused, reason); 04360 } else { 04361 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 04362 "Queue: %s\r\n" 04363 "Location: %s\r\n" 04364 "MemberName: %s\r\n" 04365 "Paused: %d\r\n", 04366 q->name, mem->interface, mem->membername, paused); 04367 } 04368 ao2_ref(mem, -1); 04369 } 04370 } 04371 04372 if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) { 04373 ao2_unlock(q); 04374 queue_t_unref(q, "Done with iterator"); 04375 break; 04376 } 04377 04378 ao2_unlock(q); 04379 queue_t_unref(q, "Done with iterator"); 04380 } 04381 ao2_iterator_destroy(&queue_iter); 04382 04383 return found ? RESULT_SUCCESS : RESULT_FAILURE; 04384 }
static int set_member_penalty | ( | char * | queuename, | |
char * | interface, | |||
int | penalty | |||
) | [static] |
Definition at line 4387 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().
04388 { 04389 int foundinterface = 0, foundqueue = 0; 04390 struct call_queue *q; 04391 struct member *mem; 04392 struct ao2_iterator queue_iter; 04393 04394 if (penalty < 0) { 04395 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty); 04396 return RESULT_FAILURE; 04397 } 04398 04399 queue_iter = ao2_iterator_init(queues, 0); 04400 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 04401 ao2_lock(q); 04402 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 04403 foundqueue++; 04404 if ((mem = interface_exists(q, interface))) { 04405 foundinterface++; 04406 mem->penalty = penalty; 04407 04408 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty); 04409 manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty", 04410 "Queue: %s\r\n" 04411 "Location: %s\r\n" 04412 "Penalty: %d\r\n", 04413 q->name, mem->interface, penalty); 04414 ao2_ref(mem, -1); 04415 } 04416 } 04417 ao2_unlock(q); 04418 queue_t_unref(q, "Done with iterator"); 04419 } 04420 ao2_iterator_destroy(&queue_iter); 04421 04422 if (foundinterface) { 04423 return RESULT_SUCCESS; 04424 } else if (!foundqueue) { 04425 ast_log (LOG_ERROR, "Invalid queuename\n"); 04426 } else { 04427 ast_log (LOG_ERROR, "Invalid interface\n"); 04428 } 04429 04430 return RESULT_FAILURE; 04431 }
static void set_queue_result | ( | struct ast_channel * | chan, | |
enum queue_result | res | |||
) | [static] |
sets the QUEUESTATUS channel variable
Definition at line 556 of file app_queue.c.
References ARRAY_LEN, pbx_builtin_setvar_helper(), queue_results, and text.
Referenced by queue_exec().
00557 { 00558 int i; 00559 00560 for (i = 0; i < ARRAY_LEN(queue_results); i++) { 00561 if (queue_results[i].id == res) { 00562 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 00563 return; 00564 } 00565 } 00566 }
static void set_queue_variables | ( | struct call_queue * | q, | |
struct ast_channel * | chan | |||
) | [static] |
Set variables of queue.
Definition at line 631 of file app_queue.c.
References 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, and call_queue::strategy.
Referenced by end_bridge_callback(), and record_abandoned().
00632 { 00633 char interfacevar[256]=""; 00634 float sl = 0; 00635 00636 if (q->setqueuevar) { 00637 sl = 0; 00638 if (q->callscompleted > 0) 00639 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 00640 00641 snprintf(interfacevar, sizeof(interfacevar), 00642 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 00643 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 00644 00645 pbx_builtin_setvar_multiple(chan, interfacevar); 00646 } 00647 }
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 3296 of file app_queue.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_log(), queue_ent::chan, ast_datastore::data, LOG_WARNING, queue_transfer_ds::member, queue_transfer_ds::qe, and queue_transfer_info.
03297 { 03298 struct ast_datastore *ds; 03299 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds)); 03300 03301 if (!qtds) { 03302 ast_log(LOG_WARNING, "Memory allocation error!\n"); 03303 return NULL; 03304 } 03305 03306 ast_channel_lock(qe->chan); 03307 if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) { 03308 ast_channel_unlock(qe->chan); 03309 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n"); 03310 return NULL; 03311 } 03312 03313 qtds->qe = qe; 03314 /* This member is refcounted in try_calling, so no need to add it here, too */ 03315 qtds->member = member; 03316 qtds->starttime = starttime; 03317 qtds->callcompletedinsl = callcompletedinsl; 03318 ds->data = qtds; 03319 ast_channel_datastore_add(qe->chan, ds); 03320 ast_channel_unlock(qe->chan); 03321 return ds; 03322 }
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 2493 of file app_queue.c.
References ast_debug, find_best(), callattempt::interface, queue_ent::linpos, queue_ent::linwrapped, and callattempt::metric.
Referenced by try_calling().
02494 { 02495 struct callattempt *best = find_best(outgoing); 02496 02497 if (best) { 02498 /* Ring just the best channel */ 02499 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 02500 qe->linpos = best->metric % 1000; 02501 } else { 02502 /* Just increment rrpos */ 02503 if (qe->linwrapped) { 02504 /* No more channels, start over */ 02505 qe->linpos = 0; 02506 } else { 02507 /* Prioritize next entry */ 02508 qe->linpos++; 02509 } 02510 } 02511 qe->linwrapped = 0; 02512 02513 return 0; 02514 }
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 2469 of file app_queue.c.
References ast_debug, find_best(), callattempt::interface, callattempt::metric, queue_ent::parent, call_queue::rrpos, and call_queue::wrapped.
Referenced by try_calling().
02470 { 02471 struct callattempt *best = find_best(outgoing); 02472 02473 if (best) { 02474 /* Ring just the best channel */ 02475 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 02476 qe->parent->rrpos = best->metric % 1000; 02477 } else { 02478 /* Just increment rrpos */ 02479 if (qe->parent->wrapped) { 02480 /* No more channels, start over */ 02481 qe->parent->rrpos = 0; 02482 } else { 02483 /* Prioritize next entry */ 02484 qe->parent->rrpos++; 02485 } 02486 } 02487 qe->parent->wrapped = 0; 02488 02489 return 0; 02490 }
static int strat2int | ( | const char * | strategy | ) | [static] |
Definition at line 580 of file app_queue.c.
References ARRAY_LEN, strategies, and strategy::strategy.
Referenced by find_queue_by_name_rt(), queue_set_param(), and reload_queues().
00581 { 00582 int x; 00583 00584 for (x = 0; x < ARRAY_LEN(strategies); x++) { 00585 if (!strcasecmp(strategy, strategies[x].name)) 00586 return strategies[x].strategy; 00587 } 00588 00589 return -1; 00590 }
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 3378 of file app_queue.c.
References ast_channel::_state, queue_ent::announce, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), ast_calloc, AST_CDR_FLAG_POST_DISABLED, ast_cdr_isset_unanswered(), ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_datastore_alloc, ast_datastore_free(), ast_debug, AST_FEATURE_AUTOMIXMON, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_free, AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_set_flag, AST_STATE_UP, ast_strlen_zero(), ast_test_flag, calc_metric(), ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_datastore::data, DATASTORE_INHERIT_FOREVER, di, dialed_interface_info, ast_cdr::dstchannel, queue_ent::expire, free, ast_datastore::inheritance, member::interface, member::lastcall, member::lastqueue, ast_dialed_interface::list, call_queue::membercount, call_queue::members, call_queue::name, ast_channel::name, queue_ent::parent, queue_ent::pending, callattempt::q_next, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRMEMORY, queues, ring_one(), member::status, store_next_lin(), store_next_rr(), call_queue::strategy, call_queue::timeout, TIMEOUT_PRIORITY_APP, call_queue::timeoutpriority, and wait_for_answer().
Referenced by queue_exec().
03379 { 03380 struct member *cur; 03381 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 03382 int to, orig; 03383 char oldexten[AST_MAX_EXTENSION]=""; 03384 char oldcontext[AST_MAX_CONTEXT]=""; 03385 char queuename[256]=""; 03386 char interfacevar[256]=""; 03387 struct ast_channel *peer; 03388 struct ast_channel *which; 03389 struct callattempt *lpeer; 03390 struct member *member; 03391 struct ast_app *application; 03392 int res = 0, bridge = 0; 03393 int numbusies = 0; 03394 int x=0; 03395 char *announce = NULL; 03396 char digit = 0; 03397 time_t callstart; 03398 time_t now = time(NULL); 03399 struct ast_bridge_config bridge_config; 03400 char nondataquality = 1; 03401 char *agiexec = NULL; 03402 char *macroexec = NULL; 03403 char *gosubexec = NULL; 03404 int ret = 0; 03405 const char *monitorfilename; 03406 const char *monitor_exec; 03407 const char *monitor_options; 03408 char tmpid[256], tmpid2[256]; 03409 char meid[1024], meid2[1024]; 03410 char mixmonargs[1512]; 03411 struct ast_app *mixmonapp = NULL; 03412 char *p; 03413 char vars[2048]; 03414 int forwardsallowed = 1; 03415 int callcompletedinsl; 03416 struct ao2_iterator memi; 03417 struct ast_datastore *datastore, *transfer_ds; 03418 struct queue_end_bridge *queue_end_bridge = NULL; 03419 const int need_weight = use_weight; 03420 03421 ast_channel_lock(qe->chan); 03422 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL); 03423 ast_channel_unlock(qe->chan); 03424 03425 memset(&bridge_config, 0, sizeof(bridge_config)); 03426 tmpid[0] = 0; 03427 meid[0] = 0; 03428 time(&now); 03429 03430 /* If we've already exceeded our timeout, then just stop 03431 * This should be extremely rare. queue_exec will take care 03432 * of removing the caller and reporting the timeout as the reason. 03433 */ 03434 if (qe->expire && now >= qe->expire) { 03435 res = 0; 03436 goto out; 03437 } 03438 03439 for (; options && *options; options++) 03440 switch (*options) { 03441 case 't': 03442 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 03443 break; 03444 case 'T': 03445 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 03446 break; 03447 case 'w': 03448 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 03449 break; 03450 case 'W': 03451 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 03452 break; 03453 case 'c': 03454 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN); 03455 break; 03456 case 'd': 03457 nondataquality = 0; 03458 break; 03459 case 'h': 03460 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 03461 break; 03462 case 'H': 03463 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 03464 break; 03465 case 'k': 03466 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL); 03467 break; 03468 case 'K': 03469 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL); 03470 break; 03471 case 'n': 03472 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR) 03473 (*tries)++; 03474 else 03475 *tries = qe->parent->membercount; 03476 *noption = 1; 03477 break; 03478 case 'i': 03479 forwardsallowed = 0; 03480 break; 03481 case 'x': 03482 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON); 03483 break; 03484 case 'X': 03485 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON); 03486 break; 03487 03488 } 03489 03490 /* Hold the lock while we setup the outgoing calls */ 03491 if (need_weight) 03492 ao2_lock(queues); 03493 ao2_lock(qe->parent); 03494 ast_debug(1, "%s is trying to call a queue member.\n", 03495 qe->chan->name); 03496 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 03497 if (!ast_strlen_zero(qe->announce)) 03498 announce = qe->announce; 03499 if (!ast_strlen_zero(announceoverride)) 03500 announce = announceoverride; 03501 03502 memi = ao2_iterator_init(qe->parent->members, 0); 03503 while ((cur = ao2_iterator_next(&memi))) { 03504 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 03505 struct ast_dialed_interface *di; 03506 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 03507 if (!tmp) { 03508 ao2_ref(cur, -1); 03509 ao2_unlock(qe->parent); 03510 ao2_iterator_destroy(&memi); 03511 if (need_weight) 03512 ao2_unlock(queues); 03513 goto out; 03514 } 03515 if (!datastore) { 03516 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) { 03517 ao2_ref(cur, -1); 03518 ao2_unlock(qe->parent); 03519 ao2_iterator_destroy(&memi); 03520 if (need_weight) 03521 ao2_unlock(queues); 03522 free(tmp); 03523 goto out; 03524 } 03525 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 03526 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 03527 ao2_ref(cur, -1); 03528 ao2_unlock(&qe->parent); 03529 ao2_iterator_destroy(&memi); 03530 if (need_weight) 03531 ao2_unlock(queues); 03532 free(tmp); 03533 goto out; 03534 } 03535 datastore->data = dialed_interfaces; 03536 AST_LIST_HEAD_INIT(dialed_interfaces); 03537 03538 ast_channel_lock(qe->chan); 03539 ast_channel_datastore_add(qe->chan, datastore); 03540 ast_channel_unlock(qe->chan); 03541 } else 03542 dialed_interfaces = datastore->data; 03543 03544 AST_LIST_LOCK(dialed_interfaces); 03545 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 03546 if (!strcasecmp(cur->interface, di->interface)) { 03547 ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n", 03548 di->interface); 03549 break; 03550 } 03551 } 03552 AST_LIST_UNLOCK(dialed_interfaces); 03553 03554 if (di) { 03555 free(tmp); 03556 continue; 03557 } 03558 03559 /* It is always ok to dial a Local interface. We only keep track of 03560 * which "real" interfaces have been dialed. The Local channel will 03561 * inherit this list so that if it ends up dialing a real interface, 03562 * it won't call one that has already been called. */ 03563 if (strncasecmp(cur->interface, "Local/", 6)) { 03564 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) { 03565 ao2_ref(cur, -1); 03566 ao2_unlock(qe->parent); 03567 ao2_iterator_destroy(&memi); 03568 if (need_weight) 03569 ao2_unlock(queues); 03570 free(tmp); 03571 goto out; 03572 } 03573 strcpy(di->interface, cur->interface); 03574 03575 AST_LIST_LOCK(dialed_interfaces); 03576 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 03577 AST_LIST_UNLOCK(dialed_interfaces); 03578 } 03579 03580 tmp->stillgoing = -1; 03581 tmp->member = cur; 03582 tmp->oldstatus = cur->status; 03583 tmp->lastcall = cur->lastcall; 03584 tmp->lastqueue = cur->lastqueue; 03585 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 03586 /* Special case: If we ring everyone, go ahead and ring them, otherwise 03587 just calculate their metric for the appropriate strategy */ 03588 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 03589 /* Put them in the list of outgoing thingies... We're ready now. 03590 XXX If we're forcibly removed, these outgoing calls won't get 03591 hung up XXX */ 03592 tmp->q_next = outgoing; 03593 outgoing = tmp; 03594 /* If this line is up, don't try anybody else */ 03595 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 03596 break; 03597 } else { 03598 ao2_ref(cur, -1); 03599 ast_free(tmp); 03600 } 03601 } 03602 ao2_iterator_destroy(&memi); 03603 03604 if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) { 03605 /* Application arguments have higher timeout priority (behaviour for <=1.6) */ 03606 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 03607 to = (qe->expire - now) * 1000; 03608 else 03609 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 03610 } else { 03611 /* Config timeout is higher priority thatn application timeout */ 03612 if (qe->expire && qe->expire<=now) { 03613 to = 0; 03614 } else if (qe->parent->timeout) { 03615 to = qe->parent->timeout * 1000; 03616 } else { 03617 to = -1; 03618 } 03619 } 03620 orig = to; 03621 ++qe->pending; 03622 ao2_unlock(qe->parent); 03623 ring_one(qe, outgoing, &numbusies); 03624 if (need_weight) 03625 ao2_unlock(queues); 03626 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed); 03627 /* The ast_channel_datastore_remove() function could fail here if the 03628 * datastore was moved to another channel during a masquerade. If this is 03629 * the case, don't free the datastore here because later, when the channel 03630 * to which the datastore was moved hangs up, it will attempt to free this 03631 * datastore again, causing a crash 03632 */ 03633 ast_channel_lock(qe->chan); 03634 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) { 03635 ast_datastore_free(datastore); 03636 } 03637 ast_channel_unlock(qe->chan); 03638 ao2_lock(qe->parent); 03639 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) { 03640 store_next_rr(qe, outgoing); 03641 } 03642 if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) { 03643 store_next_lin(qe, outgoing); 03644 } 03645 ao2_unlock(qe->parent); 03646 peer = lpeer ? lpeer->chan : NULL; 03647 if (!peer) { 03648 qe->pending = 0; 03649 if (to) { 03650 /* Must gotten hung up */ 03651 res = -1; 03652 } else { 03653 /* User exited by pressing a digit */ 03654 res = digit; 03655 } 03656 if (res == -1) 03657 ast_debug(1, "%s: Nobody answered.\n", qe->chan->name); 03658 if (ast_cdr_isset_unanswered()) { 03659 /* channel contains the name of one of the outgoing channels 03660 in its CDR; zero out this CDR to avoid a dual-posting */ 03661 struct callattempt *o; 03662 for (o = outgoing; o; o = o->q_next) { 03663 if (!o->chan) { 03664 continue; 03665 } 03666 if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) { 03667 ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED); 03668 break; 03669 } 03670 } 03671 } 03672 } else { /* peer is valid */ 03673 /* Ah ha! Someone answered within the desired timeframe. Of course after this 03674 we will always return with -1 so that it is hung up properly after the 03675 conversation. */ 03676 if (!strcmp(qe->chan->tech->type, "DAHDI")) 03677 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 03678 if (!strcmp(peer->tech->type, "DAHDI")) 03679 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 03680 /* Update parameters for the queue */ 03681 time(&now); 03682 recalc_holdtime(qe, (now - qe->start)); 03683 ao2_lock(qe->parent); 03684 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 03685 ao2_unlock(qe->parent); 03686 member = lpeer->member; 03687 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ 03688 ao2_ref(member, 1); 03689 hangupcalls(outgoing, peer); 03690 outgoing = NULL; 03691 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 03692 int res2; 03693 03694 res2 = ast_autoservice_start(qe->chan); 03695 if (!res2) { 03696 if (qe->parent->memberdelay) { 03697 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 03698 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 03699 } 03700 if (!res2 && announce) { 03701 play_file(peer, announce); 03702 } 03703 if (!res2 && qe->parent->reportholdtime) { 03704 if (!play_file(peer, qe->parent->sound_reporthold)) { 03705 int holdtime, holdtimesecs; 03706 03707 time(&now); 03708 holdtime = abs((now - qe->start) / 60); 03709 holdtimesecs = abs((now - qe->start) % 60); 03710 if (holdtime > 0) { 03711 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 03712 play_file(peer, qe->parent->sound_minutes); 03713 } 03714 if (holdtimesecs > 1) { 03715 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL); 03716 play_file(peer, qe->parent->sound_seconds); 03717 } 03718 } 03719 } 03720 } 03721 res2 |= ast_autoservice_stop(qe->chan); 03722 if (ast_check_hangup(peer)) { 03723 /* Agent must have hung up */ 03724 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name); 03725 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", ""); 03726 if (qe->parent->eventwhencalled) 03727 manager_event(EVENT_FLAG_AGENT, "AgentDump", 03728 "Queue: %s\r\n" 03729 "Uniqueid: %s\r\n" 03730 "Channel: %s\r\n" 03731 "Member: %s\r\n" 03732 "MemberName: %s\r\n" 03733 "%s", 03734 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03735 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03736 ast_hangup(peer); 03737 ao2_ref(member, -1); 03738 goto out; 03739 } else if (res2) { 03740 /* Caller must have hung up just before being connected*/ 03741 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 03742 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 03743 record_abandoned(qe); 03744 ast_cdr_noanswer(qe->chan->cdr); 03745 ast_hangup(peer); 03746 ao2_ref(member, -1); 03747 return -1; 03748 } 03749 } 03750 /* Stop music on hold */ 03751 if (ringing) 03752 ast_indicate(qe->chan,-1); 03753 else 03754 ast_moh_stop(qe->chan); 03755 /* If appropriate, log that we have a destination channel */ 03756 if (qe->chan->cdr) 03757 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 03758 /* Make sure channels are compatible */ 03759 res = ast_channel_make_compatible(qe->chan, peer); 03760 if (res < 0) { 03761 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", ""); 03762 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 03763 record_abandoned(qe); 03764 ast_cdr_failed(qe->chan->cdr); 03765 ast_hangup(peer); 03766 ao2_ref(member, -1); 03767 return -1; 03768 } 03769 03770 /* Play announcement to the caller telling it's his turn if defined */ 03771 if (!ast_strlen_zero(qe->parent->sound_callerannounce)) { 03772 if (play_file(qe->chan, qe->parent->sound_callerannounce)) 03773 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce); 03774 } 03775 03776 ao2_lock(qe->parent); 03777 /* if setinterfacevar is defined, make member variables available to the channel */ 03778 /* use pbx_builtin_setvar to set a load of variables with one call */ 03779 if (qe->parent->setinterfacevar) { 03780 snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d", 03781 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime); 03782 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 03783 pbx_builtin_setvar_multiple(peer, interfacevar); 03784 } 03785 03786 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */ 03787 /* use pbx_builtin_setvar to set a load of variables with one call */ 03788 if (qe->parent->setqueueentryvar) { 03789 snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d", 03790 (long) time(NULL) - qe->start, qe->opos); 03791 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 03792 pbx_builtin_setvar_multiple(peer, interfacevar); 03793 } 03794 03795 /* try to set queue variables if configured to do so*/ 03796 set_queue_variables(qe->parent, qe->chan); 03797 set_queue_variables(qe->parent, peer); 03798 ao2_unlock(qe->parent); 03799 03800 ast_channel_lock(qe->chan); 03801 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) { 03802 monitorfilename = ast_strdupa(monitorfilename); 03803 } 03804 ast_channel_unlock(qe->chan); 03805 /* Begin Monitoring */ 03806 if (qe->parent->monfmt && *qe->parent->monfmt) { 03807 if (!qe->parent->montype) { 03808 const char *monexec, *monargs; 03809 ast_debug(1, "Starting Monitor as requested.\n"); 03810 ast_channel_lock(qe->chan); 03811 if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || (monargs = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))) { 03812 which = qe->chan; 03813 monexec = monexec ? ast_strdupa(monexec) : NULL; 03814 } 03815 else 03816 which = peer; 03817 ast_channel_unlock(qe->chan); 03818 if (ast_monitor_start) { 03819 if (monitorfilename) { 03820 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT); 03821 } else if (qe->chan->cdr && ast_monitor_start) { 03822 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT); 03823 } else if (ast_monitor_start) { 03824 /* Last ditch effort -- no CDR, make up something */ 03825 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 03826 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT); 03827 } 03828 } 03829 if (!ast_strlen_zero(monexec) && ast_monitor_setjoinfiles) { 03830 ast_monitor_setjoinfiles(which, 1); 03831 } 03832 } else { 03833 mixmonapp = pbx_findapp("MixMonitor"); 03834 03835 if (mixmonapp) { 03836 ast_debug(1, "Starting MixMonitor as requested.\n"); 03837 if (!monitorfilename) { 03838 if (qe->chan->cdr) 03839 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)); 03840 else 03841 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 03842 } else { 03843 const char *m = monitorfilename; 03844 for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) { 03845 switch (*m) { 03846 case '^': 03847 if (*(m + 1) == '{') 03848 *p = '$'; 03849 break; 03850 case ',': 03851 *p++ = '\\'; 03852 /* Fall through */ 03853 default: 03854 *p = *m; 03855 } 03856 if (*m == '\0') 03857 break; 03858 } 03859 if (p == tmpid2 + sizeof(tmpid2)) 03860 tmpid2[sizeof(tmpid2) - 1] = '\0'; 03861 03862 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 03863 } 03864 03865 ast_channel_lock(qe->chan); 03866 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) { 03867 monitor_exec = ast_strdupa(monitor_exec); 03868 } 03869 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) { 03870 monitor_options = ast_strdupa(monitor_options); 03871 } else { 03872 monitor_options = ""; 03873 } 03874 ast_channel_unlock(qe->chan); 03875 03876 if (monitor_exec) { 03877 const char *m = monitor_exec; 03878 for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) { 03879 switch (*m) { 03880 case '^': 03881 if (*(m + 1) == '{') 03882 *p = '$'; 03883 break; 03884 case ',': 03885 *p++ = '\\'; 03886 /* Fall through */ 03887 default: 03888 *p = *m; 03889 } 03890 if (*m == '\0') 03891 break; 03892 } 03893 if (p == meid2 + sizeof(meid2)) 03894 meid2[sizeof(meid2) - 1] = '\0'; 03895 03896 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 03897 } 03898 03899 snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt); 03900 03901 if (!ast_strlen_zero(monitor_exec)) 03902 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec); 03903 else 03904 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options); 03905 03906 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 03907 /* We purposely lock the CDR so that pbx_exec does not update the application data */ 03908 if (qe->chan->cdr) 03909 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 03910 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs); 03911 if (qe->chan->cdr) 03912 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 03913 03914 } else { 03915 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 03916 } 03917 } 03918 } 03919 /* Drop out of the queue at this point, to prepare for next caller */ 03920 leave_queue(qe); 03921 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 03922 ast_debug(1, "app_queue: sendurl=%s.\n", url); 03923 ast_channel_sendurl(peer, url); 03924 } 03925 03926 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */ 03927 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */ 03928 if (!ast_strlen_zero(macro)) { 03929 macroexec = ast_strdupa(macro); 03930 } else { 03931 if (qe->parent->membermacro) 03932 macroexec = ast_strdupa(qe->parent->membermacro); 03933 } 03934 03935 if (!ast_strlen_zero(macroexec)) { 03936 ast_debug(1, "app_queue: macro=%s.\n", macroexec); 03937 03938 res = ast_autoservice_start(qe->chan); 03939 if (res) { 03940 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 03941 res = -1; 03942 } 03943 03944 application = pbx_findapp("Macro"); 03945 03946 if (application) { 03947 res = pbx_exec(peer, application, macroexec); 03948 ast_debug(1, "Macro exited with status %d\n", res); 03949 res = 0; 03950 } else { 03951 ast_log(LOG_ERROR, "Could not find application Macro\n"); 03952 res = -1; 03953 } 03954 03955 if (ast_autoservice_stop(qe->chan) < 0) { 03956 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 03957 res = -1; 03958 } 03959 } 03960 03961 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */ 03962 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */ 03963 if (!ast_strlen_zero(gosub)) { 03964 gosubexec = ast_strdupa(gosub); 03965 } else { 03966 if (qe->parent->membergosub) 03967 gosubexec = ast_strdupa(qe->parent->membergosub); 03968 } 03969 03970 if (!ast_strlen_zero(gosubexec)) { 03971 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec); 03972 03973 res = ast_autoservice_start(qe->chan); 03974 if (res) { 03975 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 03976 res = -1; 03977 } 03978 03979 application = pbx_findapp("Gosub"); 03980 03981 if (application) { 03982 char *gosub_args, *gosub_argstart; 03983 03984 /* Set where we came from */ 03985 ast_copy_string(peer->context, "app_queue_gosub_virtual_context", sizeof(peer->context)); 03986 ast_copy_string(peer->exten, "s", sizeof(peer->exten)); 03987 peer->priority = 0; 03988 03989 gosub_argstart = strchr(gosubexec, ','); 03990 if (gosub_argstart) { 03991 *gosub_argstart = 0; 03992 if (asprintf(&gosub_args, "%s,s,1(%s)", gosubexec, gosub_argstart + 1) < 0) { 03993 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 03994 gosub_args = NULL; 03995 } 03996 *gosub_argstart = ','; 03997 } else { 03998 if (asprintf(&gosub_args, "%s,s,1", gosubexec) < 0) { 03999 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 04000 gosub_args = NULL; 04001 } 04002 } 04003 if (gosub_args) { 04004 res = pbx_exec(peer, application, gosub_args); 04005 if (!res) { 04006 struct ast_pbx_args args; 04007 memset(&args, 0, sizeof(args)); 04008 args.no_hangup_chan = 1; 04009 ast_pbx_run_args(peer, &args); 04010 } 04011 ast_free(gosub_args); 04012 ast_debug(1, "Gosub exited with status %d\n", res); 04013 } else { 04014 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n"); 04015 } 04016 } else { 04017 ast_log(LOG_ERROR, "Could not find application Gosub\n"); 04018 res = -1; 04019 } 04020 04021 if (ast_autoservice_stop(qe->chan) < 0) { 04022 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 04023 res = -1; 04024 } 04025 } 04026 04027 if (!ast_strlen_zero(agi)) { 04028 ast_debug(1, "app_queue: agi=%s.\n", agi); 04029 application = pbx_findapp("agi"); 04030 if (application) { 04031 agiexec = ast_strdupa(agi); 04032 ret = pbx_exec(qe->chan, application, agiexec); 04033 } else 04034 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 04035 } 04036 qe->handled++; 04037 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid, 04038 (long)(orig - to > 0 ? (orig - to) / 1000 : 0)); 04039 if (update_cdr && qe->chan->cdr) 04040 ast_copy_string(qe->chan->cdr->dstchannel, member->membername, sizeof(qe->chan->cdr->dstchannel)); 04041 if (qe->parent->eventwhencalled) 04042 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 04043 "Queue: %s\r\n" 04044 "Uniqueid: %s\r\n" 04045 "Channel: %s\r\n" 04046 "Member: %s\r\n" 04047 "MemberName: %s\r\n" 04048 "Holdtime: %ld\r\n" 04049 "BridgedChannel: %s\r\n" 04050 "Ringtime: %ld\r\n" 04051 "%s", 04052 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 04053 (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0), 04054 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 04055 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 04056 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 04057 04058 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) { 04059 queue_end_bridge->q = qe->parent; 04060 queue_end_bridge->chan = qe->chan; 04061 bridge_config.end_bridge_callback = end_bridge_callback; 04062 bridge_config.end_bridge_callback_data = queue_end_bridge; 04063 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 04064 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need 04065 * to make sure to increase the refcount of this queue so it cannot be freed until we 04066 * are done with it. We remove this reference in end_bridge_callback. 04067 */ 04068 queue_t_ref(qe->parent, "For bridge_config reference"); 04069 } 04070 04071 time(&callstart); 04072 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl); 04073 bridge = ast_bridge_call(qe->chan,peer, &bridge_config); 04074 04075 /* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log 04076 * when the masquerade occurred. These other "ending" queue_log messages are unnecessary 04077 */ 04078 ast_channel_lock(qe->chan); 04079 if (!attended_transfer_occurred(qe->chan)) { 04080 struct ast_datastore *tds; 04081 04082 /* detect a blind transfer */ 04083 if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) { 04084 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 04085 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 04086 (long) (time(NULL) - callstart), qe->opos); 04087 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER); 04088 } else if (ast_check_hangup(qe->chan)) { 04089 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d", 04090 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 04091 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER); 04092 } else { 04093 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 04094 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 04095 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT); 04096 } 04097 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) { 04098 ast_channel_datastore_remove(qe->chan, tds); 04099 } 04100 update_queue(qe->parent, member, callcompletedinsl); 04101 } 04102 04103 if (transfer_ds) { 04104 ast_datastore_free(transfer_ds); 04105 } 04106 ast_channel_unlock(qe->chan); 04107 ast_hangup(peer); 04108 res = bridge ? bridge : 1; 04109 ao2_ref(member, -1); 04110 } 04111 out: 04112 hangupcalls(outgoing, NULL); 04113 04114 return res; 04115 }
static int unload_module | ( | void | ) | [static] |
Definition at line 6750 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_ref, ao2_t_iterator_next, ast_cli_unregister_multiple(), ast_context_destroy(), ast_context_find(), ast_context_remove_extension2(), ast_custom_function_unregister(), ast_event_unsubscribe(), ast_manager_unregister(), ast_taskprocessor_unreference(), ast_unload_realtime(), ast_unregister_application(), clear_and_free_interfaces(), cli_queue, device_state_sub, devicestate_tps, queue_t_unref, queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queues_t_unlink, queuevar_function, and queuewaitingcount_function.
06751 { 06752 int res; 06753 struct ast_context *con; 06754 struct ao2_iterator q_iter; 06755 struct call_queue *q = NULL; 06756 06757 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 06758 res = ast_manager_unregister("QueueStatus"); 06759 res |= ast_manager_unregister("Queues"); 06760 res |= ast_manager_unregister("QueueRule"); 06761 res |= ast_manager_unregister("QueueSummary"); 06762 res |= ast_manager_unregister("QueueAdd"); 06763 res |= ast_manager_unregister("QueueRemove"); 06764 res |= ast_manager_unregister("QueuePause"); 06765 res |= ast_manager_unregister("QueueLog"); 06766 res |= ast_manager_unregister("QueuePenalty"); 06767 res |= ast_unregister_application(app_aqm); 06768 res |= ast_unregister_application(app_rqm); 06769 res |= ast_unregister_application(app_pqm); 06770 res |= ast_unregister_application(app_upqm); 06771 res |= ast_unregister_application(app_ql); 06772 res |= ast_unregister_application(app); 06773 res |= ast_custom_function_unregister(&queuevar_function); 06774 res |= ast_custom_function_unregister(&queuemembercount_function); 06775 res |= ast_custom_function_unregister(&queuemembercount_dep); 06776 res |= ast_custom_function_unregister(&queuememberlist_function); 06777 res |= ast_custom_function_unregister(&queuewaitingcount_function); 06778 res |= ast_custom_function_unregister(&queuememberpenalty_function); 06779 06780 if (device_state_sub) 06781 ast_event_unsubscribe(device_state_sub); 06782 06783 if ((con = ast_context_find("app_queue_gosub_virtual_context"))) { 06784 ast_context_remove_extension2(con, "s", 1, NULL, 0); 06785 ast_context_destroy(con, "app_queue"); /* leave no trace */ 06786 } 06787 06788 clear_and_free_interfaces(); 06789 06790 q_iter = ao2_iterator_init(queues, 0); 06791 while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) { 06792 queues_t_unlink(queues, q, "Remove queue from container due to unload"); 06793 queue_t_unref(q, "Done with iterator"); 06794 } 06795 ao2_iterator_destroy(&q_iter); 06796 ao2_ref(queues, -1); 06797 devicestate_tps = ast_taskprocessor_unreference(devicestate_tps); 06798 ast_unload_realtime("queue_members"); 06799 return res; 06800 }
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 2944 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 join_queue(), queue_exec(), and wait_our_turn().
02945 { 02946 int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value; 02947 int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value; 02948 char max_penalty_str[20], min_penalty_str[20]; 02949 /* a relative change to the penalty could put it below 0 */ 02950 if (max_penalty < 0) 02951 max_penalty = 0; 02952 if (min_penalty < 0) 02953 min_penalty = 0; 02954 if (min_penalty > max_penalty) 02955 min_penalty = max_penalty; 02956 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty); 02957 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty); 02958 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str); 02959 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str); 02960 qe->max_penalty = max_penalty; 02961 qe->min_penalty = min_penalty; 02962 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); 02963 qe->pr = AST_LIST_NEXT(qe->pr, list); 02964 }
static int update_queue | ( | struct call_queue * | q, | |
struct member * | member, | |||
int | callcompletedinsl | |||
) | [static] |
update the queue status
Always | 0 |
Definition at line 3085 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, and queues.
Referenced by queue_transfer_fixup().
03086 { 03087 struct member *mem; 03088 struct call_queue *qtmp; 03089 struct ao2_iterator queue_iter; 03090 03091 if (shared_lastcall) { 03092 queue_iter = ao2_iterator_init(queues, 0); 03093 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 03094 ao2_lock(qtmp); 03095 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) { 03096 time(&mem->lastcall); 03097 mem->calls++; 03098 mem->lastqueue = q; 03099 ao2_ref(mem, -1); 03100 } 03101 ao2_unlock(qtmp); 03102 ao2_ref(qtmp, -1); 03103 } 03104 ao2_iterator_destroy(&queue_iter); 03105 } else { 03106 ao2_lock(q); 03107 time(&member->lastcall); 03108 member->calls++; 03109 member->lastqueue = q; 03110 ao2_unlock(q); 03111 } 03112 ao2_lock(q); 03113 q->callscompleted++; 03114 if (callcompletedinsl) 03115 q->callscompletedinsl++; 03116 ao2_unlock(q); 03117 return 0; 03118 }
static int update_realtime_member_field | ( | struct member * | mem, | |
const char * | queue_name, | |||
const char * | field, | |||
const char * | value | |||
) | [static] |
Definition at line 1669 of file app_queue.c.
References ast_strlen_zero(), ast_update_realtime(), member::rt_uniqueid, and SENTINEL.
Referenced by set_member_paused().
01670 { 01671 int ret = -1; 01672 01673 if (ast_strlen_zero(mem->rt_uniqueid)) 01674 return ret; 01675 01676 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0) 01677 ret = 0; 01678 01679 return ret; 01680 }
static void update_realtime_members | ( | struct call_queue * | q | ) | [static] |
Definition at line 1683 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::membercount, call_queue::members, call_queue::name, queues, member::realtime, remove_from_interfaces(), rt_handle_member_record(), S_OR, SENTINEL, and member::state_interface.
Referenced by load_realtime_queue(), and queue_exec().
01684 { 01685 struct ast_config *member_config = NULL; 01686 struct member *m; 01687 char *interface = NULL; 01688 struct ao2_iterator mem_iter; 01689 01690 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) { 01691 /*This queue doesn't have realtime members*/ 01692 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name); 01693 return; 01694 } 01695 01696 ao2_lock(queues); 01697 ao2_lock(q); 01698 01699 /* Temporarily set realtime members dead so we can detect deleted ones.*/ 01700 mem_iter = ao2_iterator_init(q->members, 0); 01701 while ((m = ao2_iterator_next(&mem_iter))) { 01702 if (m->realtime) 01703 m->dead = 1; 01704 ao2_ref(m, -1); 01705 } 01706 ao2_iterator_destroy(&mem_iter); 01707 01708 while ((interface = ast_category_browse(member_config, interface))) { 01709 rt_handle_member_record(q, interface, 01710 ast_variable_retrieve(member_config, interface, "uniqueid"), 01711 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), 01712 ast_variable_retrieve(member_config, interface, "penalty"), 01713 ast_variable_retrieve(member_config, interface, "paused"), 01714 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface)); 01715 } 01716 01717 /* Delete all realtime members that have been deleted in DB. */ 01718 mem_iter = ao2_iterator_init(q->members, 0); 01719 while ((m = ao2_iterator_next(&mem_iter))) { 01720 if (m->dead) { 01721 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 01722 ao2_unlink(q->members, m); 01723 remove_from_interfaces(m->state_interface, 0); 01724 q->membercount--; 01725 } 01726 ao2_ref(m, -1); 01727 } 01728 ao2_iterator_destroy(&mem_iter); 01729 ao2_unlock(q); 01730 ao2_unlock(queues); 01731 ast_config_destroy(member_config); 01732 }
static int update_status | ( | const char * | interface, | |
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 736 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_t_iterator_next, ao2_unlock(), ast_copy_string(), member::calls, member::dynamic, EVENT_FLAG_AGENT, member::interface, member::lastcall, manager_event, call_queue::maskmemberstatus, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, queue_t_unref, queues, member::realtime, member::state_interface, and member::status.
Referenced by handle_statechange(), and ring_entry().
00737 { 00738 struct member *cur; 00739 struct ao2_iterator mem_iter, queue_iter; 00740 struct call_queue *q; 00741 char tmp_interface[80]; 00742 00743 queue_iter = ao2_iterator_init(queues, 0); 00744 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { 00745 ao2_lock(q); 00746 mem_iter = ao2_iterator_init(q->members, 0); 00747 while ((cur = ao2_iterator_next(&mem_iter))) { 00748 char *slash_pos; 00749 ast_copy_string(tmp_interface, cur->state_interface, sizeof(tmp_interface)); 00750 if ((slash_pos = strchr(tmp_interface, '/'))) 00751 if (!strncasecmp(tmp_interface, "Local", 5) && (slash_pos = strchr(slash_pos + 1, '/'))) 00752 *slash_pos = '\0'; 00753 00754 if (strcasecmp(interface, tmp_interface)) { 00755 ao2_ref(cur, -1); 00756 continue; 00757 } 00758 00759 if (cur->status != status) { 00760 cur->status = status; 00761 if (q->maskmemberstatus) { 00762 ao2_ref(cur, -1); 00763 continue; 00764 } 00765 00766 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 00767 "Queue: %s\r\n" 00768 "Location: %s\r\n" 00769 "MemberName: %s\r\n" 00770 "Membership: %s\r\n" 00771 "Penalty: %d\r\n" 00772 "CallsTaken: %d\r\n" 00773 "LastCall: %d\r\n" 00774 "Status: %d\r\n" 00775 "Paused: %d\r\n", 00776 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static", 00777 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused); 00778 } 00779 ao2_ref(cur, -1); 00780 } 00781 queue_t_unref(q, "Done with iterator"); 00782 ao2_unlock(q); 00783 } 00784 00785 return 0; 00786 }
static int upqm_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
UnPauseQueueMember application.
Definition at line 4601 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), chan, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), and set_member_paused().
Referenced by load_module().
04602 { 04603 char *parse; 04604 AST_DECLARE_APP_ARGS(args, 04605 AST_APP_ARG(queuename); 04606 AST_APP_ARG(interface); 04607 AST_APP_ARG(options); 04608 AST_APP_ARG(reason); 04609 ); 04610 04611 if (ast_strlen_zero(data)) { 04612 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n"); 04613 return -1; 04614 } 04615 04616 parse = ast_strdupa(data); 04617 04618 AST_STANDARD_APP_ARGS(args, parse); 04619 04620 if (ast_strlen_zero(args.interface)) { 04621 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 04622 return -1; 04623 } 04624 04625 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) { 04626 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 04627 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 04628 return 0; 04629 } 04630 04631 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 04632 04633 return 0; 04634 }
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 1838 of file app_queue.c.
References ast_canmatch_extension(), ast_goto_if_exists(), ast_strlen_zero(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, queue_ent::context, queue_ent::digits, and queue_ent::valid_digits.
Referenced by say_periodic_announcement(), say_position(), wait_a_bit(), and wait_our_turn().
01839 { 01840 int digitlen = strlen(qe->digits); 01841 01842 /* Prevent possible buffer overflow */ 01843 if (digitlen < sizeof(qe->digits) - 2) { 01844 qe->digits[digitlen] = digit; 01845 qe->digits[digitlen + 1] = '\0'; 01846 } else { 01847 qe->digits[0] = '\0'; 01848 return 0; 01849 } 01850 01851 /* If there's no context to goto, short-circuit */ 01852 if (ast_strlen_zero(qe->context)) 01853 return 0; 01854 01855 /* If the extension is bad, then reset the digits to blank */ 01856 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) { 01857 qe->digits[0] = '\0'; 01858 return 0; 01859 } 01860 01861 /* We have an exact match */ 01862 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 01863 qe->valid_digits = 1; 01864 /* Return 1 on a successful goto */ 01865 return 1; 01866 } 01867 01868 return 0; 01869 }
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 2203 of file app_queue.c.
References ast_copy_string(), ast_str_alloca, buf, queue_ent::chan, and pbx_builtin_serialize_variables().
Referenced by ring_entry(), and send_agent_complete().
02204 { 02205 struct ast_str *buf = ast_str_alloca(len + 1); 02206 char *tmp; 02207 02208 if (pbx_builtin_serialize_variables(chan, &buf)) { 02209 int i, j; 02210 02211 /* convert "\n" to "\nVariable: " */ 02212 strcpy(vars, "Variable: "); 02213 tmp = buf->str; 02214 02215 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 02216 vars[j] = tmp[i]; 02217 02218 if (tmp[i + 1] == '\0') 02219 break; 02220 if (tmp[i] == '\n') { 02221 vars[j++] = '\r'; 02222 vars[j++] = '\n'; 02223 02224 ast_copy_string(&(vars[j]), "Variable: ", len - j); 02225 j += 9; 02226 } 02227 } 02228 if (j > len - 3) 02229 j = len - 3; 02230 vars[j++] = '\r'; 02231 vars[j++] = '\n'; 02232 vars[j] = '\0'; 02233 } else { 02234 /* there are no channel variables; leave it blank */ 02235 *vars = '\0'; 02236 } 02237 return vars; 02238 }
static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 4117 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
04118 { 04119 /* Don't need to hold the lock while we setup the outgoing calls */ 04120 int retrywait = qe->parent->retry * 1000; 04121 04122 int res = ast_waitfordigit(qe->chan, retrywait); 04123 if (res > 0 && !valid_exit(qe, res)) 04124 res = 0; 04125 04126 return res; 04127 }
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 2626 of file app_queue.c.
References AST_MAX_WATCHERS, ast_poll_channel_add(), callattempt::call_next, callattempt::chan, queue_ent::chan, f, call_queue::name, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), starttime, status, callattempt::stillgoing, and call_queue::strategy.
02627 { 02628 const char *queue = qe->parent->name; 02629 struct callattempt *o, *start = NULL, *prev = NULL; 02630 int status; 02631 int numbusies = prebusies; 02632 int numnochan = 0; 02633 int stillgoing = 0; 02634 int orig = *to; 02635 struct ast_frame *f; 02636 struct callattempt *peer = NULL; 02637 struct ast_channel *winner; 02638 struct ast_channel *in = qe->chan; 02639 char on[80] = ""; 02640 char membername[80] = ""; 02641 long starttime = 0; 02642 long endtime = 0; 02643 #ifdef HAVE_EPOLL 02644 struct callattempt *epollo; 02645 #endif 02646 02647 starttime = (long) time(NULL); 02648 #ifdef HAVE_EPOLL 02649 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 02650 if (epollo->chan) 02651 ast_poll_channel_add(in, epollo->chan); 02652 } 02653 #endif 02654 02655 while (*to && !peer) { 02656 int numlines, retry, pos = 1; 02657 struct ast_channel *watchers[AST_MAX_WATCHERS]; 02658 watchers[0] = in; 02659 start = NULL; 02660 02661 for (retry = 0; retry < 2; retry++) { 02662 numlines = 0; 02663 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 02664 if (o->stillgoing) { /* Keep track of important channels */ 02665 stillgoing = 1; 02666 if (o->chan) { 02667 watchers[pos++] = o->chan; 02668 if (!start) 02669 start = o; 02670 else 02671 prev->call_next = o; 02672 prev = o; 02673 } 02674 } 02675 numlines++; 02676 } 02677 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 02678 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 02679 break; 02680 /* On "ringall" strategy we only move to the next penalty level 02681 when *all* ringing phones are done in the current penalty level */ 02682 ring_one(qe, outgoing, &numbusies); 02683 /* and retry... */ 02684 } 02685 if (pos == 1 /* not found */) { 02686 if (numlines == (numbusies + numnochan)) { 02687 ast_debug(1, "Everyone is busy at this time\n"); 02688 } else { 02689 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan); 02690 } 02691 *to = 0; 02692 return NULL; 02693 } 02694 02695 /* Poll for events from both the incoming channel as well as any outgoing channels */ 02696 winner = ast_waitfor_n(watchers, pos, to); 02697 02698 /* Service all of the outgoing channels */ 02699 for (o = start; o; o = o->call_next) { 02700 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 02701 if (!peer) { 02702 ast_verb(3, "%s answered %s\n", o->chan->name, in->name); 02703 peer = o; 02704 } 02705 } else if (o->chan && (o->chan == winner)) { 02706 02707 ast_copy_string(on, o->member->interface, sizeof(on)); 02708 ast_copy_string(membername, o->member->membername, sizeof(membername)); 02709 02710 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { 02711 ast_verb(3, "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward); 02712 numnochan++; 02713 do_hang(o); 02714 winner = NULL; 02715 continue; 02716 } else if (!ast_strlen_zero(o->chan->call_forward)) { 02717 char tmpchan[256]; 02718 char *stuff; 02719 char *tech; 02720 02721 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 02722 if ((stuff = strchr(tmpchan, '/'))) { 02723 *stuff++ = '\0'; 02724 tech = tmpchan; 02725 } else { 02726 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 02727 stuff = tmpchan; 02728 tech = "Local"; 02729 } 02730 /* Before processing channel, go ahead and check for forwarding */ 02731 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name); 02732 /* Setup parameters */ 02733 o->chan = ast_request(tech, in->nativeformats, stuff, &status); 02734 if (!o->chan) { 02735 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff); 02736 o->stillgoing = 0; 02737 numnochan++; 02738 } else { 02739 ast_channel_inherit_variables(in, o->chan); 02740 ast_channel_datastore_inherit(in, o->chan); 02741 if (o->chan->cid.cid_num) 02742 ast_free(o->chan->cid.cid_num); 02743 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num); 02744 02745 if (o->chan->cid.cid_name) 02746 ast_free(o->chan->cid.cid_name); 02747 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name); 02748 02749 ast_string_field_set(o->chan, accountcode, in->accountcode); 02750 o->chan->cdrflags = in->cdrflags; 02751 02752 if (in->cid.cid_ani) { 02753 if (o->chan->cid.cid_ani) 02754 ast_free(o->chan->cid.cid_ani); 02755 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani); 02756 } 02757 if (o->chan->cid.cid_rdnis) 02758 ast_free(o->chan->cid.cid_rdnis); 02759 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten)); 02760 if (ast_call(o->chan, tmpchan, 0)) { 02761 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); 02762 do_hang(o); 02763 numnochan++; 02764 } 02765 } 02766 /* Hangup the original channel now, in case we needed it */ 02767 ast_hangup(winner); 02768 continue; 02769 } 02770 f = ast_read(winner); 02771 if (f) { 02772 if (f->frametype == AST_FRAME_CONTROL) { 02773 switch (f->subclass) { 02774 case AST_CONTROL_ANSWER: 02775 /* This is our guy if someone answered. */ 02776 if (!peer) { 02777 ast_verb(3, "%s answered %s\n", o->chan->name, in->name); 02778 peer = o; 02779 } 02780 break; 02781 case AST_CONTROL_BUSY: 02782 ast_verb(3, "%s is busy\n", o->chan->name); 02783 if (in->cdr) 02784 ast_cdr_busy(in->cdr); 02785 do_hang(o); 02786 endtime = (long) time(NULL); 02787 endtime -= starttime; 02788 rna(endtime * 1000, qe, on, membername, 0); 02789 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02790 if (qe->parent->timeoutrestart) 02791 *to = orig; 02792 /* Have enough time for a queue member to answer? */ 02793 if (*to > 500) { 02794 ring_one(qe, outgoing, &numbusies); 02795 starttime = (long) time(NULL); 02796 } 02797 } 02798 numbusies++; 02799 break; 02800 case AST_CONTROL_CONGESTION: 02801 ast_verb(3, "%s is circuit-busy\n", o->chan->name); 02802 if (in->cdr) 02803 ast_cdr_busy(in->cdr); 02804 endtime = (long) time(NULL); 02805 endtime -= starttime; 02806 rna(endtime * 1000, qe, on, membername, 0); 02807 do_hang(o); 02808 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02809 if (qe->parent->timeoutrestart) 02810 *to = orig; 02811 if (*to > 500) { 02812 ring_one(qe, outgoing, &numbusies); 02813 starttime = (long) time(NULL); 02814 } 02815 } 02816 numbusies++; 02817 break; 02818 case AST_CONTROL_RINGING: 02819 ast_verb(3, "%s is ringing\n", o->chan->name); 02820 break; 02821 case AST_CONTROL_OFFHOOK: 02822 /* Ignore going off hook */ 02823 break; 02824 default: 02825 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass); 02826 } 02827 } 02828 ast_frfree(f); 02829 } else { /* ast_read() returned NULL */ 02830 endtime = (long) time(NULL) - starttime; 02831 rna(endtime * 1000, qe, on, membername, 1); 02832 do_hang(o); 02833 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02834 if (qe->parent->timeoutrestart) 02835 *to = orig; 02836 if (*to > 500) { 02837 ring_one(qe, outgoing, &numbusies); 02838 starttime = (long) time(NULL); 02839 } 02840 } 02841 } 02842 } 02843 } 02844 02845 /* If we received an event from the caller, deal with it. */ 02846 if (winner == in) { 02847 f = ast_read(in); 02848 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 02849 /* Got hung up */ 02850 *to = -1; 02851 if (f) { 02852 if (f->data.uint32) { 02853 in->hangupcause = f->data.uint32; 02854 } 02855 ast_frfree(f); 02856 } 02857 return NULL; 02858 } 02859 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) { 02860 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass); 02861 *to = 0; 02862 ast_frfree(f); 02863 return NULL; 02864 } 02865 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) { 02866 ast_verb(3, "User pressed digit: %c\n", f->subclass); 02867 *to = 0; 02868 *digit = f->subclass; 02869 ast_frfree(f); 02870 return NULL; 02871 } 02872 ast_frfree(f); 02873 } 02874 if (!*to) { 02875 for (o = start; o; o = o->call_next) 02876 rna(orig, qe, o->interface, o->member->membername, 1); 02877 } 02878 } 02879 02880 #ifdef HAVE_EPOLL 02881 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 02882 if (epollo->chan) 02883 ast_poll_channel_del(in, epollo->chan); 02884 } 02885 #endif 02886 02887 return peer; 02888 }
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 2976 of file app_queue.c.
References call_queue::announcefrequency, ast_queue_log(), ast_waitfordigit(), queue_ent::chan, queue_ent::expire, get_member_status(), is_our_turn(), leave_queue(), call_queue::leavewhenempty, queue_ent::max_penalty, queue_ent::min_penalty, call_queue::name, queue_ent::opos, queue_ent::parent, call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::pr, QUEUE_EMPTY_LOOSE, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, QUEUE_TIMEOUT, RECHECK, say_periodic_announcement(), say_position(), queue_ent::start, status, penalty_rule::time, ast_channel::uniqueid, update_qe_rule(), and valid_exit().
Referenced by queue_exec().
02977 { 02978 int res = 0; 02979 02980 /* This is the holding pen for callers 2 through maxlen */ 02981 for (;;) { 02982 enum queue_member_status status = QUEUE_NORMAL; 02983 int exit = 0; 02984 02985 if (is_our_turn(qe)) 02986 break; 02987 02988 /* If we have timed out, break out */ 02989 if (qe->expire && (time(NULL) >= qe->expire)) { 02990 *reason = QUEUE_TIMEOUT; 02991 break; 02992 } 02993 02994 /* If we are going to exit due to a leavewhenempty condition, we should 02995 * actually attempt to keep the caller in the queue until we have 02996 * exhausted all penalty rules. 02997 */ 02998 for (; !exit || qe->pr; update_qe_rule(qe)) { 02999 status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty); 03000 03001 if (!qe->pr || status == QUEUE_NORMAL) { 03002 break; 03003 } 03004 03005 /* leave the queue if no agents, if enabled */ 03006 if ((qe->parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) || 03007 ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) || 03008 ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS))) { 03009 continue; 03010 } else { 03011 exit = 1; 03012 } 03013 } 03014 03015 if (qe->parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) { 03016 *reason = QUEUE_LEAVEEMPTY; 03017 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 03018 leave_queue(qe); 03019 break; 03020 } 03021 03022 /* leave the queue if no reachable agents, if enabled */ 03023 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) { 03024 *reason = QUEUE_LEAVEUNAVAIL; 03025 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 03026 leave_queue(qe); 03027 break; 03028 } 03029 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS)) { 03030 *reason = QUEUE_LEAVEUNAVAIL; 03031 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 03032 leave_queue(qe); 03033 break; 03034 } 03035 03036 /* Make a position announcement, if enabled */ 03037 if (qe->parent->announcefrequency && 03038 (res = say_position(qe,ringing))) 03039 break; 03040 03041 /* If we have timed out, break out */ 03042 if (qe->expire && (time(NULL) >= qe->expire)) { 03043 *reason = QUEUE_TIMEOUT; 03044 break; 03045 } 03046 03047 /* Make a periodic announcement, if enabled */ 03048 if (qe->parent->periodicannouncefrequency && 03049 (res = say_periodic_announcement(qe,ringing))) 03050 break; 03051 03052 /* see if we need to move to the next penalty level for this queue */ 03053 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) { 03054 update_qe_rule(qe); 03055 } 03056 03057 /* If we have timed out, break out */ 03058 if (qe->expire && (time(NULL) >= qe->expire)) { 03059 *reason = QUEUE_TIMEOUT; 03060 break; 03061 } 03062 03063 /* Wait a second before checking again */ 03064 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 03065 if (res > 0 && !valid_exit(qe, res)) 03066 res = 0; 03067 else 03068 break; 03069 } 03070 03071 /* If we have timed out, break out */ 03072 if (qe->expire && (time(NULL) >= qe->expire)) { 03073 *reason = QUEUE_TIMEOUT; 03074 break; 03075 } 03076 } 03077 03078 return res; 03079 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 6868 of file app_queue.c.
char* app = "Queue" [static] |
Definition at line 154 of file app_queue.c.
char* app_aqm = "AddQueueMember" [static] |
Definition at line 213 of file app_queue.c.
char* app_aqm_descrip [static] |
Definition at line 215 of file app_queue.c.
char* app_aqm_synopsis = "Dynamically adds queue members" [static] |
Definition at line 214 of file app_queue.c.
char* app_pqm = "PauseQueueMember" [static] |
Definition at line 239 of file app_queue.c.
char* app_pqm_descrip [static] |
Definition at line 241 of file app_queue.c.
char* app_pqm_synopsis = "Pauses a queue member" [static] |
Definition at line 240 of file app_queue.c.
char* app_ql = "QueueLog" [static] |
Definition at line 272 of file app_queue.c.
char* app_ql_descrip [static] |
Initial value:
" QueueLog(queuename,uniqueid,agent,event[,additionalinfo]):\n" "Allows you to write your own events into the queue log\n" "Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)\n"
Definition at line 274 of file app_queue.c.
char* app_ql_synopsis = "Writes to the queue_log" [static] |
Definition at line 273 of file app_queue.c.
char* app_rqm = "RemoveQueueMember" [static] |
Definition at line 226 of file app_queue.c.
char* app_rqm_descrip [static] |
Definition at line 228 of file app_queue.c.
char* app_rqm_synopsis = "Dynamically removes queue members" [static] |
Definition at line 227 of file app_queue.c.
char* app_upqm = "UnpauseQueueMember" [static] |
Definition at line 257 of file app_queue.c.
char* app_upqm_descrip [static] |
Definition at line 259 of file app_queue.c.
char* app_upqm_synopsis = "Unpauses a queue member" [static] |
Definition at line 258 of file app_queue.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 6868 of file app_queue.c.
int autofill_default = 0 [static] |
struct ast_cli_entry cli_queue[] [static] |
char* descrip [static] |
Definition at line 158 of file app_queue.c.
struct ast_event_sub* device_state_sub [static] |
struct ast_taskprocessor* devicestate_tps [static] |
Definition at line 138 of file app_queue.c.
Referenced by device_state_cb(), load_module(), and unload_module().
enum queue_result id |
Definition at line 320 of file app_queue.c.
Referenced by _sip_show_peers(), amixer_max(), idemodulator(), and setamixer().
int montype_default = 0 [static] |
const char* 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 6731 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 6737 of file app_queue.c.
int queue_keep_stats = 0 [static] |
int queue_persistent_members = 0 [static] |
struct { ... } queue_results[] |
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 3243 of file app_queue.c.
Referenced by attended_transfer_occurred(), queue_transfer_fixup(), and setup_transfer_datastore().
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] |
Definition at line 547 of file app_queue.c.
Referenced by __queues_show(), add_to_queue(), compare_weight(), complete_queue(), complete_queue_remove_member(), find_queue_by_name_rt(), get_member_penalty(), interface_exists_global(), join_queue(), leave_queue(), load_module(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), reload_queue_members(), reload_queues(), remove_from_queue(), set_member_paused(), set_member_penalty(), try_calling(), unload_module(), update_queue(), update_realtime_members(), and update_status().
struct ast_custom_function queuevar_function [static] |
struct ast_custom_function queuewaitingcount_function [static] |
const char qum_cmd_usage[] [static] |
Initial value:
"Usage: queue unpause member <channel> in <queue> reason <reason>\n"
Definition at line 6734 of file app_queue.c.
int shared_lastcall = 0 [static] |
struct strategy strategies[] [static] |
Referenced by int2strat(), and strat2int().
char* synopsis = "Queue a call for a call queue" [static] |
Definition at line 156 of file app_queue.c.
char* text |
Definition at line 321 of file app_queue.c.
Referenced by _sip_show_peer(), build_reply_digest(), check_auth(), festival_exec(), handle_response(), iconv_read(), method_match(), parse_sip_options(), process_sdp(), reqprep(), sendtext_exec(), set_queue_result(), and sip_new().
int update_cdr = 0 [static] |
queues.conf [general] option
Definition at line 306 of file app_queue.c.
Referenced by login_exec().
int use_weight = 0 [static] |