True call queues with optional send URL on answer. More...
#include "asterisk.h"#include <sys/time.h>#include <sys/signal.h>#include <netinet/in.h>#include <ctype.h>#include "asterisk/lock.h"#include "asterisk/file.h"#include "asterisk/channel.h"#include "asterisk/pbx.h"#include "asterisk/app.h"#include "asterisk/linkedlists.h"#include "asterisk/module.h"#include "asterisk/translate.h"#include "asterisk/say.h"#include "asterisk/features.h"#include "asterisk/musiconhold.h"#include "asterisk/cli.h"#include "asterisk/manager.h"#include "asterisk/config.h"#include "asterisk/monitor.h"#include "asterisk/utils.h"#include "asterisk/causes.h"#include "asterisk/astdb.h"#include "asterisk/devicestate.h"#include "asterisk/stringfields.h"#include "asterisk/event.h"#include "asterisk/astobj2.h"#include "asterisk/strings.h"#include "asterisk/global_datastores.h"#include "asterisk/taskprocessor.h"
Go to the source code of this file.
Data Structures | |
| struct | call_queue |
| struct | callattempt |
| We define a custom "local user" structure because we use it not only for keeping track of what is in use but also for keeping track of who we're dialing. More... | |
| struct | interfaces |
| struct | member |
| struct | member_interface |
| struct | penalty_rule |
| struct | queue_end_bridge |
| struct | queue_ent |
| struct | queue_transfer_ds |
| struct | rule_list |
| struct | rule_lists |
| struct | statechange |
| struct | strategy |
Defines | |
| #define | ANNOUNCEHOLDTIME_ALWAYS 1 |
| #define | ANNOUNCEHOLDTIME_ONCE 2 |
| #define | ANNOUNCEPOSITION_LIMIT 4 |
| #define | ANNOUNCEPOSITION_MORE_THAN 3 |
| #define | ANNOUNCEPOSITION_NO 2 |
| #define | ANNOUNCEPOSITION_YES 1 |
| #define | AST_MAX_WATCHERS 256 |
| #define | DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 |
| #define | DEFAULT_RETRY 5 |
| #define | DEFAULT_TIMEOUT 15 |
| #define | MAX_PERIODIC_ANNOUNCEMENTS 10 |
| #define | MAX_QUEUE_BUCKETS 53 |
| #define | PM_MAX_LEN 8192 |
| #define | QUEUE_EMPTY_LOOSE 3 |
| #define | QUEUE_EMPTY_NORMAL 1 |
| #define | QUEUE_EMPTY_STRICT 2 |
| #define | QUEUE_EVENT_VARIABLES 3 |
| #define | RECHECK 1 |
| #define | RES_EXISTS (-1) |
| #define | RES_NOSUCHQUEUE (-3) |
| #define | RES_NOT_DYNAMIC (-4) |
| #define | RES_OKAY 0 |
| #define | RES_OUTOFMEMORY (-2) |
Enumerations | |
| enum | { QUEUE_STRATEGY_RINGALL = 0, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_WRANDOM } |
| enum | agent_complete_reason { CALLER, AGENT, TRANSFER } |
| enum | queue_member_status { QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, QUEUE_NORMAL } |
| enum | queue_result { QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, QUEUE_JOINEMPTY = 2, QUEUE_LEAVEEMPTY = 3, QUEUE_JOINUNAVAIL = 4, QUEUE_LEAVEUNAVAIL = 5, QUEUE_FULL = 6, QUEUE_CONTINUE = 7 } |
| enum | queue_timeout_priority { TIMEOUT_PRIORITY_APP, TIMEOUT_PRIORITY_CONF } |
Functions | |
| static char * | __queues_show (struct mansession *s, int fd, int argc, char **argv) |
| Show queue(s) status and statistics. | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | add_to_interfaces (const char *interface) |
| static int | add_to_queue (const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface) |
| Add member to queue. | |
| static struct call_queue * | alloc_queue (const char *queuename) |
| static int | aqm_exec (struct ast_channel *chan, void *data) |
| AddQueueMember application. | |
| static int | attended_transfer_occurred (struct ast_channel *chan) |
| mechanism to tell if a queue caller was atxferred by a queue member. | |
| static int | calc_metric (struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp) |
| Calculate the metric of each member in the outgoing callattempts. | |
| static void | clear_and_free_interfaces (void) |
| static void | clear_queue (struct call_queue *q) |
| static int | compare_weight (struct call_queue *rq, struct member *member) |
| static char * | complete_queue (const char *line, const char *word, int pos, int state) |
| static char * | complete_queue_add_member (const char *line, const char *word, int pos, int state) |
| static char * | complete_queue_pause_member (const char *line, const char *word, int pos, int state) |
| static char * | complete_queue_remove_member (const char *line, const char *word, int pos, int state) |
| static char * | complete_queue_rule_show (const char *line, const char *word, int pos, int state) |
| static char * | complete_queue_set_member_penalty (const char *line, const char *word, int pos, int state) |
| static char * | complete_queue_show (const char *line, const char *word, int pos, int state) |
| static int | compress_char (const char c) |
| static void | copy_rules (struct queue_ent *qe, const char *rulename) |
| Copy rule from global list into specified queue. | |
| static struct member * | create_queue_member (const char *interface, const char *membername, int penalty, int paused, const char *state_interface) |
| allocate space for new queue member and set fields based on parameters passed | |
| static void | destroy_queue (void *obj) |
| Free queue's member list then its string fields. | |
| static void | device_state_cb (const struct ast_event *event, void *unused) |
| static void | do_hang (struct callattempt *o) |
| common hangup actions | |
| static void | do_print (struct mansession *s, int fd, const char *str) |
| direct ouput to manager or cli with proper terminator | |
| static void | dump_queue_members (struct call_queue *pm_queue) |
| Dump all members in a specific queue to the database. | |
| static void | end_bridge_callback (void *data) |
| static void | end_bridge_callback_data_fixup (struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator) |
| static struct callattempt * | find_best (struct callattempt *outgoing) |
| find the entry with the best metric, or NULL | |
| static struct call_queue * | find_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config) |
| Reload a single queue via realtime. | |
| static void | free_members (struct call_queue *q, int all) |
| Iterate through queue's member list and delete them. | |
| static int | get_member_penalty (char *queuename, char *interface) |
| static enum queue_member_status | get_member_status (struct call_queue *q, int max_penalty, int min_penalty) |
| Check if members are available. | |
| static char * | handle_queue_add_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_queue_pause_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_queue_remove_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_queue_rule_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_queue_rule_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_queue_set_member_penalty (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | handle_statechange (void *datap) |
| set a member's status based on device state of that member's interface | |
| static void | hangupcalls (struct callattempt *outgoing, struct ast_channel *exception) |
| Hang up a list of outgoing calls. | |
| static void | init_queue (struct call_queue *q) |
| Initialize Queue default values. | |
| static void | insert_entry (struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos) |
| Insert the 'new' entry after the 'prev' entry of queue 'q'. | |
| static int | insert_penaltychange (const char *list_name, const char *content, const int linenum) |
| Change queue penalty by adding rule. | |
| static const char * | int2strat (int strategy) |
| static struct member * | interface_exists (struct call_queue *q, const char *interface) |
| static int | interface_exists_global (const char *interface, int lock_queue_container) |
| static int | is_our_turn (struct queue_ent *qe) |
| Check if we should start attempting to call queue members. | |
| static int | join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason, const char *overriding_rule) |
| static void | leave_queue (struct queue_ent *qe) |
| Caller leaving queue. | |
| static int | load_module (void) |
| static struct call_queue * | load_realtime_queue (const char *queuename) |
| static int | manager_add_queue_member (struct mansession *s, const struct message *m) |
| static int | manager_pause_queue_member (struct mansession *s, const struct message *m) |
| static int | manager_queue_log_custom (struct mansession *s, const struct message *m) |
| static int | manager_queue_member_penalty (struct mansession *s, const struct message *m) |
| static int | manager_queue_rule_show (struct mansession *s, const struct message *m) |
| static int | manager_queues_show (struct mansession *s, const struct message *m) |
| static int | manager_queues_status (struct mansession *s, const struct message *m) |
| Queue status info via AMI. | |
| static int | manager_queues_summary (struct mansession *s, const struct message *m) |
| Summary of queue info via the AMI. | |
| static int | manager_remove_queue_member (struct mansession *s, const struct message *m) |
| static int | member_cmp_fn (void *obj1, void *obj2, int flags) |
| static int | member_hash_fn (const void *obj, const int flags) |
| static int | num_available_members (struct call_queue *q) |
| Get the number of members available to accept a call. | |
| static int | play_file (struct ast_channel *chan, const char *filename) |
| static int | pqm_exec (struct ast_channel *chan, void *data) |
| PauseQueueMember application. | |
| static int | ql_exec (struct ast_channel *chan, void *data) |
| QueueLog application. | |
| static int | queue_cmp_cb (void *obj, void *arg, int flags) |
| static int | queue_exec (struct ast_channel *chan, void *data) |
| The starting point for all queue calls. | |
| static int | queue_function_memberpenalty_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. | |
| static int | queue_function_memberpenalty_write (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
| Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. | |
| static int | queue_function_qac (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| Get number either busy / free or total members of a specific queue. | |
| static int | queue_function_qac_dep (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| Get the total number of members in a specific queue (Deprecated). | |
| static int | queue_function_queuememberlist (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue. | |
| static int | queue_function_queuewaitingcount (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue. | |
| static int | queue_function_var (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| create interface var with all queue details. | |
| static int | queue_hash_cb (const void *obj, const int flags) |
| static struct call_queue * | queue_ref (struct call_queue *q) |
| static void | queue_set_param (struct call_queue *q, const char *param, const char *val, int linenum, int failunknown) |
| Configure a queue parameter. | |
| static char * | queue_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static void | queue_transfer_destroy (void *data) |
| static void | queue_transfer_fixup (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) |
| Log an attended transfer when a queue caller channel is masqueraded. | |
| static struct call_queue * | queue_unref (struct call_queue *q) |
| static void | recalc_holdtime (struct queue_ent *qe, int newholdtime) |
| static void | record_abandoned (struct queue_ent *qe) |
| Record that a caller gave up on waiting in queue. | |
| static int | reload (void) |
| static void | reload_queue_members (void) |
| Reload dynamic queue members persisted into the astdb. | |
| static int | reload_queue_rules (int reload) |
| static int | reload_queues (int reload) |
| static int | remove_from_interfaces (const char *interface, int lock_queue_container) |
| static int | remove_from_queue (const char *queuename, const char *interface) |
| Remove member from queue. | |
| static int | ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies) |
| Part 2 of ring_one. | |
| static int | ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies) |
| Place a call to a queue member. | |
| static void | rna (int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause) |
| RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. | |
| static int | rqm_exec (struct ast_channel *chan, void *data) |
| RemoveQueueMember application. | |
| static void | rt_handle_member_record (struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface) |
| Find rt member record to update otherwise create one. | |
| static int | say_periodic_announcement (struct queue_ent *qe, int ringing) |
| Playback announcement to queued members if peroid has elapsed. | |
| static int | say_position (struct queue_ent *qe, int ringing) |
| static void | send_agent_complete (const struct queue_ent *qe, const char *queuename, const struct ast_channel *peer, const struct member *member, time_t callstart, char *vars, size_t vars_len, enum agent_complete_reason rsn) |
| Send out AMI message with member call completion status information. | |
| static int | set_member_paused (const char *queuename, const char *interface, const char *reason, int paused) |
| static int | set_member_penalty (char *queuename, char *interface, int penalty) |
| static void | set_queue_result (struct ast_channel *chan, enum queue_result res) |
| sets the QUEUESTATUS channel variable | |
| static void | set_queue_variables (struct call_queue *q, struct ast_channel *chan) |
| Set variables of queue. | |
| static struct ast_datastore * | setup_transfer_datastore (struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl) |
| create a datastore for storing relevant info to log attended transfers in the queue_log | |
| static int | store_next_lin (struct queue_ent *qe, struct callattempt *outgoing) |
| Search for best metric and add to Linear queue. | |
| static int | store_next_rr (struct queue_ent *qe, struct callattempt *outgoing) |
| Search for best metric and add to Round Robbin queue. | |
| static int | strat2int (const char *strategy) |
| static int | try_calling (struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing) |
| A large function which calls members, updates statistics, and bridges the caller and a member. | |
| static int | unload_module (void) |
| static void | update_qe_rule (struct queue_ent *qe) |
| update rules for queues | |
| static int | update_queue (struct call_queue *q, struct member *member, int callcompletedinsl) |
| update the queue status | |
| static int | update_realtime_member_field (struct member *mem, const char *queue_name, const char *field, const char *value) |
| static void | update_realtime_members (struct call_queue *q) |
| static int | update_status (const char *interface, const int status) |
| set a member's status based on device state of that member's state_interface. | |
| static int | upqm_exec (struct ast_channel *chan, void *data) |
| UnPauseQueueMember application. | |
| static int | valid_exit (struct queue_ent *qe, char digit) |
| Check for valid exit from queue via goto. | |
| static char * | vars2manager (struct ast_channel *chan, char *vars, size_t len) |
| convert "\n" to "\nVariable: " ready for manager to use | |
| static int | wait_a_bit (struct queue_ent *qe) |
| static struct callattempt * | wait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed) |
| Wait for a member to answer the call. | |
| static int | wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason) |
| The waiting areas for callers who are not actively calling members. | |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } |
| static char * | app = "Queue" |
| static char * | app_aqm = "AddQueueMember" |
| static char * | app_aqm_descrip |
| static char * | app_aqm_synopsis = "Dynamically adds queue members" |
| static char * | app_pqm = "PauseQueueMember" |
| static char * | app_pqm_descrip |
| static char * | app_pqm_synopsis = "Pauses a queue member" |
| static char * | app_ql = "QueueLog" |
| static char * | app_ql_descrip |
| static char * | app_ql_synopsis = "Writes to the queue_log" |
| static char * | app_rqm = "RemoveQueueMember" |
| static char * | app_rqm_descrip |
| static char * | app_rqm_synopsis = "Dynamically removes queue members" |
| static char * | app_upqm = "UnpauseQueueMember" |
| static char * | app_upqm_descrip |
| static char * | app_upqm_synopsis = "Unpauses a queue member" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static int | autofill_default = 0 |
| queues.conf [general] option | |
| static struct ast_cli_entry | cli_queue [] |
| static char * | descrip |
| static struct ast_event_sub * | device_state_sub |
| Subscription to device state change events. | |
| static struct ast_taskprocessor * | devicestate_tps |
| static int | montype_default = 0 |
| queues.conf [general] option | |
| static const char * | pm_family = "Queue/PersistentMembers" |
| Persistent Members astdb family. | |
| static const char | qpm_cmd_usage [] |
| static const char | qsmp_cmd_usage [] |
| static int | queue_keep_stats = 0 |
| queues.conf [general] option | |
| static int | queue_persistent_members = 0 |
| queues.conf [general] option | |
| struct { | |
| enum queue_result id | |
| char * text | |
| } | queue_results [] |
| static struct ast_datastore_info | queue_transfer_info |
| a datastore used to help correctly log attended transfers of queue callers | |
| static struct ast_custom_function | queuemembercount_dep |
| static struct ast_custom_function | queuemembercount_function |
| static struct ast_custom_function | queuememberlist_function |
| static struct ast_custom_function | queuememberpenalty_function |
| static struct ao2_container * | queues |
| static struct ast_custom_function | queuevar_function |
| static struct ast_custom_function | queuewaitingcount_function |
| static const char | qum_cmd_usage [] |
| static int | shared_lastcall = 0 |
| queues.conf [general] option | |
| static struct strategy | strategies [] |
| static char * | synopsis = "Queue a call for a call queue" |
| static int | update_cdr = 0 |
| queues.conf [general] option | |
| static int | use_weight = 0 |
| queues.conf per-queue weight option | |
True call queues with optional send URL on answer.
Each dynamic agent in each queue is now stored in the astdb. When asterisk is restarted, each agent will be automatically readded into their recorded queues. This feature can be configured with the 'persistent_members=<1|0>' setting in the '[general]' category in queues.conf. The default is on.
Patch Version 1.07 2003-12-24 01
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 |
Definition at line 418 of file app_queue.c.
Referenced by queue_set_param().
| #define ANNOUNCEHOLDTIME_ONCE 2 |
Definition at line 419 of file app_queue.c.
Referenced by queue_set_param(), and say_position().
| #define ANNOUNCEPOSITION_LIMIT 4 |
We not announce position more than <limit>
Definition at line 434 of file app_queue.c.
Referenced by queue_set_param(), and say_position().
| #define ANNOUNCEPOSITION_MORE_THAN 3 |
We say "Currently there are more than <limit>"
Definition at line 433 of file app_queue.c.
Referenced by queue_set_param(), and say_position().
| #define ANNOUNCEPOSITION_NO 2 |
We don't announce position
Definition at line 432 of file app_queue.c.
Referenced by queue_set_param().
| #define ANNOUNCEPOSITION_YES 1 |
We announce position
Definition at line 431 of file app_queue.c.
Referenced by init_queue(), queue_set_param(), and say_position().
| #define AST_MAX_WATCHERS 256 |
Definition at line 2579 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 142 of file app_queue.c.
Referenced by init_queue().
| #define DEFAULT_RETRY 5 |
Definition at line 138 of file app_queue.c.
Referenced by init_queue(), and queue_set_param().
| #define DEFAULT_TIMEOUT 15 |
Definition at line 139 of file app_queue.c.
Referenced by init_queue(), and queue_set_param().
| #define MAX_PERIODIC_ANNOUNCEMENTS 10 |
The maximum periodic announcements we can have
Definition at line 141 of file app_queue.c.
Referenced by destroy_queue(), init_queue(), and queue_set_param().
| #define MAX_QUEUE_BUCKETS 53 |
Definition at line 144 of file app_queue.c.
Referenced by load_module().
| #define PM_MAX_LEN 8192 |
Definition at line 280 of file app_queue.c.
Referenced by dump_queue_members(), and reload_queue_members().
| #define QUEUE_EMPTY_LOOSE 3 |
Definition at line 417 of file app_queue.c.
Referenced by join_queue(), queue_exec(), queue_set_param(), and wait_our_turn().
| #define QUEUE_EMPTY_NORMAL 1 |
Definition at line 415 of file app_queue.c.
Referenced by queue_set_param().
| #define QUEUE_EMPTY_STRICT 2 |
Definition at line 416 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 420 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 140 of file app_queue.c.
Referenced by wait_our_turn().
| #define RES_EXISTS (-1) |
Entry already exists
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_NOSUCHQUEUE (-3) |
No such queue
Definition at line 149 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
| #define RES_NOT_DYNAMIC (-4) |
Member is not dynamic
Definition at line 150 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 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(), remove_from_queue(), and rqm_exec().
| #define RES_OUTOFMEMORY (-2) |
Out of memory
Definition at line 148 of file app_queue.c.
Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), 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 };
Definition at line 3130 of file app_queue.c.
| enum queue_member_status |
| QUEUE_NO_MEMBERS | |
| QUEUE_NO_REACHABLE_MEMBERS | |
| QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS | |
| QUEUE_NORMAL |
Definition at line 654 of file app_queue.c.
00654 { 00655 QUEUE_NO_MEMBERS, 00656 QUEUE_NO_REACHABLE_MEMBERS, 00657 QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, 00658 QUEUE_NORMAL 00659 };
| enum queue_result |
| QUEUE_UNKNOWN | |
| QUEUE_TIMEOUT | |
| QUEUE_JOINEMPTY | |
| QUEUE_LEAVEEMPTY | |
| QUEUE_JOINUNAVAIL | |
| QUEUE_LEAVEUNAVAIL | |
| QUEUE_FULL | |
| QUEUE_CONTINUE |
Definition at line 306 of file app_queue.c.
00306 { 00307 QUEUE_UNKNOWN = 0, 00308 QUEUE_TIMEOUT = 1, 00309 QUEUE_JOINEMPTY = 2, 00310 QUEUE_LEAVEEMPTY = 3, 00311 QUEUE_JOINUNAVAIL = 4, 00312 QUEUE_LEAVEUNAVAIL = 5, 00313 QUEUE_FULL = 6, 00314 QUEUE_CONTINUE = 7, 00315 };
Definition at line 331 of file app_queue.c.
00331 { 00332 TIMEOUT_PRIORITY_APP, 00333 TIMEOUT_PRIORITY_CONF, 00334 };
| 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 5721 of file app_queue.c.
References ao2_container_count(), 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, F_AO2I_DONTLOCK, call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, load_realtime_queue(), call_queue::maxlen, member::membername, call_queue::members, call_queue::name, queue_ent::next, member::paused, member::penalty, queue_ent::pos, queue_ent::prio, queue_unref(), queues, member::realtime, call_queue::realtime, SENTINEL, call_queue::servicelevel, queue_ent::start, member::status, ast_str::str, call_queue::strategy, and call_queue::weight.
Referenced by manager_queues_show(), and queue_show().
05722 { 05723 struct call_queue *q; 05724 struct ast_str *out = ast_str_alloca(240); 05725 int found = 0; 05726 time_t now = time(NULL); 05727 struct ao2_iterator queue_iter; 05728 struct ao2_iterator mem_iter; 05729 05730 if (argc != 2 && argc != 3) 05731 return CLI_SHOWUSAGE; 05732 05733 if (argc == 3) { /* specific queue */ 05734 if ((q = load_realtime_queue(argv[2]))) { 05735 queue_unref(q); 05736 } 05737 } else if (ast_check_realtime("queues")) { 05738 /* This block is to find any queues which are defined in realtime but 05739 * which have not yet been added to the in-core container 05740 */ 05741 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 05742 char *queuename; 05743 if (cfg) { 05744 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { 05745 if ((q = load_realtime_queue(queuename))) { 05746 queue_unref(q); 05747 } 05748 } 05749 ast_config_destroy(cfg); 05750 } 05751 } 05752 05753 queue_iter = ao2_iterator_init(queues, F_AO2I_DONTLOCK); 05754 ao2_lock(queues); 05755 while ((q = ao2_iterator_next(&queue_iter))) { 05756 float sl; 05757 struct call_queue *realtime_queue = NULL; 05758 05759 ao2_lock(q); 05760 /* This check is to make sure we don't print information for realtime 05761 * queues which have been deleted from realtime but which have not yet 05762 * been deleted from the in-core container 05763 */ 05764 if (q->realtime && !(realtime_queue = load_realtime_queue(q->name))) { 05765 ao2_unlock(q); 05766 queue_unref(q); 05767 continue; 05768 } else if (q->realtime) { 05769 queue_unref(realtime_queue); 05770 } 05771 if (argc == 3 && strcasecmp(q->name, argv[2])) { 05772 ao2_unlock(q); 05773 queue_unref(q); 05774 continue; 05775 } 05776 found = 1; 05777 05778 ast_str_set(&out, 0, "%-12.12s has %d calls (max ", q->name, q->count); 05779 if (q->maxlen) 05780 ast_str_append(&out, 0, "%d", q->maxlen); 05781 else 05782 ast_str_append(&out, 0, "unlimited"); 05783 sl = 0; 05784 if (q->callscompleted > 0) 05785 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 05786 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds", 05787 int2strat(q->strategy), q->holdtime, q->weight, 05788 q->callscompleted, q->callsabandoned,sl,q->servicelevel); 05789 do_print(s, fd, out->str); 05790 if (!ao2_container_count(q->members)) 05791 do_print(s, fd, " No Members"); 05792 else { 05793 struct member *mem; 05794 05795 do_print(s, fd, " Members: "); 05796 mem_iter = ao2_iterator_init(q->members, 0); 05797 while ((mem = ao2_iterator_next(&mem_iter))) { 05798 ast_str_set(&out, 0, " %s", mem->membername); 05799 if (strcasecmp(mem->membername, mem->interface)) { 05800 ast_str_append(&out, 0, " (%s)", mem->interface); 05801 } 05802 if (mem->penalty) 05803 ast_str_append(&out, 0, " with penalty %d", mem->penalty); 05804 ast_str_append(&out, 0, "%s%s%s (%s)", 05805 mem->dynamic ? " (dynamic)" : "", 05806 mem->realtime ? " (realtime)" : "", 05807 mem->paused ? " (paused)" : "", 05808 devstate2str(mem->status)); 05809 if (mem->calls) 05810 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)", 05811 mem->calls, (long) (time(NULL) - mem->lastcall)); 05812 else 05813 ast_str_append(&out, 0, " has taken no calls yet"); 05814 do_print(s, fd, out->str); 05815 ao2_ref(mem, -1); 05816 } 05817 } 05818 if (!q->head) 05819 do_print(s, fd, " No Callers"); 05820 else { 05821 struct queue_ent *qe; 05822 int pos = 1; 05823 05824 do_print(s, fd, " Callers: "); 05825 for (qe = q->head; qe; qe = qe->next) { 05826 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)", 05827 pos++, qe->chan->name, (long) (now - qe->start) / 60, 05828 (long) (now - qe->start) % 60, qe->prio); 05829 do_print(s, fd, out->str); 05830 } 05831 } 05832 do_print(s, fd, ""); /* blank line between entries */ 05833 ao2_unlock(q); 05834 queue_unref(q); /* Unref the iterator's reference */ 05835 } 05836 ao2_unlock(queues); 05837 if (!found) { 05838 if (argc == 3) 05839 ast_str_set(&out, 0, "No such queue: %s.", argv[2]); 05840 else 05841 ast_str_set(&out, 0, "No queues."); 05842 do_print(s, fd, out->str); 05843 } 05844 return CLI_SUCCESS; 05845 }
| static void __reg_module | ( | void | ) | [static] |
Definition at line 6779 of file app_queue.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 6779 of file app_queue.c.
| static int add_to_interfaces | ( | const char * | interface | ) | [static] |
Definition at line 962 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().
00963 { 00964 struct member_interface *curint; 00965 00966 AST_LIST_LOCK(&interfaces); 00967 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00968 if (!strcasecmp(curint->interface, interface)) 00969 break; 00970 } 00971 00972 if (curint) { 00973 AST_LIST_UNLOCK(&interfaces); 00974 return 0; 00975 } 00976 00977 ast_debug(1, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface); 00978 00979 if ((curint = ast_calloc(1, sizeof(*curint)))) { 00980 ast_copy_string(curint->interface, interface, sizeof(curint->interface)); 00981 AST_LIST_INSERT_HEAD(&interfaces, curint, list); 00982 } 00983 AST_LIST_UNLOCK(&interfaces); 00984 00985 return 0; 00986 }
| 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 4191 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().
04192 { 04193 struct call_queue *q; 04194 struct member *new_member, *old_member; 04195 int res = RES_NOSUCHQUEUE; 04196 04197 /*! \note Ensure the appropriate realtime queue is loaded. Note that this 04198 * short-circuits if the queue is already in memory. */ 04199 if (!(q = load_realtime_queue(queuename))) 04200 return res; 04201 04202 ao2_lock(queues); 04203 04204 ao2_lock(q); 04205 if ((old_member = interface_exists(q, interface)) == NULL) { 04206 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { 04207 add_to_interfaces(new_member->state_interface); 04208 new_member->dynamic = 1; 04209 ao2_link(q->members, new_member); 04210 q->membercount++; 04211 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 04212 "Queue: %s\r\n" 04213 "Location: %s\r\n" 04214 "MemberName: %s\r\n" 04215 "Membership: %s\r\n" 04216 "Penalty: %d\r\n" 04217 "CallsTaken: %d\r\n" 04218 "LastCall: %d\r\n" 04219 "Status: %d\r\n" 04220 "Paused: %d\r\n", 04221 q->name, new_member->interface, new_member->membername, 04222 "dynamic", 04223 new_member->penalty, new_member->calls, (int) new_member->lastcall, 04224 new_member->status, new_member->paused); 04225 04226 ao2_ref(new_member, -1); 04227 new_member = NULL; 04228 04229 if (dump) 04230 dump_queue_members(q); 04231 04232 res = RES_OKAY; 04233 } else { 04234 res = RES_OUTOFMEMORY; 04235 } 04236 } else { 04237 ao2_ref(old_member, -1); 04238 res = RES_EXISTS; 04239 } 04240 ao2_unlock(q); 04241 ao2_unlock(queues); 04242 04243 return res; 04244 }
| static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static, read] |
Definition at line 1436 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().
01437 { 01438 struct call_queue *q; 01439 01440 if ((q = ao2_alloc(sizeof(*q), destroy_queue))) { 01441 if (ast_string_field_init(q, 64)) { 01442 ao2_ref(q, -1); 01443 return NULL; 01444 } 01445 ast_string_field_set(q, name, queuename); 01446 } 01447 return q; 01448 }
| static int aqm_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
AddQueueMember application.
Definition at line 4625 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, parse(), pbx_builtin_setvar_helper(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.
Referenced by load_module().
04626 { 04627 int res=-1; 04628 char *parse, *temppos = NULL; 04629 AST_DECLARE_APP_ARGS(args, 04630 AST_APP_ARG(queuename); 04631 AST_APP_ARG(interface); 04632 AST_APP_ARG(penalty); 04633 AST_APP_ARG(options); 04634 AST_APP_ARG(membername); 04635 AST_APP_ARG(state_interface); 04636 ); 04637 int penalty = 0; 04638 04639 if (ast_strlen_zero(data)) { 04640 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n"); 04641 return -1; 04642 } 04643 04644 parse = ast_strdupa(data); 04645 04646 AST_STANDARD_APP_ARGS(args, parse); 04647 04648 if (ast_strlen_zero(args.interface)) { 04649 args.interface = ast_strdupa(chan->name); 04650 temppos = strrchr(args.interface, '-'); 04651 if (temppos) 04652 *temppos = '\0'; 04653 } 04654 04655 if (!ast_strlen_zero(args.penalty)) { 04656 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) { 04657 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 04658 penalty = 0; 04659 } 04660 } 04661 04662 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { 04663 case RES_OKAY: 04664 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 04665 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 04666 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 04667 res = 0; 04668 break; 04669 case RES_EXISTS: 04670 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 04671 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 04672 res = 0; 04673 break; 04674 case RES_NOSUCHQUEUE: 04675 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 04676 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 04677 res = 0; 04678 break; 04679 case RES_OUTOFMEMORY: 04680 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 04681 break; 04682 } 04683 04684 return res; 04685 }
| 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 3234 of file app_queue.c.
References ast_channel_datastore_find(), and queue_transfer_info.
Referenced by try_calling().
03235 { 03236 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1; 03237 }
| 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 3073 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().
03074 { 03075 if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || (qe->min_penalty && (mem->penalty < qe->min_penalty))) 03076 return -1; 03077 03078 switch (q->strategy) { 03079 case QUEUE_STRATEGY_RINGALL: 03080 /* Everyone equal, except for penalty */ 03081 tmp->metric = mem->penalty * 1000000; 03082 break; 03083 case QUEUE_STRATEGY_LINEAR: 03084 if (pos < qe->linpos) { 03085 tmp->metric = 1000 + pos; 03086 } else { 03087 if (pos > qe->linpos) 03088 /* Indicate there is another priority */ 03089 qe->linwrapped = 1; 03090 tmp->metric = pos; 03091 } 03092 tmp->metric += mem->penalty * 1000000; 03093 break; 03094 case QUEUE_STRATEGY_RRMEMORY: 03095 if (pos < q->rrpos) { 03096 tmp->metric = 1000 + pos; 03097 } else { 03098 if (pos > q->rrpos) 03099 /* Indicate there is another priority */ 03100 q->wrapped = 1; 03101 tmp->metric = pos; 03102 } 03103 tmp->metric += mem->penalty * 1000000; 03104 break; 03105 case QUEUE_STRATEGY_RANDOM: 03106 tmp->metric = ast_random() % 1000; 03107 tmp->metric += mem->penalty * 1000000; 03108 break; 03109 case QUEUE_STRATEGY_WRANDOM: 03110 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000); 03111 break; 03112 case QUEUE_STRATEGY_FEWESTCALLS: 03113 tmp->metric = mem->calls; 03114 tmp->metric += mem->penalty * 1000000; 03115 break; 03116 case QUEUE_STRATEGY_LEASTRECENT: 03117 if (!mem->lastcall) 03118 tmp->metric = 0; 03119 else 03120 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 03121 tmp->metric += mem->penalty * 1000000; 03122 break; 03123 default: 03124 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 03125 break; 03126 } 03127 return 0; 03128 }
| static void clear_and_free_interfaces | ( | void | ) | [static] |
Definition at line 1036 of file app_queue.c.
References ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, and AST_LIST_UNLOCK.
Referenced by unload_module().
01037 { 01038 struct member_interface *curint; 01039 01040 AST_LIST_LOCK(&interfaces); 01041 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list))) 01042 ast_free(curint); 01043 AST_LIST_UNLOCK(&interfaces); 01044 }
| static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 953 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().
00954 { 00955 q->holdtime = 0; 00956 q->callscompleted = 0; 00957 q->callsabandoned = 0; 00958 q->callscompletedinsl = 0; 00959 q->wrapuptime = 0; 00960 }
| static int compare_weight | ( | struct call_queue * | rq, | |
| struct member * | member | |||
| ) | [static] |
Definition at line 2124 of file app_queue.c.
References ao2_find, 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().
02125 { 02126 struct call_queue *q; 02127 struct member *mem; 02128 int found = 0; 02129 struct ao2_iterator queue_iter; 02130 02131 /* q's lock and rq's lock already set by try_calling() 02132 * to solve deadlock */ 02133 queue_iter = ao2_iterator_init(queues, 0); 02134 while ((q = ao2_iterator_next(&queue_iter))) { 02135 if (q == rq) { /* don't check myself, could deadlock */ 02136 queue_unref(q); 02137 continue; 02138 } 02139 ao2_lock(q); 02140 if (q->count && q->members) { 02141 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 02142 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 02143 if (q->weight > rq->weight && q->count >= num_available_members(q)) { 02144 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); 02145 found = 1; 02146 } 02147 ao2_ref(mem, -1); 02148 } 02149 } 02150 ao2_unlock(q); 02151 queue_unref(q); 02152 if (found) { 02153 break; 02154 } 02155 } 02156 return found; 02157 }
| static char* complete_queue | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 5847 of file app_queue.c.
References 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().
05848 { 05849 struct call_queue *q; 05850 char *ret = NULL; 05851 int which = 0; 05852 int wordlen = strlen(word); 05853 struct ao2_iterator queue_iter; 05854 05855 queue_iter = ao2_iterator_init(queues, 0); 05856 while ((q = ao2_iterator_next(&queue_iter))) { 05857 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 05858 ret = ast_strdup(q->name); 05859 queue_unref(q); 05860 break; 05861 } 05862 queue_unref(q); 05863 } 05864 05865 return ret; 05866 }
| static char* complete_queue_add_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6224 of file app_queue.c.
References ast_malloc, ast_strdup, complete_queue(), and num.
Referenced by handle_queue_add_member().
06225 { 06226 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 06227 switch (pos) { 06228 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 06229 return NULL; 06230 case 4: /* only one possible match, "to" */ 06231 return state == 0 ? ast_strdup("to") : NULL; 06232 case 5: /* <queue> */ 06233 return complete_queue(line, word, pos, state); 06234 case 6: /* only one possible match, "penalty" */ 06235 return state == 0 ? ast_strdup("penalty") : NULL; 06236 case 7: 06237 if (state < 100) { /* 0-99 */ 06238 char *num; 06239 if ((num = ast_malloc(3))) { 06240 sprintf(num, "%d", state); 06241 } 06242 return num; 06243 } else { 06244 return NULL; 06245 } 06246 case 8: /* only one possible match, "as" */ 06247 return state == 0 ? ast_strdup("as") : NULL; 06248 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 06249 return NULL; 06250 default: 06251 return NULL; 06252 } 06253 }
| static char* complete_queue_pause_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6438 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_pause_member().
06439 { 06440 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */ 06441 switch (pos) { 06442 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 06443 return NULL; 06444 case 4: /* only one possible match, "queue" */ 06445 return state == 0 ? ast_strdup("queue") : NULL; 06446 case 5: /* <queue> */ 06447 return complete_queue(line, word, pos, state); 06448 case 6: /* "reason" */ 06449 return state == 0 ? ast_strdup("reason") : NULL; 06450 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */ 06451 return NULL; 06452 default: 06453 return NULL; 06454 } 06455 }
| static char* complete_queue_remove_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6354 of file app_queue.c.
References 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().
06355 { 06356 int which = 0; 06357 struct call_queue *q; 06358 struct member *m; 06359 struct ao2_iterator queue_iter; 06360 struct ao2_iterator mem_iter; 06361 int wordlen = strlen(word); 06362 06363 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 06364 if (pos > 5 || pos < 3) 06365 return NULL; 06366 if (pos == 4) /* only one possible match, 'from' */ 06367 return (state == 0 ? ast_strdup("from") : NULL); 06368 06369 if (pos == 5) /* No need to duplicate code */ 06370 return complete_queue(line, word, pos, state); 06371 06372 /* here is the case for 3, <member> */ 06373 queue_iter = ao2_iterator_init(queues, 0); 06374 while ((q = ao2_iterator_next(&queue_iter))) { 06375 ao2_lock(q); 06376 mem_iter = ao2_iterator_init(q->members, 0); 06377 while ((m = ao2_iterator_next(&mem_iter))) { 06378 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) { 06379 char *tmp; 06380 ao2_unlock(q); 06381 tmp = ast_strdup(m->interface); 06382 ao2_ref(m, -1); 06383 queue_unref(q); 06384 return tmp; 06385 } 06386 ao2_ref(m, -1); 06387 } 06388 ao2_unlock(q); 06389 queue_unref(q); 06390 } 06391 06392 return NULL; 06393 }
| static char* complete_queue_rule_show | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6571 of file app_queue.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, and rule_list::name.
Referenced by handle_queue_rule_show().
06572 { 06573 int which = 0; 06574 struct rule_list *rl_iter; 06575 int wordlen = strlen(word); 06576 char *ret = NULL; 06577 if (pos != 3) /* Wha? */ { 06578 return NULL; 06579 } 06580 06581 AST_LIST_LOCK(&rule_lists); 06582 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 06583 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) { 06584 ret = ast_strdup(rl_iter->name); 06585 break; 06586 } 06587 } 06588 AST_LIST_UNLOCK(&rule_lists); 06589 06590 return ret; 06591 }
| static char* complete_queue_set_member_penalty | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6508 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_set_member_penalty().
06509 { 06510 /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/ 06511 switch (pos) { 06512 case 4: 06513 if (state == 0) { 06514 return ast_strdup("on"); 06515 } else { 06516 return NULL; 06517 } 06518 case 6: 06519 if (state == 0) { 06520 return ast_strdup("in"); 06521 } else { 06522 return NULL; 06523 } 06524 case 7: 06525 return complete_queue(line, word, pos, state); 06526 default: 06527 return NULL; 06528 } 06529 }
| static char* complete_queue_show | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 5868 of file app_queue.c.
References complete_queue().
Referenced by queue_show().
05869 { 05870 if (pos == 2) 05871 return complete_queue(line, word, pos, state); 05872 return NULL; 05873 }
| static int compress_char | ( | const char | c | ) | [static] |
Definition at line 851 of file app_queue.c.
Referenced by member_hash_fn().
| static void copy_rules | ( | struct queue_ent * | qe, | |
| const char * | rulename | |||
| ) | [static] |
Copy rule from global list into specified queue.
Definition at line 4722 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().
04723 { 04724 struct penalty_rule *pr_iter; 04725 struct rule_list *rl_iter; 04726 const char *tmp = rulename; 04727 if (ast_strlen_zero(tmp)) { 04728 return; 04729 } 04730 AST_LIST_LOCK(&rule_lists); 04731 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 04732 if (!strcasecmp(rl_iter->name, tmp)) 04733 break; 04734 } 04735 if (rl_iter) { 04736 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 04737 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr)); 04738 if (!new_pr) { 04739 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n"); 04740 AST_LIST_UNLOCK(&rule_lists); 04741 break; 04742 } 04743 new_pr->time = pr_iter->time; 04744 new_pr->max_value = pr_iter->max_value; 04745 new_pr->min_value = pr_iter->min_value; 04746 new_pr->max_relative = pr_iter->max_relative; 04747 new_pr->min_relative = pr_iter->min_relative; 04748 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list); 04749 } 04750 } 04751 AST_LIST_UNLOCK(&rule_lists); 04752 }
| 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 826 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().
00827 { 00828 struct member *cur; 00829 00830 if ((cur = ao2_alloc(sizeof(*cur), NULL))) { 00831 cur->penalty = penalty; 00832 cur->paused = paused; 00833 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 00834 if (!ast_strlen_zero(state_interface)) 00835 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); 00836 else 00837 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface)); 00838 if (!ast_strlen_zero(membername)) 00839 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 00840 else 00841 ast_copy_string(cur->membername, interface, sizeof(cur->membername)); 00842 if (!strchr(cur->interface, '/')) 00843 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 00844 cur->status = ast_device_state(cur->state_interface); 00845 } 00846 00847 return cur; 00848 }
| static void destroy_queue | ( | void * | obj | ) | [static] |
Free queue's member list then its string fields.
Definition at line 1422 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().
01423 { 01424 struct call_queue *q = obj; 01425 int i; 01426 01427 free_members(q, 1); 01428 ast_string_field_free_memory(q); 01429 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 01430 if (q->sound_periodicannounce[i]) 01431 free(q->sound_periodicannounce[i]); 01432 } 01433 ao2_ref(q->members, -1); 01434 }
| static void device_state_cb | ( | const struct ast_event * | event, | |
| void * | unused | |||
| ) | [static] |
Definition at line 799 of file app_queue.c.
References ast_calloc, ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_STATE, ast_free, ast_log(), ast_strlen_zero(), ast_taskprocessor_push(), statechange::dev, handle_statechange(), LOG_ERROR, and statechange::state.
Referenced by load_module().
00800 { 00801 enum ast_device_state state; 00802 const char *device; 00803 struct statechange *sc; 00804 size_t datapsize; 00805 00806 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE); 00807 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE); 00808 00809 if (ast_strlen_zero(device)) { 00810 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n"); 00811 return; 00812 } 00813 datapsize = sizeof(*sc) + strlen(device) + 1; 00814 if (!(sc = ast_calloc(1, datapsize))) { 00815 ast_log(LOG_ERROR, "failed to calloc a state change struct\n"); 00816 return; 00817 } 00818 sc->state = state; 00819 strcpy(sc->dev, device); 00820 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) { 00821 ast_free(sc); 00822 } 00823 }
| static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 2160 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry(), and wait_for_answer().
02161 { 02162 o->stillgoing = 0; 02163 ast_hangup(o->chan); 02164 o->chan = NULL; 02165 }
| 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 5707 of file app_queue.c.
References ast_cli(), and astman_append().
Referenced by __queues_show().
05708 { 05709 if (s) 05710 astman_append(s, "%s\r\n", str); 05711 else 05712 ast_cli(fd, "%s\n", str); 05713 }
| 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 4092 of file app_queue.c.
References 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().
04093 { 04094 struct member *cur_member; 04095 char value[PM_MAX_LEN]; 04096 int value_len = 0; 04097 int res; 04098 struct ao2_iterator mem_iter; 04099 04100 memset(value, 0, sizeof(value)); 04101 04102 if (!pm_queue) 04103 return; 04104 04105 mem_iter = ao2_iterator_init(pm_queue->members, 0); 04106 while ((cur_member = ao2_iterator_next(&mem_iter))) { 04107 if (!cur_member->dynamic) { 04108 ao2_ref(cur_member, -1); 04109 continue; 04110 } 04111 04112 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s", 04113 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface); 04114 04115 ao2_ref(cur_member, -1); 04116 04117 if (res != strlen(value + value_len)) { 04118 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 04119 break; 04120 } 04121 value_len += res; 04122 } 04123 04124 if (value_len && !cur_member) { 04125 if (ast_db_put(pm_family, pm_queue->name, value)) 04126 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 04127 } else 04128 /* Delete the entry if the queue is empty or there is an error */ 04129 ast_db_del(pm_family, pm_queue->name); 04130 }
| static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 3281 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().
Referenced by try_calling().
03282 { 03283 struct queue_end_bridge *qeb = data; 03284 struct call_queue *q = qeb->q; 03285 struct ast_channel *chan = qeb->chan; 03286 03287 if (ao2_ref(qeb, -1) == 1) { 03288 ao2_lock(q); 03289 set_queue_variables(q, chan); 03290 ao2_unlock(q); 03291 /* This unrefs the reference we made in try_calling when we allocated qeb */ 03292 queue_unref(q); 03293 } 03294 }
| static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
| struct ast_channel * | originator, | |||
| struct ast_channel * | terminator | |||
| ) | [static] |
Definition at line 3274 of file app_queue.c.
References ao2_ref, queue_end_bridge::chan, and ast_bridge_config::end_bridge_callback_data.
Referenced by try_calling().
03275 { 03276 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data; 03277 ao2_ref(qeb, +1); 03278 qeb->chan = originator; 03279 }
| static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static, read] |
find the entry with the best metric, or NULL
Definition at line 2371 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
Referenced by ring_one(), store_next_lin(), and store_next_rr().
02372 { 02373 struct callattempt *best = NULL, *cur; 02374 02375 for (cur = outgoing; cur; cur = cur->q_next) { 02376 if (cur->stillgoing && /* Not already done */ 02377 !cur->chan && /* Isn't already going */ 02378 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 02379 best = cur; 02380 } 02381 } 02382 02383 return best; 02384 }
| 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 1460 of file app_queue.c.
References alloc_queue(), ao2_find, 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_queue_log(), ast_strlen_zero(), ast_variable_retrieve(), clear_queue(), member::dead, call_queue::dead, init_queue(), member::interface, 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().
01461 { 01462 struct ast_variable *v; 01463 struct call_queue *q, tmpq = { 01464 .name = queuename, 01465 }; 01466 struct member *m; 01467 struct ao2_iterator mem_iter; 01468 char *interface = NULL; 01469 const char *tmp_name; 01470 char *tmp; 01471 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 01472 01473 /* Static queues override realtime. */ 01474 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 01475 ao2_lock(q); 01476 if (!q->realtime) { 01477 if (q->dead) { 01478 ao2_unlock(q); 01479 queue_unref(q); 01480 return NULL; 01481 } else { 01482 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); 01483 ao2_unlock(q); 01484 return q; 01485 } 01486 } 01487 queue_unref(q); 01488 } else if (!member_config) 01489 /* Not found in the list, and it's not realtime ... */ 01490 return NULL; 01491 01492 /* Check if queue is defined in realtime. */ 01493 if (!queue_vars) { 01494 /* Delete queue from in-core list if it has been deleted in realtime. */ 01495 if (q) { 01496 /*! \note Hmm, can't seem to distinguish a DB failure from a not 01497 found condition... So we might delete an in-core queue 01498 in case of DB failure. */ 01499 ast_debug(1, "Queue %s not found in realtime.\n", queuename); 01500 01501 q->dead = 1; 01502 /* Delete if unused (else will be deleted when last caller leaves). */ 01503 ao2_unlink(queues, q); 01504 ao2_unlock(q); 01505 queue_unref(q); 01506 } 01507 return NULL; 01508 } 01509 01510 /* Create a new queue if an in-core entry does not exist yet. */ 01511 if (!q) { 01512 struct ast_variable *tmpvar = NULL; 01513 if (!(q = alloc_queue(queuename))) 01514 return NULL; 01515 ao2_lock(q); 01516 clear_queue(q); 01517 q->realtime = 1; 01518 /*Before we initialize the queue, we need to set the strategy, so that linear strategy 01519 * will allocate the members properly 01520 */ 01521 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) { 01522 if (!strcasecmp(tmpvar->name, "strategy")) { 01523 q->strategy = strat2int(tmpvar->value); 01524 if (q->strategy < 0) { 01525 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 01526 tmpvar->value, q->name); 01527 q->strategy = QUEUE_STRATEGY_RINGALL; 01528 } 01529 break; 01530 } 01531 } 01532 /* We traversed all variables and didn't find a strategy */ 01533 if (!tmpvar) 01534 q->strategy = QUEUE_STRATEGY_RINGALL; 01535 ao2_link(queues, q); 01536 } 01537 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 01538 01539 memset(tmpbuf, 0, sizeof(tmpbuf)); 01540 for (v = queue_vars; v; v = v->next) { 01541 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 01542 if ((tmp = strchr(v->name, '_'))) { 01543 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 01544 tmp_name = tmpbuf; 01545 tmp = tmpbuf; 01546 while ((tmp = strchr(tmp, '_'))) 01547 *tmp++ = '-'; 01548 } else 01549 tmp_name = v->name; 01550 01551 if (!ast_strlen_zero(v->value)) { 01552 /* Don't want to try to set the option if the value is empty */ 01553 queue_set_param(q, tmp_name, v->value, -1, 0); 01554 } 01555 } 01556 01557 /* Temporarily set realtime members dead so we can detect deleted ones. 01558 * Also set the membercount correctly for realtime*/ 01559 mem_iter = ao2_iterator_init(q->members, 0); 01560 while ((m = ao2_iterator_next(&mem_iter))) { 01561 q->membercount++; 01562 if (m->realtime) 01563 m->dead = 1; 01564 ao2_ref(m, -1); 01565 } 01566 01567 while ((interface = ast_category_browse(member_config, interface))) { 01568 rt_handle_member_record(q, interface, 01569 ast_variable_retrieve(member_config, interface, "uniqueid"), 01570 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface), 01571 ast_variable_retrieve(member_config, interface, "penalty"), 01572 ast_variable_retrieve(member_config, interface, "paused"), 01573 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface)); 01574 } 01575 01576 /* Delete all realtime members that have been deleted in DB. */ 01577 mem_iter = ao2_iterator_init(q->members, 0); 01578 while ((m = ao2_iterator_next(&mem_iter))) { 01579 if (m->dead) { 01580 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 01581 ao2_unlink(q->members, m); 01582 remove_from_interfaces(m->state_interface, 0); 01583 q->membercount--; 01584 } 01585 ao2_ref(m, -1); 01586 } 01587 01588 ao2_unlock(q); 01589 01590 return q; 01591 }
| static void free_members | ( | struct call_queue * | q, | |
| int | all | |||
| ) | [static] |
Iterate through queue's member list and delete them.
Definition at line 1405 of file app_queue.c.
References 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().
01406 { 01407 /* Free non-dynamic members */ 01408 struct member *cur; 01409 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01410 01411 while ((cur = ao2_iterator_next(&mem_iter))) { 01412 if (all || !cur->dynamic) { 01413 ao2_unlink(q->members, cur); 01414 remove_from_interfaces(cur->state_interface, 1); 01415 q->membercount--; 01416 } 01417 ao2_ref(cur, -1); 01418 } 01419 }
| static int get_member_penalty | ( | char * | queuename, | |
| char * | interface | |||
| ) | [static] |
Definition at line 4369 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().
04370 { 04371 int foundqueue = 0, penalty; 04372 struct call_queue *q, tmpq = { 04373 .name = queuename, 04374 }; 04375 struct member *mem; 04376 04377 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 04378 foundqueue = 1; 04379 ao2_lock(q); 04380 if ((mem = interface_exists(q, interface))) { 04381 penalty = mem->penalty; 04382 ao2_ref(mem, -1); 04383 ao2_unlock(q); 04384 queue_unref(q); 04385 return penalty; 04386 } 04387 ao2_unlock(q); 04388 queue_unref(q); 04389 } 04390 04391 /* some useful debuging */ 04392 if (foundqueue) 04393 ast_log (LOG_ERROR, "Invalid queuename\n"); 04394 else 04395 ast_log (LOG_ERROR, "Invalid interface\n"); 04396 04397 return RESULT_FAILURE; 04398 }
| 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 667 of file app_queue.c.
References 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().
00668 { 00669 struct member *member; 00670 struct ao2_iterator mem_iter; 00671 enum queue_member_status result = QUEUE_NO_MEMBERS; 00672 00673 ao2_lock(q); 00674 mem_iter = ao2_iterator_init(q->members, 0); 00675 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) { 00676 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) 00677 continue; 00678 00679 switch (member->status) { 00680 case AST_DEVICE_INVALID: 00681 /* nothing to do */ 00682 break; 00683 case AST_DEVICE_UNAVAILABLE: 00684 if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS) 00685 result = QUEUE_NO_REACHABLE_MEMBERS; 00686 break; 00687 default: 00688 if (member->paused) { 00689 result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS; 00690 } else { 00691 ao2_unlock(q); 00692 ao2_ref(member, -1); 00693 return QUEUE_NORMAL; 00694 } 00695 break; 00696 } 00697 } 00698 00699 ao2_unlock(q); 00700 return result; 00701 }
| static char* handle_queue_add_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6280 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.
06281 { 06282 char *queuename, *interface, *membername = NULL, *state_interface = NULL; 06283 int penalty; 06284 06285 switch ( cmd ) { 06286 case CLI_INIT: 06287 e->command = "queue add member"; 06288 e->usage = 06289 "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n" 06290 " Add a channel to a queue with optionally: a penalty, membername and a state_interface\n"; 06291 return NULL; 06292 case CLI_GENERATE: 06293 return complete_queue_add_member(a->line, a->word, a->pos, a->n); 06294 } 06295 06296 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) { 06297 return CLI_SHOWUSAGE; 06298 } else if (strcmp(a->argv[4], "to")) { 06299 return CLI_SHOWUSAGE; 06300 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) { 06301 return CLI_SHOWUSAGE; 06302 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) { 06303 return CLI_SHOWUSAGE; 06304 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) { 06305 return CLI_SHOWUSAGE; 06306 } 06307 06308 queuename = a->argv[5]; 06309 interface = a->argv[3]; 06310 if (a->argc >= 8) { 06311 if (sscanf(a->argv[7], "%30d", &penalty) == 1) { 06312 if (penalty < 0) { 06313 ast_cli(a->fd, "Penalty must be >= 0\n"); 06314 penalty = 0; 06315 } 06316 } else { 06317 ast_cli(a->fd, "Penalty must be an integer >= 0\n"); 06318 penalty = 0; 06319 } 06320 } else { 06321 penalty = 0; 06322 } 06323 06324 if (a->argc >= 10) { 06325 membername = a->argv[9]; 06326 } 06327 06328 if (a->argc >= 12) { 06329 state_interface = a->argv[11]; 06330 } 06331 06332 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { 06333 case RES_OKAY: 06334 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 06335 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 06336 return CLI_SUCCESS; 06337 case RES_EXISTS: 06338 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 06339 return CLI_FAILURE; 06340 case RES_NOSUCHQUEUE: 06341 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 06342 return CLI_FAILURE; 06343 case RES_OUTOFMEMORY: 06344 ast_cli(a->fd, "Out of memory\n"); 06345 return CLI_FAILURE; 06346 case RES_NOT_DYNAMIC: 06347 ast_cli(a->fd, "Member not dynamic\n"); 06348 return CLI_FAILURE; 06349 default: 06350 return CLI_FAILURE; 06351 } 06352 }
| static char* handle_queue_pause_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6457 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.
06458 { 06459 char *queuename, *interface, *reason; 06460 int paused; 06461 06462 switch (cmd) { 06463 case CLI_INIT: 06464 e->command = "queue {pause|unpause} member"; 06465 e->usage = 06466 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n" 06467 " Pause or unpause a queue member. Not specifying a particular queue\n" 06468 " will pause or unpause a member across all queues to which the member\n" 06469 " belongs.\n"; 06470 return NULL; 06471 case CLI_GENERATE: 06472 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n); 06473 } 06474 06475 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) { 06476 return CLI_SHOWUSAGE; 06477 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) { 06478 return CLI_SHOWUSAGE; 06479 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) { 06480 return CLI_SHOWUSAGE; 06481 } 06482 06483 06484 interface = a->argv[3]; 06485 queuename = a->argc >= 6 ? a->argv[5] : NULL; 06486 reason = a->argc == 8 ? a->argv[7] : NULL; 06487 paused = !strcasecmp(a->argv[1], "pause"); 06488 06489 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) { 06490 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface); 06491 if (!ast_strlen_zero(queuename)) 06492 ast_cli(a->fd, " in queue '%s'", queuename); 06493 if (!ast_strlen_zero(reason)) 06494 ast_cli(a->fd, " for reason '%s'", reason); 06495 ast_cli(a->fd, "\n"); 06496 return CLI_SUCCESS; 06497 } else { 06498 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface); 06499 if (!ast_strlen_zero(queuename)) 06500 ast_cli(a->fd, " in queue '%s'", queuename); 06501 if (!ast_strlen_zero(reason)) 06502 ast_cli(a->fd, " for reason '%s'", reason); 06503 ast_cli(a->fd, "\n"); 06504 return CLI_FAILURE; 06505 } 06506 }
| static char* handle_queue_remove_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6395 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.
06396 { 06397 char *queuename, *interface; 06398 06399 switch (cmd) { 06400 case CLI_INIT: 06401 e->command = "queue remove member"; 06402 e->usage = 06403 "Usage: queue remove member <channel> from <queue>\n" 06404 " Remove a specific channel from a queue.\n"; 06405 return NULL; 06406 case CLI_GENERATE: 06407 return complete_queue_remove_member(a->line, a->word, a->pos, a->n); 06408 } 06409 06410 if (a->argc != 6) { 06411 return CLI_SHOWUSAGE; 06412 } else if (strcmp(a->argv[4], "from")) { 06413 return CLI_SHOWUSAGE; 06414 } 06415 06416 queuename = a->argv[5]; 06417 interface = a->argv[3]; 06418 06419 switch (remove_from_queue(queuename, interface)) { 06420 case RES_OKAY: 06421 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 06422 ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 06423 return CLI_SUCCESS; 06424 case RES_EXISTS: 06425 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 06426 return CLI_FAILURE; 06427 case RES_NOSUCHQUEUE: 06428 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 06429 return CLI_FAILURE; 06430 case RES_OUTOFMEMORY: 06431 ast_cli(a->fd, "Out of memory\n"); 06432 return CLI_FAILURE; 06433 default: 06434 return CLI_FAILURE; 06435 } 06436 }
| static char* handle_queue_rule_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6627 of file app_queue.c.
References CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, reload_queue_rules(), and ast_cli_entry::usage.
06628 { 06629 switch (cmd) { 06630 case CLI_INIT: 06631 e->command = "queue rules reload"; 06632 e->usage = 06633 "Usage: queue rules reload\n" 06634 " Reloads rules defined in queuerules.conf\n"; 06635 return NULL; 06636 case CLI_GENERATE: 06637 return NULL; 06638 } 06639 reload_queue_rules(1); 06640 return CLI_SUCCESS; 06641 }
| static char* handle_queue_rule_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6593 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.
06594 { 06595 char *rule; 06596 struct rule_list *rl_iter; 06597 struct penalty_rule *pr_iter; 06598 switch (cmd) { 06599 case CLI_INIT: 06600 e->command = "queue rules show"; 06601 e->usage = 06602 "Usage: queue rules show [rulename]\n" 06603 " Show the list of rules associated with rulename. If no\n" 06604 " rulename is specified, list all rules defined in queuerules.conf\n"; 06605 return NULL; 06606 case CLI_GENERATE: 06607 return complete_queue_rule_show(a->line, a->word, a->pos, a->n); 06608 } 06609 06610 if (a->argc != 3 && a->argc != 4) 06611 return CLI_SHOWUSAGE; 06612 06613 rule = a->argc == 4 ? a->argv[3] : ""; 06614 AST_LIST_LOCK(&rule_lists); 06615 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 06616 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) { 06617 ast_cli(a->fd, "Rule: %s\n", rl_iter->name); 06618 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 06619 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); 06620 } 06621 } 06622 } 06623 AST_LIST_UNLOCK(&rule_lists); 06624 return CLI_SUCCESS; 06625 }
| static char* handle_queue_set_member_penalty | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6531 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.
06532 { 06533 char *queuename = NULL, *interface; 06534 int penalty = 0; 06535 06536 switch (cmd) { 06537 case CLI_INIT: 06538 e->command = "queue set penalty"; 06539 e->usage = 06540 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n" 06541 " Set a member's penalty in the queue specified. If no queue is specified\n" 06542 " then that interface's penalty is set in all queues to which that interface is a member\n"; 06543 return NULL; 06544 case CLI_GENERATE: 06545 return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n); 06546 } 06547 06548 if (a->argc != 6 && a->argc != 8) { 06549 return CLI_SHOWUSAGE; 06550 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) { 06551 return CLI_SHOWUSAGE; 06552 } 06553 06554 if (a->argc == 8) 06555 queuename = a->argv[7]; 06556 interface = a->argv[5]; 06557 penalty = atoi(a->argv[3]); 06558 06559 switch (set_member_penalty(queuename, interface, penalty)) { 06560 case RESULT_SUCCESS: 06561 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename); 06562 return CLI_SUCCESS; 06563 case RESULT_FAILURE: 06564 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename); 06565 return CLI_FAILURE; 06566 default: 06567 return CLI_FAILURE; 06568 } 06569 }
| static int handle_statechange | ( | void * | datap | ) | [static] |
set a member's status based on device state of that member's interface
Definition at line 767 of file app_queue.c.
References ast_copy_string(), ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, statechange::dev, devstate2str(), member_interface::interface, statechange::state, and update_status().
Referenced by device_state_cb().
00768 { 00769 struct member_interface *curint; 00770 struct statechange *sc = datap; 00771 char interface[80]; 00772 00773 AST_LIST_LOCK(&interfaces); 00774 AST_LIST_TRAVERSE(&interfaces, curint, list) { 00775 char *slash_pos; 00776 ast_copy_string(interface, curint->interface, sizeof(interface)); 00777 if ((slash_pos = strchr(interface, '/'))) 00778 if ((slash_pos = strchr(slash_pos + 1, '/'))) 00779 *slash_pos = '\0'; 00780 00781 if (!strcasecmp(interface, sc->dev)) 00782 break; 00783 } 00784 AST_LIST_UNLOCK(&interfaces); 00785 00786 if (!curint) { 00787 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)); 00788 ast_free(sc); 00789 return 0; 00790 } 00791 00792 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, devstate2str(sc->state)); 00793 00794 update_status(sc->dev, sc->state); 00795 ast_free(sc); 00796 return 0; 00797 }
| static void hangupcalls | ( | struct callattempt * | outgoing, | |
| struct ast_channel * | exception | |||
| ) | [static] |
Hang up a list of outgoing calls.
Definition at line 2058 of file app_queue.c.
References ao2_ref, ast_free, ast_hangup(), callattempt::chan, callattempt::member, and callattempt::q_next.
Referenced by try_calling().
02059 { 02060 struct callattempt *oo; 02061 02062 while (outgoing) { 02063 /* Hangup any existing lines we have open */ 02064 if (outgoing->chan && (outgoing->chan != exception)) 02065 ast_hangup(outgoing->chan); 02066 oo = outgoing; 02067 outgoing = outgoing->q_next; 02068 if (oo->member) 02069 ao2_ref(oo->member, -1); 02070 ast_free(oo); 02071 } 02072 }
| static void init_queue | ( | struct call_queue * | q | ) | [static] |
Initialize Queue default values.
Definition at line 883 of file app_queue.c.
References call_queue::announcefrequency, call_queue::announceholdtime, call_queue::announceposition, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, ao2_container_alloc, ast_free, AST_LIST_REMOVE_HEAD, ast_str_create(), ast_str_set(), ast_string_field_set, call_queue::autofill, call_queue::dead, DEFAULT_MIN_ANNOUNCE_FREQUENCY, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::eventwhencalled, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, call_queue::maskmemberstatus, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, member_cmp_fn(), member_hash_fn(), call_queue::membercount, call_queue::memberdelay, call_queue::members, call_queue::minannouncefrequency, call_queue::monfmt, call_queue::montype, call_queue::numperiodicannounce, call_queue::periodicannouncefrequency, QUEUE_STRATEGY_LINEAR, call_queue::randomperiodicannounce, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::roundingseconds, call_queue::rules, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::setqueueentryvar, call_queue::setqueuevar, call_queue::sound_periodicannounce, call_queue::strategy, call_queue::timeout, TIMEOUT_PRIORITY_APP, call_queue::timeoutpriority, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_queues().
00884 { 00885 int i; 00886 struct penalty_rule *pr_iter; 00887 00888 q->dead = 0; 00889 q->retry = DEFAULT_RETRY; 00890 q->timeout = DEFAULT_TIMEOUT; 00891 q->maxlen = 0; 00892 q->announcefrequency = 0; 00893 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY; 00894 q->announceholdtime = 1; 00895 q->announcepositionlimit = 10; /* Default 10 positions */ 00896 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */ 00897 q->roundingseconds = 0; /* Default - don't announce seconds */ 00898 q->servicelevel = 0; 00899 q->ringinuse = 1; 00900 q->setinterfacevar = 0; 00901 q->setqueuevar = 0; 00902 q->setqueueentryvar = 0; 00903 q->autofill = autofill_default; 00904 q->montype = montype_default; 00905 q->monfmt[0] = '\0'; 00906 q->reportholdtime = 0; 00907 q->wrapuptime = 0; 00908 q->joinempty = 0; 00909 q->leavewhenempty = 0; 00910 q->memberdelay = 0; 00911 q->maskmemberstatus = 0; 00912 q->eventwhencalled = 0; 00913 q->weight = 0; 00914 q->timeoutrestart = 0; 00915 q->periodicannouncefrequency = 0; 00916 q->randomperiodicannounce = 0; 00917 q->numperiodicannounce = 0; 00918 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 00919 if (!q->members) { 00920 if (q->strategy == QUEUE_STRATEGY_LINEAR) 00921 /* linear strategy depends on order, so we have to place all members in a single bucket */ 00922 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn); 00923 else 00924 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn); 00925 } 00926 q->membercount = 0; 00927 q->found = 1; 00928 00929 ast_string_field_set(q, sound_next, "queue-youarenext"); 00930 ast_string_field_set(q, sound_thereare, "queue-thereare"); 00931 ast_string_field_set(q, sound_calls, "queue-callswaiting"); 00932 ast_string_field_set(q, queue_quantity1, "queue-quantity1"); 00933 ast_string_field_set(q, queue_quantity2, "queue-quantity2"); 00934 ast_string_field_set(q, sound_holdtime, "queue-holdtime"); 00935 ast_string_field_set(q, sound_minutes, "queue-minutes"); 00936 ast_string_field_set(q, sound_minute, "queue-minute"); 00937 ast_string_field_set(q, sound_seconds, "queue-seconds"); 00938 ast_string_field_set(q, sound_thanks, "queue-thankyou"); 00939 ast_string_field_set(q, sound_reporthold, "queue-reporthold"); 00940 00941 if ((q->sound_periodicannounce[0] = ast_str_create(32))) 00942 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce"); 00943 00944 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 00945 if (q->sound_periodicannounce[i]) 00946 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", ""); 00947 } 00948 00949 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) 00950 ast_free(pr_iter); 00951 }
| 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 635 of file app_queue.c.
References call_queue::head, queue_ent::next, and queue_ent::parent.
Referenced by join_queue().
00636 { 00637 struct queue_ent *cur; 00638 00639 if (!q || !new) 00640 return; 00641 if (prev) { 00642 cur = prev->next; 00643 prev->next = new; 00644 } else { 00645 cur = q->head; 00646 q->head = new; 00647 } 00648 new->next = cur; 00649 new->parent = q; 00650 new->pos = ++(*pos); 00651 new->opos = *pos; 00652 }
| 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 1055 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().
01056 { 01057 char *timestr, *maxstr, *minstr, *contentdup; 01058 struct penalty_rule *rule = NULL, *rule_iter; 01059 struct rule_list *rl_iter; 01060 int penaltychangetime, inserted = 0; 01061 01062 if (!(rule = ast_calloc(1, sizeof(*rule)))) { 01063 ast_log(LOG_ERROR, "Cannot allocate memory for penaltychange rule at line %d!\n", linenum); 01064 return -1; 01065 } 01066 01067 contentdup = ast_strdupa(content); 01068 01069 if (!(maxstr = strchr(contentdup, ','))) { 01070 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum); 01071 ast_free(rule); 01072 return -1; 01073 } 01074 01075 *maxstr++ = '\0'; 01076 timestr = contentdup; 01077 01078 if ((penaltychangetime = atoi(timestr)) < 0) { 01079 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum); 01080 ast_free(rule); 01081 return -1; 01082 } 01083 01084 rule->time = penaltychangetime; 01085 01086 if ((minstr = strchr(maxstr,','))) 01087 *minstr++ = '\0'; 01088 01089 /* The last check will evaluate true if either no penalty change is indicated for a given rule 01090 * OR if a min penalty change is indicated but no max penalty change is */ 01091 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') { 01092 rule->max_relative = 1; 01093 } 01094 01095 rule->max_value = atoi(maxstr); 01096 01097 if (!ast_strlen_zero(minstr)) { 01098 if (*minstr == '+' || *minstr == '-') 01099 rule->min_relative = 1; 01100 rule->min_value = atoi(minstr); 01101 } else /*there was no minimum specified, so assume this means no change*/ 01102 rule->min_relative = 1; 01103 01104 /*We have the rule made, now we need to insert it where it belongs*/ 01105 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){ 01106 if (strcasecmp(rl_iter->name, list_name)) 01107 continue; 01108 01109 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) { 01110 if (rule->time < rule_iter->time) { 01111 AST_LIST_INSERT_BEFORE_CURRENT(rule, list); 01112 inserted = 1; 01113 break; 01114 } 01115 } 01116 AST_LIST_TRAVERSE_SAFE_END; 01117 01118 if (!inserted) { 01119 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list); 01120 } 01121 } 01122 01123 return 0; 01124 }
| static const char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 566 of file app_queue.c.
References ARRAY_LEN, strategy::name, and strategies.
Referenced by __queues_show(), manager_queues_status(), queue_function_var(), and set_queue_variables().
00567 { 00568 int x; 00569 00570 for (x = 0; x < ARRAY_LEN(strategies); x++) { 00571 if (strategy == strategies[x].strategy) 00572 return strategies[x].name; 00573 } 00574 00575 return "<unknown>"; 00576 }
| static struct member* interface_exists | ( | struct call_queue * | q, | |
| const char * | interface | |||
| ) | [static, read] |
Definition at line 4069 of file app_queue.c.
References 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().
04070 { 04071 struct member *mem; 04072 struct ao2_iterator mem_iter; 04073 04074 if (!q) 04075 return NULL; 04076 04077 mem_iter = ao2_iterator_init(q->members, 0); 04078 while ((mem = ao2_iterator_next(&mem_iter))) { 04079 if (!strcasecmp(interface, mem->interface)) 04080 return mem; 04081 ao2_ref(mem, -1); 04082 } 04083 04084 return NULL; 04085 }
| static int interface_exists_global | ( | const char * | interface, | |
| int | lock_queue_container | |||
| ) | [static] |
Definition at line 988 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), ast_copy_string(), F_AO2I_DONTLOCK, member::interface, call_queue::members, queue_unref(), queues, and member::state_interface.
Referenced by remove_from_interfaces().
00989 { 00990 struct call_queue *q; 00991 struct member *mem, tmpmem; 00992 struct ao2_iterator queue_iter, mem_iter; 00993 int ret = 0; 00994 00995 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 00996 queue_iter = ao2_iterator_init(queues, lock_queue_container ? 0 : F_AO2I_DONTLOCK); 00997 while ((q = ao2_iterator_next(&queue_iter))) { 00998 ao2_lock(q); 00999 mem_iter = ao2_iterator_init(q->members, 0); 01000 while ((mem = ao2_iterator_next(&mem_iter))) { 01001 if (!strcasecmp(mem->state_interface, interface)) { 01002 ao2_ref(mem, -1); 01003 ret = 1; 01004 break; 01005 } 01006 } 01007 ao2_unlock(q); 01008 queue_unref(q); 01009 } 01010 01011 return ret; 01012 }
| 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 2849 of file app_queue.c.
References ao2_lock(), ao2_unlock(), ast_debug, queue_ent::chan, call_queue::head, queue_ent::next, num_available_members(), queue_ent::parent, and queue_ent::pending.
Referenced by queue_exec(), and wait_our_turn().
02850 { 02851 struct queue_ent *ch; 02852 int res; 02853 int avl; 02854 int idx = 0; 02855 /* This needs a lock. How many members are available to be served? */ 02856 ao2_lock(qe->parent); 02857 02858 avl = num_available_members(qe->parent); 02859 02860 ch = qe->parent->head; 02861 02862 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member"); 02863 02864 while ((idx < avl) && (ch) && (ch != qe)) { 02865 if (!ch->pending) 02866 idx++; 02867 ch = ch->next; 02868 } 02869 02870 ao2_unlock(qe->parent); 02871 02872 /* If the queue entry is within avl [the number of available members] calls from the top ... */ 02873 if (ch && idx < avl) { 02874 ast_debug(1, "It's our turn (%s).\n", qe->chan->name); 02875 res = 1; 02876 } else { 02877 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name); 02878 res = 0; 02879 } 02880 02881 return res; 02882 }
| static int join_queue | ( | char * | queuename, | |
| struct queue_ent * | qe, | |||
| enum queue_result * | reason, | |||
| const char * | overriding_rule | |||
| ) | [static] |
Definition at line 1701 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, queue_ent::next, queue_ent::pos, queue_ent::pr, queue_ent::prio, queue_ent::qe_rules, QUEUE_EMPTY_LOOSE, QUEUE_EMPTY_STRICT, QUEUE_FULL, QUEUE_JOINEMPTY, QUEUE_JOINUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, queues, S_OR, status, and update_qe_rule().
Referenced by queue_exec().
01702 { 01703 struct call_queue *q; 01704 struct queue_ent *cur, *prev = NULL; 01705 int res = -1; 01706 int pos = 0; 01707 int inserted = 0; 01708 enum queue_member_status status; 01709 int exit = 0; 01710 01711 if (!(q = load_realtime_queue(queuename))) 01712 return res; 01713 01714 ao2_lock(queues); 01715 ao2_lock(q); 01716 01717 copy_rules(qe, S_OR(overriding_rule, q->defaultrule)); 01718 qe->pr = AST_LIST_FIRST(&qe->qe_rules); 01719 01720 /* This is our one */ 01721 while (!exit) { 01722 status = get_member_status(q, qe->max_penalty, qe->min_penalty); 01723 if (!q->joinempty && (status == QUEUE_NO_MEMBERS)) 01724 *reason = QUEUE_JOINEMPTY; 01725 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS || status == QUEUE_NO_MEMBERS)) 01726 *reason = QUEUE_JOINUNAVAIL; 01727 else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_MEMBERS)) 01728 *reason = QUEUE_JOINUNAVAIL; 01729 else if (q->maxlen && (q->count >= q->maxlen)) 01730 *reason = QUEUE_FULL; 01731 else { 01732 /* There's space for us, put us at the right position inside 01733 * the queue. 01734 * Take into account the priority of the calling user */ 01735 inserted = 0; 01736 prev = NULL; 01737 cur = q->head; 01738 while (cur) { 01739 /* We have higher priority than the current user, enter 01740 * before him, after all the other users with priority 01741 * higher or equal to our priority. */ 01742 if ((!inserted) && (qe->prio > cur->prio)) { 01743 insert_entry(q, prev, qe, &pos); 01744 inserted = 1; 01745 } 01746 cur->pos = ++pos; 01747 prev = cur; 01748 cur = cur->next; 01749 } 01750 /* No luck, join at the end of the queue */ 01751 if (!inserted) 01752 insert_entry(q, prev, qe, &pos); 01753 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 01754 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 01755 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 01756 q->count++; 01757 res = 0; 01758 manager_event(EVENT_FLAG_CALL, "Join", 01759 "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n", 01760 qe->chan->name, 01761 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */ 01762 S_OR(qe->chan->cid.cid_name, "unknown"), 01763 q->name, qe->pos, q->count, qe->chan->uniqueid ); 01764 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 01765 } 01766 if (!exit && qe->pr && res) { 01767 /* We failed to join the queue, but perhaps we can join if we move 01768 * to the next defined penalty rule 01769 */ 01770 update_qe_rule(qe); 01771 } else { 01772 exit = 1; 01773 } 01774 } 01775 ao2_unlock(q); 01776 ao2_unlock(queues); 01777 01778 return res; 01779 }
| 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 2001 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, queue_ent::next, queue_ent::parent, queue_ent::pos, queue_ent::qe_rules, queue_ref(), queue_unref(), queues, call_queue::realtime, SENTINEL, and var.
Referenced by queue_exec(), try_calling(), and wait_our_turn().
02002 { 02003 struct call_queue *q; 02004 struct queue_ent *current, *prev = NULL; 02005 struct penalty_rule *pr_iter; 02006 int pos = 0; 02007 02008 if (!(q = qe->parent)) 02009 return; 02010 queue_ref(q); 02011 ao2_lock(q); 02012 02013 prev = NULL; 02014 for (current = q->head; current; current = current->next) { 02015 if (current == qe) { 02016 q->count--; 02017 02018 /* Take us out of the queue */ 02019 manager_event(EVENT_FLAG_CALL, "Leave", 02020 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n", 02021 qe->chan->name, q->name, q->count, qe->chan->uniqueid); 02022 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 02023 /* Take us out of the queue */ 02024 if (prev) 02025 prev->next = current->next; 02026 else 02027 q->head = current->next; 02028 /* Free penalty rules */ 02029 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) 02030 ast_free(pr_iter); 02031 } else { 02032 /* Renumber the people after us in the queue based on a new count */ 02033 current->pos = ++pos; 02034 prev = current; 02035 } 02036 } 02037 ao2_unlock(q); 02038 02039 /*If the queue is a realtime queue, check to see if it's still defined in real time*/ 02040 if (q->realtime) { 02041 struct ast_variable *var; 02042 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) { 02043 q->dead = 1; 02044 } else { 02045 ast_variables_destroy(var); 02046 } 02047 } 02048 02049 if (q->dead) { 02050 /* It's dead and nobody is in it, so kill it */ 02051 ao2_unlink(queues, q); 02052 } 02053 /* unref the explicit ref earlier in the function */ 02054 queue_unref(q); 02055 }
| static int load_module | ( | void | ) | [static] |
Definition at line 6713 of file app_queue.c.
References ao2_container_alloc, aqm_exec(), ast_add_extension2(), ast_cli_register_multiple(), ast_context_find_or_create(), ast_custom_function_register, AST_EVENT_DEVICE_STATE, AST_EVENT_IE_END, ast_event_subscribe(), ast_free_ptr(), ast_log(), ast_manager_register, AST_MODULE_LOAD_DECLINE, ast_realtime_require_field(), ast_register_application, ast_strdup, ast_taskprocessor_get(), cli_queue, device_state_cb(), EVENT_FLAG_AGENT, LOG_ERROR, LOG_WARNING, manager_add_queue_member(), manager_pause_queue_member(), manager_queue_log_custom(), manager_queue_member_penalty(), manager_queue_rule_show(), manager_queues_show(), manager_queues_status(), manager_queues_summary(), manager_remove_queue_member(), MAX_QUEUE_BUCKETS, pqm_exec(), ql_exec(), queue_cmp_cb(), queue_exec(), queue_hash_cb(), queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queuevar_function, queuewaitingcount_function, reload_queue_members(), reload_queues(), RQ_INTEGER1, RQ_UINTEGER2, rqm_exec(), SENTINEL, and upqm_exec().
06714 { 06715 int res; 06716 struct ast_context *con; 06717 06718 queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb); 06719 06720 if (!reload_queues(0)) 06721 return AST_MODULE_LOAD_DECLINE; 06722 06723 con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue"); 06724 if (!con) 06725 ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n"); 06726 else 06727 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue"); 06728 06729 if (queue_persistent_members) 06730 reload_queue_members(); 06731 06732 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 06733 res = ast_register_application(app, queue_exec, synopsis, descrip); 06734 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip); 06735 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip); 06736 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip); 06737 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip); 06738 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip); 06739 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues"); 06740 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status"); 06741 res |= ast_manager_register("QueueSummary", 0, manager_queues_summary, "Queue Summary"); 06742 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue."); 06743 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue."); 06744 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable"); 06745 res |= ast_manager_register("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom, "Adds custom entry in queue_log"); 06746 res |= ast_manager_register("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty, "Set the penalty for a queue member"); 06747 res |= ast_manager_register("QueueRule", 0, manager_queue_rule_show, "Queue Rules"); 06748 res |= ast_custom_function_register(&queuevar_function); 06749 res |= ast_custom_function_register(&queuemembercount_function); 06750 res |= ast_custom_function_register(&queuemembercount_dep); 06751 res |= ast_custom_function_register(&queuememberlist_function); 06752 res |= ast_custom_function_register(&queuewaitingcount_function); 06753 res |= ast_custom_function_register(&queuememberpenalty_function); 06754 06755 if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) { 06756 ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n"); 06757 } 06758 06759 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL, AST_EVENT_IE_END))) { 06760 res = -1; 06761 } 06762 06763 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL); 06764 06765 return res ? AST_MODULE_LOAD_DECLINE : 0; 06766 }
| static struct call_queue* load_realtime_queue | ( | const char * | queuename | ) | [static, read] |
This will be two separate database transactions, so we might see queue parameters as they were before another process changed the queue and member list as it was after the change. Thus we might see an empty member list when a queue is deleted. In practise, this is unlikely to cause a problem.
Definition at line 1593 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, SENTINEL, and update_realtime_members().
Referenced by __queues_show(), add_to_queue(), join_queue(), queue_function_qac(), queue_function_qac_dep(), and reload_queue_members().
01594 { 01595 struct ast_variable *queue_vars; 01596 struct ast_config *member_config = NULL; 01597 struct call_queue *q = NULL, tmpq = { 01598 .name = queuename, 01599 }; 01600 01601 /* Find the queue in the in-core list first. */ 01602 q = ao2_find(queues, &tmpq, OBJ_POINTER); 01603 01604 if (!q || q->realtime) { 01605 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all 01606 queue operations while waiting for the DB. 01607 01608 This will be two separate database transactions, so we might 01609 see queue parameters as they were before another process 01610 changed the queue and member list as it was after the change. 01611 Thus we might see an empty member list when a queue is 01612 deleted. In practise, this is unlikely to cause a problem. */ 01613 01614 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL); 01615 if (queue_vars) { 01616 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL); 01617 if (!member_config) { 01618 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n"); 01619 ast_variables_destroy(queue_vars); 01620 return NULL; 01621 } 01622 } 01623 01624 ao2_lock(queues); 01625 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 01626 if (member_config) 01627 ast_config_destroy(member_config); 01628 if (queue_vars) 01629 ast_variables_destroy(queue_vars); 01630 ao2_unlock(queues); 01631 01632 } else { 01633 update_realtime_members(q); 01634 } 01635 return q; 01636 }
| static int manager_add_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6094 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().
06095 { 06096 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; 06097 int paused, penalty = 0; 06098 06099 queuename = astman_get_header(m, "Queue"); 06100 interface = astman_get_header(m, "Interface"); 06101 penalty_s = astman_get_header(m, "Penalty"); 06102 paused_s = astman_get_header(m, "Paused"); 06103 membername = astman_get_header(m, "MemberName"); 06104 state_interface = astman_get_header(m, "StateInterface"); 06105 06106 if (ast_strlen_zero(queuename)) { 06107 astman_send_error(s, m, "'Queue' not specified."); 06108 return 0; 06109 } 06110 06111 if (ast_strlen_zero(interface)) { 06112 astman_send_error(s, m, "'Interface' not specified."); 06113 return 0; 06114 } 06115 06116 if (ast_strlen_zero(penalty_s)) 06117 penalty = 0; 06118 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) 06119 penalty = 0; 06120 06121 if (ast_strlen_zero(paused_s)) 06122 paused = 0; 06123 else 06124 paused = abs(ast_true(paused_s)); 06125 06126 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { 06127 case RES_OKAY: 06128 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", ""); 06129 astman_send_ack(s, m, "Added interface to queue"); 06130 break; 06131 case RES_EXISTS: 06132 astman_send_error(s, m, "Unable to add interface: Already there"); 06133 break; 06134 case RES_NOSUCHQUEUE: 06135 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 06136 break; 06137 case RES_OUTOFMEMORY: 06138 astman_send_error(s, m, "Out of memory"); 06139 break; 06140 } 06141 06142 return 0; 06143 }
| static int manager_pause_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6179 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().
06180 { 06181 const char *queuename, *interface, *paused_s, *reason; 06182 int paused; 06183 06184 interface = astman_get_header(m, "Interface"); 06185 paused_s = astman_get_header(m, "Paused"); 06186 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 06187 reason = astman_get_header(m, "Reason"); /* Optional - Only used for logging purposes */ 06188 06189 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 06190 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 06191 return 0; 06192 } 06193 06194 paused = abs(ast_true(paused_s)); 06195 06196 if (set_member_paused(queuename, interface, reason, paused)) 06197 astman_send_error(s, m, "Interface not found"); 06198 else 06199 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 06200 return 0; 06201 }
| static int manager_queue_log_custom | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6203 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().
06204 { 06205 const char *queuename, *event, *message, *interface, *uniqueid; 06206 06207 queuename = astman_get_header(m, "Queue"); 06208 uniqueid = astman_get_header(m, "UniqueId"); 06209 interface = astman_get_header(m, "Interface"); 06210 event = astman_get_header(m, "Event"); 06211 message = astman_get_header(m, "Message"); 06212 06213 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) { 06214 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters."); 06215 return 0; 06216 } 06217 06218 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message); 06219 astman_send_ack(s, m, "Event added successfully"); 06220 06221 return 0; 06222 }
| static int manager_queue_member_penalty | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6255 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().
06256 { 06257 const char *queuename, *interface, *penalty_s; 06258 int penalty; 06259 06260 interface = astman_get_header(m, "Interface"); 06261 penalty_s = astman_get_header(m, "Penalty"); 06262 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */ 06263 queuename = astman_get_header(m, "Queue"); 06264 06265 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) { 06266 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters."); 06267 return 0; 06268 } 06269 06270 penalty = atoi(penalty_s); 06271 06272 if (set_member_penalty((char *)queuename, (char *)interface, penalty)) 06273 astman_send_error(s, m, "Invalid interface, queuename or penalty"); 06274 else 06275 astman_send_ack(s, m, "Interface penalty set successfully"); 06276 06277 return 0; 06278 }
| static int manager_queue_rule_show | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 5904 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().
05905 { 05906 const char *rule = astman_get_header(m, "Rule"); 05907 struct rule_list *rl_iter; 05908 struct penalty_rule *pr_iter; 05909 05910 AST_LIST_LOCK(&rule_lists); 05911 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 05912 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) { 05913 astman_append(s, "RuleList: %s\r\n", rl_iter->name); 05914 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 05915 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 ); 05916 } 05917 if (!ast_strlen_zero(rule)) 05918 break; 05919 } 05920 } 05921 AST_LIST_UNLOCK(&rule_lists); 05922 05923 astman_append(s, "\r\n\r\n"); 05924 05925 return RESULT_SUCCESS; 05926 }
| static int manager_queues_show | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 5894 of file app_queue.c.
References __queues_show(), astman_append(), and RESULT_SUCCESS.
Referenced by load_module().
05895 { 05896 char *a[] = { "queue", "show" }; 05897 05898 __queues_show(s, -1, 2, a); 05899 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 05900 05901 return RESULT_SUCCESS; 05902 }
| static int manager_queues_status | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Queue status info via AMI.
Definition at line 6001 of file app_queue.c.
References 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, 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().
06002 { 06003 time_t now; 06004 int pos; 06005 const char *id = astman_get_header(m,"ActionID"); 06006 const char *queuefilter = astman_get_header(m,"Queue"); 06007 const char *memberfilter = astman_get_header(m,"Member"); 06008 char idText[256] = ""; 06009 struct call_queue *q; 06010 struct queue_ent *qe; 06011 float sl = 0; 06012 struct member *mem; 06013 struct ao2_iterator queue_iter; 06014 struct ao2_iterator mem_iter; 06015 06016 astman_send_ack(s, m, "Queue status will follow"); 06017 time(&now); 06018 if (!ast_strlen_zero(id)) 06019 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 06020 06021 queue_iter = ao2_iterator_init(queues, 0); 06022 while ((q = ao2_iterator_next(&queue_iter))) { 06023 ao2_lock(q); 06024 06025 /* List queue properties */ 06026 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 06027 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 06028 astman_append(s, "Event: QueueParams\r\n" 06029 "Queue: %s\r\n" 06030 "Max: %d\r\n" 06031 "Strategy: %s\r\n" 06032 "Calls: %d\r\n" 06033 "Holdtime: %d\r\n" 06034 "Completed: %d\r\n" 06035 "Abandoned: %d\r\n" 06036 "ServiceLevel: %d\r\n" 06037 "ServicelevelPerf: %2.1f\r\n" 06038 "Weight: %d\r\n" 06039 "%s" 06040 "\r\n", 06041 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, 06042 q->callsabandoned, q->servicelevel, sl, q->weight, idText); 06043 /* List Queue Members */ 06044 mem_iter = ao2_iterator_init(q->members, 0); 06045 while ((mem = ao2_iterator_next(&mem_iter))) { 06046 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) { 06047 astman_append(s, "Event: QueueMember\r\n" 06048 "Queue: %s\r\n" 06049 "Name: %s\r\n" 06050 "Location: %s\r\n" 06051 "Membership: %s\r\n" 06052 "Penalty: %d\r\n" 06053 "CallsTaken: %d\r\n" 06054 "LastCall: %d\r\n" 06055 "Status: %d\r\n" 06056 "Paused: %d\r\n" 06057 "%s" 06058 "\r\n", 06059 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static", 06060 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 06061 } 06062 ao2_ref(mem, -1); 06063 } 06064 /* List Queue Entries */ 06065 pos = 1; 06066 for (qe = q->head; qe; qe = qe->next) { 06067 astman_append(s, "Event: QueueEntry\r\n" 06068 "Queue: %s\r\n" 06069 "Position: %d\r\n" 06070 "Channel: %s\r\n" 06071 "CallerIDNum: %s\r\n" 06072 "CallerIDName: %s\r\n" 06073 "Wait: %ld\r\n" 06074 "%s" 06075 "\r\n", 06076 q->name, pos++, qe->chan->name, 06077 S_OR(qe->chan->cid.cid_num, "unknown"), 06078 S_OR(qe->chan->cid.cid_name, "unknown"), 06079 (long) (now - qe->start), idText); 06080 } 06081 } 06082 ao2_unlock(q); 06083 queue_unref(q); 06084 } 06085 06086 astman_append(s, 06087 "Event: QueueStatusComplete\r\n" 06088 "%s" 06089 "\r\n",idText); 06090 06091 return RESULT_SUCCESS; 06092 }
| static int manager_queues_summary | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Summary of queue info via the AMI.
Definition at line 5929 of file app_queue.c.
References 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().
05930 { 05931 time_t now; 05932 int qmemcount = 0; 05933 int qmemavail = 0; 05934 int qchancount = 0; 05935 int qlongestholdtime = 0; 05936 const char *id = astman_get_header(m, "ActionID"); 05937 const char *queuefilter = astman_get_header(m, "Queue"); 05938 char idText[256] = ""; 05939 struct call_queue *q; 05940 struct queue_ent *qe; 05941 struct member *mem; 05942 struct ao2_iterator queue_iter; 05943 struct ao2_iterator mem_iter; 05944 05945 astman_send_ack(s, m, "Queue summary will follow"); 05946 time(&now); 05947 if (!ast_strlen_zero(id)) 05948 snprintf(idText, 256, "ActionID: %s\r\n", id); 05949 queue_iter = ao2_iterator_init(queues, 0); 05950 while ((q = ao2_iterator_next(&queue_iter))) { 05951 ao2_lock(q); 05952 05953 /* List queue properties */ 05954 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 05955 /* Reset the necessary local variables if no queuefilter is set*/ 05956 qmemcount = 0; 05957 qmemavail = 0; 05958 qchancount = 0; 05959 qlongestholdtime = 0; 05960 05961 /* List Queue Members */ 05962 mem_iter = ao2_iterator_init(q->members, 0); 05963 while ((mem = ao2_iterator_next(&mem_iter))) { 05964 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) { 05965 ++qmemcount; 05966 if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) { 05967 ++qmemavail; 05968 } 05969 } 05970 ao2_ref(mem, -1); 05971 } 05972 for (qe = q->head; qe; qe = qe->next) { 05973 if ((now - qe->start) > qlongestholdtime) { 05974 qlongestholdtime = now - qe->start; 05975 } 05976 ++qchancount; 05977 } 05978 astman_append(s, "Event: QueueSummary\r\n" 05979 "Queue: %s\r\n" 05980 "LoggedIn: %d\r\n" 05981 "Available: %d\r\n" 05982 "Callers: %d\r\n" 05983 "HoldTime: %d\r\n" 05984 "LongestHoldTime: %d\r\n" 05985 "%s" 05986 "\r\n", 05987 q->name, qmemcount, qmemavail, qchancount, q->holdtime, qlongestholdtime, idText); 05988 } 05989 ao2_unlock(q); 05990 queue_unref(q); 05991 } 05992 astman_append(s, 05993 "Event: QueueSummaryComplete\r\n" 05994 "%s" 05995 "\r\n", idText); 05996 05997 return RESULT_SUCCESS; 05998 }
| static int manager_remove_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6145 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().
06146 { 06147 const char *queuename, *interface; 06148 06149 queuename = astman_get_header(m, "Queue"); 06150 interface = astman_get_header(m, "Interface"); 06151 06152 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 06153 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 06154 return 0; 06155 } 06156 06157 switch (remove_from_queue(queuename, interface)) { 06158 case RES_OKAY: 06159 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 06160 astman_send_ack(s, m, "Removed interface from queue"); 06161 break; 06162 case RES_EXISTS: 06163 astman_send_error(s, m, "Unable to remove interface: Not there"); 06164 break; 06165 case RES_NOSUCHQUEUE: 06166 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 06167 break; 06168 case RES_OUTOFMEMORY: 06169 astman_send_error(s, m, "Out of memory"); 06170 break; 06171 case RES_NOT_DYNAMIC: 06172 astman_send_error(s, m, "Member not dynamic"); 06173 break; 06174 } 06175 06176 return 0; 06177 }
| static int member_cmp_fn | ( | void * | obj1, | |
| void * | obj2, | |||
| int | flags | |||
| ) | [static] |
Definition at line 873 of file app_queue.c.
References CMP_MATCH, CMP_STOP, and member::interface.
Referenced by init_queue().
| static int member_hash_fn | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 861 of file app_queue.c.
References compress_char(), and member::interface.
Referenced by init_queue().
00862 { 00863 const struct member *mem = obj; 00864 const char *chname = strchr(mem->interface, '/'); 00865 int ret = 0, i; 00866 if (!chname) 00867 chname = mem->interface; 00868 for (i = 0; i < 5 && chname[i]; i++) 00869 ret += compress_char(chname[i]) << (i * 6); 00870 return ret; 00871 }
| 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 2082 of file app_queue.c.
References 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().
02083 { 02084 struct member *mem; 02085 int avl = 0; 02086 struct ao2_iterator mem_iter; 02087 02088 mem_iter = ao2_iterator_init(q->members, 0); 02089 while ((mem = ao2_iterator_next(&mem_iter))) { 02090 switch (mem->status) { 02091 case AST_DEVICE_INUSE: 02092 if (!q->ringinuse) 02093 break; 02094 /* else fall through */ 02095 case AST_DEVICE_NOT_INUSE: 02096 case AST_DEVICE_UNKNOWN: 02097 if (!mem->paused) { 02098 avl++; 02099 } 02100 break; 02101 } 02102 ao2_ref(mem, -1); 02103 02104 /* If autofill is not enabled or if the queue's strategy is ringall, then 02105 * we really don't care about the number of available members so much as we 02106 * do that there is at least one available. 02107 * 02108 * In fact, we purposely will return from this function stating that only 02109 * one member is available if either of those conditions hold. That way, 02110 * functions which determine what action to take based on the number of available 02111 * members will operate properly. The reasoning is that even if multiple 02112 * members are available, only the head caller can actually be serviced. 02113 */ 02114 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) { 02115 break; 02116 } 02117 } 02118 02119 return avl; 02120 }
| static int play_file | ( | struct ast_channel * | chan, | |
| const char * | filename | |||
| ) | [static] |
Definition at line 1781 of file app_queue.c.
References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_strlen_zero(), and ast_waitstream().
Referenced by say_periodic_announcement(), say_position(), and try_calling().
01782 { 01783 int res; 01784 01785 if (ast_strlen_zero(filename)) { 01786 return 0; 01787 } 01788 01789 ast_stopstream(chan); 01790 01791 res = ast_streamfile(chan, filename, chan->language); 01792 if (!res) 01793 res = ast_waitstream(chan, AST_DIGIT_ANY); 01794 01795 ast_stopstream(chan); 01796 01797 return res; 01798 }
| static int pqm_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
PauseQueueMember application.
Definition at line 4498 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().
04499 { 04500 char *parse; 04501 AST_DECLARE_APP_ARGS(args, 04502 AST_APP_ARG(queuename); 04503 AST_APP_ARG(interface); 04504 AST_APP_ARG(options); 04505 AST_APP_ARG(reason); 04506 ); 04507 04508 if (ast_strlen_zero(data)) { 04509 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n"); 04510 return -1; 04511 } 04512 04513 parse = ast_strdupa(data); 04514 04515 AST_STANDARD_APP_ARGS(args, parse); 04516 04517 if (ast_strlen_zero(args.interface)) { 04518 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 04519 return -1; 04520 } 04521 04522 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) { 04523 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 04524 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 04525 return 0; 04526 } 04527 04528 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 04529 04530 return 0; 04531 }
| static int ql_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
QueueLog application.
Definition at line 4688 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().
04689 { 04690 char *parse; 04691 04692 AST_DECLARE_APP_ARGS(args, 04693 AST_APP_ARG(queuename); 04694 AST_APP_ARG(uniqueid); 04695 AST_APP_ARG(membername); 04696 AST_APP_ARG(event); 04697 AST_APP_ARG(params); 04698 ); 04699 04700 if (ast_strlen_zero(data)) { 04701 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n"); 04702 return -1; 04703 } 04704 04705 parse = ast_strdupa(data); 04706 04707 AST_STANDARD_APP_ARGS(args, parse); 04708 04709 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 04710 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 04711 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n"); 04712 return -1; 04713 } 04714 04715 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 04716 "%s", args.params ? args.params : ""); 04717 04718 return 0; 04719 }
| static int queue_cmp_cb | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 597 of file app_queue.c.
References CMP_MATCH, CMP_STOP, and call_queue::name.
Referenced by load_module().
00598 { 00599 struct call_queue *q = obj, *q2 = arg; 00600 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0; 00601 }
| 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 4766 of file app_queue.c.
References call_queue::announcefrequency, AST_APP_ARG, ast_cdr_noanswer(), ast_channel_lock, ast_channel_unlock, AST_CONTROL_RINGING, ast_debug, AST_DECLARE_APP_ARGS, ast_indicate(), ast_log(), ast_moh_start(), ast_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, 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, status, stop, penalty_rule::time, try_calling(), update_qe_rule(), update_realtime_members(), url, queue_ent::valid_digits, wait_a_bit(), and wait_our_turn().
Referenced by load_module().
04767 { 04768 int res=-1; 04769 int ringing=0; 04770 const char *user_priority; 04771 const char *max_penalty_str; 04772 const char *min_penalty_str; 04773 int prio; 04774 int qcontinue = 0; 04775 int max_penalty, min_penalty; 04776 enum queue_result reason = QUEUE_UNKNOWN; 04777 /* whether to exit Queue application after the timeout hits */ 04778 int tries = 0; 04779 int noption = 0; 04780 char *parse; 04781 int makeannouncement = 0; 04782 AST_DECLARE_APP_ARGS(args, 04783 AST_APP_ARG(queuename); 04784 AST_APP_ARG(options); 04785 AST_APP_ARG(url); 04786 AST_APP_ARG(announceoverride); 04787 AST_APP_ARG(queuetimeoutstr); 04788 AST_APP_ARG(agi); 04789 AST_APP_ARG(macro); 04790 AST_APP_ARG(gosub); 04791 AST_APP_ARG(rule); 04792 ); 04793 /* Our queue entry */ 04794 struct queue_ent qe; 04795 04796 if (ast_strlen_zero(data)) { 04797 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule]]]]]]]]\n"); 04798 return -1; 04799 } 04800 04801 parse = ast_strdupa(data); 04802 AST_STANDARD_APP_ARGS(args, parse); 04803 04804 /* Setup our queue entry */ 04805 memset(&qe, 0, sizeof(qe)); 04806 qe.start = time(NULL); 04807 04808 /* set the expire time based on the supplied timeout; */ 04809 if (!ast_strlen_zero(args.queuetimeoutstr)) 04810 qe.expire = qe.start + atoi(args.queuetimeoutstr); 04811 else 04812 qe.expire = 0; 04813 04814 /* Get the priority from the variable ${QUEUE_PRIO} */ 04815 ast_channel_lock(chan); 04816 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 04817 if (user_priority) { 04818 if (sscanf(user_priority, "%30d", &prio) == 1) { 04819 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio); 04820 } else { 04821 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 04822 user_priority, chan->name); 04823 prio = 0; 04824 } 04825 } else { 04826 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n"); 04827 prio = 0; 04828 } 04829 04830 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 04831 04832 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 04833 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) { 04834 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty); 04835 } else { 04836 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 04837 max_penalty_str, chan->name); 04838 max_penalty = 0; 04839 } 04840 } else { 04841 max_penalty = 0; 04842 } 04843 04844 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) { 04845 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) { 04846 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty); 04847 } else { 04848 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n", 04849 min_penalty_str, chan->name); 04850 min_penalty = 0; 04851 } 04852 } else { 04853 min_penalty = 0; 04854 } 04855 ast_channel_unlock(chan); 04856 04857 if (args.options && (strchr(args.options, 'r'))) 04858 ringing = 1; 04859 04860 if (args.options && (strchr(args.options, 'c'))) 04861 qcontinue = 1; 04862 04863 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 04864 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 04865 04866 qe.chan = chan; 04867 qe.prio = prio; 04868 qe.max_penalty = max_penalty; 04869 qe.min_penalty = min_penalty; 04870 qe.last_pos_said = 0; 04871 qe.last_pos = 0; 04872 qe.last_periodic_announce_time = time(NULL); 04873 qe.last_periodic_announce_sound = 0; 04874 qe.valid_digits = 0; 04875 if (join_queue(args.queuename, &qe, &reason, args.rule)) { 04876 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 04877 set_queue_result(chan, reason); 04878 return 0; 04879 } 04880 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""), 04881 S_OR(chan->cid.cid_num, "")); 04882 check_turns: 04883 if (ringing) { 04884 ast_indicate(chan, AST_CONTROL_RINGING); 04885 } else { 04886 ast_moh_start(chan, qe.moh, NULL); 04887 } 04888 04889 /* This is the wait loop for callers 2 through maxlen */ 04890 res = wait_our_turn(&qe, ringing, &reason); 04891 if (res) { 04892 goto stop; 04893 } 04894 04895 makeannouncement = 0; 04896 04897 for (;;) { 04898 /* This is the wait loop for the head caller*/ 04899 /* To exit, they may get their call answered; */ 04900 /* they may dial a digit from the queue context; */ 04901 /* or, they may timeout. */ 04902 04903 enum queue_member_status status = QUEUE_NORMAL; 04904 int exit = 0; 04905 04906 /* Leave if we have exceeded our queuetimeout */ 04907 if (qe.expire && (time(NULL) >= qe.expire)) { 04908 record_abandoned(&qe); 04909 ast_cdr_noanswer(qe.chan->cdr); 04910 reason = QUEUE_TIMEOUT; 04911 res = 0; 04912 ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 04913 qe.pos, qe.opos, (long) time(NULL) - qe.start); 04914 break; 04915 } 04916 04917 if (makeannouncement) { 04918 /* Make a position announcement, if enabled */ 04919 if (qe.parent->announcefrequency) 04920 if ((res = say_position(&qe,ringing))) 04921 goto stop; 04922 } 04923 makeannouncement = 1; 04924 04925 /* Make a periodic announcement, if enabled */ 04926 if (qe.parent->periodicannouncefrequency) 04927 if ((res = say_periodic_announcement(&qe,ringing))) 04928 goto stop; 04929 04930 /* Leave if we have exceeded our queuetimeout */ 04931 if (qe.expire && (time(NULL) >= qe.expire)) { 04932 record_abandoned(&qe); 04933 ast_cdr_noanswer(qe.chan->cdr); 04934 reason = QUEUE_TIMEOUT; 04935 res = 0; 04936 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04937 break; 04938 } 04939 04940 /* see if we need to move to the next penalty level for this queue */ 04941 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) { 04942 update_qe_rule(&qe); 04943 } 04944 04945 /* Try calling all queue members for 'timeout' seconds */ 04946 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing); 04947 if (res) { 04948 goto stop; 04949 } 04950 04951 /* exit after 'timeout' cycle if 'n' option enabled */ 04952 if (noption && tries >= qe.parent->membercount) { 04953 ast_verb(3, "Exiting on time-out cycle\n"); 04954 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 04955 record_abandoned(&qe); 04956 ast_cdr_noanswer(qe.chan->cdr); 04957 reason = QUEUE_TIMEOUT; 04958 res = 0; 04959 break; 04960 } 04961 04962 for (; !exit || qe.pr; update_qe_rule(&qe)) { 04963 status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty); 04964 04965 if (!qe.pr || status == QUEUE_NORMAL) { 04966 break; 04967 } 04968 04969 if ((qe.parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) || 04970 ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) || 04971 ((qe.parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS))) { 04972 continue; 04973 } else { 04974 exit = 1; 04975 } 04976 } 04977 04978 /* leave the queue if no agents, if enabled */ 04979 if (qe.parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) { 04980 record_abandoned(&qe); 04981 ast_cdr_noanswer(qe.chan->cdr); 04982 reason = QUEUE_LEAVEEMPTY; 04983 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 04984 res = 0; 04985 break; 04986 } 04987 04988 /* leave the queue if no reachable agents, if enabled */ 04989 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) { 04990 record_abandoned(&qe); 04991 reason = QUEUE_LEAVEUNAVAIL; 04992 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 04993 res = 0; 04994 break; 04995 } 04996 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS)) { 04997 record_abandoned(&qe); 04998 reason = QUEUE_LEAVEUNAVAIL; 04999 res = 0; 05000 break; 05001 } 05002 05003 /* Leave if we have exceeded our queuetimeout */ 05004 if (qe.expire && (time(NULL) >= qe.expire)) { 05005 record_abandoned(&qe); 05006 reason = QUEUE_TIMEOUT; 05007 res = 0; 05008 ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start); 05009 break; 05010 } 05011 05012 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 05013 update_realtime_members(qe.parent); 05014 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 05015 res = wait_a_bit(&qe); 05016 if (res) 05017 goto stop; 05018 05019 /* Since this is a priority queue and 05020 * it is not sure that we are still at the head 05021 * of the queue, go and check for our turn again. 05022 */ 05023 if (!is_our_turn(&qe)) { 05024 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name); 05025 goto check_turns; 05026 } 05027 } 05028 05029 stop: 05030 if (res) { 05031 if (res < 0) { 05032 if (!qe.handled) { 05033 record_abandoned(&qe); 05034 ast_cdr_noanswer(qe.chan->cdr); 05035 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 05036 "%d|%d|%ld", qe.pos, qe.opos, 05037 (long) time(NULL) - qe.start); 05038 res = -1; 05039 } else if (qcontinue) { 05040 reason = QUEUE_CONTINUE; 05041 res = 0; 05042 } 05043 } else if (qe.valid_digits) { 05044 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 05045 "%s|%d", qe.digits, qe.pos); 05046 } 05047 } 05048 05049 /* Don't allow return code > 0 */ 05050 if (res >= 0) { 05051 res = 0; 05052 if (ringing) { 05053 ast_indicate(chan, -1); 05054 } else { 05055 ast_moh_stop(chan); 05056 } 05057 ast_stopstream(chan); 05058 } 05059 05060 set_queue_variables(qe.parent, qe.chan); 05061 05062 leave_queue(&qe); 05063 if (reason != QUEUE_UNKNOWN) 05064 set_queue_result(chan, reason); 05065 05066 return res; 05067 }
| 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 5299 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.
05300 { 05301 int penalty; 05302 AST_DECLARE_APP_ARGS(args, 05303 AST_APP_ARG(queuename); 05304 AST_APP_ARG(interface); 05305 ); 05306 /* Make sure the returned value on error is NULL. */ 05307 buf[0] = '\0'; 05308 05309 if (ast_strlen_zero(data)) { 05310 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05311 return -1; 05312 } 05313 05314 AST_STANDARD_APP_ARGS(args, data); 05315 05316 if (args.argc < 2) { 05317 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05318 return -1; 05319 } 05320 05321 penalty = get_member_penalty (args.queuename, args.interface); 05322 05323 if (penalty >= 0) /* remember that buf is already '\0' */ 05324 snprintf (buf, len, "%d", penalty); 05325 05326 return 0; 05327 }
| 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 5330 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().
05331 { 05332 int penalty; 05333 AST_DECLARE_APP_ARGS(args, 05334 AST_APP_ARG(queuename); 05335 AST_APP_ARG(interface); 05336 ); 05337 05338 if (ast_strlen_zero(data)) { 05339 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05340 return -1; 05341 } 05342 05343 AST_STANDARD_APP_ARGS(args, data); 05344 05345 if (args.argc < 2) { 05346 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05347 return -1; 05348 } 05349 05350 penalty = atoi(value); 05351 05352 if (ast_strlen_zero(args.interface)) { 05353 ast_log (LOG_ERROR, "<interface> parameter can't be null\n"); 05354 return -1; 05355 } 05356 05357 /* if queuename = NULL then penalty will be set for interface in all the queues. */ 05358 if (set_member_penalty(args.queuename, args.interface, penalty)) { 05359 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); 05360 return -1; 05361 } 05362 05363 return 0; 05364 }
| 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 5122 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_log(), ast_strlen_zero(), call_queue::count, load_realtime_queue(), LOG_ERROR, LOG_WARNING, call_queue::membercount, call_queue::members, member::paused, queue_unref(), and member::status.
05123 { 05124 int count = 0; 05125 struct member *m; 05126 struct ao2_iterator mem_iter; 05127 struct call_queue *q; 05128 char *option; 05129 05130 if (ast_strlen_zero(data)) { 05131 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 05132 return -1; 05133 } 05134 05135 if ((option = strchr(data, ','))) 05136 *option++ = '\0'; 05137 else 05138 option = "logged"; 05139 if ((q = load_realtime_queue(data))) { 05140 ao2_lock(q); 05141 if (!strcasecmp(option, "logged")) { 05142 mem_iter = ao2_iterator_init(q->members, 0); 05143 while ((m = ao2_iterator_next(&mem_iter))) { 05144 /* Count the agents who are logged in and presently answering calls */ 05145 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05146 count++; 05147 } 05148 ao2_ref(m, -1); 05149 } 05150 } else if (!strcasecmp(option, "free")) { 05151 mem_iter = ao2_iterator_init(q->members, 0); 05152 while ((m = ao2_iterator_next(&mem_iter))) { 05153 /* Count the agents who are logged in and presently answering calls */ 05154 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) { 05155 count++; 05156 } 05157 ao2_ref(m, -1); 05158 } 05159 } else /* must be "count" */ 05160 count = q->membercount; 05161 ao2_unlock(q); 05162 queue_unref(q); 05163 } else 05164 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05165 05166 snprintf(buf, len, "%d", count); 05167 05168 return 0; 05169 }
| 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 5176 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, ast_log(), ast_strlen_zero(), call_queue::count, load_realtime_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, call_queue::members, queue_unref(), and member::status.
05177 { 05178 int count = 0; 05179 struct member *m; 05180 struct call_queue *q; 05181 struct ao2_iterator mem_iter; 05182 static int depflag = 1; 05183 05184 if (depflag) { 05185 depflag = 0; 05186 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"); 05187 } 05188 05189 if (ast_strlen_zero(data)) { 05190 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 05191 return -1; 05192 } 05193 05194 if ((q = load_realtime_queue(data))) { 05195 ao2_lock(q); 05196 mem_iter = ao2_iterator_init(q->members, 0); 05197 while ((m = ao2_iterator_next(&mem_iter))) { 05198 /* Count the agents who are logged in and presently answering calls */ 05199 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05200 count++; 05201 } 05202 ao2_ref(m, -1); 05203 } 05204 ao2_unlock(q); 05205 queue_unref(q); 05206 } else 05207 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05208 05209 snprintf(buf, len, "%d", count); 05210 05211 return 0; 05212 }
| 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 5251 of file app_queue.c.
References ao2_find, 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.
05252 { 05253 struct call_queue *q, tmpq = { 05254 .name = data, 05255 }; 05256 struct member *m; 05257 05258 /* Ensure an otherwise empty list doesn't return garbage */ 05259 buf[0] = '\0'; 05260 05261 if (ast_strlen_zero(data)) { 05262 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 05263 return -1; 05264 } 05265 05266 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 05267 int buflen = 0, count = 0; 05268 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 05269 05270 ao2_lock(q); 05271 while ((m = ao2_iterator_next(&mem_iter))) { 05272 /* strcat() is always faster than printf() */ 05273 if (count++) { 05274 strncat(buf + buflen, ",", len - buflen - 1); 05275 buflen++; 05276 } 05277 strncat(buf + buflen, m->interface, len - buflen - 1); 05278 buflen += strlen(m->interface); 05279 /* Safeguard against overflow (negative length) */ 05280 if (buflen >= len - 2) { 05281 ao2_ref(m, -1); 05282 ast_log(LOG_WARNING, "Truncating list\n"); 05283 break; 05284 } 05285 ao2_ref(m, -1); 05286 } 05287 ao2_unlock(q); 05288 queue_unref(q); 05289 } else 05290 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05291 05292 /* We should already be terminated, but let's make sure. */ 05293 buf[len - 1] = '\0'; 05294 05295 return 0; 05296 }
| 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 5215 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, SENTINEL, and var.
05216 { 05217 int count = 0; 05218 struct call_queue *q, tmpq = { 05219 .name = data, 05220 }; 05221 struct ast_variable *var = NULL; 05222 05223 buf[0] = '\0'; 05224 05225 if (ast_strlen_zero(data)) { 05226 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n"); 05227 return -1; 05228 } 05229 05230 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 05231 ao2_lock(q); 05232 count = q->count; 05233 ao2_unlock(q); 05234 queue_unref(q); 05235 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) { 05236 /* if the queue is realtime but was not found in memory, this 05237 * means that the queue had been deleted from memory since it was 05238 * "dead." This means it has a 0 waiting count 05239 */ 05240 count = 0; 05241 ast_variables_destroy(var); 05242 } else 05243 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05244 05245 snprintf(buf, len, "%d", count); 05246 05247 return 0; 05248 }
| 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 5074 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.
05075 { 05076 int res = -1; 05077 struct call_queue *q, tmpq = { 05078 .name = data, 05079 }; 05080 05081 char interfacevar[256] = ""; 05082 float sl = 0; 05083 05084 if (ast_strlen_zero(data)) { 05085 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 05086 return -1; 05087 } 05088 05089 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 05090 ao2_lock(q); 05091 if (q->setqueuevar) { 05092 sl = 0; 05093 res = 0; 05094 05095 if (q->callscompleted > 0) { 05096 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 05097 } 05098 05099 snprintf(interfacevar, sizeof(interfacevar), 05100 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 05101 q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 05102 05103 pbx_builtin_setvar_multiple(chan, interfacevar); 05104 } 05105 05106 ao2_unlock(q); 05107 queue_unref(q); 05108 } else { 05109 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05110 } 05111 05112 snprintf(buf, len, "%d", res); 05113 05114 return 0; 05115 }
| static int queue_hash_cb | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 590 of file app_queue.c.
References ast_str_case_hash(), and call_queue::name.
Referenced by load_module().
00591 { 00592 const struct call_queue *q = obj; 00593 00594 return ast_str_case_hash(q->name); 00595 }
| static struct call_queue* queue_ref | ( | struct call_queue * | q | ) | [static, read] |
Definition at line 603 of file app_queue.c.
References ao2_ref.
Referenced by leave_queue(), and try_calling().
00604 { 00605 ao2_ref(q, 1); 00606 return q; 00607 }
| 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 1134 of file app_queue.c.
References queue_ent::announce, call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_NO, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, ast_copy_string(), ast_debug, ast_log(), ast_str_create(), ast_str_set(), ast_strdupa, ast_string_field_set, ast_true(), call_queue::autofill, call_queue::autopause, buf, queue_ent::context, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::eventwhencalled, call_queue::joinempty, call_queue::leavewhenempty, LOG_WARNING, call_queue::maskmemberstatus, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, call_queue::memberdelay, call_queue::minannouncefrequency, queue_ent::moh, call_queue::monfmt, call_queue::montype, call_queue::name, call_queue::numperiodicannounce, call_queue::periodicannouncefrequency, QUEUE_EMPTY_LOOSE, QUEUE_EMPTY_NORMAL, QUEUE_EMPTY_STRICT, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RINGALL, call_queue::randomperiodicannounce, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::roundingseconds, s, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::setqueueentryvar, call_queue::setqueuevar, call_queue::sound_periodicannounce, strat2int(), call_queue::strategy, strsep(), call_queue::timeout, TIMEOUT_PRIORITY_APP, TIMEOUT_PRIORITY_CONF, call_queue::timeoutpriority, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.
Referenced by find_queue_by_name_rt(), and reload_queues().
01135 { 01136 if (!strcasecmp(param, "musicclass") || 01137 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 01138 ast_string_field_set(q, moh, val); 01139 } else if (!strcasecmp(param, "announce")) { 01140 ast_string_field_set(q, announce, val); 01141 } else if (!strcasecmp(param, "context")) { 01142 ast_string_field_set(q, context, val); 01143 } else if (!strcasecmp(param, "timeout")) { 01144 q->timeout = atoi(val); 01145 if (q->timeout < 0) 01146 q->timeout = DEFAULT_TIMEOUT; 01147 } else if (!strcasecmp(param, "ringinuse")) { 01148 q->ringinuse = ast_true(val); 01149 } else if (!strcasecmp(param, "setinterfacevar")) { 01150 q->setinterfacevar = ast_true(val); 01151 } else if (!strcasecmp(param, "setqueuevar")) { 01152 q->setqueuevar = ast_true(val); 01153 } else if (!strcasecmp(param, "setqueueentryvar")) { 01154 q->setqueueentryvar = ast_true(val); 01155 } else if (!strcasecmp(param, "monitor-format")) { 01156 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 01157 } else if (!strcasecmp(param, "membermacro")) { 01158 ast_string_field_set(q, membermacro, val); 01159 } else if (!strcasecmp(param, "membergosub")) { 01160 ast_string_field_set(q, membergosub, val); 01161 } else if (!strcasecmp(param, "queue-youarenext")) { 01162 ast_string_field_set(q, sound_next, val); 01163 } else if (!strcasecmp(param, "queue-thereare")) { 01164 ast_string_field_set(q, sound_thereare, val); 01165 } else if (!strcasecmp(param, "queue-callswaiting")) { 01166 ast_string_field_set(q, sound_calls, val); 01167 } else if (!strcasecmp(param, "queue-quantity1")) { 01168 ast_string_field_set(q, queue_quantity1, val); 01169 } else if (!strcasecmp(param, "queue-quantity2")) { 01170 ast_string_field_set(q, queue_quantity2, val); 01171 } else if (!strcasecmp(param, "queue-holdtime")) { 01172 ast_string_field_set(q, sound_holdtime, val); 01173 } else if (!strcasecmp(param, "queue-minutes")) { 01174 ast_string_field_set(q, sound_minutes, val); 01175 } else if (!strcasecmp(param, "queue-minute")) { 01176 ast_string_field_set(q, sound_minute, val); 01177 } else if (!strcasecmp(param, "queue-seconds")) { 01178 ast_string_field_set(q, sound_seconds, val); 01179 } else if (!strcasecmp(param, "queue-thankyou")) { 01180 ast_string_field_set(q, sound_thanks, val); 01181 } else if (!strcasecmp(param, "queue-callerannounce")) { 01182 ast_string_field_set(q, sound_callerannounce, val); 01183 } else if (!strcasecmp(param, "queue-reporthold")) { 01184 ast_string_field_set(q, sound_reporthold, val); 01185 } else if (!strcasecmp(param, "announce-frequency")) { 01186 q->announcefrequency = atoi(val); 01187 } else if (!strcasecmp(param, "min-announce-frequency")) { 01188 q->minannouncefrequency = atoi(val); 01189 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name); 01190 } else if (!strcasecmp(param, "announce-round-seconds")) { 01191 q->roundingseconds = atoi(val); 01192 /* Rounding to any other values just doesn't make sense... */ 01193 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10 01194 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) { 01195 if (linenum >= 0) { 01196 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01197 "using 0 instead for queue '%s' at line %d of queues.conf\n", 01198 val, param, q->name, linenum); 01199 } else { 01200 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01201 "using 0 instead for queue '%s'\n", val, param, q->name); 01202 } 01203 q->roundingseconds=0; 01204 } 01205 } else if (!strcasecmp(param, "announce-holdtime")) { 01206 if (!strcasecmp(val, "once")) 01207 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 01208 else if (ast_true(val)) 01209 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 01210 else 01211 q->announceholdtime = 0; 01212 } else if (!strcasecmp(param, "announce-position")) { 01213 if (!strcasecmp(val, "limit")) 01214 q->announceposition = ANNOUNCEPOSITION_LIMIT; 01215 else if (!strcasecmp(val, "more")) 01216 q->announceposition = ANNOUNCEPOSITION_MORE_THAN; 01217 else if (ast_true(val)) 01218 q->announceposition = ANNOUNCEPOSITION_YES; 01219 else 01220 q->announceposition = ANNOUNCEPOSITION_NO; 01221 } else if (!strcasecmp(param, "announce-position-limit")) { 01222 q->announcepositionlimit = atoi(val); 01223 } else if (!strcasecmp(param, "periodic-announce")) { 01224 if (strchr(val, ',')) { 01225 char *s, *buf = ast_strdupa(val); 01226 unsigned int i = 0; 01227 01228 while ((s = strsep(&buf, ",|"))) { 01229 if (!q->sound_periodicannounce[i]) 01230 q->sound_periodicannounce[i] = ast_str_create(16); 01231 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s); 01232 i++; 01233 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 01234 break; 01235 } 01236 q->numperiodicannounce = i; 01237 } else { 01238 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val); 01239 q->numperiodicannounce = 1; 01240 } 01241 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 01242 q->periodicannouncefrequency = atoi(val); 01243 } else if (!strcasecmp(param, "random-periodic-announce")) { 01244 q->randomperiodicannounce = ast_true(val); 01245 } else if (!strcasecmp(param, "retry")) { 01246 q->retry = atoi(val); 01247 if (q->retry <= 0) 01248 q->retry = DEFAULT_RETRY; 01249 } else if (!strcasecmp(param, "wrapuptime")) { 01250 q->wrapuptime = atoi(val); 01251 } else if (!strcasecmp(param, "autofill")) { 01252 q->autofill = ast_true(val); 01253 } else if (!strcasecmp(param, "monitor-type")) { 01254 if (!strcasecmp(val, "mixmonitor")) 01255 q->montype = 1; 01256 } else if (!strcasecmp(param, "autopause")) { 01257 q->autopause = ast_true(val); 01258 } else if (!strcasecmp(param, "maxlen")) { 01259 q->maxlen = atoi(val); 01260 if (q->maxlen < 0) 01261 q->maxlen = 0; 01262 } else if (!strcasecmp(param, "servicelevel")) { 01263 q->servicelevel= atoi(val); 01264 } else if (!strcasecmp(param, "strategy")) { 01265 int strategy; 01266 01267 /* We are a static queue and already have set this, no need to do it again */ 01268 if (failunknown) { 01269 return; 01270 } 01271 strategy = strat2int(val); 01272 if (strategy < 0) { 01273 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 01274 val, q->name); 01275 q->strategy = QUEUE_STRATEGY_RINGALL; 01276 } 01277 if (strategy == q->strategy) { 01278 return; 01279 } 01280 if (strategy == QUEUE_STRATEGY_LINEAR) { 01281 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n"); 01282 return; 01283 } 01284 q->strategy = strategy; 01285 } else if (!strcasecmp(param, "joinempty")) { 01286 if (!strcasecmp(val, "loose")) 01287 q->joinempty = QUEUE_EMPTY_LOOSE; 01288 else if (!strcasecmp(val, "strict")) 01289 q->joinempty = QUEUE_EMPTY_STRICT; 01290 else if (ast_true(val)) 01291 q->joinempty = QUEUE_EMPTY_NORMAL; 01292 else 01293 q->joinempty = 0; 01294 } else if (!strcasecmp(param, "leavewhenempty")) { 01295 if (!strcasecmp(val, "loose")) 01296 q->leavewhenempty = QUEUE_EMPTY_LOOSE; 01297 else if (!strcasecmp(val, "strict")) 01298 q->leavewhenempty = QUEUE_EMPTY_STRICT; 01299 else if (ast_true(val)) 01300 q->leavewhenempty = QUEUE_EMPTY_NORMAL; 01301 else 01302 q->leavewhenempty = 0; 01303 } else if (!strcasecmp(param, "eventmemberstatus")) { 01304 q->maskmemberstatus = !ast_true(val); 01305 } else if (!strcasecmp(param, "eventwhencalled")) { 01306 if (!strcasecmp(val, "vars")) { 01307 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 01308 } else { 01309 q->eventwhencalled = ast_true(val) ? 1 : 0; 01310 } 01311 } else if (!strcasecmp(param, "reportholdtime")) { 01312 q->reportholdtime = ast_true(val); 01313 } else if (!strcasecmp(param, "memberdelay")) { 01314 q->memberdelay = atoi(val); 01315 } else if (!strcasecmp(param, "weight")) { 01316 q->weight = atoi(val); 01317 if (q->weight) 01318 use_weight++; 01319 /* With Realtime queues, if the last queue using weights is deleted in realtime, 01320 we will not see any effect on use_weight until next reload. */ 01321 } else if (!strcasecmp(param, "timeoutrestart")) { 01322 q->timeoutrestart = ast_true(val); 01323 } else if (!strcasecmp(param, "defaultrule")) { 01324 ast_string_field_set(q, defaultrule, val); 01325 } else if (!strcasecmp(param, "timeoutpriority")) { 01326 if (!strcasecmp(val, "conf")) { 01327 q->timeoutpriority = TIMEOUT_PRIORITY_CONF; 01328 } else { 01329 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 01330 } 01331 } else if (failunknown) { 01332 if (linenum >= 0) { 01333 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 01334 q->name, param, linenum); 01335 } else { 01336 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 01337 } 01338 } 01339 }
| static char* queue_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 5875 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.
05876 { 05877 switch ( cmd ) { 05878 case CLI_INIT: 05879 e->command = "queue show"; 05880 e->usage = 05881 "Usage: queue show\n" 05882 " Provides summary information on a specified queue.\n"; 05883 return NULL; 05884 case CLI_GENERATE: 05885 return complete_queue_show(a->line, a->word, a->pos, a->n); 05886 } 05887 05888 return __queues_show(NULL, a->fd, a->argc, a->argv); 05889 }
| static void queue_transfer_destroy | ( | void * | data | ) | [static] |
Definition at line 3180 of file app_queue.c.
References ast_free.
03181 { 03182 struct queue_transfer_ds *qtds = data; 03183 ast_free(qtds); 03184 }
| 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 3203 of file app_queue.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_log(), ast_queue_log(), queue_transfer_ds::callcompletedinsl, queue_ent::chan, ast_channel::context, ast_channel::exten, LOG_WARNING, queue_transfer_ds::member, member::membername, call_queue::name, queue_ent::opos, queue_ent::parent, queue_transfer_ds::qe, queue_transfer_info, queue_ent::start, queue_transfer_ds::starttime, and update_queue().
03204 { 03205 struct queue_transfer_ds *qtds = data; 03206 struct queue_ent *qe = qtds->qe; 03207 struct member *member = qtds->member; 03208 time_t callstart = qtds->starttime; 03209 int callcompletedinsl = qtds->callcompletedinsl; 03210 struct ast_datastore *datastore; 03211 03212 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 03213 new_chan->exten, new_chan->context, (long) (callstart - qe->start), 03214 (long) (time(NULL) - callstart), qe->opos); 03215 03216 update_queue(qe->parent, member, callcompletedinsl); 03217 03218 /* No need to lock the channels because they are already locked in ast_do_masquerade */ 03219 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) { 03220 ast_channel_datastore_remove(old_chan, datastore); 03221 } else { 03222 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n"); 03223 } 03224 }
| static struct call_queue* queue_unref | ( | struct call_queue * | q | ) | [static, read] |
Definition at line 609 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().
00610 { 00611 ao2_ref(q, -1); 00612 return q; 00613 }
| static void recalc_holdtime | ( | struct queue_ent * | qe, | |
| int | newholdtime | |||
| ) | [static] |
Definition at line 1982 of file app_queue.c.
References ao2_lock(), ao2_unlock(), call_queue::holdtime, and queue_ent::parent.
Referenced by try_calling().
01983 { 01984 int oldvalue; 01985 01986 /* Calculate holdtime using an exponential average */ 01987 /* Thanks to SRT for this contribution */ 01988 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 01989 01990 ao2_lock(qe->parent); 01991 oldvalue = qe->parent->holdtime; 01992 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 01993 ao2_unlock(qe->parent); 01994 }
| static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Record that a caller gave up on waiting in queue.
Definition at line 2534 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(), and queue_ent::start.
Referenced by queue_exec(), and try_calling().
02535 { 02536 ao2_lock(qe->parent); 02537 set_queue_variables(qe->parent, qe->chan); 02538 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 02539 "Queue: %s\r\n" 02540 "Uniqueid: %s\r\n" 02541 "Position: %d\r\n" 02542 "OriginalPosition: %d\r\n" 02543 "HoldTime: %d\r\n", 02544 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 02545 02546 qe->parent->callsabandoned++; 02547 ao2_unlock(qe->parent); 02548 }
| static int reload | ( | void | ) | [static] |
Definition at line 6768 of file app_queue.c.
References ast_unload_realtime(), and reload_queues().
06769 { 06770 ast_unload_realtime("queue_members"); 06771 reload_queues(1); 06772 return 0; 06773 }
| static void reload_queue_members | ( | void | ) | [static] |
Reload dynamic queue members persisted into the astdb.
Definition at line 4401 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().
04402 { 04403 char *cur_ptr; 04404 const char *queue_name; 04405 char *member; 04406 char *interface; 04407 char *membername = NULL; 04408 char *state_interface; 04409 char *penalty_tok; 04410 int penalty = 0; 04411 char *paused_tok; 04412 int paused = 0; 04413 struct ast_db_entry *db_tree; 04414 struct ast_db_entry *entry; 04415 struct call_queue *cur_queue; 04416 char queue_data[PM_MAX_LEN]; 04417 04418 ao2_lock(queues); 04419 04420 /* Each key in 'pm_family' is the name of a queue */ 04421 db_tree = ast_db_gettree(pm_family, NULL); 04422 for (entry = db_tree; entry; entry = entry->next) { 04423 04424 queue_name = entry->key + strlen(pm_family) + 2; 04425 04426 { 04427 struct call_queue tmpq = { 04428 .name = queue_name, 04429 }; 04430 cur_queue = ao2_find(queues, &tmpq, OBJ_POINTER); 04431 } 04432 04433 if (!cur_queue) 04434 cur_queue = load_realtime_queue(queue_name); 04435 04436 if (!cur_queue) { 04437 /* If the queue no longer exists, remove it from the 04438 * database */ 04439 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 04440 ast_db_del(pm_family, queue_name); 04441 continue; 04442 } 04443 04444 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) { 04445 queue_unref(cur_queue); 04446 continue; 04447 } 04448 04449 cur_ptr = queue_data; 04450 while ((member = strsep(&cur_ptr, ",|"))) { 04451 if (ast_strlen_zero(member)) 04452 continue; 04453 04454 interface = strsep(&member, ";"); 04455 penalty_tok = strsep(&member, ";"); 04456 paused_tok = strsep(&member, ";"); 04457 membername = strsep(&member, ";"); 04458 state_interface = strsep(&member, ";"); 04459 04460 if (!penalty_tok) { 04461 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 04462 break; 04463 } 04464 penalty = strtol(penalty_tok, NULL, 10); 04465 if (errno == ERANGE) { 04466 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 04467 break; 04468 } 04469 04470 if (!paused_tok) { 04471 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 04472 break; 04473 } 04474 paused = strtol(paused_tok, NULL, 10); 04475 if ((errno == ERANGE) || paused < 0 || paused > 1) { 04476 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 04477 break; 04478 } 04479 04480 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 04481 04482 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { 04483 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 04484 break; 04485 } 04486 } 04487 queue_unref(cur_queue); 04488 } 04489 04490 ao2_unlock(queues); 04491 if (db_tree) { 04492 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 04493 ast_db_freetree(db_tree); 04494 } 04495 }
| static int reload_queue_rules | ( | int | reload | ) | [static] |
Definition at line 5435 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().
05436 { 05437 struct ast_config *cfg; 05438 struct rule_list *rl_iter, *new_rl; 05439 struct penalty_rule *pr_iter; 05440 char *rulecat = NULL; 05441 struct ast_variable *rulevar = NULL; 05442 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 05443 05444 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) { 05445 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n"); 05446 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 05447 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n"); 05448 return AST_MODULE_LOAD_SUCCESS; 05449 } else { 05450 AST_LIST_LOCK(&rule_lists); 05451 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) { 05452 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list))) 05453 ast_free(pr_iter); 05454 ast_free(rl_iter); 05455 } 05456 while ((rulecat = ast_category_browse(cfg, rulecat))) { 05457 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) { 05458 ast_log(LOG_ERROR, "Memory allocation error while loading queuerules.conf! Aborting!\n"); 05459 AST_LIST_UNLOCK(&rule_lists); 05460 return AST_MODULE_LOAD_FAILURE; 05461 } else { 05462 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name)); 05463 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list); 05464 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next) 05465 if(!strcasecmp(rulevar->name, "penaltychange")) { 05466 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno); 05467 } else { 05468 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno); 05469 } 05470 } 05471 } 05472 AST_LIST_UNLOCK(&rule_lists); 05473 } 05474 05475 ast_config_destroy(cfg); 05476 05477 return AST_MODULE_LOAD_SUCCESS; 05478 }
| static int reload_queues | ( | int | reload | ) | [static] |
Definition at line 5481 of file app_queue.c.
References add_to_interfaces(), alloc_queue(), ao2_find, 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, F_AO2I_DONTLOCK, 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().
05482 { 05483 struct call_queue *q; 05484 struct ast_config *cfg; 05485 char *cat, *tmp; 05486 struct ast_variable *var; 05487 struct member *cur, *newm; 05488 struct ao2_iterator mem_iter; 05489 int new; 05490 const char *general_val = NULL; 05491 char *parse; 05492 char *interface, *state_interface; 05493 char *membername = NULL; 05494 int penalty; 05495 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 05496 struct ao2_iterator queue_iter; 05497 AST_DECLARE_APP_ARGS(args, 05498 AST_APP_ARG(interface); 05499 AST_APP_ARG(penalty); 05500 AST_APP_ARG(membername); 05501 AST_APP_ARG(state_interface); 05502 ); 05503 05504 /*First things first. Let's load queuerules.conf*/ 05505 if (reload_queue_rules(reload) == AST_MODULE_LOAD_FAILURE) 05506 return AST_MODULE_LOAD_FAILURE; 05507 05508 if (!(cfg = ast_config_load("queues.conf", config_flags))) { 05509 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 05510 return 0; 05511 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 05512 return 0; 05513 ao2_lock(queues); 05514 use_weight=0; 05515 /* Mark all queues as dead for the moment */ 05516 queue_iter = ao2_iterator_init(queues, F_AO2I_DONTLOCK); 05517 while ((q = ao2_iterator_next(&queue_iter))) { 05518 if (!q->realtime) { 05519 q->dead = 1; 05520 q->found = 0; 05521 } 05522 queue_unref(q); 05523 } 05524 05525 /* Chug through config file */ 05526 cat = NULL; 05527 while ((cat = ast_category_browse(cfg, cat)) ) { 05528 if (!strcasecmp(cat, "general")) { 05529 /* Initialize global settings */ 05530 queue_keep_stats = 0; 05531 if ((general_val = ast_variable_retrieve(cfg, "general", "keepstats"))) 05532 queue_keep_stats = ast_true(general_val); 05533 queue_persistent_members = 0; 05534 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 05535 queue_persistent_members = ast_true(general_val); 05536 autofill_default = 0; 05537 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 05538 autofill_default = ast_true(general_val); 05539 montype_default = 0; 05540 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) { 05541 if (!strcasecmp(general_val, "mixmonitor")) 05542 montype_default = 1; 05543 } 05544 update_cdr = 0; 05545 if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr"))) 05546 update_cdr = ast_true(general_val); 05547 shared_lastcall = 0; 05548 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) 05549 shared_lastcall = ast_true(general_val); 05550 } else { /* Define queue */ 05551 /* Look for an existing one */ 05552 struct call_queue tmpq = { 05553 .name = cat, 05554 }; 05555 if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 05556 /* Make one then */ 05557 if (!(q = alloc_queue(cat))) { 05558 /* TODO: Handle memory allocation failure */ 05559 } 05560 new = 1; 05561 } else 05562 new = 0; 05563 if (q) { 05564 const char *tmpvar = NULL; 05565 if (!new) 05566 ao2_lock(q); 05567 /* Check if a queue with this name already exists */ 05568 if (q->found) { 05569 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat); 05570 if (!new) { 05571 ao2_unlock(q); 05572 queue_unref(q); 05573 } 05574 continue; 05575 } 05576 /* Due to the fact that the "linear" strategy will have a different allocation 05577 * scheme for queue members, we must devise the queue's strategy before other initializations 05578 */ 05579 if ((tmpvar = ast_variable_retrieve(cfg, cat, "strategy"))) { 05580 q->strategy = strat2int(tmpvar); 05581 if (q->strategy < 0) { 05582 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 05583 tmpvar, q->name); 05584 q->strategy = QUEUE_STRATEGY_RINGALL; 05585 } 05586 } else 05587 q->strategy = QUEUE_STRATEGY_RINGALL; 05588 /* Re-initialize the queue, and clear statistics */ 05589 init_queue(q); 05590 if (!queue_keep_stats) 05591 clear_queue(q); 05592 mem_iter = ao2_iterator_init(q->members, 0); 05593 while ((cur = ao2_iterator_next(&mem_iter))) { 05594 if (!cur->dynamic) { 05595 cur->delme = 1; 05596 } 05597 ao2_ref(cur, -1); 05598 } 05599 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 05600 if (!strcasecmp(var->name, "member")) { 05601 struct member tmpmem; 05602 membername = NULL; 05603 05604 if (ast_strlen_zero(var->value)) { 05605 ast_log(LOG_WARNING, "Empty queue member definition at line %d. Moving on!\n", var->lineno); 05606 continue; 05607 } 05608 05609 /* Add a new member */ 05610 if (!(parse = ast_strdup(var->value))) { 05611 continue; 05612 } 05613 05614 AST_STANDARD_APP_ARGS(args, parse); 05615 05616 interface = args.interface; 05617 if (!ast_strlen_zero(args.penalty)) { 05618 tmp = args.penalty; 05619 while (*tmp && *tmp < 33) tmp++; 05620 penalty = atoi(tmp); 05621 if (penalty < 0) { 05622 penalty = 0; 05623 } 05624 } else 05625 penalty = 0; 05626 05627 if (!ast_strlen_zero(args.membername)) { 05628 membername = args.membername; 05629 while (*membername && *membername < 33) membername++; 05630 } 05631 05632 if (!ast_strlen_zero(args.state_interface)) { 05633 state_interface = args.state_interface; 05634 while (*state_interface && *state_interface < 33) state_interface++; 05635 } else 05636 state_interface = interface; 05637 05638 /* Find the old position in the list */ 05639 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 05640 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); 05641 /* Only attempt removing from interfaces list if the new state_interface is different than the old one */ 05642 if (cur && strcasecmp(cur->state_interface, state_interface)) { 05643 remove_from_interfaces(cur->state_interface, 0); 05644 } 05645 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface); 05646 if (!cur || (cur && strcasecmp(cur->state_interface, state_interface))) 05647 add_to_interfaces(state_interface); 05648 ao2_link(q->members, newm); 05649 ao2_ref(newm, -1); 05650 newm = NULL; 05651 05652 if (cur) 05653 ao2_ref(cur, -1); 05654 else { 05655 q->membercount++; 05656 } 05657 ast_free(parse); 05658 } else { 05659 queue_set_param(q, var->name, var->value, var->lineno, 1); 05660 } 05661 } 05662 05663 /* Free remaining members marked as delme */ 05664 mem_iter = ao2_iterator_init(q->members, 0); 05665 while ((cur = ao2_iterator_next(&mem_iter))) { 05666 if (! cur->delme) { 05667 ao2_ref(cur, -1); 05668 continue; 05669 } 05670 q->membercount--; 05671 ao2_unlink(q->members, cur); 05672 remove_from_interfaces(cur->interface, 0); 05673 ao2_ref(cur, -1); 05674 } 05675 05676 if (new) { 05677 ao2_link(queues, q); 05678 } else 05679 ao2_unlock(q); 05680 queue_unref(q); 05681 } 05682 } 05683 } 05684 ast_config_destroy(cfg); 05685 queue_iter = ao2_iterator_init(queues, 0); 05686 while ((q = ao2_iterator_next(&queue_iter))) { 05687 if (q->dead) { 05688 ao2_unlink(queues, q); 05689 } else { 05690 ao2_lock(q); 05691 mem_iter = ao2_iterator_init(q->members, 0); 05692 while ((cur = ao2_iterator_next(&mem_iter))) { 05693 if (cur->dynamic) 05694 q->membercount++; 05695 cur->status = ast_device_state(cur->state_interface); 05696 ao2_ref(cur, -1); 05697 } 05698 ao2_unlock(q); 05699 } 05700 queue_unref(q); 05701 } 05702 ao2_unlock(queues); 05703 return 1; 05704 }
| static int remove_from_interfaces | ( | const char * | interface, | |
| int | lock_queue_container | |||
| ) | [static] |
Definition at line 1014 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().
01015 { 01016 struct member_interface *curint; 01017 01018 if (interface_exists_global(interface, lock_queue_container)) 01019 return 0; 01020 01021 AST_LIST_LOCK(&interfaces); 01022 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) { 01023 if (!strcasecmp(curint->interface, interface)) { 01024 ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface); 01025 AST_LIST_REMOVE_CURRENT(list); 01026 ast_free(curint); 01027 break; 01028 } 01029 } 01030 AST_LIST_TRAVERSE_SAFE_END; 01031 AST_LIST_UNLOCK(&interfaces); 01032 01033 return 0; 01034 }
| 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 4138 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 handle_queue_remove_member(), manager_remove_queue_member(), and rqm_exec().
04139 { 04140 struct call_queue *q, tmpq = { 04141 .name = queuename, 04142 }; 04143 struct member *mem, tmpmem; 04144 int res = RES_NOSUCHQUEUE; 04145 04146 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 04147 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 04148 ao2_lock(queues); 04149 ao2_lock(q); 04150 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 04151 /* XXX future changes should beware of this assumption!! */ 04152 if (!mem->dynamic) { 04153 ao2_ref(mem, -1); 04154 ao2_unlock(q); 04155 queue_unref(q); 04156 ao2_unlock(queues); 04157 return RES_NOT_DYNAMIC; 04158 } 04159 q->membercount--; 04160 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 04161 "Queue: %s\r\n" 04162 "Location: %s\r\n" 04163 "MemberName: %s\r\n", 04164 q->name, mem->interface, mem->membername); 04165 ao2_unlink(q->members, mem); 04166 remove_from_interfaces(mem->state_interface, 0); 04167 ao2_ref(mem, -1); 04168 04169 if (queue_persistent_members) 04170 dump_queue_members(q); 04171 04172 res = RES_OKAY; 04173 } else { 04174 res = RES_EXISTS; 04175 } 04176 ao2_unlock(q); 04177 ao2_unlock(queues); 04178 queue_unref(q); 04179 } 04180 04181 return res; 04182 }
| 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 2219 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_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_string_field_set, ast_strlen_zero(), ast_verb, ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_cdr::clid, compare_weight(), ast_channel::context, ast_channel::data, ast_cdr::dcontext, dialcontext, do_hang(), ast_cdr::dst, EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, callattempt::interface, ast_cdr::lastapp, callattempt::lastcall, ast_cdr::lastdata, callattempt::lastqueue, queue_ent::linpos, manager_event, callattempt::member, member::membername, 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, update_status(), ast_cdr::userfield, vars2manager(), ast_channel::whentohangup, and call_queue::wrapuptime.
Referenced by ring_one().
02220 { 02221 int res; 02222 int status; 02223 char tech[256]; 02224 char *location; 02225 const char *macrocontext, *macroexten; 02226 02227 /* on entry here, we know that tmp->chan == NULL */ 02228 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) || 02229 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) { 02230 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 02231 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface); 02232 if (qe->chan->cdr) 02233 ast_cdr_busy(qe->chan->cdr); 02234 tmp->stillgoing = 0; 02235 (*busies)++; 02236 return 0; 02237 } 02238 02239 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 02240 ast_debug(1, "%s in use, can't receive call\n", tmp->interface); 02241 if (qe->chan->cdr) 02242 ast_cdr_busy(qe->chan->cdr); 02243 tmp->stillgoing = 0; 02244 return 0; 02245 } 02246 02247 if (tmp->member->paused) { 02248 ast_debug(1, "%s paused, can't receive call\n", tmp->interface); 02249 if (qe->chan->cdr) 02250 ast_cdr_busy(qe->chan->cdr); 02251 tmp->stillgoing = 0; 02252 return 0; 02253 } 02254 if (use_weight && compare_weight(qe->parent,tmp->member)) { 02255 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 02256 if (qe->chan->cdr) 02257 ast_cdr_busy(qe->chan->cdr); 02258 tmp->stillgoing = 0; 02259 (*busies)++; 02260 return 0; 02261 } 02262 02263 ast_copy_string(tech, tmp->interface, sizeof(tech)); 02264 if ((location = strchr(tech, '/'))) 02265 *location++ = '\0'; 02266 else 02267 location = ""; 02268 02269 /* Request the peer */ 02270 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status); 02271 if (!tmp->chan) { /* If we can't, just go on to the next call */ 02272 if (qe->chan->cdr) 02273 ast_cdr_busy(qe->chan->cdr); 02274 tmp->stillgoing = 0; 02275 02276 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02277 02278 ao2_lock(qe->parent); 02279 qe->parent->rrpos++; 02280 qe->linpos++; 02281 ao2_unlock(qe->parent); 02282 02283 02284 (*busies)++; 02285 return 0; 02286 } 02287 02288 tmp->chan->appl = "AppQueue"; 02289 tmp->chan->data = "(Outgoing Line)"; 02290 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup)); 02291 if (tmp->chan->cid.cid_num) 02292 ast_free(tmp->chan->cid.cid_num); 02293 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num); 02294 if (tmp->chan->cid.cid_name) 02295 ast_free(tmp->chan->cid.cid_name); 02296 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name); 02297 if (tmp->chan->cid.cid_ani) 02298 ast_free(tmp->chan->cid.cid_ani); 02299 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani); 02300 02301 /* Inherit specially named variables from parent channel */ 02302 ast_channel_inherit_variables(qe->chan, tmp->chan); 02303 02304 /* Presense of ADSI CPE on outgoing channel follows ours */ 02305 tmp->chan->adsicpe = qe->chan->adsicpe; 02306 02307 /* Inherit context and extension */ 02308 ast_channel_lock(qe->chan); 02309 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 02310 ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext); 02311 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 02312 if (!ast_strlen_zero(macroexten)) 02313 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 02314 else 02315 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 02316 if (ast_cdr_isset_unanswered()) { 02317 /* they want to see the unanswered dial attempts! */ 02318 /* set up the CDR fields on all the CDRs to give sensical information */ 02319 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name); 02320 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid); 02321 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel); 02322 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src); 02323 strcpy(tmp->chan->cdr->dst, qe->chan->exten); 02324 strcpy(tmp->chan->cdr->dcontext, qe->chan->context); 02325 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp); 02326 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata); 02327 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags; 02328 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode); 02329 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); 02330 } 02331 ast_channel_unlock(qe->chan); 02332 02333 /* Place the call, but don't wait on the answer */ 02334 if ((res = ast_call(tmp->chan, location, 0))) { 02335 /* Again, keep going even if there's an error */ 02336 ast_debug(1, "ast call on peer returned %d\n", res); 02337 ast_verb(3, "Couldn't call %s\n", tmp->interface); 02338 do_hang(tmp); 02339 (*busies)++; 02340 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02341 return 0; 02342 } else if (qe->parent->eventwhencalled) { 02343 char vars[2048]; 02344 02345 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 02346 "Queue: %s\r\n" 02347 "AgentCalled: %s\r\n" 02348 "AgentName: %s\r\n" 02349 "ChannelCalling: %s\r\n" 02350 "DestinationChannel: %s\r\n" 02351 "CallerIDNum: %s\r\n" 02352 "CallerIDName: %s\r\n" 02353 "Context: %s\r\n" 02354 "Extension: %s\r\n" 02355 "Priority: %d\r\n" 02356 "Uniqueid: %s\r\n" 02357 "%s", 02358 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name, 02359 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown", 02360 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown", 02361 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid, 02362 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02363 ast_verb(3, "Called %s\n", tmp->interface); 02364 } 02365 02366 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface)); 02367 return 1; 02368 }
| 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 2396 of file app_queue.c.
References ast_debug, callattempt::chan, queue_ent::expire, find_best(), callattempt::interface, callattempt::metric, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_entry(), callattempt::stillgoing, and call_queue::strategy.
Referenced by try_calling(), and wait_for_answer().
02397 { 02398 int ret = 0; 02399 02400 while (ret == 0) { 02401 struct callattempt *best = find_best(outgoing); 02402 if (!best) { 02403 ast_debug(1, "Nobody left to try ringing in queue\n"); 02404 break; 02405 } 02406 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 02407 struct callattempt *cur; 02408 /* Ring everyone who shares this best metric (for ringall) */ 02409 for (cur = outgoing; cur; cur = cur->q_next) { 02410 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 02411 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 02412 ret |= ring_entry(qe, cur, busies); 02413 } 02414 } 02415 } else { 02416 /* Ring just the best channel */ 02417 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric); 02418 ret = ring_entry(qe, best, busies); 02419 } 02420 02421 /* If we have timed out, break out */ 02422 if (qe->expire && (time(NULL) >= qe->expire)) { 02423 ast_debug(1, "Queue timed out while ringing members.\n"); 02424 ret = 0; 02425 break; 02426 } 02427 } 02428 02429 return ret; 02430 }
| 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 2551 of file app_queue.c.
References ast_queue_log(), ast_verb, call_queue::autopause, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, manager_event, call_queue::name, queue_ent::parent, and set_member_paused().
Referenced by wait_for_answer().
02552 { 02553 ast_verb(3, "Nobody picked up in %d ms\n", rnatime); 02554 if (qe->parent->eventwhencalled) 02555 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer", 02556 "Queue: %s\r\n" 02557 "Uniqueid: %s\r\n" 02558 "Channel: %s\r\n" 02559 "Member: %s\r\n" 02560 "MemberName: %s\r\n" 02561 "Ringtime: %d\r\n", 02562 qe->parent->name, 02563 qe->chan->uniqueid, 02564 qe->chan->name, 02565 interface, 02566 membername, 02567 rnatime); 02568 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 02569 if (qe->parent->autopause && pause) { 02570 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) { 02571 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name); 02572 } else { 02573 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 02574 } 02575 } 02576 return; 02577 }
| static int rqm_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
RemoveQueueMember application.
Definition at line 4570 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, parse(), pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, and RES_OKAY.
Referenced by load_module().
04571 { 04572 int res=-1; 04573 char *parse, *temppos = NULL; 04574 AST_DECLARE_APP_ARGS(args, 04575 AST_APP_ARG(queuename); 04576 AST_APP_ARG(interface); 04577 AST_APP_ARG(options); 04578 ); 04579 04580 04581 if (ast_strlen_zero(data)) { 04582 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n"); 04583 return -1; 04584 } 04585 04586 parse = ast_strdupa(data); 04587 04588 AST_STANDARD_APP_ARGS(args, parse); 04589 04590 if (ast_strlen_zero(args.interface)) { 04591 args.interface = ast_strdupa(chan->name); 04592 temppos = strrchr(args.interface, '-'); 04593 if (temppos) 04594 *temppos = '\0'; 04595 } 04596 04597 switch (remove_from_queue(args.queuename, args.interface)) { 04598 case RES_OKAY: 04599 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 04600 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 04601 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 04602 res = 0; 04603 break; 04604 case RES_EXISTS: 04605 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 04606 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 04607 res = 0; 04608 break; 04609 case RES_NOSUCHQUEUE: 04610 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 04611 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 04612 res = 0; 04613 break; 04614 case RES_NOT_DYNAMIC: 04615 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 04616 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 04617 res = 0; 04618 break; 04619 } 04620 04621 return res; 04622 }
| static void rt_handle_member_record | ( | struct call_queue * | q, | |
| char * | interface, | |||
| const char * | rt_uniqueid, | |||
| const char * | membername, | |||
| const char * | penalty_str, | |||
| const char * | paused_str, | |||
| const char * | state_interface | |||
| ) | [static] |
Find rt member record to update otherwise create one.
Search for member in queue, if found update penalty/paused state, if no memeber exists create one flag it as a RT member and add to queue member list.
Definition at line 1347 of file app_queue.c.
References add_to_interfaces(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_ref, ast_copy_string(), ast_queue_log(), create_queue_member(), member::dead, member::interface, call_queue::membercount, call_queue::members, call_queue::name, member::paused, member::penalty, member::realtime, remove_from_interfaces(), member::rt_uniqueid, and member::state_interface.
Referenced by find_queue_by_name_rt(), and update_realtime_members().
01348 { 01349 struct member *m; 01350 struct ao2_iterator mem_iter; 01351 int penalty = 0; 01352 int paused = 0; 01353 int found = 0; 01354 01355 if (penalty_str) { 01356 penalty = atoi(penalty_str); 01357 if (penalty < 0) 01358 penalty = 0; 01359 } 01360 01361 if (paused_str) { 01362 paused = atoi(paused_str); 01363 if (paused < 0) 01364 paused = 0; 01365 } 01366 01367 /* Find member by realtime uniqueid and update */ 01368 mem_iter = ao2_iterator_init(q->members, 0); 01369 while ((m = ao2_iterator_next(&mem_iter))) { 01370 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) { 01371 m->dead = 0; /* Do not delete this one. */ 01372 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 01373 if (paused_str) 01374 m->paused = paused; 01375 if (strcasecmp(state_interface, m->state_interface)) { 01376 remove_from_interfaces(m->state_interface, 0); 01377 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface)); 01378 add_to_interfaces(m->state_interface); 01379 } 01380 m->penalty = penalty; 01381 found = 1; 01382 ao2_ref(m, -1); 01383 break; 01384 } 01385 ao2_ref(m, -1); 01386 } 01387 01388 /* Create a new member */ 01389 if (!found) { 01390 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) { 01391 m->dead = 0; 01392 m->realtime = 1; 01393 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid)); 01394 add_to_interfaces(m->state_interface); 01395 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", ""); 01396 ao2_link(q->members, m); 01397 ao2_ref(m, -1); 01398 m = NULL; 01399 q->membercount++; 01400 } 01401 } 01402 }
| static int say_periodic_announcement | ( | struct queue_ent * | qe, | |
| int | ringing | |||
| ) | [static] |
Playback announcement to queued members if peroid has elapsed.
Definition at line 2481 of file app_queue.c.
References AST_CONTROL_RINGING, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_random(), ast_strlen_zero(), ast_verb, queue_ent::chan, queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::moh, call_queue::numperiodicannounce, queue_ent::parent, call_queue::periodicannouncefrequency, play_file(), call_queue::randomperiodicannounce, call_queue::sound_periodicannounce, ast_str::str, and valid_exit().
Referenced by queue_exec(), and wait_our_turn().
02482 { 02483 int res = 0; 02484 time_t now; 02485 02486 /* Get the current time */ 02487 time(&now); 02488 02489 /* Check to see if it is time to announce */ 02490 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 02491 return 0; 02492 02493 /* Stop the music on hold so we can play our own file */ 02494 if (ringing) 02495 ast_indicate(qe->chan,-1); 02496 else 02497 ast_moh_stop(qe->chan); 02498 02499 ast_verb(3, "Playing periodic announcement\n"); 02500 02501 if (qe->parent->randomperiodicannounce) { 02502 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce; 02503 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce || 02504 ast_strlen_zero(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str)) { 02505 qe->last_periodic_announce_sound = 0; 02506 } 02507 02508 /* play the announcement */ 02509 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str); 02510 02511 if (res > 0 && !valid_exit(qe, res)) 02512 res = 0; 02513 02514 /* Resume Music on Hold if the caller is going to stay in the queue */ 02515 if (!res) { 02516 if (ringing) 02517 ast_indicate(qe->chan, AST_CONTROL_RINGING); 02518 else 02519 ast_moh_start(qe->chan, qe->moh, NULL); 02520 } 02521 02522 /* update last_periodic_announce_time */ 02523 qe->last_periodic_announce_time = now; 02524 02525 /* Update the current periodic announcement to the next announcement */ 02526 if (!qe->parent->randomperiodicannounce) { 02527 qe->last_periodic_announce_sound++; 02528 } 02529 02530 return res; 02531 }
| static int say_position | ( | struct queue_ent * | qe, | |
| int | ringing | |||
| ) | [static] |
Definition at line 1838 of file app_queue.c.
References call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, AST_CONTROL_RINGING, AST_DIGIT_ANY, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_say_number(), ast_verb, queue_ent::chan, call_queue::holdtime, queue_ent::last_pos, queue_ent::last_pos_said, call_queue::minannouncefrequency, queue_ent::moh, call_queue::name, queue_ent::parent, play_file(), queue_ent::pos, call_queue::queue_quantity1, call_queue::queue_quantity2, call_queue::roundingseconds, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_minute, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, queue_ent::start, and valid_exit().
Referenced by queue_exec(), and wait_our_turn().
01839 { 01840 int res = 0, avgholdmins, avgholdsecs, announceposition = 0; 01841 int say_thanks = 1; 01842 time_t now; 01843 01844 /* Let minannouncefrequency seconds pass between the start of each position announcement */ 01845 time(&now); 01846 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) 01847 return 0; 01848 01849 /* If either our position has changed, or we are over the freq timer, say position */ 01850 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) 01851 return 0; 01852 01853 if (ringing) { 01854 ast_indicate(qe->chan,-1); 01855 } else { 01856 ast_moh_stop(qe->chan); 01857 } 01858 01859 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES || 01860 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN || 01861 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT && 01862 qe->pos <= qe->parent->announcepositionlimit)) 01863 announceposition = 1; 01864 01865 01866 if (announceposition == 1) { 01867 /* Say we're next, if we are */ 01868 if (qe->pos == 1) { 01869 res = play_file(qe->chan, qe->parent->sound_next); 01870 if (res) 01871 goto playout; 01872 else 01873 goto posout; 01874 } else { 01875 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 01876 /* More than Case*/ 01877 res = play_file(qe->chan, qe->parent->queue_quantity1); 01878 if (res) 01879 goto playout; 01880 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 01881 if (res) 01882 goto playout; 01883 } else { 01884 /* Normal Case */ 01885 res = play_file(qe->chan, qe->parent->sound_thereare); 01886 if (res) 01887 goto playout; 01888 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */ 01889 if (res) 01890 goto playout; 01891 } 01892 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){ 01893 /* More than Case*/ 01894 res = play_file(qe->chan, qe->parent->queue_quantity2); 01895 if (res) 01896 goto playout; 01897 } else { 01898 res = play_file(qe->chan, qe->parent->sound_calls); 01899 if (res) 01900 goto playout; 01901 } 01902 } 01903 } 01904 /* Round hold time to nearest minute */ 01905 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60); 01906 01907 /* If they have specified a rounding then round the seconds as well */ 01908 if (qe->parent->roundingseconds) { 01909 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds; 01910 avgholdsecs *= qe->parent->roundingseconds; 01911 } else { 01912 avgholdsecs = 0; 01913 } 01914 01915 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 01916 01917 /* If the hold time is >1 min, if it's enabled, and if it's not 01918 supposed to be only once and we have already said it, say it */ 01919 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime && 01920 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) || 01921 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) { 01922 res = play_file(qe->chan, qe->parent->sound_holdtime); 01923 if (res) 01924 goto playout; 01925 01926 if (avgholdmins >= 1) { 01927 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL); 01928 if (res) 01929 goto playout; 01930 01931 if (avgholdmins == 1) { 01932 res = play_file(qe->chan, qe->parent->sound_minute); 01933 if (res) 01934 goto playout; 01935 } else { 01936 res = play_file(qe->chan, qe->parent->sound_minutes); 01937 if (res) 01938 goto playout; 01939 } 01940 } 01941 if (avgholdsecs >= 1) { 01942 res = ast_say_number(qe->chan, avgholdmins > 1 ? avgholdsecs : avgholdmins * 60 + avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL); 01943 if (res) 01944 goto playout; 01945 01946 res = play_file(qe->chan, qe->parent->sound_seconds); 01947 if (res) 01948 goto playout; 01949 } 01950 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) { 01951 say_thanks = 0; 01952 } 01953 01954 posout: 01955 if (qe->parent->announceposition) { 01956 ast_verb(3, "Told %s in %s their queue position (which was %d)\n", 01957 qe->chan->name, qe->parent->name, qe->pos); 01958 } 01959 if (say_thanks) { 01960 res = play_file(qe->chan, qe->parent->sound_thanks); 01961 } 01962 playout: 01963 01964 if ((res > 0 && !valid_exit(qe, res))) 01965 res = 0; 01966 01967 /* Set our last_pos indicators */ 01968 qe->last_pos = now; 01969 qe->last_pos_said = qe->pos; 01970 01971 /* Don't restart music on hold if we're about to exit the caller from the queue */ 01972 if (!res) { 01973 if (ringing) { 01974 ast_indicate(qe->chan, AST_CONTROL_RINGING); 01975 } else { 01976 ast_moh_start(qe->chan, qe->moh, NULL); 01977 } 01978 } 01979 return res; 01980 }
| 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 3137 of file app_queue.c.
References AGENT, CALLER, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, member::interface, manager_event, member::membername, queue_ent::parent, QUEUE_EVENT_VARIABLES, queue_ent::start, TRANSFER, and vars2manager().
Referenced by try_calling().
03140 { 03141 const char *reason = NULL; /* silence dumb compilers */ 03142 03143 if (!qe->parent->eventwhencalled) 03144 return; 03145 03146 switch (rsn) { 03147 case CALLER: 03148 reason = "caller"; 03149 break; 03150 case AGENT: 03151 reason = "agent"; 03152 break; 03153 case TRANSFER: 03154 reason = "transfer"; 03155 break; 03156 } 03157 03158 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 03159 "Queue: %s\r\n" 03160 "Uniqueid: %s\r\n" 03161 "Channel: %s\r\n" 03162 "Member: %s\r\n" 03163 "MemberName: %s\r\n" 03164 "HoldTime: %ld\r\n" 03165 "TalkTime: %ld\r\n" 03166 "Reason: %s\r\n" 03167 "%s", 03168 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03169 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason, 03170 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : ""); 03171 }
| static int set_member_paused | ( | const char * | queuename, | |
| const char * | interface, | |||
| const char * | reason, | |||
| int | paused | |||
| ) | [static] |
Definition at line 4246 of file app_queue.c.
References 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().
04247 { 04248 int found = 0; 04249 struct call_queue *q; 04250 struct member *mem; 04251 struct ao2_iterator queue_iter; 04252 int failed; 04253 04254 /* Special event for when all queues are paused - individual events still generated */ 04255 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */ 04256 if (ast_strlen_zero(queuename)) 04257 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 04258 04259 queue_iter = ao2_iterator_init(queues, 0); 04260 while ((q = ao2_iterator_next(&queue_iter))) { 04261 ao2_lock(q); 04262 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 04263 if ((mem = interface_exists(q, interface))) { 04264 if (mem->paused == paused) { 04265 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 04266 } 04267 04268 failed = 0; 04269 if (mem->realtime) { 04270 failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0"); 04271 } 04272 04273 if (failed) { 04274 ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface); 04275 ao2_ref(mem, -1); 04276 ao2_unlock(q); 04277 continue; 04278 } 04279 found++; 04280 mem->paused = paused; 04281 04282 if (queue_persistent_members) 04283 dump_queue_members(q); 04284 04285 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, "")); 04286 04287 if (!ast_strlen_zero(reason)) { 04288 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 04289 "Queue: %s\r\n" 04290 "Location: %s\r\n" 04291 "MemberName: %s\r\n" 04292 "Paused: %d\r\n" 04293 "Reason: %s\r\n", 04294 q->name, mem->interface, mem->membername, paused, reason); 04295 } else { 04296 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 04297 "Queue: %s\r\n" 04298 "Location: %s\r\n" 04299 "MemberName: %s\r\n" 04300 "Paused: %d\r\n", 04301 q->name, mem->interface, mem->membername, paused); 04302 } 04303 ao2_ref(mem, -1); 04304 } 04305 } 04306 04307 if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) { 04308 ao2_unlock(q); 04309 queue_unref(q); 04310 break; 04311 } 04312 04313 ao2_unlock(q); 04314 queue_unref(q); 04315 } 04316 04317 return found ? RESULT_SUCCESS : RESULT_FAILURE; 04318 }
| static int set_member_penalty | ( | char * | queuename, | |
| char * | interface, | |||
| int | penalty | |||
| ) | [static] |
Definition at line 4321 of file app_queue.c.
References 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().
04322 { 04323 int foundinterface = 0, foundqueue = 0; 04324 struct call_queue *q; 04325 struct member *mem; 04326 struct ao2_iterator queue_iter; 04327 04328 if (penalty < 0) { 04329 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty); 04330 return RESULT_FAILURE; 04331 } 04332 04333 queue_iter = ao2_iterator_init(queues, 0); 04334 while ((q = ao2_iterator_next(&queue_iter))) { 04335 ao2_lock(q); 04336 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 04337 foundqueue++; 04338 if ((mem = interface_exists(q, interface))) { 04339 foundinterface++; 04340 mem->penalty = penalty; 04341 04342 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty); 04343 manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty", 04344 "Queue: %s\r\n" 04345 "Location: %s\r\n" 04346 "Penalty: %d\r\n", 04347 q->name, mem->interface, penalty); 04348 ao2_ref(mem, -1); 04349 } 04350 } 04351 ao2_unlock(q); 04352 queue_unref(q); 04353 } 04354 04355 if (foundinterface) { 04356 return RESULT_SUCCESS; 04357 } else if (!foundqueue) { 04358 ast_log (LOG_ERROR, "Invalid queuename\n"); 04359 } else { 04360 ast_log (LOG_ERROR, "Invalid interface\n"); 04361 } 04362 04363 return RESULT_FAILURE; 04364 }
| static void set_queue_result | ( | struct ast_channel * | chan, | |
| enum queue_result | res | |||
| ) | [static] |
sets the QUEUESTATUS channel variable
Definition at line 554 of file app_queue.c.
References ARRAY_LEN, pbx_builtin_setvar_helper(), queue_results, and text.
Referenced by queue_exec().
00555 { 00556 int i; 00557 00558 for (i = 0; i < ARRAY_LEN(queue_results); i++) { 00559 if (queue_results[i].id == res) { 00560 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 00561 return; 00562 } 00563 } 00564 }
| static void set_queue_variables | ( | struct call_queue * | q, | |
| struct ast_channel * | chan | |||
| ) | [static] |
Set variables of queue.
Definition at line 616 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().
00617 { 00618 char interfacevar[256]=""; 00619 float sl = 0; 00620 00621 if (q->setqueuevar) { 00622 sl = 0; 00623 if (q->callscompleted > 0) 00624 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 00625 00626 snprintf(interfacevar, sizeof(interfacevar), 00627 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 00628 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 00629 00630 pbx_builtin_setvar_multiple(chan, interfacevar); 00631 } 00632 }
| 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 3241 of file app_queue.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_log(), queue_transfer_ds::callcompletedinsl, queue_ent::chan, ast_datastore::data, LOG_WARNING, queue_transfer_ds::member, queue_transfer_ds::qe, queue_transfer_info, and queue_transfer_ds::starttime.
Referenced by try_calling().
03242 { 03243 struct ast_datastore *ds; 03244 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds)); 03245 03246 if (!qtds) { 03247 ast_log(LOG_WARNING, "Memory allocation error!\n"); 03248 return NULL; 03249 } 03250 03251 ast_channel_lock(qe->chan); 03252 if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) { 03253 ast_channel_unlock(qe->chan); 03254 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n"); 03255 return NULL; 03256 } 03257 03258 qtds->qe = qe; 03259 /* This member is refcounted in try_calling, so no need to add it here, too */ 03260 qtds->member = member; 03261 qtds->starttime = starttime; 03262 qtds->callcompletedinsl = callcompletedinsl; 03263 ds->data = qtds; 03264 ast_channel_datastore_add(qe->chan, ds); 03265 ast_channel_unlock(qe->chan); 03266 return ds; 03267 }
| 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 2457 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().
02458 { 02459 struct callattempt *best = find_best(outgoing); 02460 02461 if (best) { 02462 /* Ring just the best channel */ 02463 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 02464 qe->linpos = best->metric % 1000; 02465 } else { 02466 /* Just increment rrpos */ 02467 if (qe->linwrapped) { 02468 /* No more channels, start over */ 02469 qe->linpos = 0; 02470 } else { 02471 /* Prioritize next entry */ 02472 qe->linpos++; 02473 } 02474 } 02475 qe->linwrapped = 0; 02476 02477 return 0; 02478 }
| static int store_next_rr | ( | struct queue_ent * | qe, | |
| struct callattempt * | outgoing | |||
| ) | [static] |
Search for best metric and add to Round Robbin queue.
Definition at line 2433 of file app_queue.c.
References ast_debug, find_best(), callattempt::interface, callattempt::metric, queue_ent::parent, call_queue::rrpos, and call_queue::wrapped.
Referenced by try_calling().
02434 { 02435 struct callattempt *best = find_best(outgoing); 02436 02437 if (best) { 02438 /* Ring just the best channel */ 02439 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric); 02440 qe->parent->rrpos = best->metric % 1000; 02441 } else { 02442 /* Just increment rrpos */ 02443 if (qe->parent->wrapped) { 02444 /* No more channels, start over */ 02445 qe->parent->rrpos = 0; 02446 } else { 02447 /* Prioritize next entry */ 02448 qe->parent->rrpos++; 02449 } 02450 } 02451 qe->parent->wrapped = 0; 02452 02453 return 0; 02454 }
| static int strat2int | ( | const char * | strategy | ) | [static] |
Definition at line 578 of file app_queue.c.
References ARRAY_LEN, and strategies.
Referenced by find_queue_by_name_rt(), queue_set_param(), and reload_queues().
00579 { 00580 int x; 00581 00582 for (x = 0; x < ARRAY_LEN(strategies); x++) { 00583 if (!strcasecmp(strategy, strategies[x].name)) 00584 return strategies[x].strategy; 00585 } 00586 00587 return -1; 00588 }
| static int try_calling | ( | struct queue_ent * | qe, | |
| const char * | options, | |||
| char * | announceoverride, | |||
| const char * | url, | |||
| int * | tries, | |||
| int * | noption, | |||
| const char * | agi, | |||
| const char * | macro, | |||
| const char * | gosub, | |||
| int | ringing | |||
| ) | [static] |
A large function which calls members, updates statistics, and bridges the caller and a member.
Here is the process of this function 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue() 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also during each iteration, we call calc_metric to determine which members should be rung when. 3. Call ring_one to place a call to the appropriate member(s) 4. Call wait_for_answer to wait for an answer. If no one answers, return. 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered. 6. Start the monitor or mixmonitor if the option is set 7. Remove the caller from the queue to allow other callers to advance 8. Bridge the call. 9. Do any post processing after the call has disconnected.
| [in] | qe | the queue_ent structure which corresponds to the caller attempting to reach members |
| [in] | options | the options passed as the third parameter to the Queue() application |
| [in] | announceoverride | filename to play to user when waiting |
| [in] | url | the url passed as the fourth parameter to the Queue() application |
| [in,out] | tries | the number of times we have tried calling queue members |
| [out] | noption | set if the call to Queue() has the 'n' option set. |
| [in] | agi | the agi passed as the fifth parameter to the Queue() application |
| [in] | macro | the macro passed as the sixth parameter to the Queue() application |
| [in] | gosub | the gosub passed as the seventh parameter to the Queue() application |
| [in] | ringing | 1 if the 'r' option is set, otherwise 0 |
Definition at line 3323 of file app_queue.c.
References ast_channel::_state, AGENT, queue_ent::announce, ao2_alloc, ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), asprintf, ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_calloc, ast_cdr_failed(), AST_CDR_FLAG_LOCKED, AST_CDR_FLAG_POST_DISABLED, ast_cdr_isset_unanswered(), ast_cdr_noanswer(), ast_cdr_setdestchan(), ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_sendurl(), ast_channel_setoption(), ast_channel_supports_html(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, ast_copy_string(), ast_datastore_alloc, ast_datastore_free(), ast_debug, AST_DIGIT_ANY, AST_FEATURE_AUTOMIXMON, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_free, ast_hangup(), ast_indicate(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_moh_stop(), ast_monitor_setjoinfiles(), ast_monitor_start(), AST_OPTION_TONE_VERIFY, ast_pbx_run_args(), ast_queue_log(), ast_random(), ast_safe_sleep(), ast_say_number(), ast_set_flag, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, attended_transfer_occurred(), calc_metric(), CALLER, member::calls, ast_channel::cdr, queue_end_bridge::chan, callattempt::chan, queue_ent::chan, ast_channel::context, ast_datastore::data, DATASTORE_INHERIT_FOREVER, di, dialed_interface_info, ast_cdr::dstchannel, member::dynamic, end_bridge_callback(), ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, end_bridge_callback_data_fixup(), ast_bridge_config::end_bridge_callback_data_fixup, errno, EVENT_FLAG_AGENT, call_queue::eventwhencalled, queue_ent::expire, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, free, queue_ent::handled, hangupcalls(), ast_datastore::inheritance, callattempt::interface, ast_dialed_interface::interface, member::interface, member::lastcall, callattempt::lastcall, member::lastqueue, callattempt::lastqueue, leave_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, manager_event, callattempt::member, call_queue::membercount, call_queue::memberdelay, call_queue::membergosub, call_queue::membermacro, member::membername, call_queue::members, call_queue::monfmt, call_queue::montype, call_queue::name, ast_pbx_args::no_hangup_chan, callattempt::oldstatus, queue_ent::opos, queue_ent::parent, pbx_builtin_getvar_helper(), pbx_builtin_setvar_multiple(), pbx_exec(), pbx_findapp(), pbx_substitute_variables_helper(), member::penalty, queue_ent::pending, play_file(), queue_ent::pos, ast_channel::priority, queue_end_bridge::q, callattempt::q_next, QUEUE_EVENT_VARIABLES, queue_ref(), QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRMEMORY, queue_transfer_info, queues, member::realtime, recalc_holdtime(), record_abandoned(), call_queue::reportholdtime, ring_one(), send_agent_complete(), call_queue::servicelevel, set_queue_variables(), call_queue::setinterfacevar, call_queue::setqueueentryvar, setup_transfer_datastore(), call_queue::sound_callerannounce, call_queue::sound_minute, call_queue::sound_minutes, call_queue::sound_reporthold, call_queue::sound_seconds, queue_ent::start, member::status, callattempt::stillgoing, store_next_lin(), store_next_rr(), call_queue::strategy, ast_channel::tech, call_queue::timeout, TIMEOUT_PRIORITY_APP, call_queue::timeoutpriority, TRANSFER, ast_channel_tech::type, ast_cdr::uniqueid, update_queue(), vars2manager(), wait_for_answer(), X_REC_IN, and X_REC_OUT.
Referenced by queue_exec().
03324 { 03325 struct member *cur; 03326 struct callattempt *outgoing = NULL; /* the list of calls we are building */ 03327 int to, orig; 03328 char oldexten[AST_MAX_EXTENSION]=""; 03329 char oldcontext[AST_MAX_CONTEXT]=""; 03330 char queuename[256]=""; 03331 char interfacevar[256]=""; 03332 struct ast_channel *peer; 03333 struct ast_channel *which; 03334 struct callattempt *lpeer; 03335 struct member *member; 03336 struct ast_app *application; 03337 int res = 0, bridge = 0; 03338 int numbusies = 0; 03339 int x=0; 03340 char *announce = NULL; 03341 char digit = 0; 03342 time_t callstart; 03343 time_t now = time(NULL); 03344 struct ast_bridge_config bridge_config; 03345 char nondataquality = 1; 03346 char *agiexec = NULL; 03347 char *macroexec = NULL; 03348 char *gosubexec = NULL; 03349 int ret = 0; 03350 const char *monitorfilename; 03351 const char *monitor_exec; 03352 const char *monitor_options; 03353 char tmpid[256], tmpid2[256]; 03354 char meid[1024], meid2[1024]; 03355 char mixmonargs[1512]; 03356 struct ast_app *mixmonapp = NULL; 03357 char *p; 03358 char vars[2048]; 03359 int forwardsallowed = 1; 03360 int callcompletedinsl; 03361 struct ao2_iterator memi; 03362 struct ast_datastore *datastore, *transfer_ds; 03363 struct queue_end_bridge *queue_end_bridge = NULL; 03364 03365 ast_channel_lock(qe->chan); 03366 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL); 03367 ast_channel_unlock(qe->chan); 03368 03369 memset(&bridge_config, 0, sizeof(bridge_config)); 03370 tmpid[0] = 0; 03371 meid[0] = 0; 03372 time(&now); 03373 03374 /* If we've already exceeded our timeout, then just stop 03375 * This should be extremely rare. queue_exec will take care 03376 * of removing the caller and reporting the timeout as the reason. 03377 */ 03378 if (qe->expire && now >= qe->expire) { 03379 res = 0; 03380 goto out; 03381 } 03382 03383 for (; options && *options; options++) 03384 switch (*options) { 03385 case 't': 03386 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 03387 break; 03388 case 'T': 03389 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 03390 break; 03391 case 'w': 03392 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 03393 break; 03394 case 'W': 03395 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 03396 break; 03397 case 'c': 03398 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN); 03399 break; 03400 case 'd': 03401 nondataquality = 0; 03402 break; 03403 case 'h': 03404 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 03405 break; 03406 case 'H': 03407 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 03408 break; 03409 case 'k': 03410 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL); 03411 break; 03412 case 'K': 03413 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL); 03414 break; 03415 case 'n': 03416 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR) 03417 (*tries)++; 03418 else 03419 *tries = qe->parent->membercount; 03420 *noption = 1; 03421 break; 03422 case 'i': 03423 forwardsallowed = 0; 03424 break; 03425 case 'x': 03426 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON); 03427 break; 03428 case 'X': 03429 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON); 03430 break; 03431 03432 } 03433 03434 /* Hold the lock while we setup the outgoing calls */ 03435 if (use_weight) 03436 ao2_lock(queues); 03437 ao2_lock(qe->parent); 03438 ast_debug(1, "%s is trying to call a queue member.\n", 03439 qe->chan->name); 03440 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 03441 if (!ast_strlen_zero(qe->announce)) 03442 announce = qe->announce; 03443 if (!ast_strlen_zero(announceoverride)) 03444 announce = announceoverride; 03445 03446 memi = ao2_iterator_init(qe->parent->members, 0); 03447 while ((cur = ao2_iterator_next(&memi))) { 03448 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp)); 03449 struct ast_dialed_interface *di; 03450 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 03451 if (!tmp) { 03452 ao2_ref(cur, -1); 03453 ao2_unlock(qe->parent); 03454 if (use_weight) 03455 ao2_unlock(queues); 03456 goto out; 03457 } 03458 if (!datastore) { 03459 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) { 03460 ao2_ref(cur, -1); 03461 ao2_unlock(qe->parent); 03462 if (use_weight) 03463 ao2_unlock(queues); 03464 free(tmp); 03465 goto out; 03466 } 03467 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 03468 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 03469 ao2_ref(cur, -1); 03470 ao2_unlock(&qe->parent); 03471 if (use_weight) 03472 ao2_unlock(queues); 03473 free(tmp); 03474 goto out; 03475 } 03476 datastore->data = dialed_interfaces; 03477 AST_LIST_HEAD_INIT(dialed_interfaces); 03478 03479 ast_channel_lock(qe->chan); 03480 ast_channel_datastore_add(qe->chan, datastore); 03481 ast_channel_unlock(qe->chan); 03482 } else 03483 dialed_interfaces = datastore->data; 03484 03485 AST_LIST_LOCK(dialed_interfaces); 03486 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 03487 if (!strcasecmp(cur->interface, di->interface)) { 03488 ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n", 03489 di->interface); 03490 break; 03491 } 03492 } 03493 AST_LIST_UNLOCK(dialed_interfaces); 03494 03495 if (di) { 03496 free(tmp); 03497 continue; 03498 } 03499 03500 /* It is always ok to dial a Local interface. We only keep track of 03501 * which "real" interfaces have been dialed. The Local channel will 03502 * inherit this list so that if it ends up dialing a real interface, 03503 * it won't call one that has already been called. */ 03504 if (strncasecmp(cur->interface, "Local/", 6)) { 03505 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) { 03506 ao2_ref(cur, -1); 03507 ao2_unlock(qe->parent); 03508 if (use_weight) 03509 ao2_unlock(queues); 03510 free(tmp); 03511 goto out; 03512 } 03513 strcpy(di->interface, cur->interface); 03514 03515 AST_LIST_LOCK(dialed_interfaces); 03516 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 03517 AST_LIST_UNLOCK(dialed_interfaces); 03518 } 03519 03520 tmp->stillgoing = -1; 03521 tmp->member = cur; 03522 tmp->oldstatus = cur->status; 03523 tmp->lastcall = cur->lastcall; 03524 tmp->lastqueue = cur->lastqueue; 03525 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 03526 /* Special case: If we ring everyone, go ahead and ring them, otherwise 03527 just calculate their metric for the appropriate strategy */ 03528 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) { 03529 /* Put them in the list of outgoing thingies... We're ready now. 03530 XXX If we're forcibly removed, these outgoing calls won't get 03531 hung up XXX */ 03532 tmp->q_next = outgoing; 03533 outgoing = tmp; 03534 /* If this line is up, don't try anybody else */ 03535 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 03536 break; 03537 } else { 03538 ao2_ref(cur, -1); 03539 ast_free(tmp); 03540 } 03541 } 03542 03543 if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) { 03544 /* Application arguments have higher timeout priority (behaviour for <=1.6) */ 03545 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) 03546 to = (qe->expire - now) * 1000; 03547 else 03548 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1; 03549 } else { 03550 /* Config timeout is higher priority thatn application timeout */ 03551 if (qe->expire && qe->expire<=now) { 03552 to = 0; 03553 } else if (qe->parent->timeout) { 03554 to = qe->parent->timeout * 1000; 03555 } else { 03556 to = -1; 03557 } 03558 } 03559 orig = to; 03560 ++qe->pending; 03561 ao2_unlock(qe->parent); 03562 ring_one(qe, outgoing, &numbusies); 03563 if (use_weight) 03564 ao2_unlock(queues); 03565 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed); 03566 /* The ast_channel_datastore_remove() function could fail here if the 03567 * datastore was moved to another channel during a masquerade. If this is 03568 * the case, don't free the datastore here because later, when the channel 03569 * to which the datastore was moved hangs up, it will attempt to free this 03570 * datastore again, causing a crash 03571 */ 03572 ast_channel_lock(qe->chan); 03573 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) { 03574 ast_datastore_free(datastore); 03575 } 03576 ast_channel_unlock(qe->chan); 03577 ao2_lock(qe->parent); 03578 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) { 03579 store_next_rr(qe, outgoing); 03580 } 03581 if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) { 03582 store_next_lin(qe, outgoing); 03583 } 03584 ao2_unlock(qe->parent); 03585 peer = lpeer ? lpeer->chan : NULL; 03586 if (!peer) { 03587 qe->pending = 0; 03588 if (to) { 03589 /* Must gotten hung up */ 03590 res = -1; 03591 } else { 03592 /* User exited by pressing a digit */ 03593 res = digit; 03594 } 03595 if (res == -1) 03596 ast_debug(1, "%s: Nobody answered.\n", qe->chan->name); 03597 if (ast_cdr_isset_unanswered()) { 03598 /* channel contains the name of one of the outgoing channels 03599 in its CDR; zero out this CDR to avoid a dual-posting */ 03600 struct callattempt *o; 03601 for (o = outgoing; o; o = o->q_next) { 03602 if (!o->chan) { 03603 continue; 03604 } 03605 if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) { 03606 ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED); 03607 break; 03608 } 03609 } 03610 } 03611 } else { /* peer is valid */ 03612 /* Ah ha! Someone answered within the desired timeframe. Of course after this 03613 we will always return with -1 so that it is hung up properly after the 03614 conversation. */ 03615 if (!strcmp(qe->chan->tech->type, "DAHDI")) 03616 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 03617 if (!strcmp(peer->tech->type, "DAHDI")) 03618 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 03619 /* Update parameters for the queue */ 03620 time(&now); 03621 recalc_holdtime(qe, (now - qe->start)); 03622 ao2_lock(qe->parent); 03623 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel); 03624 ao2_unlock(qe->parent); 03625 member = lpeer->member; 03626 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */ 03627 ao2_ref(member, 1); 03628 hangupcalls(outgoing, peer); 03629 outgoing = NULL; 03630 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 03631 int res2; 03632 03633 res2 = ast_autoservice_start(qe->chan); 03634 if (!res2) { 03635 if (qe->parent->memberdelay) { 03636 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 03637 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 03638 } 03639 if (!res2 && announce) { 03640 play_file(peer, announce); 03641 } 03642 if (!res2 && qe->parent->reportholdtime) { 03643 if (!play_file(peer, qe->parent->sound_reporthold)) { 03644 int holdtime, holdtimesecs; 03645 03646 time(&now); 03647 holdtime = abs((now - qe->start) / 60); 03648 holdtimesecs = abs((now - qe->start)); 03649 if (holdtime == 1) { 03650 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 03651 play_file(peer, qe->parent->sound_minute); 03652 } else { 03653 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 03654 play_file(peer, qe->parent->sound_minutes); 03655 } 03656 if (holdtimesecs > 1) { 03657 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL); 03658 play_file(peer, qe->parent->sound_seconds); 03659 } 03660 } 03661 } 03662 } 03663 res2 |= ast_autoservice_stop(qe->chan); 03664 if (ast_check_hangup(peer)) { 03665 /* Agent must have hung up */ 03666 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name); 03667 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", ""); 03668 if (qe->parent->eventwhencalled) 03669 manager_event(EVENT_FLAG_AGENT, "AgentDump", 03670 "Queue: %s\r\n" 03671 "Uniqueid: %s\r\n" 03672 "Channel: %s\r\n" 03673 "Member: %s\r\n" 03674 "MemberName: %s\r\n" 03675 "%s", 03676 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03677 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03678 ast_hangup(peer); 03679 ao2_ref(member, -1); 03680 goto out; 03681 } else if (res2) { 03682 /* Caller must have hung up just before being connected*/ 03683 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 03684 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 03685 record_abandoned(qe); 03686 ast_cdr_noanswer(qe->chan->cdr); 03687 ast_hangup(peer); 03688 ao2_ref(member, -1); 03689 return -1; 03690 } 03691 } 03692 /* Stop music on hold */ 03693 if (ringing) 03694 ast_indicate(qe->chan,-1); 03695 else 03696 ast_moh_stop(qe->chan); 03697 /* If appropriate, log that we have a destination channel */ 03698 if (qe->chan->cdr) 03699 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 03700 /* Make sure channels are compatible */ 03701 res = ast_channel_make_compatible(qe->chan, peer); 03702 if (res < 0) { 03703 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", ""); 03704 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 03705 record_abandoned(qe); 03706 ast_cdr_failed(qe->chan->cdr); 03707 ast_hangup(peer); 03708 ao2_ref(member, -1); 03709 return -1; 03710 } 03711 03712 /* Play announcement to the caller telling it's his turn if defined */ 03713 if (!ast_strlen_zero(qe->parent->sound_callerannounce)) { 03714 if (play_file(qe->chan, qe->parent->sound_callerannounce)) 03715 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce); 03716 } 03717 03718 ao2_lock(qe->parent); 03719 /* if setinterfacevar is defined, make member variables available to the channel */ 03720 /* use pbx_builtin_setvar to set a load of variables with one call */ 03721 if (qe->parent->setinterfacevar) { 03722 snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d", 03723 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime); 03724 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 03725 pbx_builtin_setvar_multiple(peer, interfacevar); 03726 } 03727 03728 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */ 03729 /* use pbx_builtin_setvar to set a load of variables with one call */ 03730 if (qe->parent->setqueueentryvar) { 03731 snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d", 03732 (long) time(NULL) - qe->start, qe->opos); 03733 pbx_builtin_setvar_multiple(qe->chan, interfacevar); 03734 pbx_builtin_setvar_multiple(peer, interfacevar); 03735 } 03736 03737 /* try to set queue variables if configured to do so*/ 03738 set_queue_variables(qe->parent, qe->chan); 03739 set_queue_variables(qe->parent, peer); 03740 ao2_unlock(qe->parent); 03741 03742 ast_channel_lock(qe->chan); 03743 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) { 03744 monitorfilename = ast_strdupa(monitorfilename); 03745 } 03746 ast_channel_unlock(qe->chan); 03747 /* Begin Monitoring */ 03748 if (qe->parent->monfmt && *qe->parent->monfmt) { 03749 if (!qe->parent->montype) { 03750 const char *monexec, *monargs; 03751 ast_debug(1, "Starting Monitor as requested.\n"); 03752 ast_channel_lock(qe->chan); 03753 if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || (monargs = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))) { 03754 which = qe->chan; 03755 monexec = monexec ? ast_strdupa(monexec) : NULL; 03756 } 03757 else 03758 which = peer; 03759 ast_channel_unlock(qe->chan); 03760 if (ast_monitor_start) { 03761 if (monitorfilename) { 03762 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT); 03763 } else if (qe->chan->cdr && ast_monitor_start) { 03764 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT); 03765 } else if (ast_monitor_start) { 03766 /* Last ditch effort -- no CDR, make up something */ 03767 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 03768 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT); 03769 } 03770 } 03771 if (!ast_strlen_zero(monexec) && ast_monitor_setjoinfiles) { 03772 ast_monitor_setjoinfiles(which, 1); 03773 } 03774 } else { 03775 mixmonapp = pbx_findapp("MixMonitor"); 03776 03777 if (mixmonapp) { 03778 ast_debug(1, "Starting MixMonitor as requested.\n"); 03779 if (!monitorfilename) { 03780 if (qe->chan->cdr) 03781 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)); 03782 else 03783 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); 03784 } else { 03785 const char *m = monitorfilename; 03786 for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) { 03787 switch (*m) { 03788 case '^': 03789 if (*(m + 1) == '{') 03790 *p = '$'; 03791 break; 03792 case ',': 03793 *p++ = '\\'; 03794 /* Fall through */ 03795 default: 03796 *p = *m; 03797 } 03798 if (*m == '\0') 03799 break; 03800 } 03801 if (p == tmpid2 + sizeof(tmpid2)) 03802 tmpid2[sizeof(tmpid2) - 1] = '\0'; 03803 03804 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); 03805 } 03806 03807 ast_channel_lock(qe->chan); 03808 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) { 03809 monitor_exec = ast_strdupa(monitor_exec); 03810 } 03811 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) { 03812 monitor_options = ast_strdupa(monitor_options); 03813 } else { 03814 monitor_options = ""; 03815 } 03816 ast_channel_unlock(qe->chan); 03817 03818 if (monitor_exec) { 03819 const char *m = monitor_exec; 03820 for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) { 03821 switch (*m) { 03822 case '^': 03823 if (*(m + 1) == '{') 03824 *p = '$'; 03825 break; 03826 case ',': 03827 *p++ = '\\'; 03828 /* Fall through */ 03829 default: 03830 *p = *m; 03831 } 03832 if (*m == '\0') 03833 break; 03834 } 03835 if (p == meid2 + sizeof(meid2)) 03836 meid2[sizeof(meid2) - 1] = '\0'; 03837 03838 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); 03839 } 03840 03841 snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt); 03842 03843 if (!ast_strlen_zero(monitor_exec)) 03844 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec); 03845 else 03846 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options); 03847 03848 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs); 03849 /* We purposely lock the CDR so that pbx_exec does not update the application data */ 03850 if (qe->chan->cdr) 03851 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 03852 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs); 03853 if (qe->chan->cdr) 03854 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED); 03855 03856 } else { 03857 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); 03858 } 03859 } 03860 } 03861 /* Drop out of the queue at this point, to prepare for next caller */ 03862 leave_queue(qe); 03863 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 03864 ast_debug(1, "app_queue: sendurl=%s.\n", url); 03865 ast_channel_sendurl(peer, url); 03866 } 03867 03868 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */ 03869 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */ 03870 if (!ast_strlen_zero(macro)) { 03871 macroexec = ast_strdupa(macro); 03872 } else { 03873 if (qe->parent->membermacro) 03874 macroexec = ast_strdupa(qe->parent->membermacro); 03875 } 03876 03877 if (!ast_strlen_zero(macroexec)) { 03878 ast_debug(1, "app_queue: macro=%s.\n", macroexec); 03879 03880 res = ast_autoservice_start(qe->chan); 03881 if (res) { 03882 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 03883 res = -1; 03884 } 03885 03886 application = pbx_findapp("Macro"); 03887 03888 if (application) { 03889 res = pbx_exec(peer, application, macroexec); 03890 ast_debug(1, "Macro exited with status %d\n", res); 03891 res = 0; 03892 } else { 03893 ast_log(LOG_ERROR, "Could not find application Macro\n"); 03894 res = -1; 03895 } 03896 03897 if (ast_autoservice_stop(qe->chan) < 0) { 03898 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 03899 res = -1; 03900 } 03901 } 03902 03903 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */ 03904 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */ 03905 if (!ast_strlen_zero(gosub)) { 03906 gosubexec = ast_strdupa(gosub); 03907 } else { 03908 if (qe->parent->membergosub) 03909 gosubexec = ast_strdupa(qe->parent->membergosub); 03910 } 03911 03912 if (!ast_strlen_zero(gosubexec)) { 03913 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec); 03914 03915 res = ast_autoservice_start(qe->chan); 03916 if (res) { 03917 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 03918 res = -1; 03919 } 03920 03921 application = pbx_findapp("Gosub"); 03922 03923 if (application) { 03924 char *gosub_args, *gosub_argstart; 03925 03926 /* Set where we came from */ 03927 ast_copy_string(peer->context, "app_queue_gosub_virtual_context", sizeof(peer->context)); 03928 ast_copy_string(peer->exten, "s", sizeof(peer->exten)); 03929 peer->priority = 0; 03930 03931 gosub_argstart = strchr(gosubexec, ','); 03932 if (gosub_argstart) { 03933 *gosub_argstart = 0; 03934 if (asprintf(&gosub_args, "%s,s,1(%s)", gosubexec, gosub_argstart + 1) < 0) { 03935 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 03936 gosub_args = NULL; 03937 } 03938 *gosub_argstart = ','; 03939 } else { 03940 if (asprintf(&gosub_args, "%s,s,1", gosubexec) < 0) { 03941 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 03942 gosub_args = NULL; 03943 } 03944 } 03945 if (gosub_args) { 03946 res = pbx_exec(peer, application, gosub_args); 03947 if (!res) { 03948 struct ast_pbx_args args; 03949 memset(&args, 0, sizeof(args)); 03950 args.no_hangup_chan = 1; 03951 ast_pbx_run_args(peer, &args); 03952 } 03953 ast_free(gosub_args); 03954 ast_debug(1, "Gosub exited with status %d\n", res); 03955 } else { 03956 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n"); 03957 } 03958 } else { 03959 ast_log(LOG_ERROR, "Could not find application Gosub\n"); 03960 res = -1; 03961 } 03962 03963 if (ast_autoservice_stop(qe->chan) < 0) { 03964 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 03965 res = -1; 03966 } 03967 } 03968 03969 if (!ast_strlen_zero(agi)) { 03970 ast_debug(1, "app_queue: agi=%s.\n", agi); 03971 application = pbx_findapp("agi"); 03972 if (application) { 03973 agiexec = ast_strdupa(agi); 03974 ret = pbx_exec(qe->chan, application, agiexec); 03975 } else 03976 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n"); 03977 } 03978 qe->handled++; 03979 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid, 03980 (long)(orig - to > 0 ? (orig - to) / 1000 : 0)); 03981 if (update_cdr && qe->chan->cdr) 03982 ast_copy_string(qe->chan->cdr->dstchannel, member->membername, sizeof(qe->chan->cdr->dstchannel)); 03983 if (qe->parent->eventwhencalled) 03984 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 03985 "Queue: %s\r\n" 03986 "Uniqueid: %s\r\n" 03987 "Channel: %s\r\n" 03988 "Member: %s\r\n" 03989 "MemberName: %s\r\n" 03990 "Holdtime: %ld\r\n" 03991 "BridgedChannel: %s\r\n" 03992 "Ringtime: %ld\r\n" 03993 "%s", 03994 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername, 03995 (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0), 03996 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 03997 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 03998 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 03999 04000 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) { 04001 queue_end_bridge->q = qe->parent; 04002 queue_end_bridge->chan = qe->chan; 04003 bridge_config.end_bridge_callback = end_bridge_callback; 04004 bridge_config.end_bridge_callback_data = queue_end_bridge; 04005 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 04006 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need 04007 * to make sure to increase the refcount of this queue so it cannot be freed until we 04008 * are done with it. We remove this reference in end_bridge_callback. 04009 */ 04010 queue_ref(qe->parent); 04011 } 04012 04013 time(&callstart); 04014 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl); 04015 bridge = ast_bridge_call(qe->chan,peer, &bridge_config); 04016 04017 /* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log 04018 * when the masquerade occurred. These other "ending" queue_log messages are unnecessary 04019 */ 04020 ast_channel_lock(qe->chan); 04021 if (!attended_transfer_occurred(qe->chan)) { 04022 struct ast_datastore *tds; 04023 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) { 04024 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 04025 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start), 04026 (long) (time(NULL) - callstart), qe->opos); 04027 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER); 04028 } else if (ast_check_hangup(qe->chan)) { 04029 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d", 04030 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 04031 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER); 04032 } else { 04033 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d", 04034 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos); 04035 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT); 04036 } 04037 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) { 04038 ast_channel_datastore_remove(qe->chan, tds); 04039 } 04040 update_queue(qe->parent, member, callcompletedinsl); 04041 } 04042 04043 if (transfer_ds) { 04044 ast_datastore_free(transfer_ds); 04045 } 04046 ast_channel_unlock(qe->chan); 04047 ast_hangup(peer); 04048 res = bridge ? bridge : 1; 04049 ao2_ref(member, -1); 04050 } 04051 out: 04052 hangupcalls(outgoing, NULL); 04053 04054 return res; 04055 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 6662 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_ref, ao2_unlink, ast_cli_unregister_multiple(), ast_context_destroy(), ast_context_find(), ast_context_remove_extension2(), ast_custom_function_unregister(), ast_event_unsubscribe(), ast_manager_unregister(), ast_taskprocessor_unreference(), ast_unload_realtime(), ast_unregister_application(), clear_and_free_interfaces(), cli_queue, queue_unref(), queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queuevar_function, and queuewaitingcount_function.
06663 { 06664 int res; 06665 struct ast_context *con; 06666 struct ao2_iterator q_iter; 06667 struct call_queue *q = NULL; 06668 06669 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry)); 06670 res = ast_manager_unregister("QueueStatus"); 06671 res |= ast_manager_unregister("Queues"); 06672 res |= ast_manager_unregister("QueueRule"); 06673 res |= ast_manager_unregister("QueueSummary"); 06674 res |= ast_manager_unregister("QueueAdd"); 06675 res |= ast_manager_unregister("QueueRemove"); 06676 res |= ast_manager_unregister("QueuePause"); 06677 res |= ast_manager_unregister("QueueLog"); 06678 res |= ast_manager_unregister("QueuePenalty"); 06679 res |= ast_unregister_application(app_aqm); 06680 res |= ast_unregister_application(app_rqm); 06681 res |= ast_unregister_application(app_pqm); 06682 res |= ast_unregister_application(app_upqm); 06683 res |= ast_unregister_application(app_ql); 06684 res |= ast_unregister_application(app); 06685 res |= ast_custom_function_unregister(&queuevar_function); 06686 res |= ast_custom_function_unregister(&queuemembercount_function); 06687 res |= ast_custom_function_unregister(&queuemembercount_dep); 06688 res |= ast_custom_function_unregister(&queuememberlist_function); 06689 res |= ast_custom_function_unregister(&queuewaitingcount_function); 06690 res |= ast_custom_function_unregister(&queuememberpenalty_function); 06691 06692 if (device_state_sub) 06693 ast_event_unsubscribe(device_state_sub); 06694 06695 if ((con = ast_context_find("app_queue_gosub_virtual_context"))) { 06696 ast_context_remove_extension2(con, "s", 1, NULL, 0); 06697 ast_context_destroy(con, "app_queue"); /* leave no trace */ 06698 } 06699 06700 clear_and_free_interfaces(); 06701 06702 q_iter = ao2_iterator_init(queues, 0); 06703 while ((q = ao2_iterator_next(&q_iter))) { 06704 ao2_unlink(queues, q); 06705 queue_unref(q); 06706 } 06707 ao2_ref(queues, -1); 06708 devicestate_tps = ast_taskprocessor_unreference(devicestate_tps); 06709 ast_unload_realtime("queue_members"); 06710 return res; 06711 }
| static void update_qe_rule | ( | struct queue_ent * | qe | ) | [static] |
update rules for queues
Calculate min/max penalties making sure if relative they stay within bounds. Update queues penalty and set dialplan vars, goto next list entry.
Definition at line 2890 of file app_queue.c.
References ast_debug, AST_LIST_NEXT, queue_ent::chan, queue_ent::max_penalty, penalty_rule::max_relative, penalty_rule::max_value, queue_ent::min_penalty, penalty_rule::min_relative, penalty_rule::min_value, pbx_builtin_setvar_helper(), queue_ent::pr, and penalty_rule::time.
Referenced by join_queue(), queue_exec(), and wait_our_turn().
02891 { 02892 int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value; 02893 int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value; 02894 char max_penalty_str[20], min_penalty_str[20]; 02895 /* a relative change to the penalty could put it below 0 */ 02896 if (max_penalty < 0) 02897 max_penalty = 0; 02898 if (min_penalty < 0) 02899 min_penalty = 0; 02900 if (min_penalty > max_penalty) 02901 min_penalty = max_penalty; 02902 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty); 02903 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty); 02904 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str); 02905 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str); 02906 qe->max_penalty = max_penalty; 02907 qe->min_penalty = min_penalty; 02908 ast_debug(3, "Setting max penalty to %d and min penalty to %d for caller %s since %d seconds have elapsed\n", qe->max_penalty, qe->min_penalty, qe->chan->name, qe->pr->time); 02909 qe->pr = AST_LIST_NEXT(qe->pr, list); 02910 }
| static int update_queue | ( | struct call_queue * | q, | |
| struct member * | member, | |||
| int | callcompletedinsl | |||
| ) | [static] |
update the queue status
| Always | 0 |
Definition at line 3031 of file app_queue.c.
References ao2_find, ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), member::calls, call_queue::callscompleted, call_queue::callscompletedinsl, member::lastcall, member::lastqueue, call_queue::members, OBJ_POINTER, and queues.
Referenced by queue_transfer_fixup(), and try_calling().
03032 { 03033 struct member *mem; 03034 struct call_queue *qtmp; 03035 struct ao2_iterator queue_iter; 03036 03037 if (shared_lastcall) { 03038 queue_iter = ao2_iterator_init(queues, 0); 03039 while ((qtmp = ao2_iterator_next(&queue_iter))) { 03040 ao2_lock(qtmp); 03041 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) { 03042 time(&mem->lastcall); 03043 mem->calls++; 03044 mem->lastqueue = q; 03045 ao2_ref(mem, -1); 03046 } 03047 ao2_unlock(qtmp); 03048 ao2_ref(qtmp, -1); 03049 } 03050 } else { 03051 ao2_lock(q); 03052 time(&member->lastcall); 03053 member->calls++; 03054 member->lastqueue = q; 03055 ao2_unlock(q); 03056 } 03057 ao2_lock(q); 03058 q->callscompleted++; 03059 if (callcompletedinsl) 03060 q->callscompletedinsl++; 03061 ao2_unlock(q); 03062 return 0; 03063 }
| static int update_realtime_member_field | ( | struct member * | mem, | |
| const char * | queue_name, | |||
| const char * | field, | |||
| const char * | value | |||
| ) | [static] |
Definition at line 1638 of file app_queue.c.
References ast_strlen_zero(), ast_update_realtime(), member::rt_uniqueid, and SENTINEL.
Referenced by set_member_paused().
01639 { 01640 int ret = -1; 01641 01642 if (ast_strlen_zero(mem->rt_uniqueid)) 01643 return ret; 01644 01645 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0) 01646 ret = 0; 01647 01648 return ret; 01649 }
| static void update_realtime_members | ( | struct call_queue * | q | ) | [static] |
Definition at line 1652 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlink, ao2_unlock(), ast_category_browse(), ast_config_destroy(), ast_debug, ast_load_realtime_multientry(), ast_queue_log(), ast_variable_retrieve(), member::dead, member::interface, call_queue::membercount, call_queue::members, call_queue::name, queues, member::realtime, remove_from_interfaces(), rt_handle_member_record(), S_OR, SENTINEL, and member::state_interface.
Referenced by load_realtime_queue(), and queue_exec().
01653 { 01654 struct ast_config *member_config = NULL; 01655 struct member *m; 01656 char *interface = NULL; 01657 struct ao2_iterator mem_iter; 01658 01659 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) { 01660 /*This queue doesn't have realtime members*/ 01661 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name); 01662 return; 01663 } 01664 01665 ao2_lock(queues); 01666 ao2_lock(q); 01667 01668 /* Temporarily set realtime members dead so we can detect deleted ones.*/ 01669 mem_iter = ao2_iterator_init(q->members, 0); 01670 while ((m = ao2_iterator_next(&mem_iter))) { 01671 if (m->realtime) 01672 m->dead = 1; 01673 ao2_ref(m, -1); 01674 } 01675 01676 while ((interface = ast_category_browse(member_config, interface))) { 01677 rt_handle_member_record(q, interface, 01678 ast_variable_retrieve(member_config, interface, "uniqueid"), 01679 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface), 01680 ast_variable_retrieve(member_config, interface, "penalty"), 01681 ast_variable_retrieve(member_config, interface, "paused"), 01682 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface)); 01683 } 01684 01685 /* Delete all realtime members that have been deleted in DB. */ 01686 mem_iter = ao2_iterator_init(q->members, 0); 01687 while ((m = ao2_iterator_next(&mem_iter))) { 01688 if (m->dead) { 01689 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 01690 ao2_unlink(q->members, m); 01691 remove_from_interfaces(m->state_interface, 0); 01692 q->membercount--; 01693 } 01694 ao2_ref(m, -1); 01695 } 01696 ao2_unlock(q); 01697 ao2_unlock(queues); 01698 ast_config_destroy(member_config); 01699 }
| static int update_status | ( | const char * | interface, | |
| const int | status | |||
| ) | [static] |
set a member's status based on device state of that member's state_interface.
Lock interface list find sc, iterate through each queues queue_member list for member to update state inside queues
Definition at line 714 of file app_queue.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), ast_copy_string(), member::calls, member::dynamic, EVENT_FLAG_AGENT, member::interface, member::lastcall, manager_event, call_queue::maskmemberstatus, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, queue_unref(), queues, member::realtime, member::state_interface, and member::status.
Referenced by handle_statechange(), and ring_entry().
00715 { 00716 struct member *cur; 00717 struct ao2_iterator mem_iter, queue_iter; 00718 struct call_queue *q; 00719 char tmp_interface[80]; 00720 00721 queue_iter = ao2_iterator_init(queues, 0); 00722 while ((q = ao2_iterator_next(&queue_iter))) { 00723 ao2_lock(q); 00724 mem_iter = ao2_iterator_init(q->members, 0); 00725 while ((cur = ao2_iterator_next(&mem_iter))) { 00726 char *slash_pos; 00727 ast_copy_string(tmp_interface, cur->state_interface, sizeof(tmp_interface)); 00728 if ((slash_pos = strchr(tmp_interface, '/'))) 00729 if (!strncasecmp(tmp_interface, "Local", 5) && (slash_pos = strchr(slash_pos + 1, '/'))) 00730 *slash_pos = '\0'; 00731 00732 if (strcasecmp(interface, tmp_interface)) { 00733 ao2_ref(cur, -1); 00734 continue; 00735 } 00736 00737 if (cur->status != status) { 00738 cur->status = status; 00739 if (q->maskmemberstatus) { 00740 ao2_ref(cur, -1); 00741 continue; 00742 } 00743 00744 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 00745 "Queue: %s\r\n" 00746 "Location: %s\r\n" 00747 "MemberName: %s\r\n" 00748 "Membership: %s\r\n" 00749 "Penalty: %d\r\n" 00750 "CallsTaken: %d\r\n" 00751 "LastCall: %d\r\n" 00752 "Status: %d\r\n" 00753 "Paused: %d\r\n", 00754 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static", 00755 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused); 00756 } 00757 ao2_ref(cur, -1); 00758 } 00759 queue_unref(q); 00760 ao2_unlock(q); 00761 } 00762 00763 return 0; 00764 }
| static int upqm_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
UnPauseQueueMember application.
Definition at line 4534 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().
04535 { 04536 char *parse; 04537 AST_DECLARE_APP_ARGS(args, 04538 AST_APP_ARG(queuename); 04539 AST_APP_ARG(interface); 04540 AST_APP_ARG(options); 04541 AST_APP_ARG(reason); 04542 ); 04543 04544 if (ast_strlen_zero(data)) { 04545 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n"); 04546 return -1; 04547 } 04548 04549 parse = ast_strdupa(data); 04550 04551 AST_STANDARD_APP_ARGS(args, parse); 04552 04553 if (ast_strlen_zero(args.interface)) { 04554 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 04555 return -1; 04556 } 04557 04558 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) { 04559 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 04560 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 04561 return 0; 04562 } 04563 04564 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 04565 04566 return 0; 04567 }
| static int valid_exit | ( | struct queue_ent * | qe, | |
| char | digit | |||
| ) | [static] |
Check for valid exit from queue via goto.
| 0 | if failure | |
| 1 | if successful |
Definition at line 1805 of file app_queue.c.
References ast_canmatch_extension(), ast_goto_if_exists(), ast_strlen_zero(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, queue_ent::context, queue_ent::digits, and queue_ent::valid_digits.
Referenced by say_periodic_announcement(), say_position(), wait_a_bit(), wait_for_answer(), and wait_our_turn().
01806 { 01807 int digitlen = strlen(qe->digits); 01808 01809 /* Prevent possible buffer overflow */ 01810 if (digitlen < sizeof(qe->digits) - 2) { 01811 qe->digits[digitlen] = digit; 01812 qe->digits[digitlen + 1] = '\0'; 01813 } else { 01814 qe->digits[0] = '\0'; 01815 return 0; 01816 } 01817 01818 /* If there's no context to goto, short-circuit */ 01819 if (ast_strlen_zero(qe->context)) 01820 return 0; 01821 01822 /* If the extension is bad, then reset the digits to blank */ 01823 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) { 01824 qe->digits[0] = '\0'; 01825 return 0; 01826 } 01827 01828 /* We have an exact match */ 01829 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 01830 qe->valid_digits = 1; 01831 /* Return 1 on a successful goto */ 01832 return 1; 01833 } 01834 01835 return 0; 01836 }
| static char* vars2manager | ( | struct ast_channel * | chan, | |
| char * | vars, | |||
| size_t | len | |||
| ) | [static] |
convert "\n" to "\nVariable: " ready for manager to use
Definition at line 2168 of file app_queue.c.
References ast_copy_string(), ast_str_alloca, buf, pbx_builtin_serialize_variables(), and ast_str::str.
Referenced by ring_entry(), send_agent_complete(), and try_calling().
02169 { 02170 struct ast_str *buf = ast_str_alloca(len + 1); 02171 char *tmp; 02172 02173 if (pbx_builtin_serialize_variables(chan, &buf)) { 02174 int i, j; 02175 02176 /* convert "\n" to "\nVariable: " */ 02177 strcpy(vars, "Variable: "); 02178 tmp = buf->str; 02179 02180 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) { 02181 vars[j] = tmp[i]; 02182 02183 if (tmp[i + 1] == '\0') 02184 break; 02185 if (tmp[i] == '\n') { 02186 vars[j++] = '\r'; 02187 vars[j++] = '\n'; 02188 02189 ast_copy_string(&(vars[j]), "Variable: ", len - j); 02190 j += 9; 02191 } 02192 } 02193 if (j > len - 3) 02194 j = len - 3; 02195 vars[j++] = '\r'; 02196 vars[j++] = '\n'; 02197 vars[j] = '\0'; 02198 } else { 02199 /* there are no channel variables; leave it blank */ 02200 *vars = '\0'; 02201 } 02202 return vars; 02203 }
| static int wait_a_bit | ( | struct queue_ent * | qe | ) | [static] |
Definition at line 4057 of file app_queue.c.
References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().
Referenced by queue_exec().
04058 { 04059 /* Don't need to hold the lock while we setup the outgoing calls */ 04060 int retrywait = qe->parent->retry * 1000; 04061 04062 int res = ast_waitfordigit(qe->chan, retrywait); 04063 if (res > 0 && !valid_exit(qe, res)) 04064 res = 0; 04065 04066 return res; 04067 }
| static struct callattempt* wait_for_answer | ( | struct queue_ent * | qe, | |
| struct callattempt * | outgoing, | |||
| int * | to, | |||
| char * | digit, | |||
| int | prebusies, | |||
| int | caller_disconnect, | |||
| int | forwardsallowed | |||
| ) | [static, read] |
Wait for a member to answer the call.
| [in] | qe | the queue_ent corresponding to the caller in the queue |
| [in] | outgoing | the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero |
| [in] | to | the amount of time (in milliseconds) to wait for a response |
| [out] | digit | if a user presses a digit to exit the queue, this is the digit the caller pressed |
| [in] | prebusies | number of busy members calculated prior to calling wait_for_answer |
| [in] | caller_disconnect | if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call |
| [in] | forwardsallowed | used to detect if we should allow call forwarding, based on the 'i' option to Queue() |
Definition at line 2590 of file app_queue.c.
References ast_channel::_state, accountcode, ast_call(), ast_cdr_busy(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_OFFHOOK, AST_CONTROL_RINGING, ast_copy_string(), ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_free, ast_frfree, ast_hangup(), ast_log(), AST_MAX_WATCHERS, ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), ast_request(), AST_STATE_UP, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_verb, ast_waitfor_n(), callattempt::call_next, ast_channel::cdr, ast_channel::cdrflags, callattempt::chan, queue_ent::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_channel::context, ast_frame::data, do_hang(), ast_channel::exten, f, ast_frame::frametype, ast_channel::hangupcause, callattempt::interface, member::interface, LOG_NOTICE, ast_channel::macroexten, callattempt::member, member::membername, call_queue::name, ast_channel::nativeformats, queue_ent::parent, queue_ent::pos, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), rna(), S_OR, queue_ent::start, starttime, status, callattempt::stillgoing, call_queue::strategy, ast_frame::subclass, ast_channel::tech, call_queue::timeoutrestart, ast_frame::uint32, and valid_exit().
Referenced by try_calling().
02591 { 02592 const char *queue = qe->parent->name; 02593 struct callattempt *o, *start = NULL, *prev = NULL; 02594 int status; 02595 int numbusies = prebusies; 02596 int numnochan = 0; 02597 int stillgoing = 0; 02598 int orig = *to; 02599 struct ast_frame *f; 02600 struct callattempt *peer = NULL; 02601 struct ast_channel *winner; 02602 struct ast_channel *in = qe->chan; 02603 char on[80] = ""; 02604 char membername[80] = ""; 02605 long starttime = 0; 02606 long endtime = 0; 02607 #ifdef HAVE_EPOLL 02608 struct callattempt *epollo; 02609 #endif 02610 02611 starttime = (long) time(NULL); 02612 #ifdef HAVE_EPOLL 02613 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 02614 if (epollo->chan) 02615 ast_poll_channel_add(in, epollo->chan); 02616 } 02617 #endif 02618 02619 while (*to && !peer) { 02620 int numlines, retry, pos = 1; 02621 struct ast_channel *watchers[AST_MAX_WATCHERS]; 02622 watchers[0] = in; 02623 start = NULL; 02624 02625 for (retry = 0; retry < 2; retry++) { 02626 numlines = 0; 02627 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */ 02628 if (o->stillgoing) { /* Keep track of important channels */ 02629 stillgoing = 1; 02630 if (o->chan) { 02631 watchers[pos++] = o->chan; 02632 if (!start) 02633 start = o; 02634 else 02635 prev->call_next = o; 02636 prev = o; 02637 } 02638 } 02639 numlines++; 02640 } 02641 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ || 02642 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) 02643 break; 02644 /* On "ringall" strategy we only move to the next penalty level 02645 when *all* ringing phones are done in the current penalty level */ 02646 ring_one(qe, outgoing, &numbusies); 02647 /* and retry... */ 02648 } 02649 if (pos == 1 /* not found */) { 02650 if (numlines == (numbusies + numnochan)) { 02651 ast_debug(1, "Everyone is busy at this time\n"); 02652 } else { 02653 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan); 02654 } 02655 *to = 0; 02656 return NULL; 02657 } 02658 winner = ast_waitfor_n(watchers, pos, to); 02659 for (o = start; o; o = o->call_next) { 02660 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 02661 if (!peer) { 02662 ast_verb(3, "%s answered %s\n", o->chan->name, in->name); 02663 peer = o; 02664 } 02665 } else if (o->chan && (o->chan == winner)) { 02666 02667 ast_copy_string(on, o->member->interface, sizeof(on)); 02668 ast_copy_string(membername, o->member->membername, sizeof(membername)); 02669 02670 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) { 02671 ast_verb(3, "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward); 02672 numnochan++; 02673 do_hang(o); 02674 winner = NULL; 02675 continue; 02676 } else if (!ast_strlen_zero(o->chan->call_forward)) { 02677 char tmpchan[256]; 02678 char *stuff; 02679 char *tech; 02680 02681 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 02682 if ((stuff = strchr(tmpchan, '/'))) { 02683 *stuff++ = '\0'; 02684 tech = tmpchan; 02685 } else { 02686 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 02687 stuff = tmpchan; 02688 tech = "Local"; 02689 } 02690 /* Before processing channel, go ahead and check for forwarding */ 02691 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name); 02692 /* Setup parameters */ 02693 o->chan = ast_request(tech, in->nativeformats, stuff, &status); 02694 if (!o->chan) { 02695 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff); 02696 o->stillgoing = 0; 02697 numnochan++; 02698 } else { 02699 ast_channel_inherit_variables(in, o->chan); 02700 ast_channel_datastore_inherit(in, o->chan); 02701 if (o->chan->cid.cid_num) 02702 ast_free(o->chan->cid.cid_num); 02703 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num); 02704 02705 if (o->chan->cid.cid_name) 02706 ast_free(o->chan->cid.cid_name); 02707 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name); 02708 02709 ast_string_field_set(o->chan, accountcode, in->accountcode); 02710 o->chan->cdrflags = in->cdrflags; 02711 02712 if (in->cid.cid_ani) { 02713 if (o->chan->cid.cid_ani) 02714 ast_free(o->chan->cid.cid_ani); 02715 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani); 02716 } 02717 if (o->chan->cid.cid_rdnis) 02718 ast_free(o->chan->cid.cid_rdnis); 02719 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten)); 02720 if (ast_call(o->chan, tmpchan, 0)) { 02721 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); 02722 do_hang(o); 02723 numnochan++; 02724 } 02725 } 02726 /* Hangup the original channel now, in case we needed it */ 02727 ast_hangup(winner); 02728 continue; 02729 } 02730 f = ast_read(winner); 02731 if (f) { 02732 if (f->frametype == AST_FRAME_CONTROL) { 02733 switch (f->subclass) { 02734 case AST_CONTROL_ANSWER: 02735 /* This is our guy if someone answered. */ 02736 if (!peer) { 02737 ast_verb(3, "%s answered %s\n", o->chan->name, in->name); 02738 peer = o; 02739 } 02740 break; 02741 case AST_CONTROL_BUSY: 02742 ast_verb(3, "%s is busy\n", o->chan->name); 02743 if (in->cdr) 02744 ast_cdr_busy(in->cdr); 02745 do_hang(o); 02746 endtime = (long) time(NULL); 02747 endtime -= starttime; 02748 rna(endtime * 1000, qe, on, membername, 0); 02749 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02750 if (qe->parent->timeoutrestart) 02751 *to = orig; 02752 ring_one(qe, outgoing, &numbusies); 02753 } 02754 numbusies++; 02755 break; 02756 case AST_CONTROL_CONGESTION: 02757 ast_verb(3, "%s is circuit-busy\n", o->chan->name); 02758 if (in->cdr) 02759 ast_cdr_busy(in->cdr); 02760 endtime = (long) time(NULL); 02761 endtime -= starttime; 02762 rna(endtime * 1000, qe, on, membername, 0); 02763 do_hang(o); 02764 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02765 if (qe->parent->timeoutrestart) 02766 *to = orig; 02767 ring_one(qe, outgoing, &numbusies); 02768 } 02769 numbusies++; 02770 break; 02771 case AST_CONTROL_RINGING: 02772 ast_verb(3, "%s is ringing\n", o->chan->name); 02773 break; 02774 case AST_CONTROL_OFFHOOK: 02775 /* Ignore going off hook */ 02776 break; 02777 default: 02778 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass); 02779 } 02780 } 02781 ast_frfree(f); 02782 } else { 02783 endtime = (long) time(NULL) - starttime; 02784 rna(endtime * 1000, qe, on, membername, 1); 02785 do_hang(o); 02786 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) { 02787 if (qe->parent->timeoutrestart) 02788 *to = orig; 02789 ring_one(qe, outgoing, &numbusies); 02790 } 02791 } 02792 } 02793 } 02794 if (winner == in) { 02795 f = ast_read(in); 02796 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 02797 /* Got hung up */ 02798 *to = -1; 02799 if (f) { 02800 if (f->data.uint32) { 02801 in->hangupcause = f->data.uint32; 02802 } 02803 ast_frfree(f); 02804 } 02805 return NULL; 02806 } 02807 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) { 02808 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass); 02809 *to = 0; 02810 ast_frfree(f); 02811 return NULL; 02812 } 02813 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) { 02814 ast_verb(3, "User pressed digit: %c\n", f->subclass); 02815 *to = 0; 02816 *digit = f->subclass; 02817 ast_frfree(f); 02818 return NULL; 02819 } 02820 ast_frfree(f); 02821 } 02822 if (!*to) { 02823 for (o = start; o; o = o->call_next) 02824 rna(orig, qe, o->interface, o->member->membername, 1); 02825 } 02826 } 02827 02828 #ifdef HAVE_EPOLL 02829 for (epollo = outgoing; epollo; epollo = epollo->q_next) { 02830 if (epollo->chan) 02831 ast_poll_channel_del(in, epollo->chan); 02832 } 02833 #endif 02834 02835 return peer; 02836 }
| static int wait_our_turn | ( | struct queue_ent * | qe, | |
| int | ringing, | |||
| enum queue_result * | reason | |||
| ) | [static] |
The waiting areas for callers who are not actively calling members.
This function is one large loop. This function will return if a caller either exits the queue or it becomes that caller's turn to attempt calling queue members. Inside the loop, we service the caller with periodic announcements, holdtime announcements, etc. as configured in queues.conf
| 0 | if the caller's turn has arrived | |
| -1 | if the caller should exit the queue. |
Definition at line 2922 of file app_queue.c.
References call_queue::announcefrequency, ast_queue_log(), ast_waitfordigit(), queue_ent::chan, queue_ent::expire, get_member_status(), is_our_turn(), leave_queue(), call_queue::leavewhenempty, queue_ent::max_penalty, queue_ent::min_penalty, call_queue::name, queue_ent::opos, queue_ent::parent, call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::pr, QUEUE_EMPTY_LOOSE, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, QUEUE_NORMAL, QUEUE_TIMEOUT, RECHECK, say_periodic_announcement(), say_position(), queue_ent::start, status, penalty_rule::time, update_qe_rule(), and valid_exit().
Referenced by queue_exec().
02923 { 02924 int res = 0; 02925 02926 /* This is the holding pen for callers 2 through maxlen */ 02927 for (;;) { 02928 enum queue_member_status status = QUEUE_NORMAL; 02929 int exit = 0; 02930 02931 if (is_our_turn(qe)) 02932 break; 02933 02934 /* If we have timed out, break out */ 02935 if (qe->expire && (time(NULL) >= qe->expire)) { 02936 *reason = QUEUE_TIMEOUT; 02937 break; 02938 } 02939 02940 /* If we are going to exit due to a leavewhenempty condition, we should 02941 * actually attempt to keep the caller in the queue until we have 02942 * exhausted all penalty rules. 02943 */ 02944 for (; !exit || qe->pr; update_qe_rule(qe)) { 02945 status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty); 02946 02947 if (!qe->pr || status == QUEUE_NORMAL) { 02948 break; 02949 } 02950 02951 /* leave the queue if no agents, if enabled */ 02952 if ((qe->parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) || 02953 ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) || 02954 ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS))) { 02955 continue; 02956 } else { 02957 exit = 1; 02958 } 02959 } 02960 02961 if (qe->parent->leavewhenempty && (status == QUEUE_NO_MEMBERS)) { 02962 *reason = QUEUE_LEAVEEMPTY; 02963 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 02964 leave_queue(qe); 02965 break; 02966 } 02967 02968 /* leave the queue if no reachable agents, if enabled */ 02969 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (status == QUEUE_NO_REACHABLE_MEMBERS || status == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) { 02970 *reason = QUEUE_LEAVEUNAVAIL; 02971 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 02972 leave_queue(qe); 02973 break; 02974 } 02975 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (status == QUEUE_NO_REACHABLE_MEMBERS)) { 02976 *reason = QUEUE_LEAVEUNAVAIL; 02977 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start); 02978 leave_queue(qe); 02979 break; 02980 } 02981 02982 /* Make a position announcement, if enabled */ 02983 if (qe->parent->announcefrequency && 02984 (res = say_position(qe,ringing))) 02985 break; 02986 02987 /* If we have timed out, break out */ 02988 if (qe->expire && (time(NULL) >= qe->expire)) { 02989 *reason = QUEUE_TIMEOUT; 02990 break; 02991 } 02992 02993 /* Make a periodic announcement, if enabled */ 02994 if (qe->parent->periodicannouncefrequency && 02995 (res = say_periodic_announcement(qe,ringing))) 02996 break; 02997 02998 /* see if we need to move to the next penalty level for this queue */ 02999 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) { 03000 update_qe_rule(qe); 03001 } 03002 03003 /* If we have timed out, break out */ 03004 if (qe->expire && (time(NULL) >= qe->expire)) { 03005 *reason = QUEUE_TIMEOUT; 03006 break; 03007 } 03008 03009 /* Wait a second before checking again */ 03010 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) { 03011 if (res > 0 && !valid_exit(qe, res)) 03012 res = 0; 03013 else 03014 break; 03015 } 03016 03017 /* If we have timed out, break out */ 03018 if (qe->expire && (time(NULL) >= qe->expire)) { 03019 *reason = QUEUE_TIMEOUT; 03020 break; 03021 } 03022 } 03023 03024 return res; 03025 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 6779 of file app_queue.c.
char* app = "Queue" [static] |
Definition at line 152 of file app_queue.c.
char* app_aqm = "AddQueueMember" [static] |
Definition at line 211 of file app_queue.c.
char* app_aqm_descrip [static] |
Definition at line 213 of file app_queue.c.
char* app_aqm_synopsis = "Dynamically adds queue members" [static] |
Definition at line 212 of file app_queue.c.
char* app_pqm = "PauseQueueMember" [static] |
Definition at line 237 of file app_queue.c.
char* app_pqm_descrip [static] |
Definition at line 239 of file app_queue.c.
char* app_pqm_synopsis = "Pauses a queue member" [static] |
Definition at line 238 of file app_queue.c.
char* app_ql = "QueueLog" [static] |
Definition at line 270 of file app_queue.c.
char* app_ql_descrip [static] |
" QueueLog(queuename,uniqueid,agent,event[,additionalinfo]):\n" "Allows you to write your own events into the queue log\n" "Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)\n"
Definition at line 272 of file app_queue.c.
char* app_ql_synopsis = "Writes to the queue_log" [static] |
Definition at line 271 of file app_queue.c.
char* app_rqm = "RemoveQueueMember" [static] |
Definition at line 224 of file app_queue.c.
char* app_rqm_descrip [static] |
Definition at line 226 of file app_queue.c.
char* app_rqm_synopsis = "Dynamically removes queue members" [static] |
Definition at line 225 of file app_queue.c.
char* app_upqm = "UnpauseQueueMember" [static] |
Definition at line 255 of file app_queue.c.
char* app_upqm_descrip [static] |
Definition at line 257 of file app_queue.c.
char* app_upqm_synopsis = "Unpauses a queue member" [static] |
Definition at line 256 of file app_queue.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 6779 of file app_queue.c.
int autofill_default = 0 [static] |
queues.conf [general] option
Definition at line 292 of file app_queue.c.
struct ast_cli_entry cli_queue[] [static] |
Definition at line 6652 of file app_queue.c.
Referenced by load_module(), and unload_module().
char* descrip [static] |
Definition at line 156 of file app_queue.c.
struct ast_event_sub* device_state_sub [static] |
Subscription to device state change events.
Definition at line 301 of file app_queue.c.
struct ast_taskprocessor* devicestate_tps [static] |
Definition at line 136 of file app_queue.c.
| enum queue_result id |
Definition at line 318 of file app_queue.c.
Referenced by _sip_show_peers(), amixer_max(), idemodulator(), and setamixer().
int montype_default = 0 [static] |
queues.conf [general] option
Definition at line 295 of file app_queue.c.
const char* pm_family = "Queue/PersistentMembers" [static] |
Persistent Members astdb family.
Definition at line 278 of file app_queue.c.
const char qpm_cmd_usage[] [static] |
"Usage: queue pause member <channel> in <queue> reason <reason>\n"
Definition at line 6643 of file app_queue.c.
const char qsmp_cmd_usage[] [static] |
"Usage: queue set member penalty <channel> from <queue> <penalty>\n"
Definition at line 6649 of file app_queue.c.
int queue_keep_stats = 0 [static] |
queues.conf [general] option
Definition at line 283 of file app_queue.c.
int queue_persistent_members = 0 [static] |
queues.conf [general] option
Definition at line 286 of file app_queue.c.
| struct { ... } queue_results[] |
Referenced by set_queue_result().
struct ast_datastore_info queue_transfer_info [static] |
{
.type = "queue_transfer",
.chan_fixup = queue_transfer_fixup,
.destroy = queue_transfer_destroy,
}
a datastore used to help correctly log attended transfers of queue callers
Definition at line 3188 of file app_queue.c.
Referenced by attended_transfer_occurred(), queue_transfer_fixup(), setup_transfer_datastore(), and try_calling().
struct ast_custom_function queuemembercount_dep [static] |
Definition at line 5397 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuemembercount_function [static] |
Definition at line 5384 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuememberlist_function [static] |
Definition at line 5416 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuememberpenalty_function [static] |
Definition at line 5425 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ao2_container* queues [static] |
Definition at line 545 of file app_queue.c.
Referenced by __queues_show(), add_to_queue(), compare_weight(), complete_queue(), complete_queue_remove_member(), find_queue_by_name_rt(), get_member_penalty(), interface_exists_global(), join_queue(), leave_queue(), load_module(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), reload_queue_members(), reload_queues(), remove_from_queue(), set_member_paused(), set_member_penalty(), try_calling(), unload_module(), update_queue(), update_realtime_members(), and update_status().
struct ast_custom_function queuevar_function [static] |
Definition at line 5366 of file app_queue.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function queuewaitingcount_function [static] |
Definition at line 5407 of file app_queue.c.
Referenced by load_module(), and unload_module().
const char qum_cmd_usage[] [static] |
"Usage: queue unpause member <channel> in <queue> reason <reason>\n"
Definition at line 6646 of file app_queue.c.
int shared_lastcall = 0 [static] |
queues.conf [general] option
Definition at line 298 of file app_queue.c.
struct strategy strategies[] [static] |
Referenced by int2strat(), and strat2int().
char* synopsis = "Queue a call for a call queue" [static] |
Definition at line 154 of file app_queue.c.
| char* text |
Definition at line 319 of file app_queue.c.
Referenced by _sip_show_peer(), build_reply_digest(), check_auth(), festival_exec(), handle_response(), iconv_read(), method_match(), parse_sip_options(), process_sdp(), reqprep(), sendtext_exec(), set_queue_result(), and sip_new().
int update_cdr = 0 [static] |
queues.conf [general] option
Definition at line 304 of file app_queue.c.
Referenced by login_exec().
int use_weight = 0 [static] |
queues.conf per-queue weight option
Definition at line 289 of file app_queue.c.
1.6.1