#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"

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 | 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 | 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 } |
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 * | device_state_thread (void *data) |
| Consumer of the statechange queue. | |
| 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 void * | handle_statechange (struct statechange *sc) |
| 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 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 *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 | statechange_queue (const char *dev, enum ast_device_state state) |
| Producer of the statechange queue. | |
| 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 = AST_BUILDOPT_SUM, .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 const 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 |
| struct { | |
| ast_cond_t cond | |
| ast_mutex_t lock | |
| struct { | |
| struct statechange * first | |
| struct statechange * last | |
| } state_change_q | |
| unsigned int stop:1 | |
| pthread_t thread | |
| } | device_state |
| Data used by the device state thread. | |
| static struct ast_event_sub * | device_state_sub |
| Subscription to device state change events. | |
| 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 AST_MAX_WATCHERS 256 |
Definition at line 2550 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 140 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 139 of file app_queue.c.
Referenced by destroy_queue(), init_queue(), queue_set_param(), and say_periodic_announcement().
| #define MAX_QUEUE_BUCKETS 53 |
| #define PM_MAX_LEN 8192 |
Definition at line 278 of file app_queue.c.
Referenced by dump_queue_members(), and reload_queue_members().
| #define QUEUE_EMPTY_LOOSE 3 |
Definition at line 409 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 408 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 412 of file app_queue.c.
Referenced by queue_set_param(), ring_entry(), send_agent_complete(), and try_calling().
| #define RECHECK 1 |
Recheck every second to see we we're at the top yet
Definition at line 138 of file app_queue.c.
Referenced by wait_our_turn().
| #define RES_EXISTS (-1) |
Entry already exists
Definition at line 145 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 147 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 148 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 144 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 146 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 112 of file app_queue.c.
00112 { 00113 QUEUE_STRATEGY_RINGALL = 0, 00114 QUEUE_STRATEGY_LEASTRECENT, 00115 QUEUE_STRATEGY_FEWESTCALLS, 00116 QUEUE_STRATEGY_RANDOM, 00117 QUEUE_STRATEGY_RRMEMORY, 00118 QUEUE_STRATEGY_LINEAR, 00119 QUEUE_STRATEGY_WRANDOM 00120 };
| enum queue_member_status |
| QUEUE_NO_MEMBERS | |
| QUEUE_NO_REACHABLE_MEMBERS | |
| QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS | |
| QUEUE_NORMAL |
Definition at line 634 of file app_queue.c.
00634 { 00635 QUEUE_NO_MEMBERS, 00636 QUEUE_NO_REACHABLE_MEMBERS, 00637 QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, 00638 QUEUE_NORMAL 00639 };
| enum queue_result |
| QUEUE_UNKNOWN | |
| QUEUE_TIMEOUT | |
| QUEUE_JOINEMPTY | |
| QUEUE_LEAVEEMPTY | |
| QUEUE_JOINUNAVAIL | |
| QUEUE_LEAVEUNAVAIL | |
| QUEUE_FULL | |
| QUEUE_CONTINUE |
Definition at line 304 of file app_queue.c.
00304 { 00305 QUEUE_UNKNOWN = 0, 00306 QUEUE_TIMEOUT = 1, 00307 QUEUE_JOINEMPTY = 2, 00308 QUEUE_LEAVEEMPTY = 3, 00309 QUEUE_JOINUNAVAIL = 4, 00310 QUEUE_LEAVEUNAVAIL = 5, 00311 QUEUE_FULL = 6, 00312 QUEUE_CONTINUE = 7, 00313 };
| 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 5696 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_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_unref(), queues, member::realtime, call_queue::realtime, 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().
05697 { 05698 struct call_queue *q; 05699 struct ast_str *out = ast_str_alloca(240); 05700 int found = 0; 05701 time_t now = time(NULL); 05702 struct ao2_iterator queue_iter; 05703 struct ao2_iterator mem_iter; 05704 05705 if (argc != 2 && argc != 3) 05706 return CLI_SHOWUSAGE; 05707 05708 if (argc == 3) { /* specific queue */ 05709 if ((q = load_realtime_queue(argv[2]))) { 05710 queue_unref(q); 05711 } 05712 } else if (ast_check_realtime("queues")) { 05713 /* This block is to find any queues which are defined in realtime but 05714 * which have not yet been added to the in-core container 05715 */ 05716 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", (char *) NULL); 05717 char *queuename; 05718 if (cfg) { 05719 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { 05720 if ((q = load_realtime_queue(queuename))) { 05721 queue_unref(q); 05722 } 05723 } 05724 ast_config_destroy(cfg); 05725 } 05726 } 05727 05728 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); 05729 ao2_lock(queues); 05730 while ((q = ao2_iterator_next(&queue_iter))) { 05731 float sl; 05732 struct call_queue *realtime_queue = NULL; 05733 05734 ao2_lock(q); 05735 /* This check is to make sure we don't print information for realtime 05736 * queues which have been deleted from realtime but which have not yet 05737 * been deleted from the in-core container 05738 */ 05739 if (q->realtime && !(realtime_queue = load_realtime_queue(q->name))) { 05740 ao2_unlock(q); 05741 queue_unref(q); 05742 continue; 05743 } else if (q->realtime) { 05744 queue_unref(realtime_queue); 05745 } 05746 if (argc == 3 && strcasecmp(q->name, argv[2])) { 05747 ao2_unlock(q); 05748 queue_unref(q); 05749 continue; 05750 } 05751 found = 1; 05752 05753 ast_str_set(&out, 0, "%-12.12s has %d calls (max ", q->name, q->count); 05754 if (q->maxlen) 05755 ast_str_append(&out, 0, "%d", q->maxlen); 05756 else 05757 ast_str_append(&out, 0, "unlimited"); 05758 sl = 0; 05759 if (q->callscompleted > 0) 05760 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 05761 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds", 05762 int2strat(q->strategy), q->holdtime, q->weight, 05763 q->callscompleted, q->callsabandoned,sl,q->servicelevel); 05764 do_print(s, fd, out->str); 05765 if (!ao2_container_count(q->members)) 05766 do_print(s, fd, " No Members"); 05767 else { 05768 struct member *mem; 05769 05770 do_print(s, fd, " Members: "); 05771 mem_iter = ao2_iterator_init(q->members, 0); 05772 while ((mem = ao2_iterator_next(&mem_iter))) { 05773 ast_str_set(&out, 0, " %s", mem->membername); 05774 if (strcasecmp(mem->membername, mem->interface)) { 05775 ast_str_append(&out, 0, " (%s)", mem->interface); 05776 } 05777 if (mem->penalty) 05778 ast_str_append(&out, 0, " with penalty %d", mem->penalty); 05779 ast_str_append(&out, 0, "%s%s%s (%s)", 05780 mem->dynamic ? " (dynamic)" : "", 05781 mem->realtime ? " (realtime)" : "", 05782 mem->paused ? " (paused)" : "", 05783 devstate2str(mem->status)); 05784 if (mem->calls) 05785 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)", 05786 mem->calls, (long) (time(NULL) - mem->lastcall)); 05787 else 05788 ast_str_append(&out, 0, " has taken no calls yet"); 05789 do_print(s, fd, out->str); 05790 ao2_ref(mem, -1); 05791 } 05792 ao2_iterator_destroy(&mem_iter); 05793 } 05794 if (!q->head) 05795 do_print(s, fd, " No Callers"); 05796 else { 05797 struct queue_ent *qe; 05798 int pos = 1; 05799 05800 do_print(s, fd, " Callers: "); 05801 for (qe = q->head; qe; qe = qe->next) { 05802 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)", 05803 pos++, qe->chan->name, (long) (now - qe->start) / 60, 05804 (long) (now - qe->start) % 60, qe->prio); 05805 do_print(s, fd, out->str); 05806 } 05807 } 05808 do_print(s, fd, ""); /* blank line between entries */ 05809 ao2_unlock(q); 05810 queue_unref(q); /* Unref the iterator's reference */ 05811 } 05812 ao2_iterator_destroy(&queue_iter); 05813 ao2_unlock(queues); 05814 if (!found) { 05815 if (argc == 3) 05816 ast_str_set(&out, 0, "No such queue: %s.", argv[2]); 05817 else 05818 ast_str_set(&out, 0, "No queues."); 05819 do_print(s, fd, out->str); 05820 } 05821 return CLI_SUCCESS; 05822 }
| static void __reg_module | ( | void | ) | [static] |
Definition at line 6767 of file app_queue.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 6767 of file app_queue.c.
| static int add_to_interfaces | ( | const char * | interface | ) | [static] |
Definition at line 995 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, and member_interface::interface.
Referenced by add_to_queue(), reload_queues(), and rt_handle_member_record().
00996 { 00997 struct member_interface *curint; 00998 00999 AST_LIST_LOCK(&interfaces); 01000 AST_LIST_TRAVERSE(&interfaces, curint, list) { 01001 if (!strcasecmp(curint->interface, interface)) 01002 break; 01003 } 01004 01005 if (curint) { 01006 AST_LIST_UNLOCK(&interfaces); 01007 return 0; 01008 } 01009 01010 ast_debug(1, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface); 01011 01012 if ((curint = ast_calloc(1, sizeof(*curint)))) { 01013 ast_copy_string(curint->interface, interface, sizeof(curint->interface)); 01014 AST_LIST_INSERT_HEAD(&interfaces, curint, list); 01015 } 01016 AST_LIST_UNLOCK(&interfaces); 01017 01018 return 0; 01019 }
| 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 4170 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().
04171 { 04172 struct call_queue *q; 04173 struct member *new_member, *old_member; 04174 int res = RES_NOSUCHQUEUE; 04175 04176 /*! \note Ensure the appropriate realtime queue is loaded. Note that this 04177 * short-circuits if the queue is already in memory. */ 04178 if (!(q = load_realtime_queue(queuename))) 04179 return res; 04180 04181 ao2_lock(queues); 04182 04183 ao2_lock(q); 04184 if ((old_member = interface_exists(q, interface)) == NULL) { 04185 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { 04186 add_to_interfaces(new_member->state_interface); 04187 new_member->dynamic = 1; 04188 ao2_link(q->members, new_member); 04189 q->membercount++; 04190 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 04191 "Queue: %s\r\n" 04192 "Location: %s\r\n" 04193 "MemberName: %s\r\n" 04194 "Membership: %s\r\n" 04195 "Penalty: %d\r\n" 04196 "CallsTaken: %d\r\n" 04197 "LastCall: %d\r\n" 04198 "Status: %d\r\n" 04199 "Paused: %d\r\n", 04200 q->name, new_member->interface, new_member->membername, 04201 "dynamic", 04202 new_member->penalty, new_member->calls, (int) new_member->lastcall, 04203 new_member->status, new_member->paused); 04204 04205 ao2_ref(new_member, -1); 04206 new_member = NULL; 04207 04208 if (dump) 04209 dump_queue_members(q); 04210 04211 res = RES_OKAY; 04212 } else { 04213 res = RES_OUTOFMEMORY; 04214 } 04215 } else { 04216 ao2_ref(old_member, -1); 04217 res = RES_EXISTS; 04218 } 04219 ao2_unlock(q); 04220 ao2_unlock(queues); 04221 04222 return res; 04223 }
| static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static, read] |
Definition at line 1439 of file app_queue.c.
References ao2_alloc(), ao2_ref(), ast_string_field_init, ast_string_field_set, and destroy_queue().
Referenced by find_queue_by_name_rt(), and reload_queues().
01440 { 01441 struct call_queue *q; 01442 01443 if ((q = ao2_alloc(sizeof(*q), destroy_queue))) { 01444 if (ast_string_field_init(q, 64)) { 01445 ao2_ref(q, -1); 01446 return NULL; 01447 } 01448 ast_string_field_set(q, name, queuename); 01449 } 01450 return q; 01451 }
| static int aqm_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
AddQueueMember application.
Definition at line 4600 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(), 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().
04601 { 04602 int res=-1; 04603 char *parse, *temppos = NULL; 04604 AST_DECLARE_APP_ARGS(args, 04605 AST_APP_ARG(queuename); 04606 AST_APP_ARG(interface); 04607 AST_APP_ARG(penalty); 04608 AST_APP_ARG(options); 04609 AST_APP_ARG(membername); 04610 AST_APP_ARG(state_interface); 04611 ); 04612 int penalty = 0; 04613 04614 if (ast_strlen_zero(data)) { 04615 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n"); 04616 return -1; 04617 } 04618 04619 parse = ast_strdupa(data); 04620 04621 AST_STANDARD_APP_ARGS(args, parse); 04622 04623 if (ast_strlen_zero(args.interface)) { 04624 args.interface = ast_strdupa(chan->name); 04625 temppos = strrchr(args.interface, '-'); 04626 if (temppos) 04627 *temppos = '\0'; 04628 } 04629 04630 if (!ast_strlen_zero(args.penalty)) { 04631 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) { 04632 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 04633 penalty = 0; 04634 } 04635 } 04636 04637 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { 04638 case RES_OKAY: 04639 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 04640 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 04641 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 04642 res = 0; 04643 break; 04644 case RES_EXISTS: 04645 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 04646 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 04647 res = 0; 04648 break; 04649 case RES_NOSUCHQUEUE: 04650 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 04651 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 04652 res = 0; 04653 break; 04654 case RES_OUTOFMEMORY: 04655 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 04656 break; 04657 } 04658 04659 return res; 04660 }
| 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 3219 of file app_queue.c.
References ast_channel_datastore_find(), and queue_transfer_info.
Referenced by try_calling().
03220 { 03221 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1; 03222 }
| 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 3058 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, QUEUE_STRATEGY_WRANDOM, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.
Referenced by try_calling().
03059 { 03060 if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || (qe->min_penalty && (mem->penalty < qe->min_penalty))) 03061 return -1; 03062 03063 switch (q->strategy) { 03064 case QUEUE_STRATEGY_RINGALL: 03065 /* Everyone equal, except for penalty */ 03066 tmp->metric = mem->penalty * 1000000; 03067 break; 03068 case QUEUE_STRATEGY_LINEAR: 03069 if (pos < qe->linpos) { 03070 tmp->metric = 1000 + pos; 03071 } else { 03072 if (pos > qe->linpos) 03073 /* Indicate there is another priority */ 03074 qe->linwrapped = 1; 03075 tmp->metric = pos; 03076 } 03077 tmp->metric += mem->penalty * 1000000; 03078 break; 03079 case QUEUE_STRATEGY_RRMEMORY: 03080 if (pos < q->rrpos) { 03081 tmp->metric = 1000 + pos; 03082 } else { 03083 if (pos > q->rrpos) 03084 /* Indicate there is another priority */ 03085 q->wrapped = 1; 03086 tmp->metric = pos; 03087 } 03088 tmp->metric += mem->penalty * 1000000; 03089 break; 03090 case QUEUE_STRATEGY_RANDOM: 03091 tmp->metric = ast_random() % 1000; 03092 tmp->metric += mem->penalty * 1000000; 03093 break; 03094 case QUEUE_STRATEGY_WRANDOM: 03095 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000); 03096 break; 03097 case QUEUE_STRATEGY_FEWESTCALLS: 03098 tmp->metric = mem->calls; 03099 tmp->metric += mem->penalty * 1000000; 03100 break; 03101 case QUEUE_STRATEGY_LEASTRECENT: 03102 if (!mem->lastcall) 03103 tmp->metric = 0; 03104 else 03105 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 03106 tmp->metric += mem->penalty * 1000000; 03107 break; 03108 default: 03109 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 03110 break; 03111 } 03112 return 0; 03113 }
| static void clear_and_free_interfaces | ( | void | ) | [static] |
Definition at line 1071 of file app_queue.c.
References ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, and AST_LIST_UNLOCK.
Referenced by unload_module().
01072 { 01073 struct member_interface *curint; 01074 01075 AST_LIST_LOCK(&interfaces); 01076 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list))) 01077 ast_free(curint); 01078 AST_LIST_UNLOCK(&interfaces); 01079 }
| static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 986 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().
00987 { 00988 q->holdtime = 0; 00989 q->callscompleted = 0; 00990 q->callsabandoned = 0; 00991 q->callscompletedinsl = 0; 00992 q->wrapuptime = 0; 00993 }
| static int compare_weight | ( | struct call_queue * | rq, | |
| struct member * | member | |||
| ) | [static] |
Definition at line 2113 of file app_queue.c.
References ao2_find(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), ast_debug, call_queue::count, member::interface, call_queue::members, call_queue::name, num_available_members(), OBJ_POINTER, queue_unref(), queues, and call_queue::weight.
Referenced by ring_entry().
02114 { 02115 struct call_queue *q; 02116 struct member *mem; 02117 int found = 0; 02118 struct ao2_iterator queue_iter; 02119 02120 /* q's lock and rq's lock already set by try_calling() 02121 * to solve deadlock */ 02122 queue_iter = ao2_iterator_init(queues, 0); 02123 while ((q = ao2_iterator_next(&queue_iter))) { 02124 if (q == rq) { /* don't check myself, could deadlock */ 02125 queue_unref(q); 02126 continue; 02127 } 02128 ao2_lock(q); 02129 if (q->count && q->members) { 02130 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 02131 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 02132 if (q->weight > rq->weight && q->count >= num_available_members(q)) { 02133 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); 02134 found = 1; 02135 } 02136 ao2_ref(mem, -1); 02137 } 02138 } 02139 ao2_unlock(q); 02140 queue_unref(q); 02141 if (found) { 02142 break; 02143 } 02144 } 02145 ao2_iterator_destroy(&queue_iter); 02146 return found; 02147 }
| static char* complete_queue | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 5824 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ast_strdup, call_queue::name, queue_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().
05825 { 05826 struct call_queue *q; 05827 char *ret = NULL; 05828 int which = 0; 05829 int wordlen = strlen(word); 05830 struct ao2_iterator queue_iter; 05831 05832 queue_iter = ao2_iterator_init(queues, 0); 05833 while ((q = ao2_iterator_next(&queue_iter))) { 05834 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 05835 ret = ast_strdup(q->name); 05836 queue_unref(q); 05837 break; 05838 } 05839 queue_unref(q); 05840 } 05841 ao2_iterator_destroy(&queue_iter); 05842 05843 return ret; 05844 }
| static char* complete_queue_add_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6206 of file app_queue.c.
References ast_malloc, ast_strdup, complete_queue(), and num.
Referenced by handle_queue_add_member().
06207 { 06208 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 06209 switch (pos) { 06210 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 06211 return NULL; 06212 case 4: /* only one possible match, "to" */ 06213 return state == 0 ? ast_strdup("to") : NULL; 06214 case 5: /* <queue> */ 06215 return complete_queue(line, word, pos, state); 06216 case 6: /* only one possible match, "penalty" */ 06217 return state == 0 ? ast_strdup("penalty") : NULL; 06218 case 7: 06219 if (state < 100) { /* 0-99 */ 06220 char *num; 06221 if ((num = ast_malloc(3))) { 06222 sprintf(num, "%d", state); 06223 } 06224 return num; 06225 } else { 06226 return NULL; 06227 } 06228 case 8: /* only one possible match, "as" */ 06229 return state == 0 ? ast_strdup("as") : NULL; 06230 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 06231 return NULL; 06232 default: 06233 return NULL; 06234 } 06235 }
| static char* complete_queue_pause_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6421 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_pause_member().
06422 { 06423 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */ 06424 switch (pos) { 06425 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 06426 return NULL; 06427 case 4: /* only one possible match, "queue" */ 06428 return state == 0 ? ast_strdup("queue") : NULL; 06429 case 5: /* <queue> */ 06430 return complete_queue(line, word, pos, state); 06431 case 6: /* "reason" */ 06432 return state == 0 ? ast_strdup("reason") : NULL; 06433 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */ 06434 return NULL; 06435 default: 06436 return NULL; 06437 } 06438 }
| static char* complete_queue_remove_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6335 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), ast_strdup, complete_queue(), member::interface, member::membername, call_queue::members, queue_unref(), and queues.
Referenced by handle_queue_remove_member().
06336 { 06337 int which = 0; 06338 struct call_queue *q; 06339 struct member *m; 06340 struct ao2_iterator queue_iter; 06341 struct ao2_iterator mem_iter; 06342 int wordlen = strlen(word); 06343 06344 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 06345 if (pos > 5 || pos < 3) 06346 return NULL; 06347 if (pos == 4) /* only one possible match, 'from' */ 06348 return (state == 0 ? ast_strdup("from") : NULL); 06349 06350 if (pos == 5) /* No need to duplicate code */ 06351 return complete_queue(line, word, pos, state); 06352 06353 /* here is the case for 3, <member> */ 06354 queue_iter = ao2_iterator_init(queues, 0); 06355 while ((q = ao2_iterator_next(&queue_iter))) { 06356 ao2_lock(q); 06357 mem_iter = ao2_iterator_init(q->members, 0); 06358 while ((m = ao2_iterator_next(&mem_iter))) { 06359 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) { 06360 char *tmp; 06361 ao2_unlock(q); 06362 tmp = ast_strdup(m->interface); 06363 ao2_ref(m, -1); 06364 queue_unref(q); 06365 ao2_iterator_destroy(&mem_iter); 06366 ao2_iterator_destroy(&queue_iter); 06367 return tmp; 06368 } 06369 ao2_ref(m, -1); 06370 } 06371 ao2_iterator_destroy(&mem_iter); 06372 ao2_unlock(q); 06373 queue_unref(q); 06374 } 06375 ao2_iterator_destroy(&queue_iter); 06376 06377 return NULL; 06378 }
| static char* complete_queue_rule_show | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6554 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strdup, LOG_DEBUG, and rule_list::name.
Referenced by handle_queue_rule_show().
06555 { 06556 int which = 0; 06557 struct rule_list *rl_iter; 06558 int wordlen = strlen(word); 06559 char *ret = NULL; 06560 if (pos != 3) /* Wha? */ { 06561 ast_log(LOG_DEBUG, "Hitting this???, pos is %d\n", pos); 06562 return NULL; 06563 } 06564 06565 AST_LIST_LOCK(&rule_lists); 06566 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 06567 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) { 06568 ret = ast_strdup(rl_iter->name); 06569 break; 06570 } 06571 } 06572 AST_LIST_UNLOCK(&rule_lists); 06573 06574 return ret; 06575 }
| static char* complete_queue_set_member_penalty | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6491 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_set_member_penalty().
06492 { 06493 /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/ 06494 switch (pos) { 06495 case 4: 06496 if (state == 0) { 06497 return ast_strdup("on"); 06498 } else { 06499 return NULL; 06500 } 06501 case 6: 06502 if (state == 0) { 06503 return ast_strdup("in"); 06504 } else { 06505 return NULL; 06506 } 06507 case 7: 06508 return complete_queue(line, word, pos, state); 06509 default: 06510 return NULL; 06511 } 06512 }
| static char* complete_queue_show | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 5846 of file app_queue.c.
References complete_queue().
Referenced by queue_show().
05847 { 05848 if (pos == 2) 05849 return complete_queue(line, word, pos, state); 05850 return NULL; 05851 }
| static int compress_char | ( | const char | c | ) | [static] |
Definition at line 890 of file app_queue.c.
00891 { 00892 if (c < 32) 00893 return 0; 00894 else if (c > 96) 00895 return c - 64; 00896 else 00897 return c - 32; 00898 }
| static void copy_rules | ( | struct queue_ent * | qe, | |
| const char * | rulename | |||
| ) | [static] |
Copy rule from global list into specified queue.
Definition at line 4697 of file app_queue.c.
References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), LOG_ERROR, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, queue_ent::qe_rules, rule_list::rules, and penalty_rule::time.
Referenced by join_queue().
04698 { 04699 struct penalty_rule *pr_iter; 04700 struct rule_list *rl_iter; 04701 const char *tmp = rulename; 04702 if (ast_strlen_zero(tmp)) { 04703 return; 04704 } 04705 AST_LIST_LOCK(&rule_lists); 04706 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 04707 if (!strcasecmp(rl_iter->name, tmp)) 04708 break; 04709 } 04710 if (rl_iter) { 04711 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 04712 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr)); 04713 if (!new_pr) { 04714 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n"); 04715 AST_LIST_UNLOCK(&rule_lists); 04716 break; 04717 } 04718 new_pr->time = pr_iter->time; 04719 new_pr->max_value = pr_iter->max_value; 04720 new_pr->min_value = pr_iter->min_value; 04721 new_pr->max_relative = pr_iter->max_relative; 04722 new_pr->min_relative = pr_iter->min_relative; 04723 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list); 04724 } 04725 } 04726 AST_LIST_UNLOCK(&rule_lists); 04727 }
| static struct member* create_queue_member | ( | const char * | interface, | |
| const char * | membername, | |||
| int | penalty, | |||
| int | paused, | |||
| const char * | state_interface | |||
| ) | [static, read] |
allocate space for new queue member and set fields based on parameters passed
Definition at line 865 of file app_queue.c.
References ao2_alloc(), ast_copy_string(), ast_log(), ast_strlen_zero(), member::interface, LOG_WARNING, member::membername, member::paused, member::penalty, member::state_interface, and member::status.
Referenced by add_to_queue(), reload_queues(), and rt_handle_member_record().
00866 { 00867 struct member *cur; 00868 00869 if ((cur = ao2_alloc(sizeof(*cur), NULL))) { 00870 cur->penalty = penalty; 00871 cur->paused = paused; 00872 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 00873 if (!ast_strlen_zero(state_interface)) 00874 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); 00875 else 00876 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface)); 00877 if (!ast_strlen_zero(membername)) 00878 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 00879 else 00880 ast_copy_string(cur->membername, interface, sizeof(cur->membername)); 00881 if (!strchr(cur->interface, '/')) 00882 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 00883 cur->status = ast_device_state(cur->state_interface); 00884 } 00885 00886 return cur; 00887 }
| static void destroy_queue | ( | void * | obj | ) | [static] |
Free queue's member list then its string fields.
Definition at line 1425 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().
01426 { 01427 struct call_queue *q = obj; 01428 int i; 01429 01430 free_members(q, 1); 01431 ast_string_field_free_memory(q); 01432 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 01433 if (q->sound_periodicannounce[i]) 01434 free(q->sound_periodicannounce[i]); 01435 } 01436 ao2_ref(q->members, -1); 01437 }
| static void device_state_cb | ( | const struct ast_event * | event, | |
| void * | unused | |||
| ) | [static] |
Definition at line 848 of file app_queue.c.
References ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_STATE, ast_log(), ast_strlen_zero(), LOG_ERROR, and statechange_queue().
00849 { 00850 enum ast_device_state state; 00851 const char *device; 00852 00853 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE); 00854 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE); 00855 00856 if (ast_strlen_zero(device)) { 00857 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n"); 00858 return; 00859 } 00860 00861 statechange_queue(device, state); 00862 }
| static void* device_state_thread | ( | void * | data | ) | [static] |
Consumer of the statechange queue.
Definition at line 795 of file app_queue.c.
References ast_cond_wait(), ast_free, AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), device_state, statechange::entry, and handle_statechange().
00796 { 00797 struct statechange *sc = NULL; 00798 00799 while (!device_state.stop) { 00800 ast_mutex_lock(&device_state.lock); 00801 if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) { 00802 ast_cond_wait(&device_state.cond, &device_state.lock); 00803 sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry); 00804 } 00805 ast_mutex_unlock(&device_state.lock); 00806 00807 /* Check to see if we were woken up to see the request to stop */ 00808 if (device_state.stop) 00809 break; 00810 00811 if (!sc) 00812 continue; 00813 00814 handle_statechange(sc); 00815 00816 ast_free(sc); 00817 sc = NULL; 00818 } 00819 00820 if (sc) 00821 ast_free(sc); 00822 00823 while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) 00824 ast_free(sc); 00825 00826 return NULL; 00827 }
| static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 2150 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry(), and wait_for_answer().
02151 { 02152 o->stillgoing = 0; 02153 ast_hangup(o->chan); 02154 o->chan = NULL; 02155 }
| 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 5682 of file app_queue.c.
References ast_cli(), and astman_append().
Referenced by __queues_show().
05683 { 05684 if (s) 05685 astman_append(s, "%s\r\n", str); 05686 else 05687 ast_cli(fd, "%s\n", str); 05688 }
| 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 4070 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().
04071 { 04072 struct member *cur_member; 04073 char value[PM_MAX_LEN]; 04074 int value_len = 0; 04075 int res; 04076 struct ao2_iterator mem_iter; 04077 04078 memset(value, 0, sizeof(value)); 04079 04080 if (!pm_queue) 04081 return; 04082 04083 mem_iter = ao2_iterator_init(pm_queue->members, 0); 04084 while ((cur_member = ao2_iterator_next(&mem_iter))) { 04085 if (!cur_member->dynamic) { 04086 ao2_ref(cur_member, -1); 04087 continue; 04088 } 04089 04090 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s", 04091 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface); 04092 04093 ao2_ref(cur_member, -1); 04094 04095 if (res != strlen(value + value_len)) { 04096 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 04097 break; 04098 } 04099 value_len += res; 04100 } 04101 ao2_iterator_destroy(&mem_iter); 04102 04103 if (value_len && !cur_member) { 04104 if (ast_db_put(pm_family, pm_queue->name, value)) 04105 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 04106 } else 04107 /* Delete the entry if the queue is empty or there is an error */ 04108 ast_db_del(pm_family, pm_queue->name); 04109 }
| static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 3266 of file app_queue.c.
References ao2_lock(), ao2_ref(), ao2_unlock(), queue_end_bridge::chan, queue_ent::chan, queue_end_bridge::q, queue_unref(), and set_queue_variables().
03267 { 03268 struct queue_end_bridge *qeb = data; 03269 struct call_queue *q = qeb->q; 03270 struct ast_channel *chan = qeb->chan; 03271 03272 if (ao2_ref(qeb, -1) == 1) { 03273 ao2_lock(q); 03274 set_queue_variables(q, chan); 03275 ao2_unlock(q); 03276 /* This unrefs the reference we made in try_calling when we allocated qeb */ 03277 queue_unref(q); 03278 } 03279 }
| static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
| struct ast_channel * | originator, | |||
| struct ast_channel * | terminator | |||
| ) | [static] |
Definition at line 3259 of file app_queue.c.
References ao2_ref(), queue_end_bridge::chan, and ast_bridge_config::end_bridge_callback_data.
03260 { 03261 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data; 03262 ao2_ref(qeb, +1); 03263 qeb->chan = originator; 03264 }
| static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static, read] |
find the entry with the best metric, or NULL
Definition at line 2365 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
02366 { 02367 struct callattempt *best = NULL, *cur; 02368 02369 for (cur = outgoing; cur; cur = cur->q_next) { 02370 if (cur->stillgoing && /* Not already done */ 02371 !cur->chan && /* Isn't already going */ 02372 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 02373 best = cur; 02374 } 02375 } 02376 02377 return best; 02378 }
| static struct call_queue* find_queue_by_name_rt | ( | const char * | queuename, | |
| struct ast_variable * | queue_vars, | |||
| struct ast_config * | member_config | |||
| ) | [static, read] |
Reload a single queue via realtime.
Check for statically defined queue first, check if deleted RT queue, check for new RT queue, if queue vars are not defined init them with defaults. reload RT queue vars, set RT queue members dead and reload them, return finished queue.
| the | queue, | |
| NULL | if it doesn't exist. |
Definition at line 1463 of file app_queue.c.
References alloc_queue(), ao2_find(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_link(), ao2_lock(), ao2_ref(), ao2_unlink(), ao2_unlock(), ast_category_browse(), ast_copy_string(), ast_debug, ast_log(), ast_strlen_zero(), ast_variable_retrieve(), clear_queue(), member::dead, call_queue::dead, init_queue(), LOG_WARNING, call_queue::membercount, call_queue::members, ast_variable::name, call_queue::name, ast_variable::next, OBJ_POINTER, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_unref(), queues, member::realtime, call_queue::realtime, remove_from_interfaces(), rt_handle_member_record(), S_OR, member::state_interface, strat2int(), call_queue::strategy, and ast_variable::value.
Referenced by load_realtime_queue().
01464 { 01465 struct ast_variable *v; 01466 struct call_queue *q, tmpq = { 01467 .name = queuename, 01468 }; 01469 struct member *m; 01470 struct ao2_iterator mem_iter; 01471 char *interface = NULL; 01472 const char *tmp_name; 01473 char *tmp; 01474 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 01475 01476 /* Static queues override realtime. */ 01477 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 01478 ao2_lock(q); 01479 if (!q->realtime) { 01480 if (q->dead) { 01481 ao2_unlock(q); 01482 queue_unref(q); 01483 return NULL; 01484 } else { 01485 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); 01486 ao2_unlock(q); 01487 return q; 01488 } 01489 } 01490 queue_unref(q); 01491 } else if (!member_config) 01492 /* Not found in the list, and it's not realtime ... */ 01493 return NULL; 01494 01495 /* Check if queue is defined in realtime. */ 01496 if (!queue_vars) { 01497 /* Delete queue from in-core list if it has been deleted in realtime. */ 01498 if (q) { 01499 /*! \note Hmm, can't seem to distinguish a DB failure from a not 01500 found condition... So we might delete an in-core queue 01501 in case of DB failure. */ 01502 ast_debug(1, "Queue %s not found in realtime.\n", queuename); 01503 01504 q->dead = 1; 01505 /* Delete if unused (else will be deleted when last caller leaves). */ 01506 ao2_unlink(queues, q); 01507 ao2_unlock(q); 01508 queue_unref(q); 01509 } 01510 return NULL; 01511 } 01512 01513 /* Create a new queue if an in-core entry does not exist yet. */ 01514 if (!q) { 01515 struct ast_variable *tmpvar = NULL; 01516 if (!(q = alloc_queue(queuename))) 01517 return NULL; 01518 ao2_lock(q); 01519 clear_queue(q); 01520 q->realtime = 1; 01521 /*Before we initialize the queue, we need to set the strategy, so that linear strategy 01522 * will allocate the members properly 01523 */ 01524 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) { 01525 if (!strcasecmp(tmpvar->name, "strategy")) { 01526 q->strategy = strat2int(tmpvar->value); 01527 if (q->strategy < 0) { 01528 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 01529 tmpvar->value, q->name); 01530 q->strategy = QUEUE_STRATEGY_RINGALL; 01531 } 01532 break; 01533 } 01534 } 01535 /* We traversed all variables and didn't find a strategy */ 01536 if (!tmpvar) 01537 q->strategy = QUEUE_STRATEGY_RINGALL; 01538 ao2_link(queues, q); 01539 } 01540 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 01541 01542 memset(tmpbuf, 0, sizeof(tmpbuf)); 01543 for (v = queue_vars; v; v = v->next) { 01544 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 01545 if ((tmp = strchr(v->name, '_'))) { 01546 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 01547 tmp_name = tmpbuf; 01548 tmp = tmpbuf; 01549 while ((tmp = strchr(tmp, '_'))) 01550 *tmp++ = '-'; 01551 } else 01552 tmp_name = v->name; 01553 01554 if (!ast_strlen_zero(v->value)) { 01555 /* Don't want to try to set the option if the value is empty */ 01556 queue_set_param(q, tmp_name, v->value, -1, 0); 01557 } 01558 } 01559 01560 /* Temporarily set realtime members dead so we can detect deleted ones. 01561 * Also set the membercount correctly for realtime*/ 01562 mem_iter = ao2_iterator_init(q->members, 0); 01563 while ((m = ao2_iterator_next(&mem_iter))) { 01564 q->membercount++; 01565 if (m->realtime) 01566 m->dead = 1; 01567 ao2_ref(m, -1); 01568 } 01569 ao2_iterator_destroy(&mem_iter); 01570 01571 while ((interface = ast_category_browse(member_config, interface))) { 01572 rt_handle_member_record(q, interface, 01573 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface), 01574 ast_variable_retrieve(member_config, interface, "penalty"), 01575 ast_variable_retrieve(member_config, interface, "paused"), 01576 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface)); 01577 } 01578 01579 /* Delete all realtime members that have been deleted in DB. */ 01580 mem_iter = ao2_iterator_init(q->members, 0); 01581 while ((m = ao2_iterator_next(&mem_iter))) { 01582 if (m->dead) { 01583 ao2_unlink(q->members, m); 01584 remove_from_interfaces(m->state_interface, 0); 01585 q->membercount--; 01586 } 01587 ao2_ref(m, -1); 01588 } 01589 ao2_iterator_destroy(&mem_iter); 01590 01591 ao2_unlock(q); 01592 01593 return q; 01594 }
| static void free_members | ( | struct call_queue * | q, | |
| int | all | |||
| ) | [static] |
Iterate through queue's member list and delete them.
Definition at line 1407 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().
01408 { 01409 /* Free non-dynamic members */ 01410 struct member *cur; 01411 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01412 01413 while ((cur = ao2_iterator_next(&mem_iter))) { 01414 if (all || !cur->dynamic) { 01415 ao2_unlink(q->members, cur); 01416 remove_from_interfaces(cur->state_interface, 1); 01417 q->membercount--; 01418 } 01419 ao2_ref(cur, -1); 01420 } 01421 ao2_iterator_destroy(&mem_iter); 01422 }
| static int get_member_penalty | ( | char * | queuename, | |
| char * | interface | |||
| ) | [static] |
Definition at line 4344 of file app_queue.c.
References ao2_find(), ao2_lock(), ao2_ref(), ao2_unlock(), ast_log(), interface_exists(), LOG_ERROR, OBJ_POINTER, member::penalty, queue_unref(), queues, and RESULT_FAILURE.
Referenced by queue_function_memberpenalty_read().
04345 { 04346 int foundqueue = 0, penalty; 04347 struct call_queue *q, tmpq = { 04348 .name = queuename, 04349 }; 04350 struct member *mem; 04351 04352 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 04353 foundqueue = 1; 04354 ao2_lock(q); 04355 if ((mem = interface_exists(q, interface))) { 04356 penalty = mem->penalty; 04357 ao2_ref(mem, -1); 04358 ao2_unlock(q); 04359 queue_unref(q); 04360 return penalty; 04361 } 04362 ao2_unlock(q); 04363 queue_unref(q); 04364 } 04365 04366 /* some useful debuging */ 04367 if (foundqueue) 04368 ast_log (LOG_ERROR, "Invalid queuename\n"); 04369 else 04370 ast_log (LOG_ERROR, "Invalid interface\n"); 04371 04372 return RESULT_FAILURE; 04373 }
| 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 647 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, QUEUE_NORMAL, and member::status.
Referenced by join_queue(), queue_exec(), and wait_our_turn().
00648 { 00649 struct member *member; 00650 struct ao2_iterator mem_iter; 00651 enum queue_member_status result = QUEUE_NO_MEMBERS; 00652 00653 ao2_lock(q); 00654 mem_iter = ao2_iterator_init(q->members, 0); 00655 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) { 00656 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) 00657 continue; 00658 00659 switch (member->status) { 00660 case AST_DEVICE_INVALID: 00661 /* nothing to do */ 00662 break; 00663 case AST_DEVICE_UNAVAILABLE: 00664 if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS) 00665 result = QUEUE_NO_REACHABLE_MEMBERS; 00666 break; 00667 default: 00668 if (member->paused) { 00669 result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS; 00670 } else { 00671 ao2_unlock(q); 00672 ao2_ref(member, -1); 00673 ao2_iterator_destroy(&mem_iter); 00674 return QUEUE_NORMAL; 00675 } 00676 break; 00677 } 00678 } 00679 ao2_iterator_destroy(&mem_iter); 00680 00681 ao2_unlock(q); 00682 return result; 00683 }
| static char* handle_queue_add_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6262 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.
06263 { 06264 char *queuename, *interface, *membername = NULL, *state_interface = NULL; 06265 int penalty; 06266 06267 switch ( cmd ) { 06268 case CLI_INIT: 06269 e->command = "queue add member"; 06270 e->usage = 06271 "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"; 06272 return NULL; 06273 case CLI_GENERATE: 06274 return complete_queue_add_member(a->line, a->word, a->pos, a->n); 06275 } 06276 06277 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) { 06278 return CLI_SHOWUSAGE; 06279 } else if (strcmp(a->argv[4], "to")) { 06280 return CLI_SHOWUSAGE; 06281 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) { 06282 return CLI_SHOWUSAGE; 06283 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) { 06284 return CLI_SHOWUSAGE; 06285 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) { 06286 return CLI_SHOWUSAGE; 06287 } 06288 06289 queuename = a->argv[5]; 06290 interface = a->argv[3]; 06291 if (a->argc >= 8) { 06292 if (sscanf(a->argv[7], "%30d", &penalty) == 1) { 06293 if (penalty < 0) { 06294 ast_cli(a->fd, "Penalty must be >= 0\n"); 06295 penalty = 0; 06296 } 06297 } else { 06298 ast_cli(a->fd, "Penalty must be an integer >= 0\n"); 06299 penalty = 0; 06300 } 06301 } else { 06302 penalty = 0; 06303 } 06304 06305 if (a->argc >= 10) { 06306 membername = a->argv[9]; 06307 } 06308 06309 if (a->argc >= 12) { 06310 state_interface = a->argv[11]; 06311 } 06312 06313 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { 06314 case RES_OKAY: 06315 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 06316 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 06317 return CLI_SUCCESS; 06318 case RES_EXISTS: 06319 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 06320 return CLI_FAILURE; 06321 case RES_NOSUCHQUEUE: 06322 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 06323 return CLI_FAILURE; 06324 case RES_OUTOFMEMORY: 06325 ast_cli(a->fd, "Out of memory\n"); 06326 return CLI_FAILURE; 06327 case RES_NOT_DYNAMIC: 06328 ast_cli(a->fd, "Member not dynamic\n"); 06329 return CLI_FAILURE; 06330 default: 06331 return CLI_FAILURE; 06332 } 06333 }
| static char* handle_queue_pause_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6440 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.
06441 { 06442 char *queuename, *interface, *reason; 06443 int paused; 06444 06445 switch (cmd) { 06446 case CLI_INIT: 06447 e->command = "queue {pause|unpause} member"; 06448 e->usage = 06449 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n" 06450 " Pause or unpause a queue member. Not specifying a particular queue\n" 06451 " will pause or unpause a member across all queues to which the member\n" 06452 " belongs.\n"; 06453 return NULL; 06454 case CLI_GENERATE: 06455 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n); 06456 } 06457 06458 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) { 06459 return CLI_SHOWUSAGE; 06460 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) { 06461 return CLI_SHOWUSAGE; 06462 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) { 06463 return CLI_SHOWUSAGE; 06464 } 06465 06466 06467 interface = a->argv[3]; 06468 queuename = a->argc >= 6 ? a->argv[5] : NULL; 06469 reason = a->argc == 8 ? a->argv[7] : NULL; 06470 paused = !strcasecmp(a->argv[1], "pause"); 06471 06472 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) { 06473 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface); 06474 if (!ast_strlen_zero(queuename)) 06475 ast_cli(a->fd, " in queue '%s'", queuename); 06476 if (!ast_strlen_zero(reason)) 06477 ast_cli(a->fd, " for reason '%s'", reason); 06478 ast_cli(a->fd, "\n"); 06479 return CLI_SUCCESS; 06480 } else { 06481 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface); 06482 if (!ast_strlen_zero(queuename)) 06483 ast_cli(a->fd, " in queue '%s'", queuename); 06484 if (!ast_strlen_zero(reason)) 06485 ast_cli(a->fd, " for reason '%s'", reason); 06486 ast_cli(a->fd, "\n"); 06487 return CLI_FAILURE; 06488 } 06489 }
| static char* handle_queue_remove_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6380 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.
06381 { 06382 char *queuename, *interface; 06383 06384 switch (cmd) { 06385 case CLI_INIT: 06386 e->command = "queue remove member"; 06387 e->usage = "Usage: queue remove member <channel> from <queue>\n"; 06388 return NULL; 06389 case CLI_GENERATE: 06390 return complete_queue_remove_member(a->line, a->word, a->pos, a->n); 06391 } 06392 06393 if (a->argc != 6) { 06394 return CLI_SHOWUSAGE; 06395 } else if (strcmp(a->argv[4], "from")) { 06396 return CLI_SHOWUSAGE; 06397 } 06398 06399 queuename = a->argv[5]; 06400 interface = a->argv[3]; 06401 06402 switch (remove_from_queue(queuename, interface)) { 06403 case RES_OKAY: 06404 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 06405 ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 06406 return CLI_SUCCESS; 06407 case RES_EXISTS: 06408 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 06409 return CLI_FAILURE; 06410 case RES_NOSUCHQUEUE: 06411 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 06412 return CLI_FAILURE; 06413 case RES_OUTOFMEMORY: 06414 ast_cli(a->fd, "Out of memory\n"); 06415 return CLI_FAILURE; 06416 default: 06417 return CLI_FAILURE; 06418 } 06419 }
| static char* handle_queue_rule_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6611 of file app_queue.c.
References CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, reload_queue_rules(), and ast_cli_entry::usage.
06612 { 06613 switch (cmd) { 06614 case CLI_INIT: 06615 e->command = "queue rules reload"; 06616 e->usage = 06617 "Usage: queue rules reload\n" 06618 "Reloads rules defined in queuerules.conf\n"; 06619 return NULL; 06620 case CLI_GENERATE: 06621 return NULL; 06622 } 06623 reload_queue_rules(1); 06624 return CLI_SUCCESS; 06625 }
| static char* handle_queue_rule_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6577 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_rule_show(), ast_cli_args::fd, ast_cli_args::line, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, ast_cli_args::n, rule_list::name, ast_cli_args::pos, rule_list::rules, penalty_rule::time, ast_cli_entry::usage, and ast_cli_args::word.
06578 { 06579 char *rule; 06580 struct rule_list *rl_iter; 06581 struct penalty_rule *pr_iter; 06582 switch (cmd) { 06583 case CLI_INIT: 06584 e->command = "queue rules show"; 06585 e->usage = 06586 "Usage: queue rules show [rulename]\n" 06587 "Show the list of rules associated with rulename. If no\n" 06588 "rulename is specified, list all rules defined in queuerules.conf\n"; 06589 return NULL; 06590 case CLI_GENERATE: 06591 return complete_queue_rule_show(a->line, a->word, a->pos, a->n); 06592 } 06593 06594 if (a->argc != 3 && a->argc != 4) 06595 return CLI_SHOWUSAGE; 06596 06597 rule = a->argc == 4 ? a->argv[3] : ""; 06598 AST_LIST_LOCK(&rule_lists); 06599 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 06600 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) { 06601 ast_cli(a->fd, "Rule: %s\n", rl_iter->name); 06602 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 06603 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); 06604 } 06605 } 06606 } 06607 AST_LIST_UNLOCK(&rule_lists); 06608 return CLI_SUCCESS; 06609 }
| static char* handle_queue_set_member_penalty | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6514 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.
06515 { 06516 char *queuename = NULL, *interface; 06517 int penalty = 0; 06518 06519 switch (cmd) { 06520 case CLI_INIT: 06521 e->command = "queue set penalty"; 06522 e->usage = 06523 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n" 06524 "Set a member's penalty in the queue specified. If no queue is specified\n" 06525 "then that interface's penalty is set in all queues to which that interface is a member\n"; 06526 return NULL; 06527 case CLI_GENERATE: 06528 return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n); 06529 } 06530 06531 if (a->argc != 6 && a->argc != 8) { 06532 return CLI_SHOWUSAGE; 06533 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) { 06534 return CLI_SHOWUSAGE; 06535 } 06536 06537 if (a->argc == 8) 06538 queuename = a->argv[7]; 06539 interface = a->argv[5]; 06540 penalty = atoi(a->argv[3]); 06541 06542 switch (set_member_penalty(queuename, interface, penalty)) { 06543 case RESULT_SUCCESS: 06544 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename); 06545 return CLI_SUCCESS; 06546 case RESULT_FAILURE: 06547 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename); 06548 return CLI_FAILURE; 06549 default: 06550 return CLI_FAILURE; 06551 } 06552 }
| static void* handle_statechange | ( | struct statechange * | sc | ) | [static] |
set a member's status based on device state of that member's interface
Definition at line 749 of file app_queue.c.
References ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, statechange::dev, devstate2str(), member_interface::interface, statechange::state, and update_status().
00750 { 00751 struct member_interface *curint; 00752 char interface[80]; 00753 00754 AST_LIST_LOCK(&interfaces); 00755 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00756 char *slash_pos; 00757 ast_copy_string(interface, curint->interface, sizeof(interface)); 00758 if ((slash_pos = strchr(interface, '/'))) 00759 if ((slash_pos = strchr(slash_pos + 1, '/'))) 00760 *slash_pos = '\0'; 00761 if (!strcasecmp(interface, sc->dev)) 00762 break; 00763 } 00764 AST_LIST_UNLOCK(&interfaces); 00765 00766 if (!curint) { 00767 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)); 00768 return NULL; 00769 } 00770 00771 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, devstate2str(sc->state)); 00772 00773 update_status(sc->dev, sc->state); 00774 00775 return NULL; 00776 }
| static void hangupcalls | ( | struct callattempt * | outgoing, | |
| struct ast_channel * | exception | |||
| ) | [static] |
Hang up a list of outgoing calls.
Definition at line 2046 of file app_queue.c.
References ao2_ref(), ast_free, ast_hangup(), callattempt::chan, callattempt::member, and callattempt::q_next.
Referenced by try_calling().
02047 { 02048 struct callattempt *oo; 02049 02050 while (outgoing) { 02051 /* Hangup any existing lines we have open */ 02052 if (outgoing->chan && (outgoing->chan != exception)) 02053 ast_hangup(outgoing->chan); 02054 oo = outgoing; 02055 outgoing = outgoing->q_next; 02056 if (oo->member) 02057 ao2_ref(oo->member, -1); 02058 ast_free(oo); 02059 } 02060 }
| static void init_queue | ( | struct call_queue * | q | ) | [static] |
Initialize Queue default values.
Definition at line 922 of file app_queue.c.
References call_queue::announcefrequency, call_queue::announceholdtime, 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, call_queue::eventwhencalled, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, call_queue::maskmemberstatus, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, member_cmp_fn(), member_hash_fn(), call_queue::membercount, call_queue::memberdelay, call_queue::members, call_queue::minannouncefrequency, call_queue::monfmt, call_queue::montype, call_queue::periodicannouncefrequency, QUEUE_STRATEGY_LINEAR, 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, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_queues().
00923 { 00924 int i; 00925 struct penalty_rule *pr_iter; 00926 00927 q->dead = 0; 00928 q->retry = DEFAULT_RETRY; 00929 q->timeout = -1; 00930 q->maxlen = 0; 00931 q->announcefrequency = 0; 00932 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY; 00933 q->announceholdtime = 0; 00934 q->announceholdtime = 1; 00935 q->roundingseconds = 0; /* Default - don't announce seconds */ 00936 q->servicelevel = 0; 00937 q->ringinuse = 1; 00938 q->setinterfacevar = 0; 00939 q->setqueuevar = 0; 00940 q->setqueueentryvar = 0; 00941 q->autofill = autofill_default; 00942 q->montype = montype_default; 00943 q->monfmt[0] = '\0'; 00944 q->reportholdtime = 0; 00945 q->wrapuptime = 0; 00946 q->joinempty = 0; 00947 q->leavewhenempty = 0; 00948 q->memberdelay = 0; 00949 q->maskmemberstatus = 0; 00950 q->eventwhencalled = 0; 00951 q->weight = 0; 00952 q->timeoutrestart = 0; 00953 q->periodicannouncefrequency = 0; 00954 if (!q->members) { 00955 if (q->strategy == QUEUE_STRATEGY_LINEAR) 00956 /* linear strategy depends on order, so we have to place all members in a single bucket */ 00957 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn); 00958 else 00959 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn); 00960 } 00961 q->membercount = 0; 00962 q->found = 1; 00963 00964 ast_string_field_set(q, sound_next, "queue-youarenext"); 00965 ast_string_field_set(q, sound_thereare, "queue-thereare"); 00966 ast_string_field_set(q, sound_calls, "queue-callswaiting"); 00967 ast_string_field_set(q, sound_holdtime, "queue-holdtime"); 00968 ast_string_field_set(q, sound_minutes, "queue-minutes"); 00969 ast_string_field_set(q, sound_minute, "queue-minute"); 00970 ast_string_field_set(q, sound_seconds, "queue-seconds"); 00971 ast_string_field_set(q, sound_thanks, "queue-thankyou"); 00972 ast_string_field_set(q, sound_reporthold, "queue-reporthold"); 00973 00974 if ((q->sound_periodicannounce[0] = ast_str_create(32))) 00975 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce"); 00976 00977 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 00978 if (q->sound_periodicannounce[i]) 00979 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", ""); 00980 } 00981 00982 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) 00983 ast_free(pr_iter); 00984 }
| 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 615 of file app_queue.c.
References call_queue::head, queue_ent::next, and queue_ent::parent.
Referenced by join_queue().
00616 { 00617 struct queue_ent *cur; 00618 00619 if (!q || !new) 00620 return; 00621 if (prev) { 00622 cur = prev->next; 00623 prev->next = new; 00624 } else { 00625 cur = q->head; 00626 q->head = new; 00627 } 00628 new->next = cur; 00629 new->parent = q; 00630 new->pos = ++(*pos); 00631 new->opos = *pos; 00632 }
| 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 1090 of file app_queue.c.
References ast_calloc, ast_free, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_strdupa, ast_strlen_zero(), LOG_ERROR, LOG_WARNING, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, rule_list::rules, and penalty_rule::time.
Referenced by reload_queue_rules().
01091 { 01092 char *timestr, *maxstr, *minstr, *contentdup; 01093 struct penalty_rule *rule = NULL, *rule_iter; 01094 struct rule_list *rl_iter; 01095 int time, inserted = 0; 01096 01097 if (!(rule = ast_calloc(1, sizeof(*rule)))) { 01098 ast_log(LOG_ERROR, "Cannot allocate memory for penaltychange rule at line %d!\n", linenum); 01099 return -1; 01100 } 01101 01102 contentdup = ast_strdupa(content); 01103 01104 if (!(maxstr = strchr(contentdup, ','))) { 01105 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum); 01106 ast_free(rule); 01107 return -1; 01108 } 01109 01110 *maxstr++ = '\0'; 01111 timestr = contentdup; 01112 01113 if ((time = atoi(timestr)) < 0) { 01114 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum); 01115 ast_free(rule); 01116 return -1; 01117 } 01118 01119 rule->time = time; 01120 01121 if ((minstr = strchr(maxstr,','))) 01122 *minstr++ = '\0'; 01123 01124 /* The last check will evaluate true if either no penalty change is indicated for a given rule 01125 * OR if a min penalty change is indicated but no max penalty change is */ 01126 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') { 01127 rule->max_relative = 1; 01128 } 01129 01130 rule->max_value = atoi(maxstr); 01131 01132 if (!ast_strlen_zero(minstr)) { 01133 if (*minstr == '+' || *minstr == '-') 01134 rule->min_relative = 1; 01135 rule->min_value = atoi(minstr); 01136 } else /*there was no minimum specified, so assume this means no change*/ 01137 rule->min_relative = 1; 01138 01139 /*We have the rule made, now we need to insert it where it belongs*/ 01140 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){ 01141 if (strcasecmp(rl_iter->name, list_name)) 01142 continue; 01143 01144 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) { 01145 if (rule->time < rule_iter->time) { 01146 AST_LIST_INSERT_BEFORE_CURRENT(rule, list); 01147 inserted = 1; 01148 break; 01149 } 01150 } 01151 AST_LIST_TRAVERSE_SAFE_END; 01152 01153 if (!inserted) { 01154 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list); 01155 } 01156 } 01157 01158 return 0; 01159 }
| static char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 545 of file app_queue.c.
References strategy::name, and strategies.
Referenced by __queues_show(), manager_queues_status(), queue_function_var(), and set_queue_variables().
00546 { 00547 int x; 00548 00549 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) { 00550 if (strategy == strategies[x].strategy) 00551 return strategies[x].name; 00552 } 00553 00554 return "<unknown>"; 00555 }
| static struct member* interface_exists | ( | struct call_queue * | q, | |
| const char * | interface | |||
| ) | [static, read] |
Definition at line 4044 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().
04045 { 04046 struct member *mem; 04047 struct ao2_iterator mem_iter; 04048 04049 if (!q) 04050 return NULL; 04051 04052 mem_iter = ao2_iterator_init(q->members, 0); 04053 while ((mem = ao2_iterator_next(&mem_iter))) { 04054 if (!strcasecmp(interface, mem->interface)) { 04055 ao2_iterator_destroy(&mem_iter); 04056 return mem; 04057 } 04058 ao2_ref(mem, -1); 04059 } 04060 ao2_iterator_destroy(&mem_iter); 04061 04062 return NULL; 04063 }
| static int interface_exists_global | ( | const char * | interface, | |
| int | lock_queue_container | |||
| ) | [static] |
Definition at line 1021 of file app_queue.c.
References ao2_iterator_destroy(), AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), ast_copy_string(), member::interface, call_queue::members, queue_unref(), queues, and member::state_interface.
Referenced by remove_from_interfaces().
01022 { 01023 struct call_queue *q; 01024 struct member *mem, tmpmem; 01025 struct ao2_iterator queue_iter, mem_iter; 01026 int ret = 0; 01027 01028 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 01029 queue_iter = ao2_iterator_init(queues, lock_queue_container ? 0 : AO2_ITERATOR_DONTLOCK); 01030 while ((q = ao2_iterator_next(&queue_iter))) { 01031 ao2_lock(q); 01032 mem_iter = ao2_iterator_init(q->members, 0); 01033 while ((mem = ao2_iterator_next(&mem_iter))) { 01034 if (!strcasecmp(mem->state_interface, interface)) { 01035 ao2_ref(mem, -1); 01036 ret = 1; 01037 break; 01038 } 01039 } 01040 ao2_unlock(q); 01041 queue_unref(q); 01042 ao2_iterator_destroy(&mem_iter); 01043 } 01044 ao2_iterator_destroy(&queue_iter); 01045 01046 return ret; 01047 }
| 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 2833 of file app_queue.c.
References ao2_lock(), ao2_unlock(), ast_debug, queue_ent::chan, call_queue::head, ast_channel::name, queue_ent::next, num_available_members(), queue_ent::parent, and queue_ent::pending.
Referenced by queue_exec(), and wait_our_turn().
02834 { 02835 struct queue_ent *ch; 02836 int res; 02837 int avl; 02838 int idx = 0; 02839 /* This needs a lock. How many members are available to be served? */ 02840 ao2_lock(qe->parent); 02841 02842 avl = num_available_members(qe->parent); 02843 02844 ch = qe->parent->head; 02845 02846 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member"); 02847 02848 while ((idx < avl) && (ch) && (ch != qe)) { 02849 if (!ch->pending) 02850 idx++; 02851 ch = ch->next; 02852 } 02853 02854 ao2_unlock(qe->parent); 02855 02856 /* If the queue entry is within avl [the number of available members] calls from the top ... */ 02857 if (ch && idx < avl) { 02858 ast_debug(1, "It's our turn (%s).\n", qe->chan->name); 02859 res = 1; 02860 } else { 02861 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name); 02862 res = 0; 02863 } 02864 02865 return res; 02866 }
| static int join_queue | ( | char * | queuename, | |
| struct queue_ent * | qe, | |||
| enum queue_result * | reason, | |||
| const char * | overriding_rule | |||
| ) | [static] |
Definition at line 1715 of file app_queue.c.
References call_queue::announce, 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, call_queue::context, 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, call_queue::moh, queue_ent::moh, call_queue::name, 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, ast_channel::uniqueid, and update_qe_rule().
Referenced by queue_exec().
01716 { 01717 struct call_queue *q; 01718 struct queue_ent *cur, *prev = NULL; 01719 int res = -1; 01720 int pos = 0; 01721 int inserted = 0; 01722 enum queue_member_status stat; 01723 int exit = 0; 01724 01725 if (!(q = load_realtime_queue(queuename))) 01726 return res; 01727 01728 ao2_lock(queues); 01729 ao2_lock(q); 01730 01731 copy_rules(qe, S_OR(overriding_rule, q->defaultrule)); 01732 qe->pr = AST_LIST_FIRST(&qe->qe_rules); 01733 01734 /* This is our one */ 01735 while (!exit) { 01736 stat = get_member_status(q, qe->max_penalty, qe->min_penalty); 01737 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) 01738 *reason = QUEUE_JOINEMPTY; 01739 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS)) 01740 *reason = QUEUE_JOINUNAVAIL; 01741 else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS)) 01742 *reason = QUEUE_JOINUNAVAIL; 01743 else if (q->maxlen && (q->count >= q->maxlen)) 01744 *reason = QUEUE_FULL; 01745 else { 01746 /* There's space for us, put us at the right position inside 01747 * the queue. 01748 * Take into account the priority of the calling user */ 01749 inserted = 0; 01750 prev = NULL; 01751 cur = q->head; 01752 while (cur) { 01753 /* We have higher priority than the current user, enter 01754 * before him, after all the other users with priority 01755 * higher or equal to our priority. */ 01756 if ((!inserted) && (qe->prio > cur->prio)) { 01757 insert_entry(q, prev, qe, &pos); 01758 inserted = 1; 01759 } 01760 cur->pos = ++pos; 01761 prev = cur; 01762 cur = cur->next; 01763 } 01764 /* No luck, join at the end of the queue */ 01765 if (!inserted) 01766 insert_entry(q, prev, qe, &pos); 01767 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 01768 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 01769 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 01770 q->count++; 01771 res = 0; 01772 manager_event(EVENT_FLAG_CALL, "Join", 01773 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n", 01774 qe->chan->name, 01775 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */ 01776 S_OR(qe->chan->cid.cid_name, "unknown"), 01777 q->name, qe->pos, q->count, qe->chan->uniqueid ); 01778 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 01779 } 01780 if (!exit && qe->pr && res) { 01781 /* We failed to join the queue, but perhaps we can join if we move 01782 * to the next defined penalty rule 01783 */ 01784 update_qe_rule(qe); 01785 } else { 01786 exit = 1; 01787 } 01788 } 01789 ao2_unlock(q); 01790 ao2_unlock(queues); 01791 01792 return res; 01793 }
| 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 1989 of file app_queue.c.
References ao2_lock(), ao2_unlink(), 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, manager_event, call_queue::name, ast_channel::name, queue_ent::next, queue_ent::parent, queue_ent::pos, queue_ent::qe_rules, queue_ref(), queue_unref(), queues, call_queue::realtime, ast_channel::uniqueid, and var.
Referenced by queue_exec(), try_calling(), and wait_our_turn().
01990 { 01991 struct call_queue *q; 01992 struct queue_ent *cur, *prev = NULL; 01993 struct penalty_rule *pr_iter; 01994 int pos = 0; 01995 01996 if (!(q = qe->parent)) 01997 return; 01998 queue_ref(q); 01999 ao2_lock(q); 02000 02001 prev = NULL; 02002 for (cur = q->head; cur; cur = cur->next) { 02003 if (cur == qe) { 02004 q->count--; 02005 02006 /* Take us out of the queue */ 02007 manager_event(EVENT_FLAG_CALL, "Leave", 02008 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n", 02009 qe->chan->name, q->name, q->count, qe->chan->uniqueid); 02010 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 02011 /* Take us out of the queue */ 02012 if (prev) 02013 prev->next = cur->next; 02014 else 02015 q->head = cur->next; 02016 /* Free penalty rules */ 02017 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) 02018 ast_free(pr_iter); 02019 } else { 02020 /* Renumber the people after us in the queue based on a new count */ 02021 cur->pos = ++pos; 02022 prev = cur; 02023 } 02024 } 02025 ao2_unlock(q); 02026 02027 /*If the queue is a realtime queue, check to see if it's still defined in real time*/ 02028 if (q->realtime) { 02029 struct ast_variable *var; 02030 if (!(var = ast_load_realtime("queues", "name", q->name, NULL))) { 02031 q->dead = 1; 02032 } else { 02033 ast_variables_destroy(var); 02034 } 02035 } 02036 02037 if (q->dead) { 02038 /* It's dead and nobody is in it, so kill it */ 02039 ao2_unlink(queues, q); 02040 } 02041 /* unref the explicit ref earlier in the function */ 02042 queue_unref(q); 02043 }
| static int load_module | ( | void | ) | [static] |
Definition at line 6706 of file app_queue.c.
References ao2_container_alloc(), aqm_exec(), ast_add_extension2(), ast_cli_register_multiple(), ast_cond_init(), 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_mutex_init(), ast_pthread_create, ast_register_application, ast_strdup, cli_queue, device_state, device_state_cb(), device_state_thread(), EVENT_FLAG_AGENT, LOG_ERROR, 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(), rqm_exec(), and upqm_exec().
06707 { 06708 int res; 06709 struct ast_context *con; 06710 06711 queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb); 06712 06713 if (!reload_queues(0)) 06714 return AST_MODULE_LOAD_DECLINE; 06715 06716 con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue"); 06717 if (!con) 06718 ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n"); 06719 else 06720 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue"); 06721 06722 if (queue_persistent_members) 06723 reload_queue_members(); 06724 06725 ast_mutex_init(&device_state.lock); 06726 ast_cond_init(&device_state.cond, NULL); 06727 ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL); 06728 06729 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 06730 res = ast_register_application(app, queue_exec, synopsis, descrip); 06731 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip); 06732 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip); 06733 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip); 06734 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip); 06735 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip); 06736 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues"); 06737 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status"); 06738 res |= ast_manager_register("QueueSummary", 0, manager_queues_summary, "Queue Summary"); 06739 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue."); 06740 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue."); 06741 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable"); 06742 res |= ast_manager_register("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom, "Adds custom entry in queue_log"); 06743 res |= ast_manager_register("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty, "Set the penalty for a queue member"); 06744 res |= ast_manager_register("QueueRule", 0, manager_queue_rule_show, "Queue Rules"); 06745 res |= ast_custom_function_register(&queuevar_function); 06746 res |= ast_custom_function_register(&queuemembercount_function); 06747 res |= ast_custom_function_register(&queuemembercount_dep); 06748 res |= ast_custom_function_register(&queuememberlist_function); 06749 res |= ast_custom_function_register(&queuewaitingcount_function); 06750 res |= ast_custom_function_register(&queuememberpenalty_function); 06751 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL, AST_EVENT_IE_END))) 06752 res = -1; 06753 06754 return res ? AST_MODULE_LOAD_DECLINE : 0; 06755 }
| static struct call_queue* load_realtime_queue | ( | const char * | queuename | ) | [static, read] |
Definition at line 1596 of file app_queue.c.
References ao2_find(), ao2_lock(), 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, and update_realtime_members().
Referenced by __queues_show(), add_to_queue(), join_queue(), queue_function_qac(), queue_function_qac_dep(), and reload_queue_members().
01597 { 01598 struct ast_variable *queue_vars; 01599 struct ast_config *member_config = NULL; 01600 struct call_queue *q = NULL, tmpq = { 01601 .name = queuename, 01602 }; 01603 01604 /* Find the queue in the in-core list first. */ 01605 q = ao2_find(queues, &tmpq, OBJ_POINTER); 01606 01607 if (!q || q->realtime) { 01608 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all 01609 queue operations while waiting for the DB. 01610 01611 This will be two separate database transactions, so we might 01612 see queue parameters as they were before another process 01613 changed the queue and member list as it was after the change. 01614 Thus we might see an empty member list when a queue is 01615 deleted. In practise, this is unlikely to cause a problem. */ 01616 01617 queue_vars = ast_load_realtime("queues", "name", queuename, NULL); 01618 if (queue_vars) { 01619 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL); 01620 if (!member_config) { 01621 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n"); 01622 ast_variables_destroy(queue_vars); 01623 return NULL; 01624 } 01625 } 01626 01627 ao2_lock(queues); 01628 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 01629 if (member_config) 01630 ast_config_destroy(member_config); 01631 if (queue_vars) 01632 ast_variables_destroy(queue_vars); 01633 ao2_unlock(queues); 01634 01635 } else { 01636 update_realtime_members(q); 01637 } 01638 return q; 01639 }
| static int manager_add_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6076 of file app_queue.c.
References add_to_queue(), ast_queue_log(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.
Referenced by load_module().
06077 { 06078 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; 06079 int paused, penalty = 0; 06080 06081 queuename = astman_get_header(m, "Queue"); 06082 interface = astman_get_header(m, "Interface"); 06083 penalty_s = astman_get_header(m, "Penalty"); 06084 paused_s = astman_get_header(m, "Paused"); 06085 membername = astman_get_header(m, "MemberName"); 06086 state_interface = astman_get_header(m, "StateInterface"); 06087 06088 if (ast_strlen_zero(queuename)) { 06089 astman_send_error(s, m, "'Queue' not specified."); 06090 return 0; 06091 } 06092 06093 if (ast_strlen_zero(interface)) { 06094 astman_send_error(s, m, "'Interface' not specified."); 06095 return 0; 06096 } 06097 06098 if (ast_strlen_zero(penalty_s)) 06099 penalty = 0; 06100 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) 06101 penalty = 0; 06102 06103 if (ast_strlen_zero(paused_s)) 06104 paused = 0; 06105 else 06106 paused = abs(ast_true(paused_s)); 06107 06108 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { 06109 case RES_OKAY: 06110 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", ""); 06111 astman_send_ack(s, m, "Added interface to queue"); 06112 break; 06113 case RES_EXISTS: 06114 astman_send_error(s, m, "Unable to add interface: Already there"); 06115 break; 06116 case RES_NOSUCHQUEUE: 06117 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 06118 break; 06119 case RES_OUTOFMEMORY: 06120 astman_send_error(s, m, "Out of memory"); 06121 break; 06122 } 06123 06124 return 0; 06125 }
| static int manager_pause_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6161 of file app_queue.c.
References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), and set_member_paused().
Referenced by load_module().
06162 { 06163 const char *queuename, *interface, *paused_s, *reason; 06164 int paused; 06165 06166 interface = astman_get_header(m, "Interface"); 06167 paused_s = astman_get_header(m, "Paused"); 06168 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 06169 reason = astman_get_header(m, "Reason"); /* Optional - Only used for logging purposes */ 06170 06171 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 06172 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 06173 return 0; 06174 } 06175 06176 paused = abs(ast_true(paused_s)); 06177 06178 if (set_member_paused(queuename, interface, reason, paused)) 06179 astman_send_error(s, m, "Interface not found"); 06180 else 06181 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 06182 return 0; 06183 }
| static int manager_queue_log_custom | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6185 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and S_OR.
Referenced by load_module().
06186 { 06187 const char *queuename, *event, *message, *interface, *uniqueid; 06188 06189 queuename = astman_get_header(m, "Queue"); 06190 uniqueid = astman_get_header(m, "UniqueId"); 06191 interface = astman_get_header(m, "Interface"); 06192 event = astman_get_header(m, "Event"); 06193 message = astman_get_header(m, "Message"); 06194 06195 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) { 06196 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters."); 06197 return 0; 06198 } 06199 06200 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message); 06201 astman_send_ack(s, m, "Event added successfully"); 06202 06203 return 0; 06204 }
| static int manager_queue_member_penalty | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6237 of file app_queue.c.
References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and set_member_penalty().
Referenced by load_module().
06238 { 06239 const char *queuename, *interface, *penalty_s; 06240 int penalty; 06241 06242 interface = astman_get_header(m, "Interface"); 06243 penalty_s = astman_get_header(m, "Penalty"); 06244 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */ 06245 queuename = astman_get_header(m, "Queue"); 06246 06247 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) { 06248 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters."); 06249 return 0; 06250 } 06251 06252 penalty = atoi(penalty_s); 06253 06254 if (set_member_penalty((char *)queuename, (char *)interface, penalty)) 06255 astman_send_error(s, m, "Invalid interface, queuename or penalty"); 06256 else 06257 astman_send_ack(s, m, "Interface penalty set successfully"); 06258 06259 return 0; 06260 }
| static int manager_queue_rule_show | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 5882 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, RESULT_SUCCESS, rule_list::rules, and penalty_rule::time.
Referenced by load_module().
05883 { 05884 const char *rule = astman_get_header(m, "Rule"); 05885 struct rule_list *rl_iter; 05886 struct penalty_rule *pr_iter; 05887 05888 AST_LIST_LOCK(&rule_lists); 05889 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 05890 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) { 05891 astman_append(s, "RuleList: %s\r\n", rl_iter->name); 05892 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 05893 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 ); 05894 } 05895 if (!ast_strlen_zero(rule)) 05896 break; 05897 } 05898 } 05899 AST_LIST_UNLOCK(&rule_lists); 05900 05901 astman_append(s, "\r\n\r\n"); 05902 05903 return RESULT_SUCCESS; 05904 }
| static int manager_queues_show | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 5872 of file app_queue.c.
References __queues_show(), astman_append(), and RESULT_SUCCESS.
Referenced by load_module().
05873 { 05874 char *a[] = { "queue", "show" }; 05875 05876 __queues_show(s, -1, 2, a); 05877 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 05878 05879 return RESULT_SUCCESS; 05880 }
| static int manager_queues_status | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Queue status info via AMI.
Definition at line 5981 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), 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_ent::pos, queue_unref(), queues, RESULT_SUCCESS, S_OR, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, and call_queue::weight.
Referenced by load_module().
05982 { 05983 time_t now; 05984 int pos; 05985 const char *id = astman_get_header(m,"ActionID"); 05986 const char *queuefilter = astman_get_header(m,"Queue"); 05987 const char *memberfilter = astman_get_header(m,"Member"); 05988 char idText[256] = ""; 05989 struct call_queue *q; 05990 struct queue_ent *qe; 05991 float sl = 0; 05992 struct member *mem; 05993 struct ao2_iterator queue_iter; 05994 struct ao2_iterator mem_iter; 05995 05996 astman_send_ack(s, m, "Queue status will follow"); 05997 time(&now); 05998 if (!ast_strlen_zero(id)) 05999 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 06000 06001 queue_iter = ao2_iterator_init(queues, 0); 06002 while ((q = ao2_iterator_next(&queue_iter))) { 06003 ao2_lock(q); 06004 06005 /* List queue properties */ 06006 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 06007 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 06008 astman_append(s, "Event: QueueParams\r\n" 06009 "Queue: %s\r\n" 06010 "Max: %d\r\n" 06011 "Strategy: %s\r\n" 06012 "Calls: %d\r\n" 06013 "Holdtime: %d\r\n" 06014 "Completed: %d\r\n" 06015 "Abandoned: %d\r\n" 06016 "ServiceLevel: %d\r\n" 06017 "ServicelevelPerf: %2.1f\r\n" 06018 "Weight: %d\r\n" 06019 "%s" 06020 "\r\n", 06021 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, 06022 q->callsabandoned, q->servicelevel, sl, q->weight, idText); 06023 /* List Queue Members */ 06024 mem_iter = ao2_iterator_init(q->members, 0); 06025 while ((mem = ao2_iterator_next(&mem_iter))) { 06026 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) { 06027 astman_append(s, "Event: QueueMember\r\n" 06028 "Queue: %s\r\n" 06029 "Name: %s\r\n" 06030 "Location: %s\r\n" 06031 "Membership: %s\r\n" 06032 "Penalty: %d\r\n" 06033 "CallsTaken: %d\r\n" 06034 "LastCall: %d\r\n" 06035 "Status: %d\r\n" 06036 "Paused: %d\r\n" 06037 "%s" 06038 "\r\n", 06039 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static", 06040 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 06041 } 06042 ao2_ref(mem, -1); 06043 } 06044 ao2_iterator_destroy(&mem_iter); 06045 /* List Queue Entries */ 06046 pos = 1; 06047 for (qe = q->head; qe; qe = qe->next) { 06048 astman_append(s, "Event: QueueEntry\r\n" 06049 "Queue: %s\r\n" 06050 "Position: %d\r\n" 06051 "Channel: %s\r\n" 06052 "CallerIDNum: %s\r\n" 06053 "CallerIDName: %s\r\n" 06054 "Wait: %ld\r\n" 06055 "%s" 06056 "\r\n", 06057 q->name, pos++, qe->chan->name, 06058 S_OR(qe->chan->cid.cid_num, "unknown"), 06059 S_OR(qe->chan->cid.cid_name, "unknown"), 06060 (long) (now - qe->start), idText); 06061 } 06062 } 06063 ao2_unlock(q); 06064 queue_unref(q); 06065 } 06066 ao2_iterator_destroy(&queue_iter); 06067 06068 astman_append(s, 06069 "Event: QueueStatusComplete\r\n" 06070 "%s" 06071 "\r\n",idText); 06072 06073 return RESULT_SUCCESS; 06074 }
| static int manager_queues_summary | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Summary of queue info via the AMI.
Definition at line 5907 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_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_unref(), queues, RESULT_SUCCESS, queue_ent::start, and member::status.
Referenced by load_module().
05908 { 05909 time_t now; 05910 int qmemcount = 0; 05911 int qmemavail = 0; 05912 int qchancount = 0; 05913 int qlongestholdtime = 0; 05914 const char *id = astman_get_header(m, "ActionID"); 05915 const char *queuefilter = astman_get_header(m, "Queue"); 05916 char idText[256] = ""; 05917 struct call_queue *q; 05918 struct queue_ent *qe; 05919 struct member *mem; 05920 struct ao2_iterator queue_iter; 05921 struct ao2_iterator mem_iter; 05922 05923 astman_send_ack(s, m, "Queue summary will follow"); 05924 time(&now); 05925 if (!ast_strlen_zero(id)) 05926 snprintf(idText, 256, "ActionID: %s\r\n", id); 05927 queue_iter = ao2_iterator_init(queues, 0); 05928 while ((q = ao2_iterator_next(&queue_iter))) { 05929 ao2_lock(q); 05930 05931 /* List queue properties */ 05932 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 05933 /* Reset the necessary local variables if no queuefilter is set*/ 05934 qmemcount = 0; 05935 qmemavail = 0; 05936 qchancount = 0; 05937 qlongestholdtime = 0; 05938 05939 /* List Queue Members */ 05940 mem_iter = ao2_iterator_init(q->members, 0); 05941 while ((mem = ao2_iterator_next(&mem_iter))) { 05942 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) { 05943 ++qmemcount; 05944 if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) { 05945 ++qmemavail; 05946 } 05947 } 05948 ao2_ref(mem, -1); 05949 } 05950 ao2_iterator_destroy(&mem_iter); 05951 for (qe = q->head; qe; qe = qe->next) { 05952 if ((now - qe->start) > qlongestholdtime) { 05953 qlongestholdtime = now - qe->start; 05954 } 05955 ++qchancount; 05956 } 05957 astman_append(s, "Event: QueueSummary\r\n" 05958 "Queue: %s\r\n" 05959 "LoggedIn: %d\r\n" 05960 "Available: %d\r\n" 05961 "Callers: %d\r\n" 05962 "HoldTime: %d\r\n" 05963 "LongestHoldTime: %d\r\n" 05964 "%s" 05965 "\r\n", 05966 q->name, qmemcount, qmemavail, qchancount, q->holdtime, qlongestholdtime, idText); 05967 } 05968 ao2_unlock(q); 05969 queue_unref(q); 05970 } 05971 ao2_iterator_destroy(&queue_iter); 05972 astman_append(s, 05973 "Event: QueueSummaryComplete\r\n" 05974 "%s" 05975 "\r\n", idText); 05976 05977 return RESULT_SUCCESS; 05978 }
| static int manager_remove_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6127 of file app_queue.c.
References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and RES_OUTOFMEMORY.
Referenced by load_module().
06128 { 06129 const char *queuename, *interface; 06130 06131 queuename = astman_get_header(m, "Queue"); 06132 interface = astman_get_header(m, "Interface"); 06133 06134 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 06135 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 06136 return 0; 06137 } 06138 06139 switch (remove_from_queue(queuename, interface)) { 06140 case RES_OKAY: 06141 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 06142 astman_send_ack(s, m, "Removed interface from queue"); 06143 break; 06144 case RES_EXISTS: 06145 astman_send_error(s, m, "Unable to remove interface: Not there"); 06146 break; 06147 case RES_NOSUCHQUEUE: 06148 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 06149 break; 06150 case RES_OUTOFMEMORY: 06151 astman_send_error(s, m, "Out of memory"); 06152 break; 06153 case RES_NOT_DYNAMIC: 06154 astman_send_error(s, m, "Member not dynamic"); 06155 break; 06156 } 06157 06158 return 0; 06159 }
| static int member_cmp_fn | ( | void * | obj1, | |
| void * | obj2, | |||
| int | flags | |||
| ) | [static] |
Definition at line 912 of file app_queue.c.
References CMP_MATCH, and member::interface.
Referenced by init_queue().
00913 { 00914 struct member *mem1 = obj1, *mem2 = obj2; 00915 return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH; 00916 }
| static int member_hash_fn | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 900 of file app_queue.c.
References compress_char(), and member::interface.
Referenced by init_queue().
00901 { 00902 const struct member *mem = obj; 00903 const char *chname = strchr(mem->interface, '/'); 00904 int ret = 0, i; 00905 if (!chname) 00906 chname = mem->interface; 00907 for (i = 0; i < 5 && chname[i]; i++) 00908 ret += compress_char(chname[i]) << (i * 6); 00909 return ret; 00910 }
| 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 2070 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().
02071 { 02072 struct member *mem; 02073 int avl = 0; 02074 struct ao2_iterator mem_iter; 02075 02076 mem_iter = ao2_iterator_init(q->members, 0); 02077 while ((mem = ao2_iterator_next(&mem_iter))) { 02078 switch (mem->status) { 02079 case AST_DEVICE_INUSE: 02080 if (!q->ringinuse) 02081 break; 02082 /* else fall through */ 02083 case AST_DEVICE_NOT_INUSE: 02084 case AST_DEVICE_UNKNOWN: 02085 if (!mem->paused) { 02086 avl++; 02087 } 02088 break; 02089 } 02090 ao2_ref(mem, -1); 02091 02092 /* If autofill is not enabled or if the queue's strategy is ringall, then 02093 * we really don't care about the number of available members so much as we 02094 * do that there is at least one available. 02095 * 02096 * In fact, we purposely will return from this function stating that only 02097 * one member is available if either of those conditions hold. That way, 02098 * functions which determine what action to take based on the number of available 02099 * members will operate properly. The reasoning is that even if multiple 02100 * members are available, only the head caller can actually be serviced. 02101 */ 02102 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) { 02103 break; 02104 } 02105 } 02106 ao2_iterator_destroy(&mem_iter); 02107 02108 return avl; 02109 }
| static int play_file | ( | struct ast_channel * | chan, | |
| const char * | filename | |||
| ) | [static] |
Definition at line 1795 of file app_queue.c.
References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_waitstream(), and ast_channel::language.
Referenced by say_periodic_announcement(), say_position(), and try_calling().
01796 { 01797 int res; 01798 01799 if (ast_strlen_zero(filename)) { 01800 return 0; 01801 } 01802 01803 ast_stopstream(chan); 01804 01805 res = ast_streamfile(chan, filename, chan->language); 01806 if (!res) 01807 res = ast_waitstream(chan, AST_DIGIT_ANY); 01808 01809 ast_stopstream(chan); 01810 01811 return res; 01812 }
| static int pqm_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
PauseQueueMember application.
Definition at line 4473 of file app_queue.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, parse(), pbx_builtin_setvar_helper(), and set_member_paused().
Referenced by load_module().
04474 { 04475 char *parse; 04476 AST_DECLARE_APP_ARGS(args, 04477 AST_APP_ARG(queuename); 04478 AST_APP_ARG(interface); 04479 AST_APP_ARG(options); 04480 AST_APP_ARG(reason); 04481 ); 04482 04483 if (ast_strlen_zero(data)) { 04484 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n"); 04485 return -1; 04486 } 04487 04488 parse = ast_strdupa(data); 04489 04490 AST_STANDARD_APP_ARGS(args, parse); 04491 04492 if (ast_strlen_zero(args.interface)) { 04493 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 04494 return -1; 04495 } 04496 04497 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) { 04498 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 04499 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 04500 return 0; 04501 } 04502 04503 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 04504 04505 return 0; 04506 }
| static int ql_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
QueueLog application.
Definition at line 4663 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().
04664 { 04665 char *parse; 04666 04667 AST_DECLARE_APP_ARGS(args, 04668 AST_APP_ARG(queuename); 04669 AST_APP_ARG(uniqueid); 04670 AST_APP_ARG(membername); 04671 AST_APP_ARG(event); 04672 AST_APP_ARG(params); 04673 ); 04674 04675 if (ast_strlen_zero(data)) { 04676 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n"); 04677 return -1; 04678 } 04679 04680 parse = ast_strdupa(data); 04681 04682 AST_STANDARD_APP_ARGS(args, parse); 04683 04684 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 04685 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 04686 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n"); 04687 return -1; 04688 } 04689 04690 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 04691 "%s", args.params ? args.params : ""); 04692 04693 return 0; 04694 }
| static int queue_cmp_cb | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 576 of file app_queue.c.
References CMP_MATCH, and call_queue::name.
Referenced by load_module().
00577 { 00578 struct call_queue *q = obj, *q2 = arg; 00579 return !strcasecmp(q->name, q2->name) ? CMP_MATCH : 0; 00580 }
| 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 4741 of file app_queue.c.
References call_queue::announcefrequency, AST_APP_ARG, ast_cdr_noanswer(), AST_CONTROL_RINGING, ast_debug, AST_DECLARE_APP_ARGS, ast_indicate(), ast_log(), ast_moh_start(), ast_moh_stop(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::cdr, queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, queue_ent::digits, queue_ent::expire, get_member_status(), queue_ent::handled, is_our_turn(), join_queue(), queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::last_pos, queue_ent::last_pos_said, leave_queue(), call_queue::leavewhenempty, LOG_WARNING, queue_ent::max_penalty, call_queue::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_CONTINUE, QUEUE_EMPTY_LOOSE, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, QUEUE_NORMAL, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), S_OR, say_periodic_announcement(), say_position(), set_queue_result(), set_queue_variables(), queue_ent::start, 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().
04742 { 04743 int res=-1; 04744 int ringing=0; 04745 const char *user_priority; 04746 const char *max_penalty_str; 04747 const char *min_penalty_str; 04748 int prio; 04749 int qcontinue = 0; 04750 int max_penalty, min_penalty; 04751 enum queue_result reason = QUEUE_UNKNOWN; 04752 /* whether to exit Queue application after the timeout hits */ 04753 int tries = 0; 04754 int noption = 0; 04755 char *parse; 04756 int makeannouncement = 0; 04757 AST_DECLARE_APP_ARGS(args, 04758 AST_APP_ARG(queuename); 04759 AST_APP_ARG(options); 04760 AST_APP_ARG(url); 04761 AST_APP_ARG(announceoverride); 04762 AST_APP_ARG(queuetimeoutstr); 04763 AST_APP_ARG(agi); 04764 AST_APP_ARG(macro); 04765 AST_APP_ARG(gosub); 04766 AST_APP_ARG(rule); 04767 ); 04768 /* Our queue entry */ 04769 struct queue_ent qe; 04770 04771 if (ast_strlen_zero(data)) { 04772 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule]]]]]]]]\n"); 04773 return -1; 04774 } 04775 04776 parse = ast_strdupa(data); 04777 AST_STANDARD_APP_ARGS(args, parse); 04778 04779 /* Setup our queue entry */ 04780 memset(&qe, 0, sizeof(qe)); 04781 qe.start = time(NULL); 04782 04783 /* set the expire time based on the supplied timeout; */ 04784 if (!ast_strlen_zero(args.queuetimeoutstr)) 04785 qe.expire = qe.start + atoi(args.queuetimeoutstr); 04786 else 04787 qe.expire = 0; 04788 04789 /* Get the priority from the variable ${QUEUE_PRIO} */ 04790 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 04791 if (user_priority) { 04792 if (sscanf(user_priority, "%30d", &prio) == 1) { 04793 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio); 04794 } else { 04795 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 04796 user_priority, chan->name); 04797 prio = 0; 04798 } 04799 } else { 04800 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n"); 04801 prio = 0; 04802 } 04803 04804 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 04805 04806 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 04807 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) { 04808 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty); 04809 } else { 04810 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 04811 max_penalty_str, chan->name); 04812 max_penalty = 0; 04813 } 04814 } else { 04815 max_penalty = 0; 04816 } 04817 04818 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) { 04819 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) { 04820 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty); 04821 } else { 04822 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n", 04823 min_penalty_str, chan->name); 04824 min_penalty = 0; 04825 } 04826 } else { 04827 min_penalty = 0; 04828 } 04829 04830 if (args.options && (strchr(args.options, 'r'))) 04831 ringing = 1; 04832 04833 if (args.options && (strchr(args.options, 'c'))) 04834 qcontinue = 1; 04835 04836 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 04837 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 04838 04839 qe.chan = chan; 04840 qe.prio = prio; 04841 qe.max_penalty = max_penalty; 04842 qe.min_penalty = min_penalty; 04843 qe.last_pos_said = 0; 04844 qe.last_pos = 0; 04845 qe.last_periodic_announce_time = time(NULL); 04846 qe.last_periodic_announce_sound = 0; 04847 qe.valid_digits = 0; 04848 if (join_queue(args.queuename, &qe, &reason, args.rule)) { 04849 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 04850 set_queue_result(chan, reason); 04851 return 0; 04852 } 04853 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""), 04854 S_OR(chan->cid.cid_num, "")); 04855 check_turns: 04856 if (ringing) { 04857 ast_indicate(chan, AST_CONTROL_RINGING); 04858 } else { 04859 ast_moh_start(chan, qe.moh, NULL); 04860 } 04861 04862 /* This is the wait loop for callers 2 through maxlen */ 04863 res = wait_our_turn(&qe, ringing, &reason); 04864 if (res) { 04865 goto stop; 04866 } 04867 04868 makeannouncement = 0; 04869 04870 for (;;) { 04871 /* This is the wait loop for the head caller*/ 04872 /* To exit, they may get their call answered; */ 04873 /* they may dial a digit from the queue context; */ 04874 /* or, they may timeout. */ 04875 04876 enum queue_member_status stat = QUEUE_NORMAL; 04877 int exit = 0; 04878 04879 /* Leave if we have exceeded our queuetimeout */ 04880 if (qe.expire && (time(NULL) >= qe.expire)) { 04881 record_abandoned(&qe); 04882 ast_cdr_noanswer(qe.chan->cdr); 04883 reason = QUEUE_TIMEOUT; 04884 res = 0; 04885 ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 04886 qe.pos, qe.opos, (long) time(NULL) - qe.start); 04887 break; 04888 } 04889 04890 if (makeannouncement) { 04891 /* Make a position announcement, if enabled */ 04892 if (qe.parent->announcefrequency) 04893 if ((res = say_position(&qe,ringing))) 04894 goto stop; 04895 } 04896 makeannouncement = 1; 04897 04898 /* Make a periodic announcement, if enabled */ 04899 if (qe.parent->periodicannouncefrequency) 04900 if ((res = say_periodic_announcement(&qe,ringing))) 04901 goto stop; 04902 04903 /* Leave if we have exceeded our queuetimeout */ 04904 if (qe.expire && (time(NULL) >= qe.expire)) { 04905 record_abandoned(&qe); 04906 ast_cdr_noanswer(qe.chan->cdr); 04907 reason = QUEUE_TIMEOUT; 04908 res = 0; 04909 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04910 break; 04911 } 04912 04913 /* see if we need to move to the next penalty level for this queue */ 04914 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) { 04915 update_qe_rule(&qe); 04916 } 04917 04918 /* Try calling all queue members for 'timeout' seconds */ 04919 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing); 04920 if (res) { 04921 goto stop; 04922 } 04923 04924 /* exit after 'timeout' cycle if 'n' option enabled */ 04925 if (noption && tries >= qe.parent->membercount) { 04926 ast_verb(3, "Exiting on time-out cycle\n"); 04927 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04928 record_abandoned(&qe); 04929 ast_cdr_noanswer(qe.chan->cdr); 04930 reason = QUEUE_TIMEOUT; 04931 res = 0; 04932 break; 04933 } 04934 04935 for (; !exit || qe.pr; update_qe_rule(&qe)) { 04936 stat = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty); 04937 04938 if (!qe.pr || stat == QUEUE_NORMAL) { 04939 break; 04940 } 04941 04942 if ((qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) || 04943 ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) || 04944 ((qe.parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS))) { 04945 continue; 04946 } else { 04947 exit = 1; 04948 } 04949 } 04950 04951 /* leave the queue if no agents, if enabled */ 04952 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 04953 record_abandoned(&qe); 04954 reason = QUEUE_LEAVEEMPTY; 04955 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 04956 res = 0; 04957 break; 04958 } 04959 04960 /* leave the queue if no reachable agents, if enabled */ 04961 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) { 04962 record_abandoned(&qe); 04963 reason = QUEUE_LEAVEUNAVAIL; 04964 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 04965 res = 0; 04966 break; 04967 } 04968 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 04969 record_abandoned(&qe); 04970 reason = QUEUE_LEAVEUNAVAIL; 04971 res = 0; 04972 break; 04973 } 04974 04975 /* Leave if we have exceeded our queuetimeout */ 04976 if (qe.expire && (time(NULL) >= qe.expire)) { 04977 record_abandoned(&qe); 04978 ast_cdr_noanswer(qe.chan->cdr); 04979 reason = QUEUE_TIMEOUT; 04980 res = 0; 04981 ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start); 04982 break; 04983 } 04984 04985 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 04986 update_realtime_members(qe.parent); 04987 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 04988 res = wait_a_bit(&qe); 04989 if (res) 04990 goto stop; 04991 04992 /* Since this is a priority queue and 04993 * it is not sure that we are still at the head 04994 * of the queue, go and check for our turn again. 04995 */ 04996 if (!is_our_turn(&qe)) { 04997 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name); 04998 goto check_turns; 04999 } 05000 } 05001 05002 stop: 05003 if (res) { 05004 if (res < 0) { 05005 if (!qe.handled) { 05006 record_abandoned(&qe); 05007 ast_cdr_noanswer(qe.chan->cdr); 05008 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 05009 "%d|%d|%ld", qe.pos, qe.opos, 05010 (long) time(NULL) - qe.start); 05011 res = -1; 05012 } else if (qcontinue) { 05013 reason = QUEUE_CONTINUE; 05014 res = 0; 05015 } 05016 } else if (qe.valid_digits) { 05017 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 05018 "%s|%d", qe.digits, qe.pos); 05019 } 05020 } 05021 05022 /* Don't allow return code > 0 */ 05023 if (res >= 0) { 05024 res = 0; 05025 if (ringing) { 05026 ast_indicate(chan, -1); 05027 } else { 05028 ast_moh_stop(chan); 05029 } 05030 ast_stopstream(chan); 05031 } 05032 05033 set_queue_variables(qe.parent, qe.chan); 05034 05035 leave_queue(&qe); 05036 if (reason != QUEUE_UNKNOWN) 05037 set_queue_result(chan, reason); 05038 05039 return res; 05040 }
| 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 5274 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.
05275 { 05276 int penalty; 05277 AST_DECLARE_APP_ARGS(args, 05278 AST_APP_ARG(queuename); 05279 AST_APP_ARG(interface); 05280 ); 05281 /* Make sure the returned value on error is NULL. */ 05282 buf[0] = '\0'; 05283 05284 if (ast_strlen_zero(data)) { 05285 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05286 return -1; 05287 } 05288 05289 AST_STANDARD_APP_ARGS(args, data); 05290 05291 if (args.argc < 2) { 05292 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05293 return -1; 05294 } 05295 05296 penalty = get_member_penalty (args.queuename, args.interface); 05297 05298 if (penalty >= 0) /* remember that buf is already '\0' */ 05299 snprintf (buf, len, "%d", penalty); 05300 05301 return 0; 05302 }
| 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 5305 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().
05306 { 05307 int penalty; 05308 AST_DECLARE_APP_ARGS(args, 05309 AST_APP_ARG(queuename); 05310 AST_APP_ARG(interface); 05311 ); 05312 05313 if (ast_strlen_zero(data)) { 05314 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05315 return -1; 05316 } 05317 05318 AST_STANDARD_APP_ARGS(args, data); 05319 05320 if (args.argc < 2) { 05321 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05322 return -1; 05323 } 05324 05325 penalty = atoi(value); 05326 05327 if (ast_strlen_zero(args.interface)) { 05328 ast_log (LOG_ERROR, "<interface> parameter can't be null\n"); 05329 return -1; 05330 } 05331 05332 /* if queuename = NULL then penalty will be set for interface in all the queues. */ 05333 if (set_member_penalty(args.queuename, args.interface, penalty)) { 05334 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); 05335 return -1; 05336 } 05337 05338 return 0; 05339 }
| 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 5093 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(), load_realtime_queue(), LOG_ERROR, LOG_WARNING, call_queue::membercount, call_queue::members, member::paused, queue_unref(), and member::status.
05094 { 05095 int count = 0; 05096 struct member *m; 05097 struct ao2_iterator mem_iter; 05098 struct call_queue *q; 05099 char *option; 05100 05101 if (ast_strlen_zero(data)) { 05102 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 05103 return -1; 05104 } 05105 05106 if ((option = strchr(data, ','))) 05107 *option++ = '\0'; 05108 else 05109 option = "logged"; 05110 if ((q = load_realtime_queue(data))) { 05111 ao2_lock(q); 05112 if (!strcasecmp(option, "logged")) { 05113 mem_iter = ao2_iterator_init(q->members, 0); 05114 while ((m = ao2_iterator_next(&mem_iter))) { 05115 /* Count the agents who are logged in and presently answering calls */ 05116 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05117 count++; 05118 } 05119 ao2_ref(m, -1); 05120 } 05121 ao2_iterator_destroy(&mem_iter); 05122 } else if (!strcasecmp(option, "free")) { 05123 mem_iter = ao2_iterator_init(q->members, 0); 05124 while ((m = ao2_iterator_next(&mem_iter))) { 05125 /* Count the agents who are logged in and presently answering calls */ 05126 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) { 05127 count++; 05128 } 05129 ao2_ref(m, -1); 05130 } 05131 ao2_iterator_destroy(&mem_iter); 05132 } else /* must be "count" */ 05133 count = q->membercount; 05134 ao2_unlock(q); 05135 queue_unref(q); 05136 } else 05137 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05138 05139 snprintf(buf, len, "%d", count); 05140 05141 return 0; 05142 }
| 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 5149 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(), load_realtime_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, call_queue::members, queue_unref(), and member::status.
05150 { 05151 int count = 0; 05152 struct member *m; 05153 struct call_queue *q; 05154 struct ao2_iterator mem_iter; 05155 static int depflag = 1; 05156 05157 if (depflag) { 05158 depflag = 0; 05159 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"); 05160 } 05161 05162 if (ast_strlen_zero(data)) { 05163 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 05164 return -1; 05165 } 05166 05167 if ((q = load_realtime_queue(data))) { 05168 ao2_lock(q); 05169 mem_iter = ao2_iterator_init(q->members, 0); 05170 while ((m = ao2_iterator_next(&mem_iter))) { 05171 /* Count the agents who are logged in and presently answering calls */ 05172 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05173 count++; 05174 } 05175 ao2_ref(m, -1); 05176 } 05177 ao2_iterator_destroy(&mem_iter); 05178 ao2_unlock(q); 05179 queue_unref(q); 05180 } else 05181 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05182 05183 snprintf(buf, len, "%d", count); 05184 05185 return 0; 05186 }
| 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 5225 of file app_queue.c.
References ao2_find(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), ast_log(), ast_strlen_zero(), member::interface, LOG_ERROR, LOG_WARNING, call_queue::members, OBJ_POINTER, queue_unref(), and queues.
05226 { 05227 struct call_queue *q, tmpq = { 05228 .name = data, 05229 }; 05230 struct member *m; 05231 05232 /* Ensure an otherwise empty list doesn't return garbage */ 05233 buf[0] = '\0'; 05234 05235 if (ast_strlen_zero(data)) { 05236 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 05237 return -1; 05238 } 05239 05240 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 05241 int buflen = 0, count = 0; 05242 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 05243 05244 ao2_lock(q); 05245 while ((m = ao2_iterator_next(&mem_iter))) { 05246 /* strcat() is always faster than printf() */ 05247 if (count++) { 05248 strncat(buf + buflen, ",", len - buflen - 1); 05249 buflen++; 05250 } 05251 strncat(buf + buflen, m->interface, len - buflen - 1); 05252 buflen += strlen(m->interface); 05253 /* Safeguard against overflow (negative length) */ 05254 if (buflen >= len - 2) { 05255 ao2_ref(m, -1); 05256 ast_log(LOG_WARNING, "Truncating list\n"); 05257 break; 05258 } 05259 ao2_ref(m, -1); 05260 } 05261 ao2_iterator_destroy(&mem_iter); 05262 ao2_unlock(q); 05263 queue_unref(q); 05264 } else 05265 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05266 05267 /* We should already be terminated, but let's make sure. */ 05268 buf[len - 1] = '\0'; 05269 05270 return 0; 05271 }
| 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 5189 of file app_queue.c.
References ao2_find(), ao2_lock(), ao2_unlock(), ast_load_realtime(), ast_log(), ast_strlen_zero(), ast_variables_destroy(), call_queue::count, LOG_ERROR, LOG_WARNING, OBJ_POINTER, queue_unref(), queues, and var.
05190 { 05191 int count = 0; 05192 struct call_queue *q, tmpq = { 05193 .name = data, 05194 }; 05195 struct ast_variable *var = NULL; 05196 05197 buf[0] = '\0'; 05198 05199 if (ast_strlen_zero(data)) { 05200 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n"); 05201 return -1; 05202 } 05203 05204 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 05205 ao2_lock(q); 05206 count = q->count; 05207 ao2_unlock(q); 05208 queue_unref(q); 05209 } else if ((var = ast_load_realtime("queues", "name", data, NULL))) { 05210 /* if the queue is realtime but was not found in memory, this 05211 * means that the queue had been deleted from memory since it was 05212 * "dead." This means it has a 0 waiting count 05213 */ 05214 count = 0; 05215 ast_variables_destroy(var); 05216 } else 05217 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05218 05219 snprintf(buf, len, "%d", count); 05220 05221 return 0; 05222 }
| 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 5047 of file app_queue.c.
References ao2_find(), ao2_lock(), ao2_unlock(), ast_log(), ast_strlen_zero(), call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::count, call_queue::holdtime, int2strat(), LOG_ERROR, LOG_WARNING, call_queue::maxlen, OBJ_POINTER, pbx_builtin_setvar_multiple(), queue_unref(), queues, call_queue::servicelevel, call_queue::setqueuevar, and call_queue::strategy.
05048 { 05049 int res = -1; 05050 struct call_queue *q, tmpq = { 05051 .name = data, 05052 }; 05053 05054 char interfacevar[256]=""; 05055 float sl = 0; 05056 05057 if (ast_strlen_zero(data)) { 05058 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 05059 return -1; 05060 } 05061 05062 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 05063 ao2_lock(q); 05064 if (q->setqueuevar) { 05065 sl = 0; 05066 res = 0; 05067 05068 if (q->callscompleted > 0) 05069 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 05070 05071 snprintf(interfacevar, sizeof(interfacevar), 05072 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 05073 q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 05074 05075 pbx_builtin_setvar_multiple(chan, interfacevar); 05076 } 05077 05078 ao2_unlock(q); 05079 queue_unref(q); 05080 } else 05081 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05082 05083 snprintf(buf, len, "%d", res); 05084 05085 return 0; 05086 }
| static int queue_hash_cb | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 569 of file app_queue.c.
References ast_str_case_hash(), and call_queue::name.
Referenced by load_module().
00570 { 00571 const struct call_queue *q = obj; 00572 00573 return ast_str_case_hash(q->name); 00574 }
| static struct call_queue* queue_ref | ( | struct call_queue * | q | ) | [static, read] |
Definition at line 582 of file app_queue.c.
References ao2_ref().
Referenced by leave_queue(), and try_calling().
00583 { 00584 ao2_ref(q, 1); 00585 return q; 00586 }
| 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 1169 of file app_queue.c.
References queue_ent::announce, call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, 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, queue_ent::moh, call_queue::monfmt, call_queue::montype, call_queue::name, call_queue::periodicannouncefrequency, QUEUE_EMPTY_LOOSE, QUEUE_EMPTY_NORMAL, QUEUE_EMPTY_STRICT, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RINGALL, 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, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_queues().
01170 { 01171 if (!strcasecmp(param, "musicclass") || 01172 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 01173 ast_string_field_set(q, moh, val); 01174 } else if (!strcasecmp(param, "announce")) { 01175 ast_string_field_set(q, announce, val); 01176 } else if (!strcasecmp(param, "context")) { 01177 ast_string_field_set(q, context, val); 01178 } else if (!strcasecmp(param, "timeout")) { 01179 q->timeout = atoi(val); 01180 if (q->timeout < 0) 01181 q->timeout = DEFAULT_TIMEOUT; 01182 } else if (!strcasecmp(param, "ringinuse")) { 01183 q->ringinuse = ast_true(val); 01184 } else if (!strcasecmp(param, "setinterfacevar")) { 01185 q->setinterfacevar = ast_true(val); 01186 } else if (!strcasecmp(param, "setqueuevar")) { 01187 q->setqueuevar = ast_true(val); 01188 } else if (!strcasecmp(param, "setqueueentryvar")) { 01189 q->setqueueentryvar = ast_true(val); 01190 } else if (!strcasecmp(param, "monitor-format")) { 01191 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 01192 } else if (!strcasecmp(param, "membermacro")) { 01193 ast_string_field_set(q, membermacro, val); 01194 } else if (!strcasecmp(param, "membergosub")) { 01195 ast_string_field_set(q, membergosub, val); 01196 } else if (!strcasecmp(param, "queue-youarenext")) { 01197 ast_string_field_set(q, sound_next, val); 01198 } else if (!strcasecmp(param, "queue-thereare")) { 01199 ast_string_field_set(q, sound_thereare, val); 01200 } else if (!strcasecmp(param, "queue-callswaiting")) { 01201 ast_string_field_set(q, sound_calls, val); 01202 } else if (!strcasecmp(param, "queue-holdtime")) { 01203 ast_string_field_set(q, sound_holdtime, val); 01204 } else if (!strcasecmp(param, "queue-minutes")) { 01205 ast_string_field_set(q, sound_minutes, val); 01206 } else if (!strcasecmp(param, "queue-minute")) { 01207 ast_string_field_set(q, sound_minute, val); 01208 } else if (!strcasecmp(param, "queue-seconds")) { 01209 ast_string_field_set(q, sound_seconds, val); 01210 } else if (!strcasecmp(param, "queue-thankyou")) { 01211 ast_string_field_set(q, sound_thanks, val); 01212 } else if (!strcasecmp(param, "queue-callerannounce")) { 01213 ast_string_field_set(q, sound_callerannounce, val); 01214 } else if (!strcasecmp(param, "queue-reporthold")) { 01215 ast_string_field_set(q, sound_reporthold, val); 01216 } else if (!strcasecmp(param, "announce-frequency")) { 01217 q->announcefrequency = atoi(val); 01218 } else if (!strcasecmp(param, "min-announce-frequency")) { 01219 q->minannouncefrequency = atoi(val); 01220 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name); 01221 } else if (!strcasecmp(param, "announce-round-seconds")) { 01222 q->roundingseconds = atoi(val); 01223 /* Rounding to any other values just doesn't make sense... */ 01224 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10 01225 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) { 01226 if (linenum >= 0) { 01227 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01228 "using 0 instead for queue '%s' at line %d of queues.conf\n", 01229 val, param, q->name, linenum); 01230 } else { 01231 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01232 "using 0 instead for queue '%s'\n", val, param, q->name); 01233 } 01234 q->roundingseconds=0; 01235 } 01236 } else if (!strcasecmp(param, "announce-holdtime")) { 01237 if (!strcasecmp(val, "once")) 01238 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 01239 else if (ast_true(val)) 01240 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 01241 else 01242 q->announceholdtime = 0; 01243 } else if (!strcasecmp(param, "announce-position")) { 01244 q->announceposition = ast_true(val); 01245 } else if (!strcasecmp(param, "periodic-announce")) { 01246 if (strchr(val, ',')) { 01247 char *s, *buf = ast_strdupa(val); 01248 unsigned int i = 0; 01249 01250 while ((s = strsep(&buf, ",|"))) { 01251 if (!q->sound_periodicannounce[i]) 01252 q->sound_periodicannounce[i] = ast_str_create(16); 01253 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s); 01254 i++; 01255 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 01256 break; 01257 } 01258 } else { 01259 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val); 01260 } 01261 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 01262 q->periodicannouncefrequency = atoi(val); 01263 } else if (!strcasecmp(param, "retry")) { 01264 q->retry = atoi(val); 01265 if (q->retry <= 0) 01266 q->retry = DEFAULT_RETRY; 01267 } else if (!strcasecmp(param, "wrapuptime")) { 01268 q->wrapuptime = atoi(val); 01269 } else if (!strcasecmp(param, "autofill")) { 01270 q->autofill = ast_true(val); 01271 } else if (!strcasecmp(param, "monitor-type")) { 01272 if (!strcasecmp(val, "mixmonitor")) 01273 q->montype = 1; 01274 } else if (!strcasecmp(param, "autopause")) { 01275 q->autopause = ast_true(val); 01276 } else if (!strcasecmp(param, "maxlen")) { 01277 q->maxlen = atoi(val); 01278 if (q->maxlen < 0) 01279 q->maxlen = 0; 01280 } else if (!strcasecmp(param, "servicelevel")) { 01281 q->servicelevel= atoi(val); 01282 } else if (!strcasecmp(param, "strategy")) { 01283 int strategy; 01284 01285 /* We are a static queue and already have set this, no need to do it again */ 01286 if (failunknown) { 01287 return; 01288 } 01289 strategy = strat2int(val); 01290 if (strategy < 0) { 01291 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 01292 val, q->name); 01293 q->strategy = QUEUE_STRATEGY_RINGALL; 01294 } 01295 if (strategy == q->strategy) { 01296 return; 01297 } 01298 if (strategy == QUEUE_STRATEGY_LINEAR) { 01299 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n"); 01300 return; 01301 } 01302 q->strategy = strategy; 01303 } else if (!strcasecmp(param, "joinempty")) { 01304 if (!strcasecmp(val, "loose")) 01305 q->joinempty = QUEUE_EMPTY_LOOSE; 01306 else if (!strcasecmp(val, "strict")) 01307 q->joinempty = QUEUE_EMPTY_STRICT; 01308 else if (ast_true(val)) 01309 q->joinempty = QUEUE_EMPTY_NORMAL; 01310 else 01311 q->joinempty = 0; 01312 } else if (!strcasecmp(param, "leavewhenempty")) { 01313 if (!strcasecmp(val, "loose")) 01314 q->leavewhenempty = QUEUE_EMPTY_LOOSE; 01315 else if (!strcasecmp(val, "strict")) 01316 q->leavewhenempty = QUEUE_EMPTY_STRICT; 01317 else if (ast_true(val)) 01318 q->leavewhenempty = QUEUE_EMPTY_NORMAL; 01319 else 01320 q->leavewhenempty = 0; 01321 } else if (!strcasecmp(param, "eventmemberstatus")) { 01322 q->maskmemberstatus = !ast_true(val); 01323 } else if (!strcasecmp(param, "eventwhencalled")) { 01324 if (!strcasecmp(val, "vars")) { 01325 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 01326 } else { 01327 q->eventwhencalled = ast_true(val) ? 1 : 0; 01328 } 01329 } else if (!strcasecmp(param, "reportholdtime")) { 01330 q->reportholdtime = ast_true(val); 01331 } else if (!strcasecmp(param, "memberdelay")) { 01332 q->memberdelay = atoi(val); 01333 } else if (!strcasecmp(param, "weight")) { 01334 q->weight = atoi(val); 01335 if (q->weight) 01336 use_weight++; 01337 /* With Realtime queues, if the last queue using weights is deleted in realtime, 01338 we will not see any effect on use_weight until next reload. */ 01339 } else if (!strcasecmp(param, "timeoutrestart")) { 01340 q->timeoutrestart = ast_true(val); 01341 } else if (!strcasecmp(param, "defaultrule")) { 01342 ast_string_field_set(q, defaultrule, val); 01343 } else if (failunknown) { 01344 if (linenum >= 0) { 01345 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 01346 q->name, param, linenum); 01347 } else { 01348 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 01349 } 01350 } 01351 }
| static char* queue_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 5853 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.
05854 { 05855 switch ( cmd ) { 05856 case CLI_INIT: 05857 e->command = "queue show"; 05858 e->usage = 05859 "Usage: queue show\n" 05860 " Provides summary information on a specified queue.\n"; 05861 return NULL; 05862 case CLI_GENERATE: 05863 return complete_queue_show(a->line, a->word, a->pos, a->n); 05864 } 05865 05866 return __queues_show(NULL, a->fd, a->argc, a->argv); 05867 }
| static void queue_transfer_destroy | ( | void * | data | ) | [static] |
Definition at line 3165 of file app_queue.c.
References ast_free.
03166 { 03167 struct queue_transfer_ds *qtds = data; 03168 ast_free(qtds); 03169 }
| 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 3188 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::parent, queue_transfer_ds::qe, queue_transfer_info, queue_ent::start, queue_transfer_ds::starttime, ast_channel::uniqueid, and update_queue().
03189 { 03190 struct queue_transfer_ds *qtds = data; 03191 struct queue_ent *qe = qtds->qe; 03192 struct member *member = qtds->member; 03193 time_t callstart = qtds->starttime; 03194 int callcompletedinsl = qtds->callcompletedinsl; 03195 struct ast_datastore *datastore; 03196 03197 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld", 03198 new_chan->exten, new_chan->context, (long) (callstart - qe->start), 03199 (long) (time(NULL) - callstart)); 03200 03201 update_queue(qe->parent, member, callcompletedinsl); 03202 03203 /* No need to lock the channels because they are already locked in ast_do_masquerade */ 03204 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) { 03205 ast_channel_datastore_remove(old_chan, datastore); 03206 } else { 03207 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n"); 03208 } 03209 }
| static struct call_queue* queue_unref | ( | struct call_queue * | q | ) | [static, read] |
Definition at line 588 of file app_queue.c.
References ao2_ref().
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().
00589 { 00590 ao2_ref(q, -1); 00591 return q; 00592 }
| static void recalc_holdtime | ( | struct queue_ent * | qe, | |
| int | newholdtime | |||
| ) | [static] |
Definition at line 1970 of file app_queue.c.
References ao2_lock(), ao2_unlock(), call_queue::holdtime, and queue_ent::parent.
Referenced by try_calling().
01971 { 01972 int oldvalue; 01973 01974 /* Calculate holdtime using an exponential average */ 01975 /* Thanks to SRT for this contribution */ 01976 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 01977 01978 ao2_lock(qe->parent); 01979 oldvalue = qe->parent->holdtime; 01980 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 01981 ao2_unlock(qe->parent); 01982 }
| static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Record that a caller gave up on waiting in queue.
Definition at line 2519 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(), and try_calling().
02520 { 02521 ao2_lock(qe->parent); 02522 set_queue_variables(qe->parent, qe->chan); 02523 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 02524 "Queue: %s\r\n" 02525 "Uniqueid: %s\r\n" 02526 "Position: %d\r\n" 02527 "OriginalPosition: %d\r\n" 02528 "HoldTime: %d\r\n", 02529 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 02530 02531 qe->parent->callsabandoned++; 02532 ao2_unlock(qe->parent); 02533 }
| static int reload | ( | void | ) | [static] |
Definition at line 6757 of file app_queue.c.
References reload_queues().
06758 { 06759 reload_queues(1); 06760 return 0; 06761 }
| static void reload_queue_members | ( | void | ) | [static] |
Reload dynamic queue members persisted into the astdb.
Definition at line 4376 of file app_queue.c.
References add_to_queue(), ao2_find(), ao2_lock(), ao2_unlock(), ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), ast_debug, ast_log(), ast_strlen_zero(), ERANGE, errno, member::interface, ast_db_entry::key, load_realtime_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, member::membername, call_queue::name, ast_db_entry::next, OBJ_POINTER, member::paused, member::penalty, PM_MAX_LEN, queue_unref(), queues, RES_OUTOFMEMORY, member::state_interface, and strsep().
Referenced by load_module().
04377 { 04378 char *cur_ptr; 04379 const char *queue_name; 04380 char *member; 04381 char *interface; 04382 char *membername = NULL; 04383 char *state_interface; 04384 char *penalty_tok; 04385 int penalty = 0; 04386 char *paused_tok; 04387 int paused = 0; 04388 struct ast_db_entry *db_tree; 04389 struct ast_db_entry *entry; 04390 struct call_queue *cur_queue; 04391 char queue_data[PM_MAX_LEN]; 04392 04393 ao2_lock(queues); 04394 04395 /* Each key in 'pm_family' is the name of a queue */ 04396 db_tree = ast_db_gettree(pm_family, NULL); 04397 for (entry = db_tree; entry; entry = entry->next) { 04398 04399 queue_name = entry->key + strlen(pm_family) + 2; 04400 04401 { 04402 struct call_queue tmpq = { 04403 .name = queue_name, 04404 }; 04405 cur_queue = ao2_find(queues, &tmpq, OBJ_POINTER); 04406 } 04407 04408 if (!cur_queue) 04409 cur_queue = load_realtime_queue(queue_name); 04410 04411 if (!cur_queue) { 04412 /* If the queue no longer exists, remove it from the 04413 * database */ 04414 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 04415 ast_db_del(pm_family, queue_name); 04416 continue; 04417 } 04418 04419 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) { 04420 queue_unref(cur_queue); 04421 continue; 04422 } 04423 04424 cur_ptr = queue_data; 04425 while ((member = strsep(&cur_ptr, ",|"))) { 04426 if (ast_strlen_zero(member)) 04427 continue; 04428 04429 interface = strsep(&member, ";"); 04430 penalty_tok = strsep(&member, ";"); 04431 paused_tok = strsep(&member, ";"); 04432 membername = strsep(&member, ";"); 04433 state_interface = strsep(&member, ";"); 04434 04435 if (!penalty_tok) { 04436 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 04437 break; 04438 } 04439 penalty = strtol(penalty_tok, NULL, 10); 04440 if (errno == ERANGE) { 04441 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 04442 break; 04443 } 04444 04445 if (!paused_tok) { 04446 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 04447 break; 04448 } 04449 paused = strtol(paused_tok, NULL, 10); 04450 if ((errno == ERANGE) || paused < 0 || paused > 1) { 04451 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 04452 break; 04453 } 04454 04455 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 04456 04457 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { 04458 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 04459 break; 04460 } 04461 } 04462 queue_unref(cur_queue); 04463 } 04464 04465 ao2_unlock(queues); 04466 if (db_tree) { 04467 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 04468 ast_db_freetree(db_tree); 04469 } 04470 }
| static int reload_queue_rules | ( | int | reload | ) | [static] |
Definition at line 5410 of file app_queue.c.
References ast_calloc, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, insert_penaltychange(), ast_variable::lineno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_variable::name, rule_list::name, ast_variable::next, rule_list::rules, and ast_variable::value.
Referenced by handle_queue_rule_reload(), and reload_queues().
05411 { 05412 struct ast_config *cfg; 05413 struct rule_list *rl_iter, *new_rl; 05414 struct penalty_rule *pr_iter; 05415 char *rulecat = NULL; 05416 struct ast_variable *rulevar = NULL; 05417 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 05418 05419 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) { 05420 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n"); 05421 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 05422 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n"); 05423 return AST_MODULE_LOAD_SUCCESS; 05424 } else { 05425 AST_LIST_LOCK(&rule_lists); 05426 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) { 05427 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list))) 05428 ast_free(pr_iter); 05429 ast_free(rl_iter); 05430 } 05431 while ((rulecat = ast_category_browse(cfg, rulecat))) { 05432 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) { 05433 ast_log(LOG_ERROR, "Memory allocation error while loading queuerules.conf! Aborting!\n"); 05434 AST_LIST_UNLOCK(&rule_lists); 05435 return AST_MODULE_LOAD_FAILURE; 05436 } else { 05437 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name)); 05438 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list); 05439 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next) 05440 if(!strcasecmp(rulevar->name, "penaltychange")) { 05441 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno); 05442 } else { 05443 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno); 05444 } 05445 } 05446 } 05447 AST_LIST_UNLOCK(&rule_lists); 05448 } 05449 05450 ast_config_destroy(cfg); 05451 05452 return AST_MODULE_LOAD_SUCCESS; 05453 }
| static int reload_queues | ( | int | reload | ) | [static] |
Definition at line 5456 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_unlink(), ao2_unlock(), AST_APP_ARG, ast_category_browse(), ast_config_destroy(), 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_STATUS_FILEUNCHANGED, create_queue_member(), call_queue::dead, member::delme, member::dynamic, call_queue::found, init_queue(), member::interface, ast_variable::lineno, LOG_NOTICE, LOG_WARNING, call_queue::membercount, call_queue::members, ast_variable::name, call_queue::name, ast_variable::next, OBJ_POINTER, OBJ_UNLINK, parse(), member::paused, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_unref(), queues, call_queue::realtime, reload_queue_rules(), remove_from_interfaces(), member::state_interface, member::status, strat2int(), call_queue::strategy, ast_variable::value, and var.
Referenced by load_module(), and reload().
05457 { 05458 struct call_queue *q; 05459 struct ast_config *cfg; 05460 char *cat, *tmp; 05461 struct ast_variable *var; 05462 struct member *cur, *newm; 05463 struct ao2_iterator mem_iter; 05464 int new; 05465 const char *general_val = NULL; 05466 char *parse; 05467 char *interface, *state_interface; 05468 char *membername = NULL; 05469 int penalty; 05470 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 05471 struct ao2_iterator queue_iter; 05472 AST_DECLARE_APP_ARGS(args, 05473 AST_APP_ARG(interface); 05474 AST_APP_ARG(penalty); 05475 AST_APP_ARG(membername); 05476 AST_APP_ARG(state_interface); 05477 ); 05478 05479 /*First things first. Let's load queuerules.conf*/ 05480 if (reload_queue_rules(reload) == AST_MODULE_LOAD_FAILURE) 05481 return AST_MODULE_LOAD_FAILURE; 05482 05483 if (!(cfg = ast_config_load("queues.conf", config_flags))) { 05484 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 05485 return 0; 05486 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 05487 return 0; 05488 ao2_lock(queues); 05489 use_weight=0; 05490 /* Mark all queues as dead for the moment */ 05491 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); 05492 while ((q = ao2_iterator_next(&queue_iter))) { 05493 if (!q->realtime) { 05494 q->dead = 1; 05495 q->found = 0; 05496 } 05497 queue_unref(q); 05498 } 05499 05500 /* Chug through config file */ 05501 cat = NULL; 05502 while ((cat = ast_category_browse(cfg, cat)) ) { 05503 if (!strcasecmp(cat, "general")) { 05504 /* Initialize global settings */ 05505 queue_keep_stats = 0; 05506 if ((general_val = ast_variable_retrieve(cfg, "general", "keepstats"))) 05507 queue_keep_stats = ast_true(general_val); 05508 queue_persistent_members = 0; 05509 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 05510 queue_persistent_members = ast_true(general_val); 05511 autofill_default = 0; 05512 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 05513 autofill_default = ast_true(general_val); 05514 montype_default = 0; 05515 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) { 05516 if (!strcasecmp(general_val, "mixmonitor")) 05517 montype_default = 1; 05518 } 05519 update_cdr = 0; 05520 if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr"))) 05521 update_cdr = ast_true(general_val); 05522 shared_lastcall = 0; 05523 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) 05524 shared_lastcall = ast_true(general_val); 05525 } else { /* Define queue */ 05526 /* Look for an existing one */ 05527 struct call_queue tmpq = { 05528 .name = cat, 05529 }; 05530 if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 05531 /* Make one then */ 05532 if (!(q = alloc_queue(cat))) { 05533 /* TODO: Handle memory allocation failure */ 05534 } 05535 new = 1; 05536 } else 05537 new = 0; 05538 if (q) { 05539 const char *tmpvar = NULL; 05540 if (!new) 05541 ao2_lock(q); 05542 /* Check if a queue with this name already exists */ 05543 if (q->found) { 05544 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat); 05545 if (!new) { 05546 ao2_unlock(q); 05547 queue_unref(q); 05548 } 05549 continue; 05550 } 05551 /* Due to the fact that the "linear" strategy will have a different allocation 05552 * scheme for queue members, we must devise the queue's strategy before other initializations 05553 */ 05554 if ((tmpvar = ast_variable_retrieve(cfg, cat, "strategy"))) { 05555 q->strategy = strat2int(tmpvar); 05556 if (q->strategy < 0) { 05557 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 05558 tmpvar, q->name); 05559 q->strategy = QUEUE_STRATEGY_RINGALL; 05560 } 05561 } else 05562 q->strategy = QUEUE_STRATEGY_RINGALL; 05563 /* Re-initialize the queue, and clear statistics */ 05564 init_queue(q); 05565 if (!queue_keep_stats) 05566 clear_queue(q); 05567 mem_iter = ao2_iterator_init(q->members, 0); 05568 while ((cur = ao2_iterator_next(&mem_iter))) { 05569 if (!cur->dynamic) { 05570 cur->delme = 1; 05571 } 05572 ao2_ref(cur, -1); 05573 } 05574 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 05575 if (!strcasecmp(var->name, "member")) { 05576 struct member tmpmem; 05577 membername = NULL; 05578 05579 if (ast_strlen_zero(var->value)) { 05580 ast_log(LOG_WARNING, "Empty queue member definition at line %d. Moving on!\n", var->lineno); 05581 continue; 05582 } 05583 05584 /* Add a new member */ 05585 if (!(parse = ast_strdup(var->value))) { 05586 continue; 05587 } 05588 05589 AST_STANDARD_APP_ARGS(args, parse); 05590 05591 interface = args.interface; 05592 if (!ast_strlen_zero(args.penalty)) { 05593 tmp = args.penalty; 05594 while (*tmp && *tmp < 33) tmp++; 05595 penalty = atoi(tmp); 05596 if (penalty < 0) { 05597 penalty = 0; 05598 } 05599 } else 05600 penalty = 0; 05601 05602 if (!ast_strlen_zero(args.membername)) { 05603 membername = args.membername; 05604 while (*membername && *membername < 33) membername++; 05605 } 05606 05607 if (!ast_strlen_zero(args.state_interface)) { 05608 state_interface = args.state_interface; 05609 while (*state_interface && *state_interface < 33) state_interface++; 05610 } else 05611 state_interface = interface; 05612 05613 /* Find the old position in the list */ 05614 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 05615 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); 05616 /* Only attempt removing from interfaces list if the new state_interface is different than the old one */ 05617 if (cur && strcasecmp(cur->state_interface, state_interface)) { 05618 remove_from_interfaces(cur->state_interface, 0); 05619 } 05620 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface); 05621 if (!cur || (cur && strcasecmp(cur->state_interface, state_interface))) 05622 add_to_interfaces(state_interface); 05623 ao2_link(q->members, newm); 05624 ao2_ref(newm, -1); 05625 newm = NULL; 05626 05627 if (cur) 05628 ao2_ref(cur, -1); 05629 else { 05630 q->membercount++; 05631 } 05632 ast_free(parse); 05633 } else { 05634 queue_set_param(q, var->name, var->value, var->lineno, 1); 05635 } 05636 } 05637 05638 /* Free remaining members marked as delme */ 05639 mem_iter = ao2_iterator_init(q->members, 0); 05640 while ((cur = ao2_iterator_next(&mem_iter))) { 05641 if (! cur->delme) { 05642 ao2_ref(cur, -1); 05643 continue; 05644 } 05645 q->membercount--; 05646 ao2_unlink(q->members, cur); 05647 remove_from_interfaces(cur->interface, 0); 05648 ao2_ref(cur, -1); 05649 } 05650 05651 if (new) { 05652 ao2_link(queues, q); 05653 } else 05654 ao2_unlock(q); 05655 queue_unref(q); 05656 } 05657 } 05658 } 05659 ast_config_destroy(cfg); 05660 queue_iter = ao2_iterator_init(queues, 0); 05661 while ((q = ao2_iterator_next(&queue_iter))) { 05662 if (q->dead) { 05663 ao2_unlink(queues, q); 05664 } else { 05665 ao2_lock(q); 05666 mem_iter = ao2_iterator_init(q->members, 0); 05667 while ((cur = ao2_iterator_next(&mem_iter))) { 05668 if (cur->dynamic) 05669 q->membercount++; 05670 cur->status = ast_device_state(cur->state_interface); 05671 ao2_ref(cur, -1); 05672 } 05673 ao2_unlock(q); 05674 } 05675 queue_unref(q); 05676 } 05677 ao2_unlock(queues); 05678 return 1; 05679 }
| static int remove_from_interfaces | ( | const char * | interface, | |
| int | lock_queue_container | |||
| ) | [static] |
Definition at line 1049 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, and interface_exists_global().
Referenced by find_queue_by_name_rt(), free_members(), reload_queues(), remove_from_queue(), rt_handle_member_record(), and update_realtime_members().
01050 { 01051 struct member_interface *curint; 01052 01053 if (interface_exists_global(interface, lock_queue_container)) 01054 return 0; 01055 01056 AST_LIST_LOCK(&interfaces); 01057 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) { 01058 if (!strcasecmp(curint->interface, interface)) { 01059 ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface); 01060 AST_LIST_REMOVE_CURRENT(list); 01061 ast_free(curint); 01062 break; 01063 } 01064 } 01065 AST_LIST_TRAVERSE_SAFE_END; 01066 AST_LIST_UNLOCK(&interfaces); 01067 01068 return 0; 01069 }
| 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 4117 of file app_queue.c.
References ao2_find(), ao2_lock(), ao2_ref(), 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_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().
04118 { 04119 struct call_queue *q, tmpq = { 04120 .name = queuename, 04121 }; 04122 struct member *mem, tmpmem; 04123 int res = RES_NOSUCHQUEUE; 04124 04125 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 04126 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 04127 ao2_lock(queues); 04128 ao2_lock(q); 04129 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 04130 /* XXX future changes should beware of this assumption!! */ 04131 if (!mem->dynamic) { 04132 ao2_ref(mem, -1); 04133 ao2_unlock(q); 04134 queue_unref(q); 04135 ao2_unlock(queues); 04136 return RES_NOT_DYNAMIC; 04137 } 04138 q->membercount--; 04139 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 04140 "Queue: %s\r\n" 04141 "Location: %s\r\n" 04142 "MemberName: %s\r\n", 04143 q->name, mem->interface, mem->membername); 04144 ao2_unlink(q->members, mem); 04145 remove_from_interfaces(mem->state_interface, 0); 04146 ao2_ref(mem, -1); 04147 04148 if (queue_persistent_members) 04149 dump_queue_members(q); 04150 04151 res = RES_OKAY; 04152 } else { 04153 res = RES_EXISTS; 04154 } 04155 ao2_unlock(q); 04156 ao2_unlock(queues); 04157 queue_unref(q); 04158 } 04159 04160 return res; 04161 }
| 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 2209 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_UNKNOWN, ast_free, ast_request(), ast_strdup, 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, ast_channel::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().
02210 { 02211 int res; 02212 int status; 02213 char tech[256]; 02214 char *location; 02215 const char *macrocontext, *macroexten; 02216 02217 /* on entry here, we know that tmp->chan == NULL */ 02218 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) || 02219 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) { 02220 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 02221 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface); 02222 if (qe->chan->cdr) 02223 ast_cdr_busy(qe->chan->cdr); 02224 tmp->stillgoing = 0; 02225 (*busies)++; 02226 return 0; 02227 } 02228 02229 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 02230 ast_debug(1, "%s in use, can't receive call\n", tmp->interface); 02231 if (qe->chan->cdr) 02232 ast_cdr_busy(qe->chan->cdr); 02233 tmp->stillgoing = 0; 02234 return 0; 02235 } 02236 02237 if (tmp->member->paused) { 02238 ast_debug(1, "%s paused, can't receive call\n", tmp->interface); 02239 if (qe->chan->cdr) 02240 ast_cdr_busy(qe->chan->cdr); 02241 tmp->stillgoing = 0; 02242 return 0; 02243 } 02244 if (use_weight && compare_weight(qe->parent,tmp->member)) { 02245 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 02246 if (qe->chan->cdr) 02247 ast_cdr_busy(qe->chan->cdr); 02248 tmp->stillgoing = 0; 02249 (*busies)++; 02250 return 0; 02251 } 02252 02253 ast_copy_string(tech, tmp->interface, sizeof(tech)); 02254 if ((location = strchr(tech, '/'))) 02255 *location++ = '\0'; 02256 else 02257 location = ""; 02258 02259 /* Request the peer */ 02260 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status); 02261 if (!tmp->chan) { /* If we can't, just go on to the next call */ 02262 if (qe->chan->cdr) 02263 ast_cdr_busy(qe->chan->cdr); 02264 tmp->stillgoing = 0; 02265 02266 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02267 02268 ao2_lock(qe->parent); 02269 qe->parent->rrpos++; 02270 qe->linpos++; 02271 ao2_unlock(qe->parent); 02272 02273 02274 (*busies)++; 02275 return 0; 02276 } 02277 02278 tmp->chan->appl = "AppQueue"; 02279 tmp->chan->data = "(Outgoing Line)"; 02280 tmp->chan->whentohangup = 0; 02281 if (tmp->chan->cid.cid_num) 02282 ast_free(tmp->chan->cid.cid_num); 02283 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num); 02284 if (tmp->chan->cid.cid_name) 02285 ast_free(tmp->chan->cid.cid_name); 02286 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name); 02287 if (tmp->chan->cid.cid_ani) 02288 ast_free(tmp->chan->cid.cid_ani); 02289 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani); 02290 02291 /* Inherit specially named variables from parent channel */ 02292 ast_channel_inherit_variables(qe->chan, tmp->chan); 02293 ast_channel_datastore_inherit(qe->chan, tmp->chan); 02294 02295 /* Presense of ADSI CPE on outgoing channel follows ours */ 02296 tmp->chan->adsicpe = qe->chan->adsicpe; 02297 02298 /* Inherit context and extension */ 02299 ast_channel_lock(qe->chan); 02300 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 02301 if (!ast_strlen_zero(macrocontext)) 02302 ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext)); 02303 else 02304 ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext)); 02305 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 02306 if (!ast_strlen_zero(macroexten)) 02307 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 02308 else 02309 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 02310 if (ast_cdr_isset_unanswered()) { 02311 /* they want to see the unanswered dial attempts! */ 02312 /* set up the CDR fields on all the CDRs to give sensical information */ 02313 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name); 02314 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid); 02315 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel); 02316 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src); 02317 strcpy(tmp->chan->cdr->dst, qe->chan->exten); 02318 strcpy(tmp->chan->cdr->dcontext, qe->chan->context); 02319 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp); 02320 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata); 02321 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags; 02322 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode); 02323 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); 02324 } 02325 ast_channel_unlock(qe->chan); 02326 02327 /* Place the call, but don't wait on the answer */ 02328 if ((res = ast_call(tmp->chan, location, 0))) { 02329 /* Again, keep going even if there's an error */ 02330 ast_debug(1, "ast call on peer returned %d\n", res); 02331 ast_verb(3, "Couldn't call %s\n", tmp->interface); 02332 do_hang(tmp); 02333 (*busies)++; 02334 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02335 return 0; 02336 } else if (qe->parent->eventwhencalled) { 02337 char vars[2048]; 02338 02339 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 02340 "Queue: %s\r\n" 02341 "AgentCalled: %s\r\n" 02342 "AgentName: %s\r\n" 02343 "ChannelCalling: %s\r\n" 02344 "DestinationChannel: %s\r\n" 02345 "CallerIDNum: %s\r\n" 02346 "CallerIDName: %s\r\n" 02347 "Context: %s\r\n" 02348 "Extension: %s\r\n" 02349 "Priority: %d\r\n" 02350 "Uniqueid: %s\r\n" 02351 "%s", 02352 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name, 02353 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown", 02354 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown", 02355 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid, 02356 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02357 ast_verb(3, "Called %s\n", tmp->interface); 02358 } 02359 02360 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02361 return 1; 02362 }
| 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 2390 of file app_queue.c.
References ast_debug, callattempt::chan, 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().
02391 { 02392 int ret = 0; 02393 02394 while (ret == 0) { 02395 struct callattempt *best = find_best(outgoing); 02396 if (!best) { 02397 ast_debug(1, "Nobody left to try ringing in queue\n"); 02398 break; 02399 } 02400 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 02401 struct callattempt *cur; 02402 /* Ring everyone who shares this best metric (for ringall) */ 02403 for (cur = outgoing; cur; cur = cur->q_next) { 02404 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 02405 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 02406 ret |= ring_entry(qe, cur, busies); 02407 } 02408 } 02409 } else { 02410 /* Ring just the best channel */ 02411 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric); 02412 ret = ring_entry(qe, best, busies); 02413 } 02414 } 02415 02416 return ret; 02417 }
| 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 2536 of file app_queue.c.
References ast_queue_log(), ast_verb, call_queue::autopause, queue_ent::chan, call_queue::name, queue_ent::parent, set_member_paused(), and ast_channel::uniqueid.
Referenced by wait_for_answer().
02537 { 02538 ast_verb(3, "Nobody picked up in %d ms\n", rnatime); 02539 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 02540 if (qe->parent->autopause && pause) { 02541 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) { 02542 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name); 02543 } else { 02544 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 02545 } 02546 } 02547 return; 02548 }
| static int rqm_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
RemoveQueueMember application.
Definition at line 4545 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(), 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().
04546 { 04547 int res=-1; 04548 char *parse, *temppos = NULL; 04549 AST_DECLARE_APP_ARGS(args, 04550 AST_APP_ARG(queuename); 04551 AST_APP_ARG(interface); 04552 AST_APP_ARG(options); 04553 ); 04554 04555 04556 if (ast_strlen_zero(data)) { 04557 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n"); 04558 return -1; 04559 } 04560 04561 parse = ast_strdupa(data); 04562 04563 AST_STANDARD_APP_ARGS(args, parse); 04564 04565 if (ast_strlen_zero(args.interface)) { 04566 args.interface = ast_strdupa(chan->name); 04567 temppos = strrchr(args.interface, '-'); 04568 if (temppos) 04569 *temppos = '\0'; 04570 } 04571 04572 switch (remove_from_queue(args.queuename, args.interface)) { 04573 case RES_OKAY: 04574 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 04575 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 04576 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 04577 res = 0; 04578 break; 04579 case RES_EXISTS: 04580 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 04581 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 04582 res = 0; 04583 break; 04584 case RES_NOSUCHQUEUE: 04585 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 04586 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 04587 res = 0; 04588 break; 04589 case RES_NOT_DYNAMIC: 04590 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 04591 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 04592 res = 0; 04593 break; 04594 } 04595 04596 return res; 04597 }
| static void rt_handle_member_record | ( | struct call_queue * | q, | |
| char * | interface, | |||
| 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 memeber exists create one flag it as a RT member and add to queue member list.
Definition at line 1359 of file app_queue.c.
References add_to_interfaces(), ao2_find(), ao2_link(), ao2_ref(), ast_copy_string(), create_queue_member(), member::dead, member::interface, call_queue::membercount, call_queue::members, OBJ_POINTER, member::paused, member::penalty, member::realtime, remove_from_interfaces(), and member::state_interface.
Referenced by find_queue_by_name_rt(), and update_realtime_members().
01360 { 01361 struct member *m, tmpmem; 01362 int penalty = 0; 01363 int paused = 0; 01364 01365 if (penalty_str) { 01366 penalty = atoi(penalty_str); 01367 if (penalty < 0) 01368 penalty = 0; 01369 } 01370 01371 if (paused_str) { 01372 paused = atoi(paused_str); 01373 if (paused < 0) 01374 paused = 0; 01375 } 01376 01377 /* Find the member, or the place to put a new one. */ 01378 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 01379 m = ao2_find(q->members, &tmpmem, OBJ_POINTER); 01380 01381 /* Create a new one if not found, else update penalty */ 01382 if (!m) { 01383 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { 01384 m->dead = 0; 01385 m->realtime = 1; 01386 add_to_interfaces(m->state_interface); 01387 ao2_link(q->members, m); 01388 ao2_ref(m, -1); 01389 m = NULL; 01390 q->membercount++; 01391 } 01392 } else { 01393 m->dead = 0; /* Do not delete this one. */ 01394 if (paused_str) 01395 m->paused = paused; 01396 if (strcasecmp(state_interface, m->state_interface)) { 01397 remove_from_interfaces(m->state_interface, 0); 01398 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); 01399 add_to_interfaces(m->state_interface); 01400 } 01401 m->penalty = penalty; 01402 ao2_ref(m, -1); 01403 } 01404 }
| static int say_periodic_announcement | ( | struct queue_ent * | qe, | |
| int | ringing | |||
| ) | [static] |
Playback announcement to queued members if peroid has elapsed.
Definition at line 2468 of file app_queue.c.
References AST_CONTROL_RINGING, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_verb, queue_ent::chan, queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, MAX_PERIODIC_ANNOUNCEMENTS, queue_ent::moh, queue_ent::parent, call_queue::periodicannouncefrequency, play_file(), call_queue::sound_periodicannounce, ast_str::str, and valid_exit().
Referenced by queue_exec(), and wait_our_turn().
02469 { 02470 int res = 0; 02471 time_t now; 02472 02473 /* Get the current time */ 02474 time(&now); 02475 02476 /* Check to see if it is time to announce */ 02477 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 02478 return 0; 02479 02480 /* Stop the music on hold so we can play our own file */ 02481 if (ringing) 02482 ast_indicate(qe->chan,-1); 02483 else 02484 ast_moh_stop(qe->chan); 02485 02486 ast_verb(3, "Playing periodic announcement\n"); 02487 02488 /* Check to make sure we have a sound file. If not, reset to the first sound file */ 02489 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || 02490 !qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound] || 02491 ast_strlen_zero(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str)) { 02492 qe->last_periodic_announce_sound = 0; 02493 } 02494 02495 /* play the announcement */ 02496 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str); 02497 02498 if (res > 0 && !valid_exit(qe, res)) 02499 res = 0; 02500 02501 /* Resume Music on Hold if the caller is going to stay in the queue */ 02502 if (!res) { 02503 if (ringing) 02504 ast_indicate(qe->chan, AST_CONTROL_RINGING); 02505 else 02506 ast_moh_start(qe->chan, qe->moh, NULL); 02507 } 02508 02509 /* update last_periodic_announce_time */ 02510 qe->last_periodic_announce_time = now; 02511 02512 /* Update the current periodic announcement to the next announcement */ 02513 qe->last_periodic_announce_sound++; 02514 02515 return res; 02516 }
| static int say_position | ( | struct queue_ent * | qe, | |
| int | ringing | |||
| ) | [static] |
Definition at line 1852 of file app_queue.c.
References call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, 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::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().
01853 { 01854 int res = 0, avgholdmins, avgholdsecs; 01855 int say_thanks = 1; 01856 time_t now; 01857 01858 /* Let minannouncefrequency seconds pass between the start of each position announcement */ 01859 time(&now); 01860 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) 01861 return 0; 01862 01863 /* If either our position has changed, or we are over the freq timer, say position */ 01864 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 01865 return 0; 01866 01867 if (ringing) { 01868 ast_indicate(qe->chan,-1); 01869 } else { 01870 ast_moh_stop(qe->chan); 01871 } 01872 if (qe->parent->announceposition) { 01873 /* Say we're next, if we are */ 01874 if (qe->pos == 1) { 01875 res = play_file(qe->chan, qe->parent->sound_next); 01876 if (res) 01877 goto playout; 01878 else 01879 goto posout; 01880 } else { 01881 res = play_file(qe->chan, qe->parent->sound_thereare); 01882 if (res) 01883 goto playout; 01884 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 01885 if (res) 01886 goto playout; 01887 res = play_file(qe->chan, qe->parent->sound_calls); 01888 if (res) 01889 goto playout; 01890 } 01891 } 01892 /* Round hold time to nearest minute */ 01893 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 01894 01895 /* If they have specified a rounding then round the seconds as well */ 01896 if (qe->parent->roundingseconds) { 01897 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 01898 avgholdsecs *= qe->parent->roundingseconds; 01899 } else { 01900 avgholdsecs = 0; 01901 } 01902 01903 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 01904 01905 /* If the hold time is >1 min, if it's enabled, and if it's not 01906 supposed to be only once and we have already said it, say it */ 01907 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime && 01908 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) || 01909 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) { 01910 res = play_file(qe->chan, qe->parent->sound_holdtime); 01911 if (res) 01912 goto playout; 01913 01914 if (avgholdmins >= 1) { 01915 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL); 01916 if (res) 01917 goto playout; 01918 01919 if (avgholdmins == 1) { 01920 res = play_file(qe->chan, qe->parent->sound_minute); 01921 if (res) 01922 goto playout; 01923 } else { 01924 res = play_file(qe->chan, qe->parent->sound_minutes); 01925 if (res) 01926 goto playout; 01927 } 01928 } 01929 if (avgholdsecs >= 1) { 01930 res = ast_say_number(qe->chan, avgholdmins > 1 ? avgholdsecs : avgholdmins * 60 + avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL); 01931 if (res) 01932 goto playout; 01933 01934 res = play_file(qe->chan, qe->parent->sound_seconds); 01935 if (res) 01936 goto playout; 01937 } 01938 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) { 01939 say_thanks = 0; 01940 } 01941 01942 posout: 01943 if (qe->parent->announceposition) { 01944 ast_verb(3, "Told %s in %s their queue position (which was %d)\n", 01945 qe->chan->name, qe->parent->name, qe->pos); 01946 } 01947 if (say_thanks) { 01948 res = play_file(qe->chan, qe->parent->sound_thanks); 01949 } 01950 01951 playout: 01952 01953 if ((res > 0 && !valid_exit(qe, res))) 01954 res = 0; 01955 01956 /* Set our last_pos indicators */ 01957 qe->last_pos = now; 01958 qe->last_pos_said = qe->pos; 01959 01960 /* Don't restart music on hold if we're about to exit the caller from the queue */ 01961 if (!res) { 01962 if (ringing) 01963 ast_indicate(qe->chan, AST_CONTROL_RINGING); 01964 else 01965 ast_moh_start(qe->chan, qe->moh, NULL); 01966 } 01967 return res; 01968 }
| 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 3122 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, TRANSFER, ast_channel::uniqueid, and vars2manager().
Referenced by try_calling().
03125 { 03126 const char *reason = NULL; /* silence dumb compilers */ 03127 03128 if (!qe->parent->eventwhencalled) 03129 return; 03130 03131 switch (rsn) { 03132 case CALLER: 03133 reason = "caller"; 03134 break; 03135 case AGENT: 03136 reason = "agent"; 03137 break; 03138 case TRANSFER: 03139 reason = "transfer"; 03140 break; 03141 } 03142 03143 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03144 "Queue: %s\r\n" 03145 "Uniqueid: %s\r\n" 03146 "Channel: %s\r\n" 03147 "Member: %s\r\n" 03148 "MemberName: %s\r\n" 03149 "HoldTime: %ld\r\n" 03150 "TalkTime: %ld\r\n" 03151 "Reason: %s\r\n" 03152 "%s", 03153 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03154 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason, 03155 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : ""); 03156 }
| static int set_member_paused | ( | const char * | queuename, | |
| const char * | interface, | |||
| const char * | reason, | |||
| int | paused | |||
| ) | [static] |
Definition at line 4225 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), 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_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().
04226 { 04227 int found = 0; 04228 struct call_queue *q; 04229 struct member *mem; 04230 struct ao2_iterator queue_iter; 04231 int failed; 04232 04233 /* Special event for when all queues are paused - individual events still generated */ 04234 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 04235 if (ast_strlen_zero(queuename)) 04236 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 04237 04238 queue_iter = ao2_iterator_init(queues, 0); 04239 while ((q = ao2_iterator_next(&queue_iter))) { 04240 ao2_lock(q); 04241 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 04242 if ((mem = interface_exists(q, interface))) { 04243 found++; 04244 if (mem->paused == paused) { 04245 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 04246 } 04247 04248 failed = 0; 04249 if (mem->realtime) { 04250 failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); 04251 } 04252 04253 if (failed) { 04254 ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface); 04255 ao2_ref(mem, -1); 04256 ao2_unlock(q); 04257 continue; 04258 } 04259 04260 mem->paused = paused; 04261 04262 if (queue_persistent_members) 04263 dump_queue_members(q); 04264 04265 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, "")); 04266 04267 if (!ast_strlen_zero(reason)) { 04268 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 04269 "Queue: %s\r\n" 04270 "Location: %s\r\n" 04271 "MemberName: %s\r\n" 04272 "Paused: %d\r\n" 04273 "Reason: %s\r\n", 04274 q->name, mem->interface, mem->membername, paused, reason); 04275 } else { 04276 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 04277 "Queue: %s\r\n" 04278 "Location: %s\r\n" 04279 "MemberName: %s\r\n" 04280 "Paused: %d\r\n", 04281 q->name, mem->interface, mem->membername, paused); 04282 } 04283 ao2_ref(mem, -1); 04284 } 04285 } 04286 ao2_unlock(q); 04287 queue_unref(q); 04288 } 04289 ao2_iterator_destroy(&queue_iter); 04290 04291 return found ? RESULT_SUCCESS : RESULT_FAILURE; 04292 }
| static int set_member_penalty | ( | char * | queuename, | |
| char * | interface, | |||
| int | penalty | |||
| ) | [static] |
Definition at line 4295 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), 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_unref(), queues, RESULT_FAILURE, and RESULT_SUCCESS.
Referenced by handle_queue_set_member_penalty(), manager_queue_member_penalty(), and queue_function_memberpenalty_write().
04296 { 04297 int foundinterface = 0, foundqueue = 0; 04298 struct call_queue *q; 04299 struct member *mem; 04300 struct ao2_iterator queue_iter; 04301 04302 if (penalty < 0) { 04303 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty); 04304 return RESULT_FAILURE; 04305 } 04306 04307 queue_iter = ao2_iterator_init(queues, 0); 04308 while ((q = ao2_iterator_next(&queue_iter))) { 04309 ao2_lock(q); 04310 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 04311 foundqueue++; 04312 if ((mem = interface_exists(q, interface))) { 04313 foundinterface++; 04314 mem->penalty = penalty; 04315 04316 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty); 04317 manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty", 04318 "Queue: %s\r\n" 04319 "Location: %s\r\n" 04320 "Penalty: %d\r\n", 04321 q->name, mem->interface, penalty); 04322 ao2_ref(mem, -1); 04323 } 04324 } 04325 ao2_unlock(q); 04326 queue_unref(q); 04327 } 04328 ao2_iterator_destroy(&queue_iter); 04329 04330 if (foundinterface) { 04331 return RESULT_SUCCESS; 04332 } else if (!foundqueue) { 04333 ast_log (LOG_ERROR, "Invalid queuename\n"); 04334 } else { 04335 ast_log (LOG_ERROR, "Invalid interface\n"); 04336 } 04337 04338 return RESULT_FAILURE; 04339 }
| static void set_queue_result | ( | struct ast_channel * | chan, | |
| enum queue_result | res | |||
| ) | [static] |
sets the QUEUESTATUS channel variable
Definition at line 533 of file app_queue.c.
References pbx_builtin_setvar_helper(), queue_results, and text.
Referenced by queue_exec().
00534 { 00535 int i; 00536 00537 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) { 00538 if (queue_results[i].id == res) { 00539 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 00540 return; 00541 } 00542 } 00543 }
| static void set_queue_variables | ( | struct call_queue * | q, | |
| struct ast_channel * | chan | |||
| ) | [static] |
Set variables of queue.
Definition at line 595 of file app_queue.c.
References call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::count, call_queue::holdtime, int2strat(), call_queue::maxlen, call_queue::name, pbx_builtin_setvar_multiple(), call_queue::servicelevel, call_queue::setqueuevar, and call_queue::strategy.
Referenced by end_bridge_callback(), queue_exec(), record_abandoned(), and try_calling().
00596 { 00597 00598 char interfacevar[256]=""; 00599 float sl = 0; 00600 00601 if (q->setqueuevar) { 00602 sl = 0; 00603 if (q->callscompleted > 0) 00604 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 00605 00606 snprintf(interfacevar, sizeof(interfacevar), 00607 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 00608 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 00609 00610 pbx_builtin_setvar_multiple(chan, interfacevar); 00611 } 00612 }
| static struct ast_datastore* setup_transfer_datastore | ( | struct queue_ent * | qe, | |
| struct member * | member, | |||
| time_t | starttime, | |||
| int | callcompletedinsl | |||
| ) | [static, read] |
create a datastore for storing relevant info to log attended transfers in the queue_log
Definition at line 3226 of file app_queue.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_lock, ast_channel_unlock, ast_log(), queue_transfer_ds::callcompletedinsl, queue_ent::chan, ast_datastore::data, LOG_WARNING, queue_transfer_ds::member, queue_transfer_ds::qe, queue_transfer_info, and queue_transfer_ds::starttime.
Referenced by try_calling().
03227 { 03228 struct ast_datastore *ds; 03229 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds)); 03230 03231 if (!qtds) { 03232 ast_log(LOG_WARNING, "Memory allocation error!\n"); 03233 return NULL; 03234 } 03235 03236 ast_channel_lock(qe->chan); 03237 if (!(ds = ast_channel_datastore_alloc(&queue_transfer_info, NULL))) { 03238 ast_channel_unlock(qe->chan); 03239 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n"); 03240 return NULL; 03241 } 03242 03243 qtds->qe = qe; 03244 /* This member is refcounted in try_calling, so no need to add it here, too */ 03245 qtds->member = member; 03246 qtds->starttime = starttime; 03247 qtds->callcompletedinsl = callcompletedinsl; 03248 ds->data = qtds; 03249 ast_channel_datastore_add(qe->chan, ds); 03250 ast_channel_unlock(qe->chan); 03251 return ds; 03252 }
| static int statechange_queue | ( | const char * | dev, | |
| enum ast_device_state | state | |||
| ) | [static] |
Producer of the statechange queue.
Definition at line 830 of file app_queue.c.
References ast_calloc, ast_cond_signal(), AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), statechange::dev, device_state, statechange::entry, and statechange::state.
00831 { 00832 struct statechange *sc; 00833 00834 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1))) 00835 return 0; 00836 00837 sc->state = state; 00838 strcpy(sc->dev, dev); 00839 00840 ast_mutex_lock(&device_state.lock); 00841 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry); 00842 ast_cond_signal(&device_state.cond); 00843 ast_mutex_unlock(&device_state.lock); 00844 00845 return 0; 00846 }
| 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 2444 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().
02445 { 02446 struct callattempt *best = find_best(outgoing); 02447 02448 if (best) { 02449 /* Ring just the best channel */ 02450 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 02451 qe->linpos = best->metric % 1000; 02452 } else { 02453 /* Just increment rrpos */ 02454 if (qe->linwrapped) { 02455 /* No more channels, start over */ 02456 qe->linpos = 0; 02457 } else { 02458 /* Prioritize next entry */ 02459 qe->linpos++; 02460 } 02461 } 02462 qe->