#include "asterisk.h"
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <ctype.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
#include "asterisk/monitor.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/stringfields.h"
#include "asterisk/event.h"
#include "asterisk/astobj2.h"
#include "asterisk/strings.h"
#include "asterisk/global_datastores.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/callerid.h"
#include "asterisk/cel.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 | member |
| struct | penalty_rule |
| struct | queue_end_bridge |
| struct | queue_ent |
| struct | queue_transfer_ds |
| struct | rule_list |
| struct | rule_lists |
| struct | statechange |
| struct | strategy |
Defines | |
| #define | ANNOUNCEHOLDTIME_ALWAYS 1 |
| #define | ANNOUNCEHOLDTIME_ONCE 2 |
| #define | ANNOUNCEPOSITION_LIMIT 4 |
| #define | ANNOUNCEPOSITION_MORE_THAN 3 |
| #define | ANNOUNCEPOSITION_NO 2 |
| #define | ANNOUNCEPOSITION_YES 1 |
| #define | AST_MAX_WATCHERS 256 |
| #define | DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 |
| #define | DEFAULT_RETRY 5 |
| #define | DEFAULT_TIMEOUT 15 |
| #define | MAX_PERIODIC_ANNOUNCEMENTS 10 |
| #define | MAX_QUEUE_BUCKETS 53 |
| #define | PM_MAX_LEN 8192 |
| #define | QUEUE_EVENT_VARIABLES 3 |
| #define | 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 | empty_conditions { QUEUE_EMPTY_PENALTY = (1 << 0), QUEUE_EMPTY_PAUSED = (1 << 1), QUEUE_EMPTY_INUSE = (1 << 2), QUEUE_EMPTY_RINGING = (1 << 3), QUEUE_EMPTY_UNAVAILABLE = (1 << 4), QUEUE_EMPTY_INVALID = (1 << 5), QUEUE_EMPTY_UNKNOWN = (1 << 6), QUEUE_EMPTY_WRAPUP = (1 << 7) } |
| enum | queue_reload_mask { QUEUE_RELOAD_PARAMETERS = (1 << 0), QUEUE_RELOAD_MEMBER = (1 << 1), QUEUE_RELOAD_RULES = (1 << 2), QUEUE_RESET_STATS = (1 << 3) } |
| enum | queue_result { QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, QUEUE_JOINEMPTY = 2, QUEUE_LEAVEEMPTY = 3, QUEUE_JOINUNAVAIL = 4, QUEUE_LEAVEUNAVAIL = 5, QUEUE_FULL = 6, QUEUE_CONTINUE = 7 } |
| enum | queue_timeout_priority { TIMEOUT_PRIORITY_APP, TIMEOUT_PRIORITY_CONF } |
Functions | |
| static char * | __queues_show (struct mansession *s, int fd, int argc, const char *const *argv) |
| Show queue(s) status and statistics. | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | add_to_queue (const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface) |
| Add member to queue. | |
| static struct call_queue * | alloc_queue (const char *queuename) |
| static int | aqm_exec (struct ast_channel *chan, const char *data) |
| AddQueueMember application. | |
| 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_queue (struct call_queue *q) |
| static int | clear_stats (const char *queuename) |
| Facilitates resetting statistics for a queue. | |
| static int | compare_weight (struct call_queue *rq, struct member *member) |
| static char * | complete_queue (const char *line, const char *word, int pos, int state) |
| static char * | complete_queue_add_member (const char *line, const char *word, int pos, int state) |
| static char * | complete_queue_pause_member (const char *line, const char *word, int pos, int state) |
| static char * | complete_queue_remove_member (const char *line, const char *word, int pos, int state) |
| static char * | complete_queue_rule_show (const char *line, const char *word, int pos, int state) |
| static char * | complete_queue_set_member_penalty (const char *line, const char *word, int pos, int state) |
| static char * | complete_queue_show (const char *line, const char *word, int pos, int state) |
| static int | compress_char (const char c) |
| static void | copy_rules (struct queue_ent *qe, const char *rulename) |
| Copy rule from global list into specified queue. | |
| static struct member * | create_queue_member (const char *interface, const char *membername, int penalty, int paused, const char *state_interface) |
| allocate space for new queue member and set fields based on parameters passed | |
| static void | destroy_queue (void *obj) |
| Free queue's member list then its string fields. | |
| static void | device_state_cb (const struct ast_event *event, void *unused) |
| static void | do_hang (struct callattempt *o) |
| common hangup actions | |
| static void | do_print (struct mansession *s, int fd, const char *str) |
| direct ouput to manager or cli with proper terminator | |
| static void | dump_queue_members (struct call_queue *pm_queue) |
| Dump all members in a specific queue to the database. | |
| static void | end_bridge_callback (void *data) |
| static void | end_bridge_callback_data_fixup (struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator) |
| static struct callattempt * | find_best (struct callattempt *outgoing) |
| find the entry with the best metric, or NULL | |
| static struct call_queue * | find_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config) |
| Reload a single queue via realtime. | |
| static void | free_members (struct call_queue *q, int all) |
| Iterate through queue's member list and delete them. | |
| static int | get_member_penalty (char *queuename, char *interface) |
| static int | get_member_status (struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions) |
| Check if members are available. | |
| static char * | handle_queue_add_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_queue_pause_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_queue_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_queue_remove_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_queue_reset (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_queue_rule_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_queue_set_member_penalty (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | handle_statechange (void *datap) |
| set a member's status based on device state of that member's interface | |
| static void | hangupcalls (struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere) |
| Hang up a list of outgoing calls. | |
| static void | init_queue (struct call_queue *q) |
| Initialize Queue default values. | |
| static void | insert_entry (struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos) |
| Insert the 'new' entry after the 'prev' entry of queue 'q'. | |
| static int | insert_penaltychange (const char *list_name, const char *content, const int linenum) |
| Change queue penalty by adding rule. | |
| static const char * | int2strat (int strategy) |
| static struct member * | interface_exists (struct call_queue *q, const char *interface) |
| static int | is_our_turn (struct queue_ent *qe) |
| Check if we should start attempting to call queue members. | |
| static int | join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason, int position) |
| static int | kill_dead_members (void *obj, void *arg, int flags) |
| static int | kill_dead_queues (void *obj, void *arg, int flags) |
| static void | leave_queue (struct queue_ent *qe) |
| Caller leaving queue. | |
| static int | load_module (void) |
| static struct call_queue * | load_realtime_queue (const char *queuename) |
| static int | manager_add_queue_member (struct mansession *s, const struct message *m) |
| static int | manager_pause_queue_member (struct mansession *s, const struct message *m) |
| static int | manager_queue_log_custom (struct mansession *s, const struct message *m) |
| static int | manager_queue_member_penalty (struct mansession *s, const struct message *m) |
| static int | manager_queue_reload (struct mansession *s, const struct message *m) |
| static int | manager_queue_reset (struct mansession *s, const struct message *m) |
| static int | manager_queue_rule_show (struct mansession *s, const struct message *m) |
| static int | manager_queues_show (struct mansession *s, const struct message *m) |
| static int | manager_queues_status (struct mansession *s, const struct message *m) |
| Queue status info via AMI. | |
| static int | manager_queues_summary (struct mansession *s, const struct message *m) |
| Summary of queue info via the AMI. | |
| static int | manager_remove_queue_member (struct mansession *s, const struct message *m) |
| static int | mark_dead_and_unfound (void *obj, void *arg, int flags) |
| static int | mark_member_dead (void *obj, void *arg, int flags) |
| static int | member_cmp_fn (void *obj1, void *obj2, int flags) |
| static int | member_hash_fn (const void *obj, const int flags) |
| static int | num_available_members (struct call_queue *q) |
| Get the number of members available to accept a call. | |
| static void | parse_empty_options (const char *value, enum empty_conditions *empty, int joinempty) |
| static int | play_file (struct ast_channel *chan, const char *filename) |
| static int | pqm_exec (struct ast_channel *chan, const char *data) |
| PauseQueueMember application. | |
| static int | ql_exec (struct ast_channel *chan, const char *data) |
| QueueLog application. | |
| static int | queue_cmp_cb (void *obj, void *arg, int flags) |
| static int | queue_exec (struct ast_channel *chan, const char *data) |
| The starting point for all queue calls. | |
| static int | queue_function_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_global_params (struct ast_config *cfg) |
| static void | queue_set_param (struct call_queue *q, const char *param, const char *val, int linenum, int failunknown) |
| Configure a queue parameter. | |
| static char * | queue_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static void | queue_transfer_destroy (void *data) |
| static void | queue_transfer_fixup (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) |
| Log an attended transfer when a queue caller channel is masqueraded. | |
| static struct call_queue * | queue_unref (struct call_queue *q) |
| static void | recalc_holdtime (struct queue_ent *qe, int newholdtime) |
| static void | record_abandoned (struct queue_ent *qe) |
| Record that a caller gave up on waiting in queue. | |
| static int | reload (void) |
| static int | reload_handler (int reload, struct ast_flags *mask, const char *queuename) |
| The command center for all reload operations. | |
| static void | reload_queue_members (void) |
| Reload dynamic queue members persisted into the astdb. | |
| static int | reload_queue_rules (int reload) |
| Reload the rules defined in queuerules.conf. | |
| static int | reload_queues (int reload, struct ast_flags *mask, const char *queuename) |
| reload the queues.conf file | |
| static void | reload_single_member (const char *memberdata, struct call_queue *q) |
| reload information pertaining to a single member | |
| static void | reload_single_queue (struct ast_config *cfg, struct ast_flags *mask, const char *queuename) |
| Reload information pertaining to a particular queue. | |
| static int | remove_from_queue (const char *queuename, const char *interface) |
| Remove member from queue. | |
| static int | ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies) |
| Part 2 of ring_one. | |
| static int | ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies) |
| Place a call to a queue member. | |
| static void | rna (int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause) |
| RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. | |
| static int | rqm_exec (struct ast_channel *chan, const char *data) |
| RemoveQueueMember application. | |
| static void | rt_handle_member_record (struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface) |
| Find rt member record to update otherwise create one. | |
| static int | say_periodic_announcement (struct queue_ent *qe, int ringing) |
| Playback announcement to queued members if 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 (const char *queuename, const char *interface, int penalty) |
| static void | set_queue_result (struct ast_channel *chan, enum queue_result res) |
| sets the QUEUESTATUS channel variable | |
| static void | set_queue_variables (struct call_queue *q, struct ast_channel *chan) |
| Set variables of queue. | |
| static struct ast_datastore * | setup_transfer_datastore (struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl) |
| create a datastore for storing relevant info to log attended transfers in the queue_log | |
| static int | store_next_lin (struct queue_ent *qe, struct callattempt *outgoing) |
| Search for best metric and add to Linear queue. | |
| static int | store_next_rr (struct queue_ent *qe, struct callattempt *outgoing) |
| Search for best metric and add to Round Robbin queue. | |
| static int | strat2int (const char *strategy) |
| static int | try_calling (struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing) |
| A large function which calls members, updates statistics, and bridges the caller and a member. | |
| static int | unload_module (void) |
| static void | update_qe_rule (struct queue_ent *qe) |
| update rules for queues | |
| static int | update_queue (struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime) |
| update the queue status | |
| static int | update_realtime_member_field (struct member *mem, const char *queue_name, const char *field, const char *value) |
| static void | update_realtime_members (struct call_queue *q) |
| static int | update_status (struct call_queue *q, struct member *m, const int status) |
| set a member's status based on device state of that member's state_interface. | |
| static int | upqm_exec (struct ast_channel *chan, const char *data) |
| UnPauseQueueMember application. | |
| static int | valid_exit (struct queue_ent *qe, char digit) |
| Check for valid exit from queue via goto. | |
| static char * | vars2manager (struct ast_channel *chan, char *vars, size_t len) |
| convert "\n" to "\nVariable: " ready for manager to use | |
| static int | wait_a_bit (struct queue_ent *qe) |
| static struct callattempt * | wait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int update_connectedline) |
| Wait for a member to answer the call. | |
| static int | wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason) |
| The waiting areas for callers who are not actively calling members. | |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } |
| static char * | app = "Queue" |
| static char * | app_aqm = "AddQueueMember" |
| static char * | app_pqm = "PauseQueueMember" |
| static char * | app_ql = "QueueLog" |
| static char * | app_rqm = "RemoveQueueMember" |
| static char * | app_upqm = "UnpauseQueueMember" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static int | autofill_default = 0 |
| queues.conf [general] option | |
| static struct ast_cli_entry | cli_queue [] |
| static struct ast_event_sub * | device_state_sub |
| Subscription to device state change events. | |
| static struct ast_taskprocessor * | devicestate_tps |
| static int | montype_default = 0 |
| queues.conf [general] option | |
| static const char *const | pm_family = "Queue/PersistentMembers" |
| Persistent Members astdb family. | |
| static const char | qpm_cmd_usage [] |
| static const char | qsmp_cmd_usage [] |
| static 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 int | update_cdr = 0 |
| queues.conf [general] option | |
| static int | use_weight = 0 |
| queues.conf per-queue weight option | |
These features added by David C. Troy <dave@toad.net>:
Added servicelevel statistic by Michiel Betel <michiel@betel.nl> Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
Fixed to work with CVS as of 2004-02-25 and released as 1.07a by Matthew Enger <m.enger@xi.com.au>
Definition in file app_queue.c.
| #define ANNOUNCEHOLDTIME_ALWAYS 1 |
| #define ANNOUNCEHOLDTIME_ONCE 2 |
| #define ANNOUNCEPOSITION_LIMIT 4 |
We not announce position more than <limit>
Definition at line 871 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 870 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 869 of file app_queue.c.
Referenced by queue_set_param().
| #define ANNOUNCEPOSITION_YES 1 |
We announce position
Definition at line 868 of file app_queue.c.
Referenced by init_queue(), queue_set_param(), and say_position().
| #define AST_MAX_WATCHERS 256 |
Definition at line 3009 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 691 of file app_queue.c.
Referenced by init_queue().
| #define DEFAULT_RETRY 5 |
| #define DEFAULT_TIMEOUT 15 |
| #define MAX_PERIODIC_ANNOUNCEMENTS 10 |
The maximum periodic announcements we can have
Definition at line 690 of file app_queue.c.
Referenced by destroy_queue(), init_queue(), and queue_set_param().
| #define MAX_QUEUE_BUCKETS 53 |
| #define PM_MAX_LEN 8192 |
Definition at line 716 of file app_queue.c.
Referenced by dump_queue_members(), and reload_queue_members().
| #define QUEUE_EVENT_VARIABLES 3 |
Definition at line 857 of file app_queue.c.
Referenced by queue_set_param(), ring_entry(), rna(), send_agent_complete(), and try_calling().
| #define RECHECK 1 |
Recheck every second to see we we're at the top yet
Definition at line 689 of file app_queue.c.
Referenced by wait_our_turn().
| #define RES_EXISTS (-1) |
Entry already exists
Definition at line 696 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 698 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 699 of file app_queue.c.
Referenced by handle_queue_add_member(), handle_queue_remove_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().
| #define RES_OKAY 0 |
Action completed
Definition at line 695 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 697 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 654 of file app_queue.c.
00654 { 00655 QUEUE_STRATEGY_RINGALL = 0, 00656 QUEUE_STRATEGY_LEASTRECENT, 00657 QUEUE_STRATEGY_FEWESTCALLS, 00658 QUEUE_STRATEGY_RANDOM, 00659 QUEUE_STRATEGY_RRMEMORY, 00660 QUEUE_STRATEGY_LINEAR, 00661 QUEUE_STRATEGY_WRANDOM 00662 };
| enum empty_conditions |
| QUEUE_EMPTY_PENALTY | |
| QUEUE_EMPTY_PAUSED | |
| QUEUE_EMPTY_INUSE | |
| QUEUE_EMPTY_RINGING | |
| QUEUE_EMPTY_UNAVAILABLE | |
| QUEUE_EMPTY_INVALID | |
| QUEUE_EMPTY_UNKNOWN | |
| QUEUE_EMPTY_WRAPUP |
Definition at line 843 of file app_queue.c.
00843 { 00844 QUEUE_EMPTY_PENALTY = (1 << 0), 00845 QUEUE_EMPTY_PAUSED = (1 << 1), 00846 QUEUE_EMPTY_INUSE = (1 << 2), 00847 QUEUE_EMPTY_RINGING = (1 << 3), 00848 QUEUE_EMPTY_UNAVAILABLE = (1 << 4), 00849 QUEUE_EMPTY_INVALID = (1 << 5), 00850 QUEUE_EMPTY_UNKNOWN = (1 << 6), 00851 QUEUE_EMPTY_WRAPUP = (1 << 7), 00852 };
| enum queue_reload_mask |
Definition at line 664 of file app_queue.c.
00664 { 00665 QUEUE_RELOAD_PARAMETERS = (1 << 0), 00666 QUEUE_RELOAD_MEMBER = (1 << 1), 00667 QUEUE_RELOAD_RULES = (1 << 2), 00668 QUEUE_RESET_STATS = (1 << 3), 00669 };
| enum queue_result |
| QUEUE_UNKNOWN | |
| QUEUE_TIMEOUT | |
| QUEUE_JOINEMPTY | |
| QUEUE_LEAVEEMPTY | |
| QUEUE_JOINUNAVAIL | |
| QUEUE_LEAVEUNAVAIL | |
| QUEUE_FULL | |
| QUEUE_CONTINUE |
Definition at line 739 of file app_queue.c.
00739 { 00740 QUEUE_UNKNOWN = 0, 00741 QUEUE_TIMEOUT = 1, 00742 QUEUE_JOINEMPTY = 2, 00743 QUEUE_LEAVEEMPTY = 3, 00744 QUEUE_JOINUNAVAIL = 4, 00745 QUEUE_LEAVEUNAVAIL = 5, 00746 QUEUE_FULL = 6, 00747 QUEUE_CONTINUE = 7, 00748 };
Definition at line 764 of file app_queue.c.
00764 { 00765 TIMEOUT_PRIORITY_APP, 00766 TIMEOUT_PRIORITY_CONF, 00767 };
| static char* __queues_show | ( | struct mansession * | s, | |
| int | fd, | |||
| int | argc, | |||
| const char *const * | argv | |||
| ) | [static] |
Show queue(s) status and statistics.
List the queues strategy, calls processed, members logged in, other queue statistics such as avg hold time.
Definition at line 6363 of file app_queue.c.
References ao2_container_count(), ao2_iterator_destroy(), AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), ast_category_browse(), ast_check_realtime(), ast_config_destroy(), ast_devstate2str(), ast_load_realtime_multientry(), ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_strlen_zero(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, CLI_SHOWUSAGE, CLI_SUCCESS, call_queue::count, do_print(), member::dynamic, call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, load_realtime_queue(), call_queue::maxlen, member::membername, call_queue::members, ast_channel::name, call_queue::name, queue_ent::next, member::paused, member::penalty, queue_ent::pos, queue_ent::prio, queue_unref(), queues, member::realtime, call_queue::realtime, SENTINEL, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, call_queue::talktime, and call_queue::weight.
Referenced by manager_queues_show(), and queue_show().
06364 { 06365 struct call_queue *q; 06366 struct ast_str *out = ast_str_alloca(240); 06367 int found = 0; 06368 time_t now = time(NULL); 06369 struct ao2_iterator queue_iter; 06370 struct ao2_iterator mem_iter; 06371 06372 if (argc != 2 && argc != 3) 06373 return CLI_SHOWUSAGE; 06374 06375 if (argc == 3) { /* specific queue */ 06376 if ((q = load_realtime_queue(argv[2]))) { 06377 queue_unref(q); 06378 } 06379 } else if (ast_check_realtime("queues")) { 06380 /* This block is to find any queues which are defined in realtime but 06381 * which have not yet been added to the in-core container 06382 */ 06383 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL); 06384 char *queuename; 06385 if (cfg) { 06386 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) { 06387 if ((q = load_realtime_queue(queuename))) { 06388 queue_unref(q); 06389 } 06390 } 06391 ast_config_destroy(cfg); 06392 } 06393 } 06394 06395 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); 06396 ao2_lock(queues); 06397 while ((q = ao2_iterator_next(&queue_iter))) { 06398 float sl; 06399 struct call_queue *realtime_queue = NULL; 06400 06401 ao2_lock(q); 06402 /* This check is to make sure we don't print information for realtime 06403 * queues which have been deleted from realtime but which have not yet 06404 * been deleted from the in-core container 06405 */ 06406 if (q->realtime && !(realtime_queue = load_realtime_queue(q->name))) { 06407 ao2_unlock(q); 06408 queue_unref(q); 06409 continue; 06410 } else if (q->realtime) { 06411 queue_unref(realtime_queue); 06412 } 06413 if (argc == 3 && strcasecmp(q->name, argv[2])) { 06414 ao2_unlock(q); 06415 queue_unref(q); 06416 continue; 06417 } 06418 found = 1; 06419 06420 ast_str_set(&out, 0, "%-12.12s has %d calls (max ", q->name, q->count); 06421 if (q->maxlen) 06422 ast_str_append(&out, 0, "%d", q->maxlen); 06423 else 06424 ast_str_append(&out, 0, "unlimited"); 06425 sl = 0; 06426 if (q->callscompleted > 0) 06427 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 06428 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds", 06429 int2strat(q->strategy), q->holdtime, q->talktime, q->weight, 06430 q->callscompleted, q->callsabandoned,sl,q->servicelevel); 06431 do_print(s, fd, ast_str_buffer(out)); 06432 if (!ao2_container_count(q->members)) 06433 do_print(s, fd, " No Members"); 06434 else { 06435 struct member *mem; 06436 06437 do_print(s, fd, " Members: "); 06438 mem_iter = ao2_iterator_init(q->members, 0); 06439 while ((mem = ao2_iterator_next(&mem_iter))) { 06440 ast_str_set(&out, 0, " %s", mem->membername); 06441 if (strcasecmp(mem->membername, mem->interface)) { 06442 ast_str_append(&out, 0, " (%s)", mem->interface); 06443 } 06444 if (mem->penalty) 06445 ast_str_append(&out, 0, " with penalty %d", mem->penalty); 06446 ast_str_append(&out, 0, "%s%s%s (%s)", 06447 mem->dynamic ? " (dynamic)" : "", 06448 mem->realtime ? " (realtime)" : "", 06449 mem->paused ? " (paused)" : "", 06450 ast_devstate2str(mem->status)); 06451 if (mem->calls) 06452 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)", 06453 mem->calls, (long) (time(NULL) - mem->lastcall)); 06454 else 06455 ast_str_append(&out, 0, " has taken no calls yet"); 06456 do_print(s, fd, ast_str_buffer(out)); 06457 ao2_ref(mem, -1); 06458 } 06459 ao2_iterator_destroy(&mem_iter); 06460 } 06461 if (!q->head) 06462 do_print(s, fd, " No Callers"); 06463 else { 06464 struct queue_ent *qe; 06465 int pos = 1; 06466 06467 do_print(s, fd, " Callers: "); 06468 for (qe = q->head; qe; qe = qe->next) { 06469 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)", 06470 pos++, qe->chan->name, (long) (now - qe->start) / 60, 06471 (long) (now - qe->start) % 60, qe->prio); 06472 do_print(s, fd, ast_str_buffer(out)); 06473 } 06474 } 06475 do_print(s, fd, ""); /* blank line between entries */ 06476 ao2_unlock(q); 06477 queue_unref(q); /* Unref the iterator's reference */ 06478 } 06479 ao2_iterator_destroy(&queue_iter); 06480 ao2_unlock(queues); 06481 if (!found) { 06482 if (argc == 3) 06483 ast_str_set(&out, 0, "No such queue: %s.", argv[2]); 06484 else 06485 ast_str_set(&out, 0, "No queues."); 06486 do_print(s, fd, ast_str_buffer(out)); 06487 } 06488 return CLI_SUCCESS; 06489 }
| static void __reg_module | ( | void | ) | [static] |
Definition at line 7573 of file app_queue.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 7573 of file app_queue.c.
| static int add_to_queue | ( | const char * | queuename, | |
| const char * | interface, | |||
| const char * | membername, | |||
| int | penalty, | |||
| int | paused, | |||
| int | dump, | |||
| const char * | state_interface | |||
| ) | [static] |
Add member to queue.
| RES_NOT_DYNAMIC | when they aren't a RT member | |
| RES_NOSUCHQUEUE | queue does not exist | |
| RES_OKAY | added member from queue | |
| RES_EXISTS | queue exists but no members | |
| RES_OUT_OF_MEMORY | queue exists but not enough memory to create member |
Definition at line 4733 of file app_queue.c.
References ao2_link, ao2_lock(), ao2_ref, ao2_unlock(), member::calls, create_queue_member(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, interface_exists(), member::lastcall, load_realtime_queue(), manager_event, call_queue::membercount, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, queues, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and member::status.
Referenced by aqm_exec(), handle_queue_add_member(), manager_add_queue_member(), and reload_queue_members().
04734 { 04735 struct call_queue *q; 04736 struct member *new_member, *old_member; 04737 int res = RES_NOSUCHQUEUE; 04738 04739 /*! \note Ensure the appropriate realtime queue is loaded. Note that this 04740 * short-circuits if the queue is already in memory. */ 04741 if (!(q = load_realtime_queue(queuename))) 04742 return res; 04743 04744 ao2_lock(queues); 04745 04746 ao2_lock(q); 04747 if ((old_member = interface_exists(q, interface)) == NULL) { 04748 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) { 04749 new_member->dynamic = 1; 04750 ao2_link(q->members, new_member); 04751 q->membercount++; 04752 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 04753 "Queue: %s\r\n" 04754 "Location: %s\r\n" 04755 "MemberName: %s\r\n" 04756 "Membership: %s\r\n" 04757 "Penalty: %d\r\n" 04758 "CallsTaken: %d\r\n" 04759 "LastCall: %d\r\n" 04760 "Status: %d\r\n" 04761 "Paused: %d\r\n", 04762 q->name, new_member->interface, new_member->membername, 04763 "dynamic", 04764 new_member->penalty, new_member->calls, (int) new_member->lastcall, 04765 new_member->status, new_member->paused); 04766 04767 ao2_ref(new_member, -1); 04768 new_member = NULL; 04769 04770 if (dump) 04771 dump_queue_members(q); 04772 04773 res = RES_OKAY; 04774 } else { 04775 res = RES_OUTOFMEMORY; 04776 } 04777 } else { 04778 ao2_ref(old_member, -1); 04779 res = RES_EXISTS; 04780 } 04781 ao2_unlock(q); 04782 ao2_unlock(queues); 04783 04784 return res; 04785 }
| static struct call_queue* alloc_queue | ( | const char * | queuename | ) | [static, read] |
Definition at line 1812 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_single_queue().
01813 { 01814 struct call_queue *q; 01815 01816 if ((q = ao2_alloc(sizeof(*q), destroy_queue))) { 01817 if (ast_string_field_init(q, 64)) { 01818 ao2_ref(q, -1); 01819 return NULL; 01820 } 01821 ast_string_field_set(q, name, queuename); 01822 } 01823 return q; 01824 }
| static int aqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
AddQueueMember application.
Definition at line 5170 of file app_queue.c.
References add_to_queue(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::name, parse(), pbx_builtin_setvar_helper(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and ast_channel::uniqueid.
Referenced by load_module().
05171 { 05172 int res=-1; 05173 char *parse, *temppos = NULL; 05174 AST_DECLARE_APP_ARGS(args, 05175 AST_APP_ARG(queuename); 05176 AST_APP_ARG(interface); 05177 AST_APP_ARG(penalty); 05178 AST_APP_ARG(options); 05179 AST_APP_ARG(membername); 05180 AST_APP_ARG(state_interface); 05181 ); 05182 int penalty = 0; 05183 05184 if (ast_strlen_zero(data)) { 05185 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n"); 05186 return -1; 05187 } 05188 05189 parse = ast_strdupa(data); 05190 05191 AST_STANDARD_APP_ARGS(args, parse); 05192 05193 if (ast_strlen_zero(args.interface)) { 05194 args.interface = ast_strdupa(chan->name); 05195 temppos = strrchr(args.interface, '-'); 05196 if (temppos) 05197 *temppos = '\0'; 05198 } 05199 05200 if (!ast_strlen_zero(args.penalty)) { 05201 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) { 05202 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 05203 penalty = 0; 05204 } 05205 } 05206 05207 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) { 05208 case RES_OKAY: 05209 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", ""); 05210 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 05211 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 05212 res = 0; 05213 break; 05214 case RES_EXISTS: 05215 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 05216 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 05217 res = 0; 05218 break; 05219 case RES_NOSUCHQUEUE: 05220 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 05221 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 05222 res = 0; 05223 break; 05224 case RES_OUTOFMEMORY: 05225 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 05226 break; 05227 } 05228 05229 return res; 05230 }
| 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 3743 of file app_queue.c.
References ast_channel_datastore_find(), and queue_transfer_info.
Referenced by try_calling().
03744 { 03745 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1; 03746 }
| 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 3582 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().
03583 { 03584 if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || (qe->min_penalty && (mem->penalty < qe->min_penalty))) 03585 return -1; 03586 03587 switch (q->strategy) { 03588 case QUEUE_STRATEGY_RINGALL: 03589 /* Everyone equal, except for penalty */ 03590 tmp->metric = mem->penalty * 1000000; 03591 break; 03592 case QUEUE_STRATEGY_LINEAR: 03593 if (pos < qe->linpos) { 03594 tmp->metric = 1000 + pos; 03595 } else { 03596 if (pos > qe->linpos) 03597 /* Indicate there is another priority */ 03598 qe->linwrapped = 1; 03599 tmp->metric = pos; 03600 } 03601 tmp->metric += mem->penalty * 1000000; 03602 break; 03603 case QUEUE_STRATEGY_RRMEMORY: 03604 if (pos < q->rrpos) { 03605 tmp->metric = 1000 + pos; 03606 } else { 03607 if (pos > q->rrpos) 03608 /* Indicate there is another priority */ 03609 q->wrapped = 1; 03610 tmp->metric = pos; 03611 } 03612 tmp->metric += mem->penalty * 1000000; 03613 break; 03614 case QUEUE_STRATEGY_RANDOM: 03615 tmp->metric = ast_random() % 1000; 03616 tmp->metric += mem->penalty * 1000000; 03617 break; 03618 case QUEUE_STRATEGY_WRANDOM: 03619 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000); 03620 break; 03621 case QUEUE_STRATEGY_FEWESTCALLS: 03622 tmp->metric = mem->calls; 03623 tmp->metric += mem->penalty * 1000000; 03624 break; 03625 case QUEUE_STRATEGY_LEASTRECENT: 03626 if (!mem->lastcall) 03627 tmp->metric = 0; 03628 else 03629 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 03630 tmp->metric += mem->penalty * 1000000; 03631 break; 03632 default: 03633 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 03634 break; 03635 } 03636 return 0; 03637 }
| static void clear_queue | ( | struct call_queue * | q | ) | [static] |
Definition at line 1388 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::holdtime, call_queue::members, call_queue::talktime, and call_queue::wrapuptime.
Referenced by clear_stats(), and find_queue_by_name_rt().
01389 { 01390 q->holdtime = 0; 01391 q->callscompleted = 0; 01392 q->callsabandoned = 0; 01393 q->callscompletedinsl = 0; 01394 q->wrapuptime = 0; 01395 q->talktime = 0; 01396 01397 if (q->members) { 01398 struct member *mem; 01399 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01400 while ((mem = ao2_iterator_next(&mem_iter))) { 01401 mem->calls = 0; 01402 ao2_ref(mem, -1); 01403 } 01404 ao2_iterator_destroy(&mem_iter); 01405 } 01406 }
| static int clear_stats | ( | const char * | queuename | ) | [static] |
Facilitates resetting statistics for a queue.
This function actually does not reset any statistics, but rather finds a call_queue struct which corresponds to the passed-in queue name and passes that structure to the clear_queue function. If no queuename is passed in, then all queues will have their statistics reset.
| queuename | The name of the queue to reset the statistics for. If this is NULL or zero-length, then this means to reset the statistics for all queues |
| void |
Definition at line 6305 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_unlock(), ast_strlen_zero(), clear_queue(), call_queue::name, and queues.
Referenced by reload_handler().
06306 { 06307 struct call_queue *q; 06308 struct ao2_iterator queue_iter = ao2_iterator_init(queues, 0); 06309 while ((q = ao2_iterator_next(&queue_iter))) { 06310 ao2_lock(q); 06311 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) 06312 clear_queue(q); 06313 ao2_unlock(q); 06314 } 06315 ao2_iterator_destroy(&queue_iter); 06316 return 0; 06317 }
| static int compare_weight | ( | struct call_queue * | rq, | |
| struct member * | member | |||
| ) | [static] |
Definition at line 2526 of file app_queue.c.
References ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), ast_debug, call_queue::count, member::interface, call_queue::members, call_queue::name, num_available_members(), OBJ_POINTER, queue_unref(), queues, and call_queue::weight.
Referenced by ring_entry().
02527 { 02528 struct call_queue *q; 02529 struct member *mem; 02530 int found = 0; 02531 struct ao2_iterator queue_iter; 02532 02533 /* q's lock and rq's lock already set by try_calling() 02534 * to solve deadlock */ 02535 queue_iter = ao2_iterator_init(queues, 0); 02536 while ((q = ao2_iterator_next(&queue_iter))) { 02537 if (q == rq) { /* don't check myself, could deadlock */ 02538 queue_unref(q); 02539 continue; 02540 } 02541 ao2_lock(q); 02542 if (q->count && q->members) { 02543 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) { 02544 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 02545 if (q->weight > rq->weight && q->count >= num_available_members(q)) { 02546 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); 02547 found = 1; 02548 } 02549 ao2_ref(mem, -1); 02550 } 02551 } 02552 ao2_unlock(q); 02553 queue_unref(q); 02554 if (found) { 02555 break; 02556 } 02557 } 02558 ao2_iterator_destroy(&queue_iter); 02559 return found; 02560 }
| static char* complete_queue | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6491 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_strdup, call_queue::name, queue_unref(), and queues.
Referenced by complete_queue_add_member(), complete_queue_pause_member(), complete_queue_remove_member(), complete_queue_set_member_penalty(), complete_queue_show(), handle_queue_reload(), and handle_queue_reset().
06492 { 06493 struct call_queue *q; 06494 char *ret = NULL; 06495 int which = 0; 06496 int wordlen = strlen(word); 06497 struct ao2_iterator queue_iter; 06498 06499 queue_iter = ao2_iterator_init(queues, 0); 06500 while ((q = ao2_iterator_next(&queue_iter))) { 06501 if (!strncasecmp(word, q->name, wordlen) && ++which > state) { 06502 ret = ast_strdup(q->name); 06503 queue_unref(q); 06504 break; 06505 } 06506 queue_unref(q); 06507 } 06508 ao2_iterator_destroy(&queue_iter); 06509 06510 return ret; 06511 }
| static char* complete_queue_add_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6923 of file app_queue.c.
References ast_malloc, ast_strdup, complete_queue(), and num.
Referenced by handle_queue_add_member().
06924 { 06925 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */ 06926 switch (pos) { 06927 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 06928 return NULL; 06929 case 4: /* only one possible match, "to" */ 06930 return state == 0 ? ast_strdup("to") : NULL; 06931 case 5: /* <queue> */ 06932 return complete_queue(line, word, pos, state); 06933 case 6: /* only one possible match, "penalty" */ 06934 return state == 0 ? ast_strdup("penalty") : NULL; 06935 case 7: 06936 if (state < 100) { /* 0-99 */ 06937 char *num; 06938 if ((num = ast_malloc(3))) { 06939 sprintf(num, "%d", state); 06940 } 06941 return num; 06942 } else { 06943 return NULL; 06944 } 06945 case 8: /* only one possible match, "as" */ 06946 return state == 0 ? ast_strdup("as") : NULL; 06947 case 9: /* Don't attempt to complete name of member (infinite possibilities) */ 06948 return NULL; 06949 default: 06950 return NULL; 06951 } 06952 }
| static char* complete_queue_pause_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 7144 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_pause_member().
07145 { 07146 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */ 07147 switch (pos) { 07148 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */ 07149 return NULL; 07150 case 4: /* only one possible match, "queue" */ 07151 return state == 0 ? ast_strdup("queue") : NULL; 07152 case 5: /* <queue> */ 07153 return complete_queue(line, word, pos, state); 07154 case 6: /* "reason" */ 07155 return state == 0 ? ast_strdup("reason") : NULL; 07156 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */ 07157 return NULL; 07158 default: 07159 return NULL; 07160 } 07161 }
| static char* complete_queue_remove_member | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 7053 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), ast_strdup, complete_queue(), member::interface, member::membername, call_queue::members, queue_unref(), and queues.
Referenced by handle_queue_remove_member().
07054 { 07055 int which = 0; 07056 struct call_queue *q; 07057 struct member *m; 07058 struct ao2_iterator queue_iter; 07059 struct ao2_iterator mem_iter; 07060 int wordlen = strlen(word); 07061 07062 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */ 07063 if (pos > 5 || pos < 3) 07064 return NULL; 07065 if (pos == 4) /* only one possible match, 'from' */ 07066 return (state == 0 ? ast_strdup("from") : NULL); 07067 07068 if (pos == 5) /* No need to duplicate code */ 07069 return complete_queue(line, word, pos, state); 07070 07071 /* here is the case for 3, <member> */ 07072 queue_iter = ao2_iterator_init(queues, 0); 07073 while ((q = ao2_iterator_next(&queue_iter))) { 07074 ao2_lock(q); 07075 mem_iter = ao2_iterator_init(q->members, 0); 07076 while ((m = ao2_iterator_next(&mem_iter))) { 07077 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) { 07078 char *tmp; 07079 ao2_unlock(q); 07080 tmp = ast_strdup(m->interface); 07081 ao2_ref(m, -1); 07082 queue_unref(q); 07083 ao2_iterator_destroy(&mem_iter); 07084 ao2_iterator_destroy(&queue_iter); 07085 return tmp; 07086 } 07087 ao2_ref(m, -1); 07088 } 07089 ao2_iterator_destroy(&mem_iter); 07090 ao2_unlock(q); 07091 queue_unref(q); 07092 } 07093 ao2_iterator_destroy(&queue_iter); 07094 07095 return NULL; 07096 }
| static char* complete_queue_rule_show | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 7277 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().
07278 { 07279 int which = 0; 07280 struct rule_list *rl_iter; 07281 int wordlen = strlen(word); 07282 char *ret = NULL; 07283 if (pos != 3) /* Wha? */ { 07284 return NULL; 07285 } 07286 07287 AST_LIST_LOCK(&rule_lists); 07288 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 07289 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) { 07290 ret = ast_strdup(rl_iter->name); 07291 break; 07292 } 07293 } 07294 AST_LIST_UNLOCK(&rule_lists); 07295 07296 return ret; 07297 }
| static char* complete_queue_set_member_penalty | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 7214 of file app_queue.c.
References ast_strdup, and complete_queue().
Referenced by handle_queue_set_member_penalty().
07215 { 07216 /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/ 07217 switch (pos) { 07218 case 4: 07219 if (state == 0) { 07220 return ast_strdup("on"); 07221 } else { 07222 return NULL; 07223 } 07224 case 6: 07225 if (state == 0) { 07226 return ast_strdup("in"); 07227 } else { 07228 return NULL; 07229 } 07230 case 7: 07231 return complete_queue(line, word, pos, state); 07232 default: 07233 return NULL; 07234 } 07235 }
| static char* complete_queue_show | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 6513 of file app_queue.c.
References complete_queue().
Referenced by queue_show().
06514 { 06515 if (pos == 2) 06516 return complete_queue(line, word, pos, state); 06517 return NULL; 06518 }
| static int compress_char | ( | const char | c | ) | [static] |
Definition at line 1287 of file app_queue.c.
Referenced by member_hash_fn().
01288 { 01289 if (c < 32) 01290 return 0; 01291 else if (c > 96) 01292 return c - 64; 01293 else 01294 return c - 32; 01295 }
| static void copy_rules | ( | struct queue_ent * | qe, | |
| const char * | rulename | |||
| ) | [static] |
Copy rule from global list into specified queue.
Definition at line 5267 of file app_queue.c.
References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), call_queue::defaultrule, LOG_ERROR, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, queue_ent::parent, queue_ent::qe_rules, rule_list::rules, and penalty_rule::time.
Referenced by queue_exec().
05268 { 05269 struct penalty_rule *pr_iter; 05270 struct rule_list *rl_iter; 05271 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename; 05272 AST_LIST_LOCK(&rule_lists); 05273 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 05274 if (!strcasecmp(rl_iter->name, tmp)) 05275 break; 05276 } 05277 if (rl_iter) { 05278 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 05279 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr)); 05280 if (!new_pr) { 05281 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n"); 05282 AST_LIST_UNLOCK(&rule_lists); 05283 break; 05284 } 05285 new_pr->time = pr_iter->time; 05286 new_pr->max_value = pr_iter->max_value; 05287 new_pr->min_value = pr_iter->min_value; 05288 new_pr->max_relative = pr_iter->max_relative; 05289 new_pr->min_relative = pr_iter->min_relative; 05290 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list); 05291 } 05292 } 05293 AST_LIST_UNLOCK(&rule_lists); 05294 }
| 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 1262 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_single_member(), and rt_handle_member_record().
01263 { 01264 struct member *cur; 01265 01266 if ((cur = ao2_alloc(sizeof(*cur), NULL))) { 01267 cur->penalty = penalty; 01268 cur->paused = paused; 01269 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 01270 if (!ast_strlen_zero(state_interface)) 01271 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface)); 01272 else 01273 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface)); 01274 if (!ast_strlen_zero(membername)) 01275 ast_copy_string(cur->membername, membername, sizeof(cur->membername)); 01276 else 01277 ast_copy_string(cur->membername, interface, sizeof(cur->membername)); 01278 if (!strchr(cur->interface, '/')) 01279 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 01280 cur->status = ast_device_state(cur->state_interface); 01281 } 01282 01283 return cur; 01284 }
| static void destroy_queue | ( | void * | obj | ) | [static] |
Free queue's member list then its string fields.
Definition at line 1798 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().
01799 { 01800 struct call_queue *q = obj; 01801 int i; 01802 01803 free_members(q, 1); 01804 ast_string_field_free_memory(q); 01805 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 01806 if (q->sound_periodicannounce[i]) 01807 free(q->sound_periodicannounce[i]); 01808 } 01809 ao2_ref(q->members, -1); 01810 }
| static void device_state_cb | ( | const struct ast_event * | event, | |
| void * | unused | |||
| ) | [static] |
Definition at line 1235 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(), and load_pbx().
01236 { 01237 enum ast_device_state state; 01238 const char *device; 01239 struct statechange *sc; 01240 size_t datapsize; 01241 01242 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE); 01243 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE); 01244 01245 if (ast_strlen_zero(device)) { 01246 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n"); 01247 return; 01248 } 01249 datapsize = sizeof(*sc) + strlen(device) + 1; 01250 if (!(sc = ast_calloc(1, datapsize))) { 01251 ast_log(LOG_ERROR, "failed to calloc a state change struct\n"); 01252 return; 01253 } 01254 sc->state = state; 01255 strcpy(sc->dev, device); 01256 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) { 01257 ast_free(sc); 01258 } 01259 }
| static void do_hang | ( | struct callattempt * | o | ) | [static] |
common hangup actions
Definition at line 2563 of file app_queue.c.
References ast_hangup(), callattempt::chan, and callattempt::stillgoing.
Referenced by ring_entry(), and wait_for_answer().
02564 { 02565 o->stillgoing = 0; 02566 ast_hangup(o->chan); 02567 o->chan = NULL; 02568 }
| 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 6349 of file app_queue.c.
References ast_cli(), and astman_append().
Referenced by __queues_show().
06350 { 06351 if (s) 06352 astman_append(s, "%s\r\n", str); 06353 else 06354 ast_cli(fd, "%s\n", str); 06355 }
| 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 4634 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_db_del(), ast_db_put(), ast_log(), member::dynamic, member::interface, LOG_WARNING, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, PM_MAX_LEN, member::state_interface, and value.
Referenced by add_to_queue(), remove_from_queue(), and set_member_paused().
04635 { 04636 struct member *cur_member; 04637 char value[PM_MAX_LEN]; 04638 int value_len = 0; 04639 int res; 04640 struct ao2_iterator mem_iter; 04641 04642 memset(value, 0, sizeof(value)); 04643 04644 if (!pm_queue) 04645 return; 04646 04647 mem_iter = ao2_iterator_init(pm_queue->members, 0); 04648 while ((cur_member = ao2_iterator_next(&mem_iter))) { 04649 if (!cur_member->dynamic) { 04650 ao2_ref(cur_member, -1); 04651 continue; 04652 } 04653 04654 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s", 04655 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface); 04656 04657 ao2_ref(cur_member, -1); 04658 04659 if (res != strlen(value + value_len)) { 04660 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 04661 break; 04662 } 04663 value_len += res; 04664 } 04665 ao2_iterator_destroy(&mem_iter); 04666 04667 if (value_len && !cur_member) { 04668 if (ast_db_put(pm_family, pm_queue->name, value)) 04669 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 04670 } else 04671 /* Delete the entry if the queue is empty or there is an error */ 04672 ast_db_del(pm_family, pm_queue->name); 04673 }
| static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 3790 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().
03791 { 03792 struct queue_end_bridge *qeb = data; 03793 struct call_queue *q = qeb->q; 03794 struct ast_channel *chan = qeb->chan; 03795 03796 if (ao2_ref(qeb, -1) == 1) { 03797 ao2_lock(q); 03798 set_queue_variables(q, chan); 03799 ao2_unlock(q); 03800 /* This unrefs the reference we made in try_calling when we allocated qeb */ 03801 queue_unref(q); 03802 } 03803 }
| static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
| struct ast_channel * | originator, | |||
| struct ast_channel * | terminator | |||
| ) | [static] |
Definition at line 3783 of file app_queue.c.
References ao2_ref, queue_end_bridge::chan, and ast_bridge_config::end_bridge_callback_data.
03784 { 03785 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data; 03786 ao2_ref(qeb, +1); 03787 qeb->chan = originator; 03788 }
| static struct callattempt* find_best | ( | struct callattempt * | outgoing | ) | [static, read] |
find the entry with the best metric, or NULL
Definition at line 2796 of file app_queue.c.
References callattempt::metric, and callattempt::q_next.
Referenced by ast_cli_command_full(), ring_one(), store_next_lin(), and store_next_rr().
02797 { 02798 struct callattempt *best = NULL, *cur; 02799 02800 for (cur = outgoing; cur; cur = cur->q_next) { 02801 if (cur->stillgoing && /* Not already done */ 02802 !cur->chan && /* Isn't already going */ 02803 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */ 02804 best = cur; 02805 } 02806 } 02807 02808 return best; 02809 }
| 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 1836 of file app_queue.c.
References alloc_queue(), ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_lock(), ao2_ref, ao2_unlink, ao2_unlock(), ast_category_browse(), ast_copy_string(), ast_debug, ast_log(), ast_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, rt_handle_member_record(), S_OR, strat2int(), call_queue::strategy, and ast_variable::value.
Referenced by load_realtime_queue().
01837 { 01838 struct ast_variable *v; 01839 struct call_queue *q, tmpq = { 01840 .name = queuename, 01841 }; 01842 struct member *m; 01843 struct ao2_iterator mem_iter; 01844 char *interface = NULL; 01845 const char *tmp_name; 01846 char *tmp; 01847 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 01848 01849 /* Static queues override realtime. */ 01850 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 01851 ao2_lock(q); 01852 if (!q->realtime) { 01853 if (q->dead) { 01854 ao2_unlock(q); 01855 queue_unref(q); 01856 return NULL; 01857 } else { 01858 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name); 01859 ao2_unlock(q); 01860 return q; 01861 } 01862 } 01863 queue_unref(q); 01864 } else if (!member_config) 01865 /* Not found in the list, and it's not realtime ... */ 01866 return NULL; 01867 01868 /* Check if queue is defined in realtime. */ 01869 if (!queue_vars) { 01870 /* Delete queue from in-core list if it has been deleted in realtime. */ 01871 if (q) { 01872 /*! \note Hmm, can't seem to distinguish a DB failure from a not 01873 found condition... So we might delete an in-core queue 01874 in case of DB failure. */ 01875 ast_debug(1, "Queue %s not found in realtime.\n", queuename); 01876 01877 q->dead = 1; 01878 /* Delete if unused (else will be deleted when last caller leaves). */ 01879 ao2_unlink(queues, q); 01880 ao2_unlock(q); 01881 queue_unref(q); 01882 } 01883 return NULL; 01884 } 01885 01886 /* Create a new queue if an in-core entry does not exist yet. */ 01887 if (!q) { 01888 struct ast_variable *tmpvar = NULL; 01889 if (!(q = alloc_queue(queuename))) 01890 return NULL; 01891 ao2_lock(q); 01892 clear_queue(q); 01893 q->realtime = 1; 01894 q->membercount = 0; 01895 /*Before we initialize the queue, we need to set the strategy, so that linear strategy 01896 * will allocate the members properly 01897 */ 01898 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) { 01899 if (!strcasecmp(tmpvar->name, "strategy")) { 01900 q->strategy = strat2int(tmpvar->value); 01901 if (q->strategy < 0) { 01902 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 01903 tmpvar->value, q->name); 01904 q->strategy = QUEUE_STRATEGY_RINGALL; 01905 } 01906 break; 01907 } 01908 } 01909 /* We traversed all variables and didn't find a strategy */ 01910 if (!tmpvar) 01911 q->strategy = QUEUE_STRATEGY_RINGALL; 01912 ao2_link(queues, q); 01913 } 01914 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 01915 01916 memset(tmpbuf, 0, sizeof(tmpbuf)); 01917 for (v = queue_vars; v; v = v->next) { 01918 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 01919 if ((tmp = strchr(v->name, '_'))) { 01920 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 01921 tmp_name = tmpbuf; 01922 tmp = tmpbuf; 01923 while ((tmp = strchr(tmp, '_'))) 01924 *tmp++ = '-'; 01925 } else 01926 tmp_name = v->name; 01927 01928 if (!ast_strlen_zero(v->value)) { 01929 /* Don't want to try to set the option if the value is empty */ 01930 queue_set_param(q, tmp_name, v->value, -1, 0); 01931 } 01932 } 01933 01934 /* Temporarily set realtime members dead so we can detect deleted ones. 01935 * Also set the membercount correctly for realtime*/ 01936 mem_iter = ao2_iterator_init(q->members, 0); 01937 while ((m = ao2_iterator_next(&mem_iter))) { 01938 q->membercount++; 01939 if (m->realtime) 01940 m->dead = 1; 01941 ao2_ref(m, -1); 01942 } 01943 ao2_iterator_destroy(&mem_iter); 01944 01945 while ((interface = ast_category_browse(member_config, interface))) { 01946 rt_handle_member_record(q, interface, 01947 ast_variable_retrieve(member_config, interface, "uniqueid"), 01948 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface), 01949 ast_variable_retrieve(member_config, interface, "penalty"), 01950 ast_variable_retrieve(member_config, interface, "paused"), 01951 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface)); 01952 } 01953 01954 /* Delete all realtime members that have been deleted in DB. */ 01955 mem_iter = ao2_iterator_init(q->members, 0); 01956 while ((m = ao2_iterator_next(&mem_iter))) { 01957 if (m->dead) { 01958 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", ""); 01959 ao2_unlink(q->members, m); 01960 q->membercount--; 01961 } 01962 ao2_ref(m, -1); 01963 } 01964 ao2_iterator_destroy(&mem_iter); 01965 01966 ao2_unlock(q); 01967 01968 return q; 01969 }
| static void free_members | ( | struct call_queue * | q, | |
| int | all | |||
| ) | [static] |
Iterate through queue's member list and delete them.
Definition at line 1781 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ao2_unlink, member::dynamic, call_queue::membercount, and call_queue::members.
Referenced by destroy_queue().
01782 { 01783 /* Free non-dynamic members */ 01784 struct member *cur; 01785 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 01786 01787 while ((cur = ao2_iterator_next(&mem_iter))) { 01788 if (all || !cur->dynamic) { 01789 ao2_unlink(q->members, cur); 01790 q->membercount--; 01791 } 01792 ao2_ref(cur, -1); 01793 } 01794 ao2_iterator_destroy(&mem_iter); 01795 }
| static int get_member_penalty | ( | char * | queuename, | |
| char * | interface | |||
| ) | [static] |
Definition at line 4912 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().
04913 { 04914 int foundqueue = 0, penalty; 04915 struct call_queue *q, tmpq = { 04916 .name = queuename, 04917 }; 04918 struct member *mem; 04919 04920 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 04921 foundqueue = 1; 04922 ao2_lock(q); 04923 if ((mem = interface_exists(q, interface))) { 04924 penalty = mem->penalty; 04925 ao2_ref(mem, -1); 04926 ao2_unlock(q); 04927 queue_unref(q); 04928 return penalty; 04929 } 04930 ao2_unlock(q); 04931 queue_unref(q); 04932 } 04933 04934 /* some useful debuging */ 04935 if (foundqueue) 04936 ast_log (LOG_ERROR, "Invalid queuename\n"); 04937 else 04938 ast_log (LOG_ERROR, "Invalid interface\n"); 04939 04940 return RESULT_FAILURE; 04941 }
| static int get_member_status | ( | struct call_queue * | q, | |
| int | max_penalty, | |||
| int | min_penalty, | |||
| enum empty_conditions | conditions | |||
| ) | [static] |
Check if members are available.
This function checks to see if members are available to be called. If any member is available, the function immediately returns 0. If no members are available, then -1 is returned.
Definition at line 1096 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, member::lastcall, member::membername, call_queue::members, member::paused, member::penalty, QUEUE_EMPTY_INUSE, QUEUE_EMPTY_INVALID, QUEUE_EMPTY_PAUSED, QUEUE_EMPTY_PENALTY, QUEUE_EMPTY_UNAVAILABLE, QUEUE_EMPTY_UNKNOWN, QUEUE_EMPTY_WRAPUP, member::status, and call_queue::wrapuptime.
Referenced by join_queue(), queue_exec(), and wait_our_turn().
01097 { 01098 struct member *member; 01099 struct ao2_iterator mem_iter; 01100 01101 ao2_lock(q); 01102 mem_iter = ao2_iterator_init(q->members, 0); 01103 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) { 01104 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) { 01105 if (conditions & QUEUE_EMPTY_PENALTY) { 01106 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty); 01107 continue; 01108 } 01109 } 01110 01111 switch (member->status) { 01112 case AST_DEVICE_INVALID: 01113 if (conditions & QUEUE_EMPTY_INVALID) { 01114 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername); 01115 break; 01116 } 01117 case AST_DEVICE_UNAVAILABLE: 01118 if (conditions & QUEUE_EMPTY_UNAVAILABLE) { 01119 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername); 01120 break; 01121 } 01122 case AST_DEVICE_INUSE: 01123 if (conditions & QUEUE_EMPTY_INUSE) { 01124 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername); 01125 break; 01126 } 01127 case AST_DEVICE_UNKNOWN: 01128 if (conditions & QUEUE_EMPTY_UNKNOWN) { 01129 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername); 01130 break; 01131 } 01132 default: 01133 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) { 01134 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername); 01135 break; 01136 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) { 01137 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime); 01138 break; 01139 } else { 01140 ao2_unlock(q); 01141 ao2_ref(member, -1); 01142 ao2_iterator_destroy(&mem_iter); 01143 ast_debug(4, "%s is available.\n", member->membername); 01144 return 0; 01145 } 01146 break; 01147 } 01148 } 01149 ao2_iterator_destroy(&mem_iter); 01150 01151 ao2_unlock(q); 01152 return -1; 01153 }
| static char* handle_queue_add_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6979 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.
06980 { 06981 const char *queuename, *interface, *membername = NULL, *state_interface = NULL; 06982 int penalty; 06983 06984 switch ( cmd ) { 06985 case CLI_INIT: 06986 e->command = "queue add member"; 06987 e->usage = 06988 "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n" 06989 " Add a channel to a queue with optionally: a penalty, membername and a state_interface\n"; 06990 return NULL; 06991 case CLI_GENERATE: 06992 return complete_queue_add_member(a->line, a->word, a->pos, a->n); 06993 } 06994 06995 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) { 06996 return CLI_SHOWUSAGE; 06997 } else if (strcmp(a->argv[4], "to")) { 06998 return CLI_SHOWUSAGE; 06999 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) { 07000 return CLI_SHOWUSAGE; 07001 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) { 07002 return CLI_SHOWUSAGE; 07003 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) { 07004 return CLI_SHOWUSAGE; 07005 } 07006 07007 queuename = a->argv[5]; 07008 interface = a->argv[3]; 07009 if (a->argc >= 8) { 07010 if (sscanf(a->argv[7], "%30d", &penalty) == 1) { 07011 if (penalty < 0) { 07012 ast_cli(a->fd, "Penalty must be >= 0\n"); 07013 penalty = 0; 07014 } 07015 } else { 07016 ast_cli(a->fd, "Penalty must be an integer >= 0\n"); 07017 penalty = 0; 07018 } 07019 } else { 07020 penalty = 0; 07021 } 07022 07023 if (a->argc >= 10) { 07024 membername = a->argv[9]; 07025 } 07026 07027 if (a->argc >= 12) { 07028 state_interface = a->argv[11]; 07029 } 07030 07031 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) { 07032 case RES_OKAY: 07033 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", ""); 07034 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 07035 return CLI_SUCCESS; 07036 case RES_EXISTS: 07037 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 07038 return CLI_FAILURE; 07039 case RES_NOSUCHQUEUE: 07040 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 07041 return CLI_FAILURE; 07042 case RES_OUTOFMEMORY: 07043 ast_cli(a->fd, "Out of memory\n"); 07044 return CLI_FAILURE; 07045 case RES_NOT_DYNAMIC: 07046 ast_cli(a->fd, "Member not dynamic\n"); 07047 return CLI_FAILURE; 07048 default: 07049 return CLI_FAILURE; 07050 } 07051 }
| static char* handle_queue_pause_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7163 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_pause_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RESULT_SUCCESS, set_member_paused(), ast_cli_entry::usage, and word.
07164 { 07165 const char *queuename, *interface, *reason; 07166 int paused; 07167 07168 switch (cmd) { 07169 case CLI_INIT: 07170 e->command = "queue {pause|unpause} member"; 07171 e->usage = 07172 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n" 07173 " Pause or unpause a queue member. Not specifying a particular queue\n" 07174 " will pause or unpause a member across all queues to which the member\n" 07175 " belongs.\n"; 07176 return NULL; 07177 case CLI_GENERATE: 07178 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n); 07179 } 07180 07181 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) { 07182 return CLI_SHOWUSAGE; 07183 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) { 07184 return CLI_SHOWUSAGE; 07185 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) { 07186 return CLI_SHOWUSAGE; 07187 } 07188 07189 07190 interface = a->argv[3]; 07191 queuename = a->argc >= 6 ? a->argv[5] : NULL; 07192 reason = a->argc == 8 ? a->argv[7] : NULL; 07193 paused = !strcasecmp(a->argv[1], "pause"); 07194 07195 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) { 07196 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface); 07197 if (!ast_strlen_zero(queuename)) 07198 ast_cli(a->fd, " in queue '%s'", queuename); 07199 if (!ast_strlen_zero(reason)) 07200 ast_cli(a->fd, " for reason '%s'", reason); 07201 ast_cli(a->fd, "\n"); 07202 return CLI_SUCCESS; 07203 } else { 07204 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface); 07205 if (!ast_strlen_zero(queuename)) 07206 ast_cli(a->fd, " in queue '%s'", queuename); 07207 if (!ast_strlen_zero(reason)) 07208 ast_cli(a->fd, " for reason '%s'", reason); 07209 ast_cli(a->fd, "\n"); 07210 return CLI_FAILURE; 07211 } 07212 }
| static char* handle_queue_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7372 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, AST_FLAGS_ALL, ast_set_flag, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue(), ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, reload_handler(), ast_cli_entry::usage, and ast_cli_args::word.
07373 { 07374 struct ast_flags mask = {0,}; 07375 int i; 07376 07377 switch (cmd) { 07378 case CLI_INIT: 07379 e->command = "queue reload {parameters|members|rules|all}"; 07380 e->usage = 07381 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n" 07382 "Reload queues. If <queuenames> are specified, only reload information pertaining\n" 07383 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n" 07384 "specified in order to know what information to reload. Below is an explanation\n" 07385 "of each of these qualifiers.\n" 07386 "\n" 07387 "\t'members' - reload queue members from queues.conf\n" 07388 "\t'parameters' - reload all queue options except for queue members\n" 07389 "\t'rules' - reload the queuerules.conf file\n" 07390 "\t'all' - reload queue rules, parameters, and members\n" 07391 "\n" 07392 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n" 07393 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n" 07394 "one queue is specified when using this command, reloading queue rules may cause\n" 07395 "other queues to be affected\n"; 07396 return NULL; 07397 case CLI_GENERATE: 07398 if (a->pos >= 3) { 07399 return complete_queue(a->line, a->word, a->pos, a->n); 07400 } else { 07401 return NULL; 07402 } 07403 } 07404 07405 if (a->argc < 3) 07406 return CLI_SHOWUSAGE; 07407 07408 if (!strcasecmp(a->argv[2], "rules")) { 07409 ast_set_flag(&mask, QUEUE_RELOAD_RULES); 07410 } else if (!strcasecmp(a->argv[2], "members")) { 07411 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER); 07412 } else if (!strcasecmp(a->argv[2], "parameters")) { 07413 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); 07414 } else if (!strcasecmp(a->argv[2], "all")) { 07415 ast_set_flag(&mask, AST_FLAGS_ALL); 07416 } 07417 07418 if (a->argc == 3) { 07419 reload_handler(1, &mask, NULL); 07420 return CLI_SUCCESS; 07421 } 07422 07423 for (i = 3; i < a->argc; ++i) { 07424 reload_handler(1, &mask, a->argv[i]); 07425 } 07426 07427 return CLI_SUCCESS; 07428 }
| static char* handle_queue_remove_member | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7098 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_remove_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, ast_cli_entry::usage, and ast_cli_args::word.
07099 { 07100 const char *queuename, *interface; 07101 07102 switch (cmd) { 07103 case CLI_INIT: 07104 e->command = "queue remove member"; 07105 e->usage = 07106 "Usage: queue remove member <channel> from <queue>\n" 07107 " Remove a specific channel from a queue.\n"; 07108 return NULL; 07109 case CLI_GENERATE: 07110 return complete_queue_remove_member(a->line, a->word, a->pos, a->n); 07111 } 07112 07113 if (a->argc != 6) { 07114 return CLI_SHOWUSAGE; 07115 } else if (strcmp(a->argv[4], "from")) { 07116 return CLI_SHOWUSAGE; 07117 } 07118 07119 queuename = a->argv[5]; 07120 interface = a->argv[3]; 07121 07122 switch (remove_from_queue(queuename, interface)) { 07123 case RES_OKAY: 07124 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", ""); 07125 ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 07126 return CLI_SUCCESS; 07127 case RES_EXISTS: 07128 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 07129 return CLI_FAILURE; 07130 case RES_NOSUCHQUEUE: 07131 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 07132 return CLI_FAILURE; 07133 case RES_OUTOFMEMORY: 07134 ast_cli(a->fd, "Out of memory\n"); 07135 return CLI_FAILURE; 07136 case RES_NOT_DYNAMIC: 07137 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename); 07138 return CLI_FAILURE; 07139 default: 07140 return CLI_FAILURE; 07141 } 07142 }
| static char* handle_queue_reset | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7333 of file app_queue.c.
References ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue(), ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, QUEUE_RESET_STATS, reload_handler(), ast_cli_entry::usage, and ast_cli_args::word.
07334 { 07335 struct ast_flags mask = {QUEUE_RESET_STATS,}; 07336 int i; 07337 07338 switch (cmd) { 07339 case CLI_INIT: 07340 e->command = "queue reset stats"; 07341 e->usage = 07342 "Usage: queue reset stats [<queuenames>]\n" 07343 "\n" 07344 "Issuing this command will reset statistics for\n" 07345 "<queuenames>, or for all queues if no queue is\n" 07346 "specified.\n"; 07347 return NULL; 07348 case CLI_GENERATE: 07349 if (a->pos >= 3) { 07350 return complete_queue(a->line, a->word, a->pos, a->n); 07351 } else { 07352 return NULL; 07353 } 07354 } 07355 07356 if (a->argc < 3) { 07357 return CLI_SHOWUSAGE; 07358 } 07359 07360 if (a->argc == 3) { 07361 reload_handler(1, &mask, NULL); 07362 return CLI_SUCCESS; 07363 } 07364 07365 for (i = 3; i < a->argc; ++i) { 07366 reload_handler(1, &mask, a->argv[i]); 07367 } 07368 07369 return CLI_SUCCESS; 07370 }
| static char* handle_queue_rule_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7299 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.
07300 { 07301 const char *rule; 07302 struct rule_list *rl_iter; 07303 struct penalty_rule *pr_iter; 07304 switch (cmd) { 07305 case CLI_INIT: 07306 e->command = "queue show rules"; 07307 e->usage = 07308 "Usage: queue show rules [rulename]\n" 07309 " Show the list of rules associated with rulename. If no\n" 07310 " rulename is specified, list all rules defined in queuerules.conf\n"; 07311 return NULL; 07312 case CLI_GENERATE: 07313 return complete_queue_rule_show(a->line, a->word, a->pos, a->n); 07314 } 07315 07316 if (a->argc != 3 && a->argc != 4) 07317 return CLI_SHOWUSAGE; 07318 07319 rule = a->argc == 4 ? a->argv[3] : ""; 07320 AST_LIST_LOCK(&rule_lists); 07321 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 07322 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) { 07323 ast_cli(a->fd, "Rule: %s\n", rl_iter->name); 07324 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 07325 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); 07326 } 07327 } 07328 } 07329 AST_LIST_UNLOCK(&rule_lists); 07330 return CLI_SUCCESS; 07331 }
| static char* handle_queue_set_member_penalty | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 7237 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.
07238 { 07239 const char *queuename = NULL, *interface; 07240 int penalty = 0; 07241 07242 switch (cmd) { 07243 case CLI_INIT: 07244 e->command = "queue set penalty"; 07245 e->usage = 07246 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n" 07247 " Set a member's penalty in the queue specified. If no queue is specified\n" 07248 " then that interface's penalty is set in all queues to which that interface is a member\n"; 07249 return NULL; 07250 case CLI_GENERATE: 07251 return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n); 07252 } 07253 07254 if (a->argc != 6 && a->argc != 8) { 07255 return CLI_SHOWUSAGE; 07256 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) { 07257 return CLI_SHOWUSAGE; 07258 } 07259 07260 if (a->argc == 8) 07261 queuename = a->argv[7]; 07262 interface = a->argv[5]; 07263 penalty = atoi(a->argv[3]); 07264 07265 switch (set_member_penalty(queuename, interface, penalty)) { 07266 case RESULT_SUCCESS: 07267 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename); 07268 return CLI_SUCCESS; 07269 case RESULT_FAILURE: 07270 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename); 07271 return CLI_FAILURE; 07272 default: 07273 return CLI_FAILURE; 07274 } 07275 }
| static int handle_statechange | ( | void * | datap | ) | [static] |
set a member's status based on device state of that member's interface
Definition at line 1191 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), ast_copy_string(), ast_debug, ast_devstate2str(), ast_free, statechange::dev, call_queue::found, call_queue::members, queues, statechange::state, member::state_interface, and update_status().
Referenced by device_state_cb().
01192 { 01193 struct statechange *sc = datap; 01194 struct ao2_iterator miter, qiter; 01195 struct member *m; 01196 struct call_queue *q; 01197 char interface[80], *slash_pos; 01198 int found = 0; 01199 01200 qiter = ao2_iterator_init(queues, 0); 01201 while ((q = ao2_iterator_next(&qiter))) { 01202 ao2_lock(q); 01203 01204 miter = ao2_iterator_init(q->members, 0); 01205 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) { 01206 ast_copy_string(interface, m->state_interface, sizeof(interface)); 01207 01208 if ((slash_pos = strchr(interface, '/'))) 01209 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) 01210 *slash_pos = '\0'; 01211 01212 if (!strcasecmp(interface, sc->dev)) { 01213 found = 1; 01214 update_status(q, m, sc->state); 01215 ao2_ref(m, -1); 01216 break; 01217 } 01218 } 01219 ao2_iterator_destroy(&miter); 01220 01221 ao2_unlock(q); 01222 ao2_ref(q, -1); 01223 } 01224 ao2_iterator_destroy(&qiter); 01225 01226 if (found) 01227 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state)); 01228 else 01229 ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", sc->dev, sc->state, ast_devstate2str(sc->state)); 01230 01231 ast_free(sc); 01232 return 0; 01233 }
| static void hangupcalls | ( | struct callattempt * | outgoing, | |
| struct ast_channel * | exception, | |||
| int | cancel_answered_elsewhere | |||
| ) | [static] |
Hang up a list of outgoing calls.
Definition at line 2455 of file app_queue.c.
References ao2_ref, AST_FLAG_ANSWERED_ELSEWHERE, ast_free, ast_hangup(), ast_set_flag, callattempt::chan, callattempt::member, and callattempt::q_next.
Referenced by try_calling().
02456 { 02457 struct callattempt *oo; 02458 02459 while (outgoing) { 02460 /* If someone else answered the call we should indicate this in the CANCEL */ 02461 /* Hangup any existing lines we have open */ 02462 if (outgoing->chan && (outgoing->chan != exception || cancel_answered_elsewhere)) { 02463 if (exception || cancel_answered_elsewhere) 02464 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE); 02465 ast_hangup(outgoing->chan); 02466 } 02467 oo = outgoing; 02468 outgoing = outgoing->q_next; 02469 if (oo->member) 02470 ao2_ref(oo->member, -1); 02471 ast_free(oo); 02472 } 02473 }
| static void init_queue | ( | struct call_queue * | q | ) | [static] |
Initialize Queue default values.
Definition at line 1319 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::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_single_queue().
01320 { 01321 int i; 01322 struct penalty_rule *pr_iter; 01323 01324 q->dead = 0; 01325 q->retry = DEFAULT_RETRY; 01326 q->timeout = DEFAULT_TIMEOUT; 01327 q->maxlen = 0; 01328 q->announcefrequency = 0; 01329 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY; 01330 q->announceholdtime = 1; 01331 q->announcepositionlimit = 10; /* Default 10 positions */ 01332 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */ 01333 q->roundingseconds = 0; /* Default - don't announce seconds */ 01334 q->servicelevel = 0; 01335 q->ringinuse = 1; 01336 q->setinterfacevar = 0; 01337 q->setqueuevar = 0; 01338 q->setqueueentryvar = 0; 01339 q->autofill = autofill_default; 01340 q->montype = montype_default; 01341 q->monfmt[0] = '\0'; 01342 q->reportholdtime = 0; 01343 q->wrapuptime = 0; 01344 q->joinempty = 0; 01345 q->leavewhenempty = 0; 01346 q->memberdelay = 0; 01347 q->maskmemberstatus = 0; 01348 q->eventwhencalled = 0; 01349 q->weight = 0; 01350 q->timeoutrestart = 0; 01351 q->periodicannouncefrequency = 0; 01352 q->randomperiodicannounce = 0; 01353 q->numperiodicannounce = 0; 01354 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 01355 if (!q->members) { 01356 if (q->strategy == QUEUE_STRATEGY_LINEAR) 01357 /* linear strategy depends on order, so we have to place all members in a single bucket */ 01358 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn); 01359 else 01360 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn); 01361 } 01362 q->found = 1; 01363 01364 ast_string_field_set(q, sound_next, "queue-youarenext"); 01365 ast_string_field_set(q, sound_thereare, "queue-thereare"); 01366 ast_string_field_set(q, sound_calls, "queue-callswaiting"); 01367 ast_string_field_set(q, queue_quantity1, "queue-quantity1"); 01368 ast_string_field_set(q, queue_quantity2, "queue-quantity2"); 01369 ast_string_field_set(q, sound_holdtime, "queue-holdtime"); 01370 ast_string_field_set(q, sound_minutes, "queue-minutes"); 01371 ast_string_field_set(q, sound_minute, "queue-minute"); 01372 ast_string_field_set(q, sound_seconds, "queue-seconds"); 01373 ast_string_field_set(q, sound_thanks, "queue-thankyou"); 01374 ast_string_field_set(q, sound_reporthold, "queue-reporthold"); 01375 01376 if ((q->sound_periodicannounce[0] = ast_str_create(32))) 01377 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce"); 01378 01379 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) { 01380 if (q->sound_periodicannounce[i]) 01381 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", ""); 01382 } 01383 01384 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) 01385 ast_free(pr_iter); 01386 }
| 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 1071 of file app_queue.c.
References call_queue::head, queue_ent::next, and queue_ent::parent.
Referenced by join_queue().
01072 { 01073 struct queue_ent *cur; 01074 01075 if (!q || !new) 01076 return; 01077 if (prev) { 01078 cur = prev->next; 01079 prev->next = new; 01080 } else { 01081 cur = q->head; 01082 q->head = new; 01083 } 01084 new->next = cur; 01085 new->parent = q; 01086 new->pos = ++(*pos); 01087 new->opos = *pos; 01088 }
| 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 1417 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_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().
01418 { 01419 char *timestr, *maxstr, *minstr, *contentdup; 01420 struct penalty_rule *rule = NULL, *rule_iter; 01421 struct rule_list *rl_iter; 01422 int penaltychangetime, inserted = 0; 01423 01424 if (!(rule = ast_calloc(1, sizeof(*rule)))) { 01425 return -1; 01426 } 01427 01428 contentdup = ast_strdupa(content); 01429 01430 if (!(maxstr = strchr(contentdup, ','))) { 01431 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum); 01432 ast_free(rule); 01433 return -1; 01434 } 01435 01436 *maxstr++ = '\0'; 01437 timestr = contentdup; 01438 01439 if ((penaltychangetime = atoi(timestr)) < 0) { 01440 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum); 01441 ast_free(rule); 01442 return -1; 01443 } 01444 01445 rule->time = penaltychangetime; 01446 01447 if ((minstr = strchr(maxstr,','))) 01448 *minstr++ = '\0'; 01449 01450 /* The last check will evaluate true if either no penalty change is indicated for a given rule 01451 * OR if a min penalty change is indicated but no max penalty change is */ 01452 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') { 01453 rule->max_relative = 1; 01454 } 01455 01456 rule->max_value = atoi(maxstr); 01457 01458 if (!ast_strlen_zero(minstr)) { 01459 if (*minstr == '+' || *minstr == '-') 01460 rule->min_relative = 1; 01461 rule->min_value = atoi(minstr); 01462 } else /*there was no minimum specified, so assume this means no change*/ 01463 rule->min_relative = 1; 01464 01465 /*We have the rule made, now we need to insert it where it belongs*/ 01466 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){ 01467 if (strcasecmp(rl_iter->name, list_name)) 01468 continue; 01469 01470 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) { 01471 if (rule->time < rule_iter->time) { 01472 AST_LIST_INSERT_BEFORE_CURRENT(rule, list); 01473 inserted = 1; 01474 break; 01475 } 01476 } 01477 AST_LIST_TRAVERSE_SAFE_END; 01478 01479 if (!inserted) { 01480 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list); 01481 } 01482 } 01483 01484 return 0; 01485 }
| static const char* int2strat | ( | int | strategy | ) | [static] |
Definition at line 1002 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().
01003 { 01004 int x; 01005 01006 for (x = 0; x < ARRAY_LEN(strategies); x++) { 01007 if (strategy == strategies[x].strategy) 01008 return strategies[x].name; 01009 } 01010 01011 return "<unknown>"; 01012 }
| static struct member* interface_exists | ( | struct call_queue * | q, | |
| const char * | interface | |||
| ) | [static, read] |
Definition at line 4608 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, member::interface, and call_queue::members.
Referenced by add_to_queue(), get_member_penalty(), set_member_paused(), and set_member_penalty().
04609 { 04610 struct member *mem; 04611 struct ao2_iterator mem_iter; 04612 04613 if (!q) 04614 return NULL; 04615 04616 mem_iter = ao2_iterator_init(q->members, 0); 04617 while ((mem = ao2_iterator_next(&mem_iter))) { 04618 if (!strcasecmp(interface, mem->interface)) { 04619 ao2_iterator_destroy(&mem_iter); 04620 return mem; 04621 } 04622 ao2_ref(mem, -1); 04623 } 04624 ao2_iterator_destroy(&mem_iter); 04625 04626 return NULL; 04627 }
| 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 3385 of file app_queue.c.
References ao2_lock(), ao2_unlock(), ast_debug, queue_ent::chan, call_queue::head, ast_channel::name, queue_ent::next, num_available_members(), queue_ent::parent, and queue_ent::pending.
Referenced by queue_exec(), and wait_our_turn().
03386 { 03387 struct queue_ent *ch; 03388 int res; 03389 int avl; 03390 int idx = 0; 03391 /* This needs a lock. How many members are available to be served? */ 03392 ao2_lock(qe->parent); 03393 03394 avl = num_available_members(qe->parent); 03395 03396 ch = qe->parent->head; 03397 03398 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member"); 03399 03400 while ((idx < avl) && (ch) && (ch != qe)) { 03401 if (!ch->pending) 03402 idx++; 03403 ch = ch->next; 03404 } 03405 03406 ao2_unlock(qe->parent); 03407 03408 /* If the queue entry is within avl [the number of available members] calls from the top ... */ 03409 if (ch && idx < avl) { 03410 ast_debug(1, "It's our turn (%s).\n", qe->chan->name); 03411 res = 1; 03412 } else { 03413 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name); 03414 res = 0; 03415 } 03416 03417 return res; 03418 }
| static int join_queue | ( | char * | queuename, | |
| struct queue_ent * | qe, | |||
| enum queue_result * | reason, | |||
| int | position | |||
| ) | [static] |
Definition at line 2097 of file app_queue.c.
References call_queue::announce, queue_ent::announce, ao2_lock(), ao2_unlock(), ast_copy_string(), ast_debug, ast_log(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, call_queue::context, queue_ent::context, call_queue::count, EVENT_FLAG_CALL, get_member_status(), call_queue::head, insert_entry(), call_queue::joinempty, load_realtime_queue(), LOG_NOTICE, manager_event, queue_ent::max_penalty, call_queue::maxlen, queue_ent::min_penalty, call_queue::moh, queue_ent::moh, call_queue::name, ast_channel::name, queue_ent::next, queue_ent::pos, queue_ent::prio, QUEUE_FULL, QUEUE_JOINEMPTY, QUEUE_UNKNOWN, queues, S_OR, status, and ast_channel::uniqueid.
Referenced by queue_exec().
02098 { 02099 struct call_queue *q; 02100 struct queue_ent *cur, *prev = NULL; 02101 int res = -1; 02102 int pos = 0; 02103 int inserted = 0; 02104 02105 if (!(q = load_realtime_queue(queuename))) 02106 return res; 02107 02108 ao2_lock(queues); 02109 ao2_lock(q); 02110 02111 /* This is our one */ 02112 if (q->joinempty) { 02113 int status = 0; 02114 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) { 02115 *reason = QUEUE_JOINEMPTY; 02116 ao2_unlock(q); 02117 ao2_unlock(queues); 02118 return res; 02119 } 02120 } 02121 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) 02122 *reason = QUEUE_FULL; 02123 else if (*reason == QUEUE_UNKNOWN) { 02124 /* There's space for us, put us at the right position inside 02125 * the queue. 02126 * Take into account the priority of the calling user */ 02127 inserted = 0; 02128 prev = NULL; 02129 cur = q->head; 02130 while (cur) { 02131 /* We have higher priority than the current user, enter 02132 * before him, after all the other users with priority 02133 * higher or equal to our priority. */ 02134 if ((!inserted) && (qe->prio > cur->prio)) { 02135 insert_entry(q, prev, qe, &pos); 02136 inserted = 1; 02137 } 02138 /* <= is necessary for the position comparison because it may not be possible to enter 02139 * at our desired position since higher-priority callers may have taken the position we want 02140 */ 02141 if (!inserted && (qe->prio <= cur->prio) && position && (position <= pos + 1)) { 02142 insert_entry(q, prev, qe, &pos); 02143 /*pos is incremented inside insert_entry, so don't need to add 1 here*/ 02144 if (position < pos) { 02145 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos); 02146 } 02147 inserted = 1; 02148 } 02149 cur->pos = ++pos; 02150 prev = cur; 02151 cur = cur->next; 02152 } 02153 /* No luck, join at the end of the queue */ 02154 if (!inserted) 02155 insert_entry(q, prev, qe, &pos); 02156 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 02157 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 02158 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 02159 q->count++; 02160 res = 0; 02161 manager_event(EVENT_FLAG_CALL, "Join", 02162 "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n", 02163 qe->chan->name, 02164 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */ 02165 S_OR(qe->chan->cid.cid_name, "unknown"), 02166 q->name, qe->pos, q->count, qe->chan->uniqueid ); 02167 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 02168 } 02169 ao2_unlock(q); 02170 ao2_unlock(queues); 02171 02172 return res; 02173 }
| static int kill_dead_members | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 6084 of file app_queue.c.
References CMP_MATCH, member::delme, member::dynamic, call_queue::membercount, member::state_interface, and member::status.
Referenced by reload_single_queue().
06085 { 06086 struct member *member = obj; 06087 struct call_queue *q = arg; 06088 06089 if (!member->delme) { 06090 if (member->dynamic) { 06091 /* dynamic members were not counted toward the member count 06092 * when reloading members from queues.conf, so we do that here 06093 */ 06094 q->membercount++; 06095 } 06096 member->status = ast_device_state(member->state_interface); 06097 return 0; 06098 } else { 06099 q->membercount--; 06100 return CMP_MATCH; 06101 } 06102 }
| static int kill_dead_queues | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 6222 of file app_queue.c.
References ast_strlen_zero(), CMP_MATCH, call_queue::dead, and call_queue::name.
Referenced by reload_queues().
06223 { 06224 struct call_queue *q = obj; 06225 char *queuename = arg; 06226 if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) { 06227 return CMP_MATCH; 06228 } else { 06229 return 0; 06230 } 06231 }
| 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 2395 of file app_queue.c.
References ao2_lock(), ao2_unlink, ao2_unlock(), ast_debug, ast_free, AST_LIST_REMOVE_HEAD, ast_load_realtime(), ast_variables_destroy(), queue_ent::chan, call_queue::count, call_queue::dead, EVENT_FLAG_CALL, call_queue::head, manager_event, call_queue::name, ast_channel::name, queue_ent::next, queue_ent::parent, pbx_builtin_setvar_helper(), queue_ent::pos, queue_ent::qe_rules, queue_ref(), queue_unref(), queues, call_queue::realtime, SENTINEL, ast_channel::uniqueid, and var.
Referenced by queue_exec(), try_calling(), and wait_our_turn().
02396 { 02397 struct call_queue *q; 02398 struct queue_ent *current, *prev = NULL; 02399 struct penalty_rule *pr_iter; 02400 int pos = 0; 02401 02402 if (!(q = qe->parent)) 02403 return; 02404 queue_ref(q); 02405 ao2_lock(q); 02406 02407 prev = NULL; 02408 for (current = q->head; current; current = current->next) { 02409 if (current == qe) { 02410 char posstr[20]; 02411 q->count--; 02412 02413 /* Take us out of the queue */ 02414 manager_event(EVENT_FLAG_CALL, "Leave", 02415 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n", 02416 qe->chan->name, q->name, q->count, qe->pos, qe->chan->uniqueid); 02417 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 02418 /* Take us out of the queue */ 02419 if (prev) 02420 prev->next = current->next; 02421 else 02422 q->head = current->next; 02423 /* Free penalty rules */ 02424 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) 02425 ast_free(pr_iter); 02426 snprintf(posstr, sizeof(posstr), "%d", qe->pos); 02427 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr); 02428 } else { 02429 /* Renumber the people after us in the queue based on a new count */ 02430 current->pos = ++pos; 02431 prev = current; 02432 } 02433 } 02434 ao2_unlock(q); 02435 02436 /*If the queue is a realtime queue, check to see if it's still defined in real time*/ 02437 if (q->realtime) { 02438 struct ast_variable *var; 02439 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) { 02440 q->dead = 1; 02441 } else { 02442 ast_variables_destroy(var); 02443 } 02444 } 02445 02446 if (q->dead) { 02447 /* It's dead and nobody is in it, so kill it */ 02448 ao2_unlink(queues, q); 02449 } 02450 /* unref the explicit ref earlier in the function */ 02451 queue_unref(q); 02452 }
| static int load_module | ( | void | ) | [static] |
Definition at line 7500 of file app_queue.c.
References ao2_container_alloc, aqm_exec(), ARRAY_LEN, ast_add_extension2(), ast_cli_register_multiple(), ast_context_find_or_create(), ast_custom_function_register, AST_EVENT_DEVICE_STATE, AST_EVENT_IE_END, ast_event_subscribe(), AST_FLAGS_ALL, ast_free_ptr, ast_log(), ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, ast_realtime_require_field(), ast_register_application_xml, ast_strdup, ast_taskprocessor_get(), cli_queue, device_state_cb(), 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_reload(), manager_queue_reset(), manager_queue_rule_show(), manager_queues_show(), manager_queues_status(), manager_queues_summary(), manager_remove_queue_member(), MAX_QUEUE_BUCKETS, pqm_exec(), ql_exec(), queue_cmp_cb(), queue_exec(), queue_hash_cb(), queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queuevar_function, queuewaitingcount_function, reload_handler(), reload_queue_members(), RQ_INTEGER1, RQ_UINTEGER2, rqm_exec(), SENTINEL, and upqm_exec().
07501 { 07502 int res; 07503 struct ast_context *con; 07504 struct ast_flags mask = {AST_FLAGS_ALL, }; 07505 07506 queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb); 07507 07508 use_weight = 0; 07509 07510 if (reload_handler(0, &mask, NULL)) 07511 return AST_MODULE_LOAD_DECLINE; 07512 07513 con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue"); 07514 if (!con) 07515 ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n"); 07516 else 07517 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue"); 07518 07519 if (queue_persistent_members) 07520 reload_queue_members(); 07521 07522 ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue)); 07523 res = ast_register_application_xml(app, queue_exec); 07524 res |= ast_register_application_xml(app_aqm, aqm_exec); 07525 res |= ast_register_application_xml(app_rqm, rqm_exec); 07526 res |= ast_register_application_xml(app_pqm, pqm_exec); 07527 res |= ast_register_application_xml(app_upqm, upqm_exec); 07528 res |= ast_register_application_xml(app_ql, ql_exec); 07529 res |= ast_manager_register_xml("Queues", 0, manager_queues_show); 07530 res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status); 07531 res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary); 07532 res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member); 07533 res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member); 07534 res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member); 07535 res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom); 07536 res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty); 07537 res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show); 07538 res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload); 07539 res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset); 07540 res |= ast_custom_function_register(&queuevar_function); 07541 res |= ast_custom_function_register(&queuemembercount_function); 07542 res |= ast_custom_function_register(&queuemembercount_dep); 07543 res |= ast_custom_function_register(&queuememberlist_function); 07544 res |= ast_custom_function_register(&queuewaitingcount_function); 07545 res |= ast_custom_function_register(&queuememberpenalty_function); 07546 07547 if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) { 07548 ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n"); 07549 } 07550 07551 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */ 07552 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) { 07553 res = -1; 07554 } 07555 07556 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL); 07557 07558 return res ? AST_MODULE_LOAD_DECLINE : 0; 07559 }
| static struct call_queue* load_realtime_queue | ( | const char * | queuename | ) | [static, read] |
Definition at line 1971 of file app_queue.c.
References ao2_find, ao2_lock(), ao2_unlock(), ast_atomic_fetchadd_int(), 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, update_realtime_members(), and call_queue::weight.
Referenced by __queues_show(), add_to_queue(), join_queue(), queue_function_qac(), queue_function_qac_dep(), and reload_queue_members().
01972 { 01973 struct ast_variable *queue_vars; 01974 struct ast_config *member_config = NULL; 01975 struct call_queue *q = NULL, tmpq = { 01976 .name = queuename, 01977 }; 01978 int prev_weight = 0; 01979 01980 /* Find the queue in the in-core list first. */ 01981 q = ao2_find(queues, &tmpq, OBJ_POINTER); 01982 01983 if (!q || q->realtime) { 01984 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all 01985 queue operations while waiting for the DB. 01986 01987 This will be two separate database transactions, so we might 01988 see queue parameters as they were before another process 01989 changed the queue and member list as it was after the change. 01990 Thus we might see an empty member list when a queue is 01991 deleted. In practise, this is unlikely to cause a problem. */ 01992 01993 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL); 01994 if (queue_vars) { 01995 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL); 01996 if (!member_config) { 01997 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n"); 01998 ast_variables_destroy(queue_vars); 01999 return NULL; 02000 } 02001 } 02002 if (q) { 02003 prev_weight = q->weight ? 1 : 0; 02004 } 02005 02006 ao2_lock(queues); 02007 02008 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 02009 if (member_config) { 02010 ast_config_destroy(member_config); 02011 } 02012 if (queue_vars) { 02013 ast_variables_destroy(queue_vars); 02014 } 02015 /* update the use_weight value if the queue's has gained or lost a weight */ 02016 if (q) { 02017 if (!q->weight && prev_weight) { 02018 ast_atomic_fetchadd_int(&use_weight, -1); 02019 } 02020 if (q->weight && !prev_weight) { 02021 ast_atomic_fetchadd_int(&use_weight, +1); 02022 } 02023 } 02024 /* Other cases will end up with the proper value for use_weight */ 02025 ao2_unlock(queues); 02026 02027 } else { 02028 update_realtime_members(q); 02029 } 02030 return q; 02031 }
| static int manager_add_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6746 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().
06747 { 06748 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface; 06749 int paused, penalty = 0; 06750 06751 queuename = astman_get_header(m, "Queue"); 06752 interface = astman_get_header(m, "Interface"); 06753 penalty_s = astman_get_header(m, "Penalty"); 06754 paused_s = astman_get_header(m, "Paused"); 06755 membername = astman_get_header(m, "MemberName"); 06756 state_interface = astman_get_header(m, "StateInterface"); 06757 06758 if (ast_strlen_zero(queuename)) { 06759 astman_send_error(s, m, "'Queue' not specified."); 06760 return 0; 06761 } 06762 06763 if (ast_strlen_zero(interface)) { 06764 astman_send_error(s, m, "'Interface' not specified."); 06765 return 0; 06766 } 06767 06768 if (ast_strlen_zero(penalty_s)) 06769 penalty = 0; 06770 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) 06771 penalty = 0; 06772 06773 if (ast_strlen_zero(paused_s)) 06774 paused = 0; 06775 else 06776 paused = abs(ast_true(paused_s)); 06777 06778 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) { 06779 case RES_OKAY: 06780 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", ""); 06781 astman_send_ack(s, m, "Added interface to queue"); 06782 break; 06783 case RES_EXISTS: 06784 astman_send_error(s, m, "Unable to add interface: Already there"); 06785 break; 06786 case RES_NOSUCHQUEUE: 06787 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 06788 break; 06789 case RES_OUTOFMEMORY: 06790 astman_send_error(s, m, "Out of memory"); 06791 break; 06792 } 06793 06794 return 0; 06795 }
| static int manager_pause_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6831 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().
06832 { 06833 const char *queuename, *interface, *paused_s, *reason; 06834 int paused; 06835 06836 interface = astman_get_header(m, "Interface"); 06837 paused_s = astman_get_header(m, "Paused"); 06838 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 06839 reason = astman_get_header(m, "Reason"); /* Optional - Only used for logging purposes */ 06840 06841 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 06842 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 06843 return 0; 06844 } 06845 06846 paused = abs(ast_true(paused_s)); 06847 06848 if (set_member_paused(queuename, interface, reason, paused)) 06849 astman_send_error(s, m, "Interface not found"); 06850 else 06851 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully"); 06852 return 0; 06853 }
| static int manager_queue_log_custom | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6855 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().
06856 { 06857 const char *queuename, *event, *message, *interface, *uniqueid; 06858 06859 queuename = astman_get_header(m, "Queue"); 06860 uniqueid = astman_get_header(m, "UniqueId"); 06861 interface = astman_get_header(m, "Interface"); 06862 event = astman_get_header(m, "Event"); 06863 message = astman_get_header(m, "Message"); 06864 06865 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) { 06866 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters."); 06867 return 0; 06868 } 06869 06870 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message); 06871 astman_send_ack(s, m, "Event added successfully"); 06872 06873 return 0; 06874 }
| static int manager_queue_member_penalty | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6954 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().
06955 { 06956 const char *queuename, *interface, *penalty_s; 06957 int penalty; 06958 06959 interface = astman_get_header(m, "Interface"); 06960 penalty_s = astman_get_header(m, "Penalty"); 06961 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */ 06962 queuename = astman_get_header(m, "Queue"); 06963 06964 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) { 06965 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters."); 06966 return 0; 06967 } 06968 06969 penalty = atoi(penalty_s); 06970 06971 if (set_member_penalty((char *)queuename, (char *)interface, penalty)) 06972 astman_send_error(s, m, "Invalid interface, queuename or penalty"); 06973 else 06974 astman_send_ack(s, m, "Interface penalty set successfully"); 06975 06976 return 0; 06977 }
| static int manager_queue_reload | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6876 of file app_queue.c.
References AST_FLAGS_ALL, ast_set_flag, astman_get_header(), astman_send_ack(), astman_send_error(), QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, reload_handler(), and S_OR.
Referenced by load_module().
06877 { 06878 struct ast_flags mask = {0,}; 06879 const char *queuename = NULL; 06880 int header_found = 0; 06881 06882 queuename = astman_get_header(m, "Queue"); 06883 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) { 06884 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER); 06885 header_found = 1; 06886 } 06887 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) { 06888 ast_set_flag(&mask, QUEUE_RELOAD_RULES); 06889 header_found = 1; 06890 } 06891 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) { 06892 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS); 06893 header_found = 1; 06894 } 06895 06896 if (!header_found) { 06897 ast_set_flag(&mask, AST_FLAGS_ALL); 06898 } 06899 06900 if (!reload_handler(1, &mask, queuename)) { 06901 astman_send_ack(s, m, "Queue reloaded successfully"); 06902 } else { 06903 astman_send_error(s, m, "Error encountered while reloading queue"); 06904 } 06905 return 0; 06906 }
| static int manager_queue_reset | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6908 of file app_queue.c.
References astman_get_header(), astman_send_ack(), astman_send_error(), QUEUE_RESET_STATS, and reload_handler().
Referenced by load_module().
06909 { 06910 const char *queuename = NULL; 06911 struct ast_flags mask = {QUEUE_RESET_STATS,}; 06912 06913 queuename = astman_get_header(m, "Queue"); 06914 06915 if (!reload_handler(1, &mask, queuename)) { 06916 astman_send_ack(s, m, "Queue stats reset successfully"); 06917 } else { 06918 astman_send_error(s, m, "Error encountered while resetting queue stats"); 06919 } 06920 return 0; 06921 }
| static int manager_queue_rule_show | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6549 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().
06550 { 06551 const char *rule = astman_get_header(m, "Rule"); 06552 struct rule_list *rl_iter; 06553 struct penalty_rule *pr_iter; 06554 06555 AST_LIST_LOCK(&rule_lists); 06556 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) { 06557 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) { 06558 astman_append(s, "RuleList: %s\r\n", rl_iter->name); 06559 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) { 06560 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 ); 06561 } 06562 if (!ast_strlen_zero(rule)) 06563 break; 06564 } 06565 } 06566 AST_LIST_UNLOCK(&rule_lists); 06567 06568 astman_append(s, "\r\n\r\n"); 06569 06570 return RESULT_SUCCESS; 06571 }
| static int manager_queues_show | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6539 of file app_queue.c.
References __queues_show(), astman_append(), and RESULT_SUCCESS.
Referenced by load_module().
06540 { 06541 static const char * const a[] = { "queue", "show" }; 06542 06543 __queues_show(s, -1, 2, a); 06544 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */ 06545 06546 return RESULT_SUCCESS; 06547 }
| static int manager_queues_status | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Queue status info via AMI.
Definition at line 6649 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, call_queue::count, member::dynamic, call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, call_queue::maxlen, member::membername, call_queue::members, ast_channel::name, call_queue::name, queue_ent::next, member::paused, member::penalty, queue_ent::pos, queue_unref(), queues, RESULT_SUCCESS, S_OR, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, call_queue::talktime, ast_channel::uniqueid, and call_queue::weight.
Referenced by load_module().
06650 { 06651 time_t now; 06652 int pos; 06653 const char *id = astman_get_header(m,"ActionID"); 06654 const char *queuefilter = astman_get_header(m,"Queue"); 06655 const char *memberfilter = astman_get_header(m,"Member"); 06656 char idText[256] = ""; 06657 struct call_queue *q; 06658 struct queue_ent *qe; 06659 float sl = 0; 06660 struct member *mem; 06661 struct ao2_iterator queue_iter; 06662 struct ao2_iterator mem_iter; 06663 06664 astman_send_ack(s, m, "Queue status will follow"); 06665 time(&now); 06666 if (!ast_strlen_zero(id)) 06667 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 06668 06669 queue_iter = ao2_iterator_init(queues, 0); 06670 while ((q = ao2_iterator_next(&queue_iter))) { 06671 ao2_lock(q); 06672 06673 /* List queue properties */ 06674 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 06675 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0); 06676 astman_append(s, "Event: QueueParams\r\n" 06677 "Queue: %s\r\n" 06678 "Max: %d\r\n" 06679 "Strategy: %s\r\n" 06680 "Calls: %d\r\n" 06681 "Holdtime: %d\r\n" 06682 "TalkTime: %d\r\n" 06683 "Completed: %d\r\n" 06684 "Abandoned: %d\r\n" 06685 "ServiceLevel: %d\r\n" 06686 "ServicelevelPerf: %2.1f\r\n" 06687 "Weight: %d\r\n" 06688 "%s" 06689 "\r\n", 06690 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, 06691 q->callsabandoned, q->servicelevel, sl, q->weight, idText); 06692 /* List Queue Members */ 06693 mem_iter = ao2_iterator_init(q->members, 0); 06694 while ((mem = ao2_iterator_next(&mem_iter))) { 06695 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) { 06696 astman_append(s, "Event: QueueMember\r\n" 06697 "Queue: %s\r\n" 06698 "Name: %s\r\n" 06699 "Location: %s\r\n" 06700 "Membership: %s\r\n" 06701 "Penalty: %d\r\n" 06702 "CallsTaken: %d\r\n" 06703 "LastCall: %d\r\n" 06704 "Status: %d\r\n" 06705 "Paused: %d\r\n" 06706 "%s" 06707 "\r\n", 06708 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static", 06709 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 06710 } 06711 ao2_ref(mem, -1); 06712 } 06713 ao2_iterator_destroy(&mem_iter); 06714 /* List Queue Entries */ 06715 pos = 1; 06716 for (qe = q->head; qe; qe = qe->next) { 06717 astman_append(s, "Event: QueueEntry\r\n" 06718 "Queue: %s\r\n" 06719 "Position: %d\r\n" 06720 "Channel: %s\r\n" 06721 "Uniqueid: %s\r\n" 06722 "CallerIDNum: %s\r\n" 06723 "CallerIDName: %s\r\n" 06724 "Wait: %ld\r\n" 06725 "%s" 06726 "\r\n", 06727 q->name, pos++, qe->chan->name, qe->chan->uniqueid, 06728 S_OR(qe->chan->cid.cid_num, "unknown"), 06729 S_OR(qe->chan->cid.cid_name, "unknown"), 06730 (long) (now - qe->start), idText); 06731 } 06732 } 06733 ao2_unlock(q); 06734 queue_unref(q); 06735 } 06736 ao2_iterator_destroy(&queue_iter); 06737 06738 astman_append(s, 06739 "Event: QueueStatusComplete\r\n" 06740 "%s" 06741 "\r\n",idText); 06742 06743 return RESULT_SUCCESS; 06744 }
| static int manager_queues_summary | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Summary of queue info via the AMI.
Definition at line 6574 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), call_queue::head, call_queue::holdtime, call_queue::members, call_queue::name, queue_ent::next, member::paused, queue_unref(), queues, RESULT_SUCCESS, queue_ent::start, member::status, and call_queue::talktime.
Referenced by load_module().
06575 { 06576 time_t now; 06577 int qmemcount = 0; 06578 int qmemavail = 0; 06579 int qchancount = 0; 06580 int qlongestholdtime = 0; 06581 const char *id = astman_get_header(m, "ActionID"); 06582 const char *queuefilter = astman_get_header(m, "Queue"); 06583 char idText[256] = ""; 06584 struct call_queue *q; 06585 struct queue_ent *qe; 06586 struct member *mem; 06587 struct ao2_iterator queue_iter; 06588 struct ao2_iterator mem_iter; 06589 06590 astman_send_ack(s, m, "Queue summary will follow"); 06591 time(&now); 06592 if (!ast_strlen_zero(id)) 06593 snprintf(idText, 256, "ActionID: %s\r\n", id); 06594 queue_iter = ao2_iterator_init(queues, 0); 06595 while ((q = ao2_iterator_next(&queue_iter))) { 06596 ao2_lock(q); 06597 06598 /* List queue properties */ 06599 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 06600 /* Reset the necessary local variables if no queuefilter is set*/ 06601 qmemcount = 0; 06602 qmemavail = 0; 06603 qchancount = 0; 06604 qlongestholdtime = 0; 06605 06606 /* List Queue Members */ 06607 mem_iter = ao2_iterator_init(q->members, 0); 06608 while ((mem = ao2_iterator_next(&mem_iter))) { 06609 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) { 06610 ++qmemcount; 06611 if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) { 06612 ++qmemavail; 06613 } 06614 } 06615 ao2_ref(mem, -1); 06616 } 06617 ao2_iterator_destroy(&mem_iter); 06618 for (qe = q->head; qe; qe = qe->next) { 06619 if ((now - qe->start) > qlongestholdtime) { 06620 qlongestholdtime = now - qe->start; 06621 } 06622 ++qchancount; 06623 } 06624 astman_append(s, "Event: QueueSummary\r\n" 06625 "Queue: %s\r\n" 06626 "LoggedIn: %d\r\n" 06627 "Available: %d\r\n" 06628 "Callers: %d\r\n" 06629 "HoldTime: %d\r\n" 06630 "TalkTime: %d\r\n" 06631 "LongestHoldTime: %d\r\n" 06632 "%s" 06633 "\r\n", 06634 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText); 06635 } 06636 ao2_unlock(q); 06637 queue_unref(q); 06638 } 06639 ao2_iterator_destroy(&queue_iter); 06640 astman_append(s, 06641 "Event: QueueSummaryComplete\r\n" 06642 "%s" 06643 "\r\n", idText); 06644 06645 return RESULT_SUCCESS; 06646 }
| static int manager_remove_queue_member | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Definition at line 6797 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().
06798 { 06799 const char *queuename, *interface; 06800 06801 queuename = astman_get_header(m, "Queue"); 06802 interface = astman_get_header(m, "Interface"); 06803 06804 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 06805 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 06806 return 0; 06807 } 06808 06809 switch (remove_from_queue(queuename, interface)) { 06810 case RES_OKAY: 06811 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", ""); 06812 astman_send_ack(s, m, "Removed interface from queue"); 06813 break; 06814 case RES_EXISTS: 06815 astman_send_error(s, m, "Unable to remove interface: Not there"); 06816 break; 06817 case RES_NOSUCHQUEUE: 06818 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 06819 break; 06820 case RES_OUTOFMEMORY: 06821 astman_send_error(s, m, "Out of memory"); 06822 break; 06823 case RES_NOT_DYNAMIC: 06824 astman_send_error(s, m, "Member not dynamic"); 06825 break; 06826 } 06827 06828 return 0; 06829 }
| static int mark_dead_and_unfound | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 6211 of file app_queue.c.
References ast_strlen_zero(), call_queue::dead, call_queue::found, call_queue::name, and call_queue::realtime.
Referenced by reload_queues().
06212 { 06213 struct call_queue *q = obj; 06214 char *queuename = arg; 06215 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) { 06216 q->dead = 1; 06217 q->found = 0; 06218 } 06219 return 0; 06220 }
| static int mark_member_dead | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 6075 of file app_queue.c.
References member::delme, and member::dynamic.
Referenced by reload_single_queue().
06076 { 06077 struct member *member = obj; 06078 if (!member->dynamic) { 06079 member->delme = 1; 06080 } 06081 return 0; 06082 }
| static int member_cmp_fn | ( | void * | obj1, | |
| void * | obj2, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1309 of file app_queue.c.
References CMP_MATCH, CMP_STOP, and member::interface.
Referenced by init_queue().
01310 { 01311 struct member *mem1 = obj1, *mem2 = obj2; 01312 return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP; 01313 }
| static int member_hash_fn | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 1297 of file app_queue.c.
References compress_char(), and member::interface.
Referenced by init_queue().
01298 { 01299 const struct member *mem = obj; 01300 const char *chname = strchr(mem->interface, '/'); 01301 int ret = 0, i; 01302 if (!chname) 01303 chname = mem->interface; 01304 for (i = 0; i < 5 && chname[i]; i++) 01305 ret += compress_char(chname[i]) << (i * 6); 01306 return ret; 01307 }
| 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 2483 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, call_queue::autofill, call_queue::members, member::paused, QUEUE_STRATEGY_RINGALL, call_queue::ringinuse, member::status, and call_queue::strategy.
Referenced by compare_weight(), and is_our_turn().
02484 { 02485 struct member *mem; 02486 int avl = 0; 02487 struct ao2_iterator mem_iter; 02488 02489 mem_iter = ao2_iterator_init(q->members, 0); 02490 while ((mem = ao2_iterator_next(&mem_iter))) { 02491 switch (mem->status) { 02492 case AST_DEVICE_INUSE: 02493 if (!q->ringinuse) 02494 break; 02495 /* else fall through */ 02496 case AST_DEVICE_NOT_INUSE: 02497 case AST_DEVICE_UNKNOWN: 02498 if (!mem->paused) { 02499 avl++; 02500 } 02501 break; 02502 } 02503 ao2_ref(mem, -1); 02504 02505 /* If autofill is not enabled or if the queue's strategy is ringall, then 02506 * we really don't care about the number of available members so much as we 02507 * do that there is at least one available. 02508 * 02509 * In fact, we purposely will return from this function stating that only 02510 * one member is available if either of those conditions hold. That way, 02511 * functions which determine what action to take based on the number of available 02512 * members will operate properly. The reasoning is that even if multiple 02513 * members are available, only the head caller can actually be serviced. 02514 */ 02515 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) { 02516 break; 02517 } 02518 } 02519 ao2_iterator_destroy(&mem_iter); 02520 02521 return avl; 02522 }
| static void parse_empty_options | ( | const char * | value, | |
| enum empty_conditions * | empty, | |||
| int | joinempty | |||
| ) | [static] |
Definition at line 1487 of file app_queue.c.
References ast_false(), ast_log(), ast_strdupa, ast_true(), LOG_WARNING, QUEUE_EMPTY_INUSE, QUEUE_EMPTY_INVALID, QUEUE_EMPTY_PAUSED, QUEUE_EMPTY_PENALTY, QUEUE_EMPTY_RINGING, QUEUE_EMPTY_UNAVAILABLE, QUEUE_EMPTY_UNKNOWN, QUEUE_EMPTY_WRAPUP, and strsep().
Referenced by queue_set_param().
01488 { 01489 char *value_copy = ast_strdupa(value); 01490 char *option = NULL; 01491 while ((option = strsep(&value_copy, ","))) { 01492 if (!strcasecmp(option, "paused")) { 01493 *empty |= QUEUE_EMPTY_PAUSED; 01494 } else if (!strcasecmp(option, "penalty")) { 01495 *empty |= QUEUE_EMPTY_PENALTY; 01496 } else if (!strcasecmp(option, "inuse")) { 01497 *empty |= QUEUE_EMPTY_INUSE; 01498 } else if (!strcasecmp(option, "ringing")) { 01499 *empty |= QUEUE_EMPTY_RINGING; 01500 } else if (!strcasecmp(option, "invalid")) { 01501 *empty |= QUEUE_EMPTY_INVALID; 01502 } else if (!strcasecmp(option, "wrapup")) { 01503 *empty |= QUEUE_EMPTY_WRAPUP; 01504 } else if (!strcasecmp(option, "unavailable")) { 01505 *empty |= QUEUE_EMPTY_UNAVAILABLE; 01506 } else if (!strcasecmp(option, "unknown")) { 01507 *empty |= QUEUE_EMPTY_UNKNOWN; 01508 } else if (!strcasecmp(option, "loose")) { 01509 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID); 01510 } else if (!strcasecmp(option, "strict")) { 01511 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE); 01512 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) { 01513 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED); 01514 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) { 01515 *empty = 0; 01516 } else { 01517 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty"); 01518 } 01519 } 01520 }
| static int play_file | ( | struct ast_channel * | chan, | |
| const char * | filename | |||
| ) | [static] |
Definition at line 2175 of file app_queue.c.
References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_waitstream(), and ast_channel::language.
Referenced by say_periodic_announcement(), say_position(), and try_calling().
02176 { 02177 int res; 02178 02179 if (ast_strlen_zero(filename)) { 02180 return 0; 02181 } 02182 02183 ast_stopstream(chan); 02184 02185 res = ast_streamfile(chan, filename, chan->language); 02186 if (!res) 02187 res = ast_waitstream(chan, AST_DIGIT_ANY); 02188 02189 ast_stopstream(chan); 02190 02191 return res; 02192 }
| static int pqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
PauseQueueMember application.
Definition at line 5041 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().
05042 { 05043 char *parse; 05044 AST_DECLARE_APP_ARGS(args, 05045 AST_APP_ARG(queuename); 05046 AST_APP_ARG(interface); 05047 AST_APP_ARG(options); 05048 AST_APP_ARG(reason); 05049 ); 05050 05051 if (ast_strlen_zero(data)) { 05052 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n"); 05053 return -1; 05054 } 05055 05056 parse = ast_strdupa(data); 05057 05058 AST_STANDARD_APP_ARGS(args, parse); 05059 05060 if (ast_strlen_zero(args.interface)) { 05061 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n"); 05062 return -1; 05063 } 05064 05065 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) { 05066 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 05067 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 05068 return 0; 05069 } 05070 05071 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 05072 05073 return 0; 05074 }
| static int ql_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
QueueLog application.
Definition at line 5233 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().
05234 { 05235 char *parse; 05236 05237 AST_DECLARE_APP_ARGS(args, 05238 AST_APP_ARG(queuename); 05239 AST_APP_ARG(uniqueid); 05240 AST_APP_ARG(membername); 05241 AST_APP_ARG(event); 05242 AST_APP_ARG(params); 05243 ); 05244 05245 if (ast_strlen_zero(data)) { 05246 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n"); 05247 return -1; 05248 } 05249 05250 parse = ast_strdupa(data); 05251 05252 AST_STANDARD_APP_ARGS(args, parse); 05253 05254 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) 05255 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) { 05256 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n"); 05257 return -1; 05258 } 05259 05260 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 05261 "%s", args.params ? args.params : ""); 05262 05263 return 0; 05264 }
| static int queue_cmp_cb | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1033 of file app_queue.c.
References CMP_MATCH, CMP_STOP, and call_queue::name.
Referenced by load_module().
01034 { 01035 struct call_queue *q = obj, *q2 = arg; 01036 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0; 01037 }
| static int queue_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
The starting point for all queue calls.
The process involved here is to 1. Parse the options specified in the call to Queue() 2. Join the queue 3. Wait in a loop until it is our turn to try calling a queue member 4. Attempt to call a queue member 5. If 4. did not result in a bridged call, then check for between call options such as periodic announcements etc. 6. Try 4 again unless some condition (such as an expiration time) causes us to exit the queue.
Definition at line 5308 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_LIST_FIRST, 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, copy_rules(), queue_ent::digits, queue_ent::expire, get_member_status(), queue_ent::handled, is_our_turn(), join_queue(), queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::last_pos, queue_ent::last_pos_said, leave_queue(), call_queue::leavewhenempty, LOG_WARNING, queue_ent::max_penalty, call_queue::membercount, queue_ent::min_penalty, queue_ent::moh, call_queue::name, ast_channel::name, queue_ent::opos, queue_ent::parent, parse(), pbx_builtin_getvar_helper(), call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::pr, queue_ent::prio, queue_ent::qe_rules, QUEUE_CONTINUE, QUEUE_LEAVEEMPTY, 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(), ast_channel::uniqueid, update_qe_rule(), update_realtime_members(), url, queue_ent::valid_digits, wait_a_bit(), and wait_our_turn().
Referenced by load_module().
05309 { 05310 int res=-1; 05311 int ringing=0; 05312 const char *user_priority; 05313 const char *max_penalty_str; 05314 const char *min_penalty_str; 05315 int prio; 05316 int qcontinue = 0; 05317 int max_penalty, min_penalty; 05318 enum queue_result reason = QUEUE_UNKNOWN; 05319 /* whether to exit Queue application after the timeout hits */ 05320 int tries = 0; 05321 int noption = 0; 05322 char *parse; 05323 int makeannouncement = 0; 05324 int position = 0; 05325 AST_DECLARE_APP_ARGS(args, 05326 AST_APP_ARG(queuename); 05327 AST_APP_ARG(options); 05328 AST_APP_ARG(url); 05329 AST_APP_ARG(announceoverride); 05330 AST_APP_ARG(queuetimeoutstr); 05331 AST_APP_ARG(agi); 05332 AST_APP_ARG(macro); 05333 AST_APP_ARG(gosub); 05334 AST_APP_ARG(rule); 05335 AST_APP_ARG(position); 05336 ); 05337 /* Our queue entry */ 05338 struct queue_ent qe; 05339 05340 if (ast_strlen_zero(data)) { 05341 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n"); 05342 return -1; 05343 } 05344 05345 parse = ast_strdupa(data); 05346 AST_STANDARD_APP_ARGS(args, parse); 05347 05348 /* Setup our queue entry */ 05349 memset(&qe, 0, sizeof(qe)); 05350 qe.start = time(NULL); 05351 05352 /* set the expire time based on the supplied timeout; */ 05353 if (!ast_strlen_zero(args.queuetimeoutstr)) 05354 qe.expire = qe.start + atoi(args.queuetimeoutstr); 05355 else 05356 qe.expire = 0; 05357 05358 /* Get the priority from the variable ${QUEUE_PRIO} */ 05359 ast_channel_lock(chan); 05360 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 05361 if (user_priority) { 05362 if (sscanf(user_priority, "%30d", &prio) == 1) { 05363 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio); 05364 } else { 05365 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 05366 user_priority, chan->name); 05367 prio = 0; 05368 } 05369 } else { 05370 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n"); 05371 prio = 0; 05372 } 05373 05374 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */ 05375 05376 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) { 05377 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) { 05378 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty); 05379 } else { 05380 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n", 05381 max_penalty_str, chan->name); 05382 max_penalty = 0; 05383 } 05384 } else { 05385 max_penalty = 0; 05386 } 05387 05388 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) { 05389 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) { 05390 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty); 05391 } else { 05392 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n", 05393 min_penalty_str, chan->name); 05394 min_penalty = 0; 05395 } 05396 } else { 05397 min_penalty = 0; 05398 } 05399 ast_channel_unlock(chan); 05400 05401 if (args.options && (strchr(args.options, 'r'))) 05402 ringing = 1; 05403 05404 if (args.options && (strchr(args.options, 'c'))) 05405 qcontinue = 1; 05406 05407 if (args.position) { 05408 position = atoi(args.position); 05409 if (position < 0) { 05410 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename); 05411 position = 0; 05412 } 05413 } 05414 05415 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 05416 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio); 05417 05418 qe.chan = chan; 05419 qe.prio = prio; 05420 qe.max_penalty = max_penalty; 05421 qe.min_penalty = min_penalty; 05422 qe.last_pos_said = 0; 05423 qe.last_pos = 0; 05424 qe.last_periodic_announce_time = time(NULL); 05425 qe.last_periodic_announce_sound = 0; 05426 qe.valid_digits = 0; 05427 if (join_queue(args.queuename, &qe, &reason, position)) { 05428 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename); 05429 set_queue_result(chan, reason); 05430 return 0; 05431 } 05432 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d", S_OR(args.url, ""), 05433 S_OR(chan->cid.cid_num, ""), qe.opos); 05434 copy_rules(&qe, args.rule); 05435 qe.pr = AST_LIST_FIRST(&qe.qe_rules); 05436 check_turns: 05437 if (ringing) { 05438 ast_indicate(chan, AST_CONTROL_RINGING); 05439 } else { 05440 ast_moh_start(chan, qe.moh, NULL); 05441 } 05442 05443 /* This is the wait loop for callers 2 through maxlen */ 05444 res = wait_our_turn(&qe, ringing, &reason); 05445 if (res) { 05446 goto stop; 05447 } 05448 05449 makeannouncement = 0; 05450 05451 for (;;) { 05452 /* This is the wait loop for the head caller*/ 05453 /* To exit, they may get their call answered; */ 05454 /* they may dial a digit from the queue context; */ 05455 /* or, they may timeout. */ 05456 05457 /* Leave if we have exceeded our queuetimeout */ 05458 if (qe.expire && (time(NULL) >= qe.expire)) { 05459 record_abandoned(&qe); 05460 ast_cdr_noanswer(qe.chan->cdr); 05461 reason = QUEUE_TIMEOUT; 05462 res = 0; 05463 ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 05464 qe.pos, qe.opos, (long) time(NULL) - qe.start); 05465 break; 05466 } 05467 05468 if (makeannouncement) { 05469 /* Make a position announcement, if enabled */ 05470 if (qe.parent->announcefrequency) 05471 if ((res = say_position(&qe,ringing))) 05472 goto stop; 05473 } 05474 makeannouncement = 1; 05475 05476 /* Make a periodic announcement, if enabled */ 05477 if (qe.parent->periodicannouncefrequency) 05478 if ((res = say_periodic_announcement(&qe,ringing))) 05479 goto stop; 05480 05481 /* Leave if we have exceeded our queuetimeout */ 05482 if (qe.expire && (time(NULL) >= qe.expire)) { 05483 record_abandoned(&qe); 05484 ast_cdr_noanswer(qe.chan->cdr); 05485 reason = QUEUE_TIMEOUT; 05486 res = 0; 05487 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 05488 break; 05489 } 05490 05491 /* see if we need to move to the next penalty level for this queue */ 05492 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) { 05493 update_qe_rule(&qe); 05494 } 05495 05496 /* Try calling all queue members for 'timeout' seconds */ 05497 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing); 05498 if (res) { 05499 goto stop; 05500 } 05501 05502 if (qe.parent->leavewhenempty) { 05503 int status = 0; 05504 if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty))) { 05505 record_abandoned(&qe); 05506 ast_cdr_noanswer(qe.chan->cdr); 05507 reason = QUEUE_LEAVEEMPTY; 05508 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start)); 05509 res = 0; 05510 break; 05511 } 05512 } 05513 05514 /* exit after 'timeout' cycle if 'n' option enabled */ 05515 if (noption && tries >= qe.parent->membercount) { 05516 ast_verb(3, "Exiting on time-out cycle\n"); 05517 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 05518 record_abandoned(&qe); 05519 ast_cdr_noanswer(qe.chan->cdr); 05520 reason = QUEUE_TIMEOUT; 05521 res = 0; 05522 break; 05523 } 05524 05525 05526 /* Leave if we have exceeded our queuetimeout */ 05527 if (qe.expire && (time(NULL) >= qe.expire)) { 05528 record_abandoned(&qe); 05529 ast_cdr_noanswer(qe.chan->cdr); 05530 reason = QUEUE_TIMEOUT; 05531 res = 0; 05532 ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start); 05533 break; 05534 } 05535 05536 /* If using dynamic realtime members, we should regenerate the member list for this queue */ 05537 update_realtime_members(qe.parent); 05538 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 05539 res = wait_a_bit(&qe); 05540 if (res) 05541 goto stop; 05542 05543 /* Since this is a priority queue and 05544 * it is not sure that we are still at the head 05545 * of the queue, go and check for our turn again. 05546 */ 05547 if (!is_our_turn(&qe)) { 05548 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name); 05549 goto check_turns; 05550 } 05551 } 05552 05553 stop: 05554 if (res) { 05555 if (res < 0) { 05556 if (!qe.handled) { 05557 record_abandoned(&qe); 05558 ast_cdr_noanswer(qe.chan->cdr); 05559 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", 05560 "%d|%d|%ld", qe.pos, qe.opos, 05561 (long) time(NULL) - qe.start); 05562 res = -1; 05563 } else if (qcontinue) { 05564 reason = QUEUE_CONTINUE; 05565 res = 0; 05566 } 05567 } else if (qe.valid_digits) { 05568 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", 05569 "%s|%d", qe.digits, qe.pos); 05570 } 05571 } 05572 05573 /* Don't allow return code > 0 */ 05574 if (res >= 0) { 05575 res = 0; 05576 if (ringing) { 05577 ast_indicate(chan, -1); 05578 } else { 05579 ast_moh_stop(chan); 05580 } 05581 ast_stopstream(chan); 05582 } 05583 05584 set_queue_variables(qe.parent, qe.chan); 05585 05586 leave_queue(&qe); 05587 if (reason != QUEUE_UNKNOWN) 05588 set_queue_result(chan, reason); 05589 05590 return res; 05591 }
| 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 5827 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.
05828 { 05829 int penalty; 05830 AST_DECLARE_APP_ARGS(args, 05831 AST_APP_ARG(queuename); 05832 AST_APP_ARG(interface); 05833 ); 05834 /* Make sure the returned value on error is NULL. */ 05835 buf[0] = '\0'; 05836 05837 if (ast_strlen_zero(data)) { 05838 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05839 return -1; 05840 } 05841 05842 AST_STANDARD_APP_ARGS(args, data); 05843 05844 if (args.argc < 2) { 05845 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05846 return -1; 05847 } 05848 05849 penalty = get_member_penalty (args.queuename, args.interface); 05850 05851 if (penalty >= 0) /* remember that buf is already '\0' */ 05852 snprintf (buf, len, "%d", penalty); 05853 05854 return 0; 05855 }
| 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 5858 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().
05859 { 05860 int penalty; 05861 AST_DECLARE_APP_ARGS(args, 05862 AST_APP_ARG(queuename); 05863 AST_APP_ARG(interface); 05864 ); 05865 05866 if (ast_strlen_zero(data)) { 05867 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05868 return -1; 05869 } 05870 05871 AST_STANDARD_APP_ARGS(args, data); 05872 05873 if (args.argc < 2) { 05874 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n"); 05875 return -1; 05876 } 05877 05878 penalty = atoi(value); 05879 05880 if (ast_strlen_zero(args.interface)) { 05881 ast_log (LOG_ERROR, "<interface> parameter can't be null\n"); 05882 return -1; 05883 } 05884 05885 /* if queuename = NULL then penalty will be set for interface in all the queues. */ 05886 if (set_member_penalty(args.queuename, args.interface, penalty)) { 05887 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n"); 05888 return -1; 05889 } 05890 05891 return 0; 05892 }
| 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 5646 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_log(), ast_strlen_zero(), call_queue::count, load_realtime_queue(), LOG_ERROR, LOG_WARNING, call_queue::membercount, call_queue::members, member::paused, queue_unref(), and member::status.
05647 { 05648 int count = 0; 05649 struct member *m; 05650 struct ao2_iterator mem_iter; 05651 struct call_queue *q; 05652 char *option; 05653 05654 if (ast_strlen_zero(data)) { 05655 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 05656 return -1; 05657 } 05658 05659 if ((option = strchr(data, ','))) 05660 *option++ = '\0'; 05661 else 05662 option = "logged"; 05663 if ((q = load_realtime_queue(data))) { 05664 ao2_lock(q); 05665 if (!strcasecmp(option, "logged")) { 05666 mem_iter = ao2_iterator_init(q->members, 0); 05667 while ((m = ao2_iterator_next(&mem_iter))) { 05668 /* Count the agents who are logged in and presently answering calls */ 05669 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05670 count++; 05671 } 05672 ao2_ref(m, -1); 05673 } 05674 ao2_iterator_destroy(&mem_iter); 05675 } else if (!strcasecmp(option, "free")) { 05676 mem_iter = ao2_iterator_init(q->members, 0); 05677 while ((m = ao2_iterator_next(&mem_iter))) { 05678 /* Count the agents who are logged in and presently answering calls */ 05679 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) { 05680 count++; 05681 } 05682 ao2_ref(m, -1); 05683 } 05684 ao2_iterator_destroy(&mem_iter); 05685 } else /* must be "count" */ 05686 count = q->membercount; 05687 ao2_unlock(q); 05688 queue_unref(q); 05689 } else 05690 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05691 05692 snprintf(buf, len, "%d", count); 05693 05694 return 0; 05695 }
| 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 5702 of file app_queue.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, ast_log(), ast_strlen_zero(), call_queue::count, load_realtime_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, call_queue::members, queue_unref(), and member::status.
05703 { 05704 int count = 0; 05705 struct member *m; 05706 struct call_queue *q; 05707 struct ao2_iterator mem_iter; 05708 static int depflag = 1; 05709 05710 if (depflag) { 05711 depflag = 0; 05712 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"); 05713 } 05714 05715 if (ast_strlen_zero(data)) { 05716 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 05717 return -1; 05718 } 05719 05720 if ((q = load_realtime_queue(data))) { 05721 ao2_lock(q); 05722 mem_iter = ao2_iterator_init(q->members, 0); 05723 while ((m = ao2_iterator_next(&mem_iter))) { 05724 /* Count the agents who are logged in and presently answering calls */ 05725 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 05726 count++; 05727 } 05728 ao2_ref(m, -1); 05729 } 05730 ao2_iterator_destroy(&mem_iter); 05731 ao2_unlock(q); 05732 queue_unref(q); 05733 } else 05734 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05735 05736 snprintf(buf, len, "%d", count); 05737 05738 return 0; 05739 }
| 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 5778 of file app_queue.c.
References ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), ast_log(), ast_strlen_zero(), member::interface, LOG_ERROR, LOG_WARNING, call_queue::members, OBJ_POINTER, queue_unref(), and queues.
05779 { 05780 struct call_queue *q, tmpq = { 05781 .name = data, 05782 }; 05783 struct member *m; 05784 05785 /* Ensure an otherwise empty list doesn't return garbage */ 05786 buf[0] = '\0'; 05787 05788 if (ast_strlen_zero(data)) { 05789 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n"); 05790 return -1; 05791 } 05792 05793 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 05794 int buflen = 0, count = 0; 05795 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0); 05796 05797 ao2_lock(q); 05798 while ((m = ao2_iterator_next(&mem_iter))) { 05799 /* strcat() is always faster than printf() */ 05800 if (count++) { 05801 strncat(buf + buflen, ",", len - buflen - 1); 05802 buflen++; 05803 } 05804 strncat(buf + buflen, m->interface, len - buflen - 1); 05805 buflen += strlen(m->interface); 05806 /* Safeguard against overflow (negative length) */ 05807 if (buflen >= len - 2) { 05808 ao2_ref(m, -1); 05809 ast_log(LOG_WARNING, "Truncating list\n"); 05810 break; 05811 } 05812 ao2_ref(m, -1); 05813 } 05814 ao2_iterator_destroy(&mem_iter); 05815 ao2_unlock(q); 05816 queue_unref(q); 05817 } else 05818 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05819 05820 /* We should already be terminated, but let's make sure. */ 05821 buf[len - 1] = '\0'; 05822 05823 return 0; 05824 }
| 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 5742 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.
05743 { 05744 int count = 0; 05745 struct call_queue *q, tmpq = { 05746 .name = data, 05747 }; 05748 struct ast_variable *var = NULL; 05749 05750 buf[0] = '\0'; 05751 05752 if (ast_strlen_zero(data)) { 05753 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n"); 05754 return -1; 05755 } 05756 05757 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 05758 ao2_lock(q); 05759 count = q->count; 05760 ao2_unlock(q); 05761 queue_unref(q); 05762 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) { 05763 /* if the queue is realtime but was not found in memory, this 05764 * means that the queue had been deleted from memory since it was 05765 * "dead." This means it has a 0 waiting count 05766 */ 05767 count = 0; 05768 ast_variables_destroy(var); 05769 } else 05770 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05771 05772 snprintf(buf, len, "%d", count); 05773 05774 return 0; 05775 }
| 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 5598 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, call_queue::strategy, and call_queue::talktime.
05599 { 05600 int res = -1; 05601 struct call_queue *q, tmpq = { 05602 .name = data, 05603 }; 05604 05605 char interfacevar[256] = ""; 05606 float sl = 0; 05607 05608 if (ast_strlen_zero(data)) { 05609 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd); 05610 return -1; 05611 } 05612 05613 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 05614 ao2_lock(q); 05615 if (q->setqueuevar) { 05616 sl = 0; 05617 res = 0; 05618 05619 if (q->callscompleted > 0) { 05620 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); 05621 } 05622 05623 snprintf(interfacevar, sizeof(interfacevar), 05624 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f", 05625 q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl); 05626 05627 pbx_builtin_setvar_multiple(chan, interfacevar); 05628 } 05629 05630 ao2_unlock(q); 05631 queue_unref(q); 05632 } else { 05633 ast_log(LOG_WARNING, "queue %s was not found\n", data); 05634 } 05635 05636 snprintf(buf, len, "%d", res); 05637 05638 return 0; 05639 }
| static int queue_hash_cb | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 1026 of file app_queue.c.
References ast_str_case_hash(), and call_queue::name.
Referenced by load_module().
01027 { 01028 const struct call_queue *q = obj; 01029 01030 return ast_str_case_hash(q->name); 01031 }
| static struct call_queue* queue_ref | ( | struct call_queue * | q | ) | [static, read] |
Definition at line 1039 of file app_queue.c.
References ao2_ref.
Referenced by leave_queue(), and try_calling().
01040 { 01041 ao2_ref(q, 1); 01042 return q; 01043 }
| static void queue_set_global_params | ( | struct ast_config * | cfg | ) | [static] |
Set the global queue parameters as defined in the "general" section of queues.conf
Definition at line 5979 of file app_queue.c.
References ast_true(), and ast_variable_retrieve().
Referenced by reload_queues().
05980 { 05981 const char *general_val = NULL; 05982 queue_persistent_members = 0; 05983 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 05984 queue_persistent_members = ast_true(general_val); 05985 autofill_default = 0; 05986 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) 05987 autofill_default = ast_true(general_val); 05988 montype_default = 0; 05989 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) { 05990 if (!strcasecmp(general_val, "mixmonitor")) 05991 montype_default = 1; 05992 } 05993 update_cdr = 0; 05994 if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr"))) 05995 update_cdr = ast_true(general_val); 05996 shared_lastcall = 0; 05997 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) 05998 shared_lastcall = ast_true(general_val); 05999 }
| 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 1530 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, parse_empty_options(), call_queue::periodicannouncefrequency, 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_single_queue().
01531 { 01532 if (!strcasecmp(param, "musicclass") || 01533 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 01534 ast_string_field_set(q, moh, val); 01535 } else if (!strcasecmp(param, "announce")) { 01536 ast_string_field_set(q, announce, val); 01537 } else if (!strcasecmp(param, "context")) { 01538 ast_string_field_set(q, context, val); 01539 } else if (!strcasecmp(param, "timeout")) { 01540 q->timeout = atoi(val); 01541 if (q->timeout < 0) 01542 q->timeout = DEFAULT_TIMEOUT; 01543 } else if (!strcasecmp(param, "ringinuse")) { 01544 q->ringinuse = ast_true(val); 01545 } else if (!strcasecmp(param, "setinterfacevar")) { 01546 q->setinterfacevar = ast_true(val); 01547 } else if (!strcasecmp(param, "setqueuevar")) { 01548 q->setqueuevar = ast_true(val); 01549 } else if (!strcasecmp(param, "setqueueentryvar")) { 01550 q->setqueueentryvar = ast_true(val); 01551 } else if (!strcasecmp(param, "monitor-format")) { 01552 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 01553 } else if (!strcasecmp(param, "membermacro")) { 01554 ast_string_field_set(q, membermacro, val); 01555 } else if (!strcasecmp(param, "membergosub")) { 01556 ast_string_field_set(q, membergosub, val); 01557 } else if (!strcasecmp(param, "queue-youarenext")) { 01558 ast_string_field_set(q, sound_next, val); 01559 } else if (!strcasecmp(param, "queue-thereare")) { 01560 ast_string_field_set(q, sound_thereare, val); 01561 } else if (!strcasecmp(param, "queue-callswaiting")) { 01562 ast_string_field_set(q, sound_calls, val); 01563 } else if (!strcasecmp(param, "queue-quantity1")) { 01564 ast_string_field_set(q, queue_quantity1, val); 01565 } else if (!strcasecmp(param, "queue-quantity2")) { 01566 ast_string_field_set(q, queue_quantity2, val); 01567 } else if (!strcasecmp(param, "queue-holdtime")) { 01568 ast_string_field_set(q, sound_holdtime, val); 01569 } else if (!strcasecmp(param, "queue-minutes")) { 01570 ast_string_field_set(q, sound_minutes, val); 01571 } else if (!strcasecmp(param, "queue-minute")) { 01572 ast_string_field_set(q, sound_minute, val); 01573 } else if (!strcasecmp(param, "queue-seconds")) { 01574 ast_string_field_set(q, sound_seconds, val); 01575 } else if (!strcasecmp(param, "queue-thankyou")) { 01576 ast_string_field_set(q, sound_thanks, val); 01577 } else if (!strcasecmp(param, "queue-callerannounce")) { 01578 ast_string_field_set(q, sound_callerannounce, val); 01579 } else if (!strcasecmp(param, "queue-reporthold")) { 01580 ast_string_field_set(q, sound_reporthold, val); 01581 } else if (!strcasecmp(param, "announce-frequency")) { 01582 q->announcefrequency = atoi(val); 01583 } else if (!strcasecmp(param, "min-announce-frequency")) { 01584 q->minannouncefrequency = atoi(val); 01585 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name); 01586 } else if (!strcasecmp(param, "announce-round-seconds")) { 01587 q->roundingseconds = atoi(val); 01588 /* Rounding to any other values just doesn't make sense... */ 01589 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10 01590 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) { 01591 if (linenum >= 0) { 01592 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01593 "using 0 instead for queue '%s' at line %d of queues.conf\n", 01594 val, param, q->name, linenum); 01595 } else { 01596 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 01597 "using 0 instead for queue '%s'\n", val, param, q->name); 01598 } 01599 q->roundingseconds=0; 01600 } 01601 } else if (!strcasecmp(param, "announce-holdtime")) { 01602 if (!strcasecmp(val, "once")) 01603 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 01604 else if (ast_true(val)) 01605 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 01606 else 01607 q->announceholdtime = 0; 01608 } else if (!strcasecmp(param, "announce-position")) { 01609 if (!strcasecmp(val, "limit")) 01610 q->announceposition = ANNOUNCEPOSITION_LIMIT; 01611 else if (!strcasecmp(val, "more")) 01612 q->announceposition = ANNOUNCEPOSITION_MORE_THAN; 01613 else if (ast_true(val)) 01614 q->announceposition = ANNOUNCEPOSITION_YES; 01615 else 01616 q->announceposition = ANNOUNCEPOSITION_NO; 01617 } else if (!strcasecmp(param, "announce-position-limit")) { 01618 q->announcepositionlimit = atoi(val); 01619 } else if (!strcasecmp(param, "periodic-announce")) { 01620 if (strchr(val, ',')) { 01621 char *s, *buf = ast_strdupa(val); 01622 unsigned int i = 0; 01623 01624 while ((s = strsep(&buf, ",|"))) { 01625 if (!q->sound_periodicannounce[i]) 01626 q->sound_periodicannounce[i] = ast_str_create(16); 01627 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s); 01628 i++; 01629 if (i == MAX_PERIODIC_ANNOUNCEMENTS) 01630 break; 01631 } 01632 q->numperiodicannounce = i; 01633 } else { 01634 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val); 01635 q->numperiodicannounce = 1; 01636 } 01637 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 01638 q->periodicannouncefrequency = atoi(val); 01639 } else if (!strcasecmp(param, "random-periodic-announce")) { 01640 q->randomperiodicannounce = ast_true(val); 01641 } else if (!strcasecmp(param, "retry")) { 01642 q->retry = atoi(val); 01643 if (q->retry <= 0) 01644 q->retry = DEFAULT_RETRY; 01645 } else if (!strcasecmp(param, "wrapuptime")) { 01646 q->wrapuptime = atoi(val); 01647 } else if (!strcasecmp(param, "autofill")) { 01648 q->autofill = ast_true(val); 01649 } else if (!strcasecmp(param, "monitor-type")) { 01650 if (!strcasecmp(val, "mixmonitor")) 01651 q->montype = 1; 01652 } else if (!strcasecmp(param, "autopause")) { 01653 q->autopause = ast_true(val); 01654 } else if (!strcasecmp(param, "maxlen")) { 01655 q->maxlen = atoi(val); 01656 if (q->maxlen < 0) 01657 q->maxlen = 0; 01658 } else if (!strcasecmp(param, "servicelevel")) { 01659 q->servicelevel= atoi(val); 01660 } else if (!strcasecmp(param, "strategy")) { 01661 int strategy; 01662 01663 /* We are a static queue and already have set this, no need to do it again */ 01664 if (failunknown) { 01665 return; 01666 } 01667 strategy = strat2int(val); 01668 if (strategy < 0) { 01669 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 01670 val, q->name); 01671 q->strategy = QUEUE_STRATEGY_RINGALL; 01672 } 01673 if (strategy == q->strategy) { 01674 return; 01675 } 01676 if (strategy == QUEUE_STRATEGY_LINEAR) { 01677 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n"); 01678 return; 01679 } 01680 q->strategy = strategy; 01681 } else if (!strcasecmp(param, "joinempty")) { 01682 parse_empty_options(val, &q->joinempty, 1); 01683 } else if (!strcasecmp(param, "leavewhenempty")) { 01684 parse_empty_options(val, &q->leavewhenempty, 0); 01685 } else if (!strcasecmp(param, "eventmemberstatus")) { 01686 q->maskmemberstatus = !ast_true(val); 01687 } else if (!strcasecmp(param, "eventwhencalled")) { 01688 if (!strcasecmp(val, "vars")) { 01689 q->eventwhencalled = QUEUE_EVENT_VARIABLES; 01690 } else { 01691 q->eventwhencalled = ast_true(val) ? 1 : 0; 01692 } 01693 } else if (!strcasecmp(param, "reportholdtime")) { 01694 q->reportholdtime = ast_true(val); 01695 } else if (!strcasecmp(param, "memberdelay")) { 01696 q->memberdelay = atoi(val); 01697 } else if (!strcasecmp(param, "weight")) { 01698 q->weight = atoi(val); 01699 } else if (!strcasecmp(param, "timeoutrestart")) { 01700 q->timeoutrestart = ast_true(val); 01701 } else if (!strcasecmp(param, "defaultrule")) { 01702 ast_string_field_set(q, defaultrule, val); 01703 } else if (!strcasecmp(param, "timeoutpriority")) { 01704 if (!strcasecmp(val, "conf")) { 01705 q->timeoutpriority = TIMEOUT_PRIORITY_CONF; 01706 } else { 01707 q->timeoutpriority = TIMEOUT_PRIORITY_APP; 01708 } 01709 } else if (failunknown) { 01710 if (linenum >= 0) { 01711 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 01712 q->name, param, linenum); 01713 } else { 01714 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 01715 } 01716 } 01717 }
| static char* queue_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 6520 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.
06521 { 06522 switch ( cmd ) { 06523 case CLI_INIT: 06524 e->command = "queue show"; 06525 e->usage = 06526 "Usage: queue show\n" 06527 " Provides summary information on a specified queue.\n"; 06528 return NULL; 06529 case CLI_GENERATE: 06530 return complete_queue_show(a->line, a->word, a->pos, a->n); 06531 } 06532 06533 return __queues_show(NULL, a->fd, a->argc, a->argv); 06534 }
| static void queue_transfer_destroy | ( | void * | data | ) | [static] |
Definition at line 3689 of file app_queue.c.
References ast_free.
03690 { 03691 struct queue_transfer_ds *qtds = data; 03692 ast_free(qtds); 03693 }
| 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 3712 of file app_queue.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_log(), ast_queue_log(), queue_transfer_ds::callcompletedinsl, queue_ent::chan, ast_channel::context, ast_channel::exten, LOG_WARNING, queue_transfer_ds::member, member::membername, call_queue::name, queue_ent::opos, queue_ent::parent, queue_transfer_ds::qe, queue_transfer_info, queue_ent::start, queue_transfer_ds::starttime, ast_channel::uniqueid, and update_queue().
03713 { 03714 struct queue_transfer_ds *qtds = data; 03715 struct queue_ent *qe = qtds->qe; 03716 struct member *member = qtds->member; 03717 time_t callstart = qtds->starttime; 03718 int callcompletedinsl = qtds->callcompletedinsl; 03719 struct ast_datastore *datastore; 03720 03721 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d", 03722 new_chan->exten, new_chan->context, (long) (callstart - qe->start), 03723 (long) (time(NULL) - callstart), qe->opos); 03724 03725 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart)); 03726 03727 /* No need to lock the channels because they are already locked in ast_do_masquerade */ 03728 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) { 03729 ast_channel_datastore_remove(old_chan, datastore); 03730 } else { 03731 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n"); 03732 } 03733 }
| static struct call_queue* queue_unref | ( | struct call_queue * | q | ) | [static, read] |
Definition at line 1045 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(), 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_single_queue(), remove_from_queue(), set_member_paused(), set_member_penalty(), and unload_module().
01046 { 01047 ao2_ref(q, -1); 01048 return q; 01049 }
| static void recalc_holdtime | ( | struct queue_ent * | qe, | |
| int | newholdtime | |||
| ) | [static] |
Definition at line 2376 of file app_queue.c.
References ao2_lock(), ao2_unlock(), call_queue::holdtime, and queue_ent::parent.
Referenced by try_calling().
02377 { 02378 int oldvalue; 02379 02380 /* Calculate holdtime using an exponential average */ 02381 /* Thanks to SRT for this contribution */ 02382 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 02383 02384 ao2_lock(qe->parent); 02385 oldvalue = qe->parent->holdtime; 02386 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2; 02387 ao2_unlock(qe->parent); 02388 }
| static void record_abandoned | ( | struct queue_ent * | qe | ) | [static] |
Record that a caller gave up on waiting in queue.
Definition at line 2959 of file app_queue.c.
References ao2_lock(), ao2_unlock(), call_queue::callsabandoned, queue_ent::chan, EVENT_FLAG_AGENT, manager_event, call_queue::name, queue_ent::opos, queue_ent::parent, queue_ent::pos, set_queue_variables(), queue_ent::start, and ast_channel::uniqueid.
Referenced by queue_exec(), and try_calling().
02960 { 02961 ao2_lock(qe->parent); 02962 set_queue_variables(qe->parent, qe->chan); 02963 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon", 02964 "Queue: %s\r\n" 02965 "Uniqueid: %s\r\n" 02966 "Position: %d\r\n" 02967 "OriginalPosition: %d\r\n" 02968 "HoldTime: %d\r\n", 02969 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start)); 02970 02971 qe->parent->callsabandoned++; 02972 ao2_unlock(qe->parent); 02973 }
| static int reload | ( | void | ) | [static] |
Definition at line 7561 of file app_queue.c.
References AST_FLAGS_ALL, ast_unload_realtime(), and reload_handler().
07562 { 07563 struct ast_flags mask = {AST_FLAGS_ALL,}; 07564 ast_unload_realtime("queue_members"); 07565 reload_handler(1, &mask, NULL); 07566 return 0; 07567 }
| static int reload_handler | ( | int | reload, | |
| struct ast_flags * | mask, | |||
| const char * | queuename | |||
| ) | [static] |
The command center for all reload operations.
Whenever any piece of queue information is to be reloaded, this function is called. It interprets the flags set in the mask parameter and acts based on how they are set.
| reload | True if we are reloading information, false if we are loading information for the first time. | |
| mask | A bitmask which tells the handler what actions to take | |
| queuename | The name of the queue on which we wish to take action |
| 0 | All reloads were successful | |
| non-zero | There was a failure |
Definition at line 6332 of file app_queue.c.
References ast_test_flag, clear_stats(), QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, QUEUE_RESET_STATS, reload_queue_rules(), and reload_queues().
Referenced by handle_queue_reload(), handle_queue_reset(), load_module(), manager_queue_reload(), manager_queue_reset(), and reload().
06333 { 06334 int res = 0; 06335 06336 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) { 06337 res |= reload_queue_rules(reload); 06338 } 06339 if (ast_test_flag(mask, QUEUE_RESET_STATS)) { 06340 res |= clear_stats(queuename); 06341 } 06342 if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) { 06343 res |= reload_queues(reload, mask, queuename); 06344 } 06345 return res; 06346 }
| static void reload_queue_members | ( | void | ) | [static] |
Reload dynamic queue members persisted into the astdb.
Definition at line 4944 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().
04945 { 04946 char *cur_ptr; 04947 const char *queue_name; 04948 char *member; 04949 char *interface; 04950 char *membername = NULL; 04951 char *state_interface; 04952 char *penalty_tok; 04953 int penalty = 0; 04954 char *paused_tok; 04955 int paused = 0; 04956 struct ast_db_entry *db_tree; 04957 struct ast_db_entry *entry; 04958 struct call_queue *cur_queue; 04959 char queue_data[PM_MAX_LEN]; 04960 04961 ao2_lock(queues); 04962 04963 /* Each key in 'pm_family' is the name of a queue */ 04964 db_tree = ast_db_gettree(pm_family, NULL); 04965 for (entry = db_tree; entry; entry = entry->next) { 04966 04967 queue_name = entry->key + strlen(pm_family) + 2; 04968 04969 { 04970 struct call_queue tmpq = { 04971 .name = queue_name, 04972 }; 04973 cur_queue = ao2_find(queues, &tmpq, OBJ_POINTER); 04974 } 04975 04976 if (!cur_queue) 04977 cur_queue = load_realtime_queue(queue_name); 04978 04979 if (!cur_queue) { 04980 /* If the queue no longer exists, remove it from the 04981 * database */ 04982 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name); 04983 ast_db_del(pm_family, queue_name); 04984 continue; 04985 } 04986 04987 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) { 04988 queue_unref(cur_queue); 04989 continue; 04990 } 04991 04992 cur_ptr = queue_data; 04993 while ((member = strsep(&cur_ptr, ",|"))) { 04994 if (ast_strlen_zero(member)) 04995 continue; 04996 04997 interface = strsep(&member, ";"); 04998 penalty_tok = strsep(&member, ";"); 04999 paused_tok = strsep(&member, ";"); 05000 membername = strsep(&member, ";"); 05001 state_interface = strsep(&member, ";"); 05002 05003 if (!penalty_tok) { 05004 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name); 05005 break; 05006 } 05007 penalty = strtol(penalty_tok, NULL, 10); 05008 if (errno == ERANGE) { 05009 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 05010 break; 05011 } 05012 05013 if (!paused_tok) { 05014 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 05015 break; 05016 } 05017 paused = strtol(paused_tok, NULL, 10); 05018 if ((errno == ERANGE) || paused < 0 || paused > 1) { 05019 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 05020 break; 05021 } 05022 05023 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused); 05024 05025 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) { 05026 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 05027 break; 05028 } 05029 } 05030 queue_unref(cur_queue); 05031 } 05032 05033 ao2_unlock(queues); 05034 if (db_tree) { 05035 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n"); 05036 ast_db_freetree(db_tree); 05037 } 05038 }
| static int reload_queue_rules | ( | int | reload | ) | [static] |
Reload the rules defined in queuerules.conf.
| reload | If 1, then only process queuerules.conf if the file has changed since the last time we inspected it. |
Definition at line 5931 of file app_queue.c.
References ast_calloc, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, insert_penaltychange(), ast_variable::lineno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_variable::name, rule_list::name, ast_variable::next, rule_list::rules, and ast_variable::value.
Referenced by reload_handler().
05932 { 05933 struct ast_config *cfg; 05934 struct rule_list *rl_iter, *new_rl; 05935 struct penalty_rule *pr_iter; 05936 char *rulecat = NULL; 05937 struct ast_variable *rulevar = NULL; 05938 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 05939 05940 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) { 05941 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n"); 05942 return AST_MODULE_LOAD_SUCCESS; 05943 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 05944 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n"); 05945 return AST_MODULE_LOAD_SUCCESS; 05946 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 05947 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n"); 05948 return AST_MODULE_LOAD_SUCCESS; 05949 } 05950 05951 AST_LIST_LOCK(&rule_lists); 05952 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) { 05953 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list))) 05954 ast_free(pr_iter); 05955 ast_free(rl_iter); 05956 } 05957 while ((rulecat = ast_category_browse(cfg, rulecat))) { 05958 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) { 05959 AST_LIST_UNLOCK(&rule_lists); 05960 return AST_MODULE_LOAD_FAILURE; 05961 } else { 05962 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name)); 05963 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list); 05964 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next) 05965 if(!strcasecmp(rulevar->name, "penaltychange")) 05966 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno); 05967 else 05968 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno); 05969 } 05970 } 05971 AST_LIST_UNLOCK(&rule_lists); 05972 05973 ast_config_destroy(cfg); 05974 05975 return AST_MODULE_LOAD_SUCCESS; 05976 }
| static int reload_queues | ( | int | reload, | |
| struct ast_flags * | mask, | |||
| const char * | queuename | |||
| ) | [static] |
reload the queues.conf file
This function reloads the information in the general section of the queues.conf file and potentially more, depending on the value of mask.
| reload | 0 if we are calling this the first time, 1 every other time | |
| mask | Gives flags telling us what information to actually reload | |
| queuename | If set to a non-zero string, then only reload information from that particular queue. Otherwise inspect all queues |
| -1 | Failure occurred | |
| 0 | All clear! |
Definition at line 6245 of file app_queue.c.
References ao2_callback, ao2_lock(), ao2_unlock(), ast_category_browse(), ast_config_destroy(), ast_config_load, ast_log(), ast_strlen_zero(), ast_test_flag, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, kill_dead_queues(), LOG_ERROR, LOG_NOTICE, mark_dead_and_unfound(), OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, QUEUE_RELOAD_PARAMETERS, queue_set_global_params(), queues, and reload_single_queue().
Referenced by reload_handler().
06246 { 06247 struct ast_config *cfg; 06248 char *cat; 06249 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 06250 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); 06251 06252 if (!(cfg = ast_config_load("queues.conf", config_flags))) { 06253 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 06254 return -1; 06255 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 06256 return 0; 06257 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 06258 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n"); 06259 return -1; 06260 } 06261 06262 /* We've made it here, so it looks like we're doing operations on all queues. */ 06263 ao2_lock(queues); 06264 06265 /* Mark all queues as dead for the moment if we're reloading queues. 06266 * For clarity, we could just be reloading members, in which case we don't want to mess 06267 * with the other queue parameters at all*/ 06268 if (queue_reload) { 06269 ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename); 06270 } 06271 06272 /* Chug through config file */ 06273 cat = NULL; 06274 while ((cat = ast_category_browse(cfg, cat)) ) { 06275 if (!strcasecmp(cat, "general") && queue_reload) { 06276 queue_set_global_params(cfg); 06277 continue; 06278 } 06279 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename)) 06280 reload_single_queue(cfg, mask, cat); 06281 } 06282 06283 ast_config_destroy(cfg); 06284 /* Unref all the dead queues if we were reloading queues */ 06285 if (queue_reload) { 06286 ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename); 06287 } 06288 ao2_unlock(queues); 06289 return 0; 06290 }
| static void reload_single_member | ( | const char * | memberdata, | |
| struct call_queue * | q | |||
| ) | [static] |
reload information pertaining to a single member
This function is called when a member = line is encountered in queues.conf.
| memberdata | The part after member = in the config file | |
| q | The queue to which this member belongs |
Definition at line 6009 of file app_queue.c.
References ao2_find, ao2_link, ao2_ref, AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strip(), ast_strlen_zero(), create_queue_member(), member::interface, LOG_WARNING, call_queue::membercount, call_queue::members, OBJ_POINTER, OBJ_UNLINK, parse(), member::paused, and member::penalty.
Referenced by reload_single_queue().
06010 { 06011 char *membername, *interface, *state_interface, *tmp; 06012 char *parse; 06013 struct member *cur, *newm; 06014 struct member tmpmem; 06015 int penalty; 06016 AST_DECLARE_APP_ARGS(args, 06017 AST_APP_ARG(interface); 06018 AST_APP_ARG(penalty); 06019 AST_APP_ARG(membername); 06020 AST_APP_ARG(state_interface); 06021 ); 06022 06023 if (ast_strlen_zero(memberdata)) { 06024 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n"); 06025 return; 06026 } 06027 06028 /* Add a new member */ 06029 parse = ast_strdupa(memberdata); 06030 06031 AST_STANDARD_APP_ARGS(args, parse); 06032 06033 interface = args.interface; 06034 if (!ast_strlen_zero(args.penalty)) { 06035 tmp = args.penalty; 06036 ast_strip(tmp); 06037 penalty = atoi(tmp); 06038 if (penalty < 0) { 06039 penalty = 0; 06040 } 06041 } else { 06042 penalty = 0; 06043 } 06044 06045 if (!ast_strlen_zero(args.membername)) { 06046 membername = args.membername; 06047 ast_strip(membername); 06048 } else { 06049 membername = interface; 06050 } 06051 06052 if (!ast_strlen_zero(args.state_interface)) { 06053 state_interface = args.state_interface; 06054 ast_strip(state_interface); 06055 } else { 06056 state_interface = interface; 06057 } 06058 06059 /* Find the old position in the list */ 06060 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 06061 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK); 06062 if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) { 06063 ao2_link(q->members, newm); 06064 ao2_ref(newm, -1); 06065 } 06066 newm = NULL; 06067 06068 if (cur) { 06069 ao2_ref(cur, -1); 06070 } else { 06071 q->membercount++; 06072 } 06073 }
| static void reload_single_queue | ( | struct ast_config * | cfg, | |
| struct ast_flags * | mask, | |||
| const char * | queuename | |||
| ) | [static] |
Reload information pertaining to a particular queue.
Once we have isolated a queue within reload_queues, we call this. This will either reload information for the queue or if we're just reloading member information, we'll just reload that without touching other settings within the queue
| cfg | The configuration which we are reading | |
| mask | Tells us what information we need to reload | |
| queuename | The name of the queue we are reloading information from |
| void |
Definition at line 6115 of file app_queue.c.
References alloc_queue(), ao2_callback, ao2_find, ao2_link, ao2_lock(), ao2_unlock(), ast_atomic_fetchadd_int(), ast_log(), ast_test_flag, ast_variable_browse(), ast_variable_retrieve(), call_queue::found, init_queue(), kill_dead_members(), ast_variable::lineno, LOG_WARNING, mark_member_dead(), call_queue::membercount, call_queue::members, ast_variable::name, call_queue::name, ast_variable::next, OBJ_MULTIPLE, OBJ_NODATA, OBJ_POINTER, OBJ_UNLINK, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_unref(), queues, reload_single_member(), strat2int(), call_queue::strategy, ast_variable::value, var, and call_queue::weight.
Referenced by reload_queues().
06116 { 06117 int new; 06118 struct call_queue *q = NULL; 06119 /*We're defining a queue*/ 06120 struct call_queue tmpq = { 06121 .name = queuename, 06122 }; 06123 const char *tmpvar; 06124 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS); 06125 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER); 06126 int prev_weight = 0; 06127 struct ast_variable *var; 06128 if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 06129 if (queue_reload) { 06130 /* Make one then */ 06131 if (!(q = alloc_queue(queuename))) { 06132 return; 06133 } 06134 } else { 06135 /* Since we're not reloading queues, this means that we found a queue 06136 * in the configuration file which we don't know about yet. Just return. 06137 */ 06138 return; 06139 } 06140 new = 1; 06141 } else { 06142 new = 0; 06143 } 06144 06145 if (!new) { 06146 ao2_lock(q); 06147 prev_weight = q->weight ? 1 : 0; 06148 } 06149 /* Check if we already found a queue with this name in the config file */ 06150 if (q->found) { 06151 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename); 06152 if (!new) { 06153 /* It should be impossible to *not* hit this case*/ 06154 ao2_unlock(q); 06155 } 06156 queue_unref(q); 06157 return; 06158 } 06159 /* Due to the fact that the "linear" strategy will have a different allocation 06160 * scheme for queue members, we must devise the queue's strategy before other initializations. 06161 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2 06162 * container used will have only a single bucket instead of the typical number. 06163 */ 06164 if (queue_reload) { 06165 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) { 06166 q->strategy = strat2int(tmpvar); 06167 if (q->strategy < 0) { 06168 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 06169 tmpvar, q->name); 06170 q->strategy = QUEUE_STRATEGY_RINGALL; 06171 } 06172 } else { 06173 q->strategy = QUEUE_STRATEGY_RINGALL; 06174 } 06175 init_queue(q); 06176 } 06177 if (member_reload) { 06178 q->membercount = 0; 06179 ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL); 06180 } 06181 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) { 06182 if (member_reload && !strcasecmp(var->name, "member")) { 06183 reload_single_member(var->value, q); 06184 } else if (queue_reload) { 06185 queue_set_param(q, var->name, var->value, var->lineno, 1); 06186 } 06187 } 06188 /* At this point, we've determined if the queue has a weight, so update use_weight 06189 * as appropriate 06190 */ 06191 if (!q->weight && prev_weight) { 06192 ast_atomic_fetchadd_int(&use_weight, -1); 06193 } 06194 else if (q->weight && !prev_weight) { 06195 ast_atomic_fetchadd_int(&use_weight, +1); 06196 } 06197 06198 /* Free remaining members marked as delme */ 06199 if (member_reload) { 06200 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q); 06201 } 06202 06203 if (new) { 06204 ao2_link(queues, q); 06205 } else { 06206 ao2_unlock(q); 06207 } 06208 queue_unref(q); 06209 }
| 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 4681 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, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, and RES_OKAY.
Referenced by attempt_thread(), handle_queue_remove_member(), manager_remove_queue_member(), rqm_exec(), and scan_service().
04682 { 04683 struct call_queue *q, tmpq = { 04684 .name = queuename, 04685 }; 04686 struct member *mem, tmpmem; 04687 int res = RES_NOSUCHQUEUE; 04688 04689 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface)); 04690 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) { 04691 ao2_lock(queues); 04692 ao2_lock(q); 04693 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) { 04694 /* XXX future changes should beware of this assumption!! */ 04695 if (!mem->dynamic) { 04696 ao2_ref(mem, -1); 04697 ao2_unlock(q); 04698 queue_unref(q); 04699 ao2_unlock(queues); 04700 return RES_NOT_DYNAMIC; 04701 } 04702 q->membercount--; 04703 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 04704 "Queue: %s\r\n" 04705 "Location: %s\r\n" 04706 "MemberName: %s\r\n", 04707 q->name, mem->interface, mem->membername); 04708 ao2_unlink(q->members, mem); 04709 ao2_ref(mem, -1); 04710 04711 if (queue_persistent_members) 04712 dump_queue_members(q); 04713 04714 res = RES_OKAY; 04715 } else { 04716 res = RES_EXISTS; 04717 } 04718 ao2_unlock(q); 04719 ao2_unlock(queues); 04720 queue_unref(q); 04721 } 04722 04723 return res; 04724 }
| 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 2622 of file app_queue.c.
References ast_cdr::accountcode, ast_channel::adsicpe, ast_cdr::amaflags, ast_party_connected_line::ani, ao2_lock(), ao2_unlock(), ast_channel::appl, ast_call(), ast_cdr_busy(), ast_cdr_isset_unanswered(), ast_cdr_setdestchan(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_connected_line_copy_from_caller(), ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, AST_FLAG_ANSWERED_ELSEWHERE, ast_free, ast_party_redirecting_copy(), ast_request(), ast_set_callerid(), ast_set_flag, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_verb, queue_ent::cancel_answered_elsewhere, ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_cdr::channel, CHANNEL_DEADLOCK_AVOIDANCE, ast_channel::cid, ast_callerid::cid_dnid, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_cdr::clid, compare_weight(), ast_channel::connected, ast_channel::context, ast_channel::data, ast_cdr::dcontext, dialcontext, do_hang(), ast_cdr::dst, EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, ast_party_connected_line::id, callattempt::interface, ast_cdr::lastapp, callattempt::lastcall, ast_cdr::lastdata, callattempt::lastqueue, queue_ent::linpos, ast_channel::macroexten, manager_event, callattempt::member, member::membername, ast_channel::name, ast_party_id::name, call_queue::name, ast_channel::nativeformats, ast_party_id::number, ast_party_id::number_presentation, queue_ent::parent, member::paused, pbx_builtin_getvar_helper(), ast_channel::priority, QUEUE_EVENT_VARIABLES, ast_channel::redirecting, call_queue::ringinuse, call_queue::rrpos, S_OR, ast_cdr::src, member::state_interface, member::status, status, callattempt::stillgoing, ast_channel::uniqueid, callattempt::update_connectedline, update_status(), ast_cdr::userfield, vars2manager(), ast_channel::whentohangup, and call_queue::wrapuptime.
Referenced by ring_one().
02623 { 02624 int res; 02625 int status; 02626 char tech[256]; 02627 char *location; 02628 const char *macrocontext, *macroexten; 02629 02630 /* on entry here, we know that tmp->chan == NULL */ 02631 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) || 02632 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) { 02633 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 02634 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface); 02635 if (qe->chan->cdr) 02636 ast_cdr_busy(qe->chan->cdr); 02637 tmp->stillgoing = 0; 02638 (*busies)++; 02639 return 0; 02640 } 02641 02642 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) { 02643 ast_debug(1, "%s in use, can't receive call\n", tmp->interface); 02644 if (qe->chan->cdr) 02645 ast_cdr_busy(qe->chan->cdr); 02646 tmp->stillgoing = 0; 02647 return 0; 02648 } 02649 02650 if (tmp->member->paused) { 02651 ast_debug(1, "%s paused, can't receive call\n", tmp->interface); 02652 if (qe->chan->cdr) 02653 ast_cdr_busy(qe->chan->cdr); 02654 tmp->stillgoing = 0; 02655 return 0; 02656 } 02657 if (use_weight && compare_weight(qe->parent,tmp->member)) { 02658 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 02659 if (qe->chan->cdr) 02660 ast_cdr_busy(qe->chan->cdr); 02661 tmp->stillgoing = 0; 02662 (*busies)++; 02663 return 0; 02664 } 02665 02666 ast_copy_string(tech, tmp->interface, sizeof(tech)); 02667 if ((location = strchr(tech, '/'))) 02668 *location++ = '\0'; 02669 else 02670 location = ""; 02671 02672 /* Request the peer */ 02673 tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status); 02674 if (!tmp->chan) { /* If we can't, just go on to the next call */ 02675 if (qe->chan->cdr) 02676 ast_cdr_busy(qe->chan->cdr); 02677 tmp->stillgoing = 0; 02678 02679 ao2_lock(qe->parent); 02680 update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface)); 02681 qe->parent->rrpos++; 02682 qe->linpos++; 02683 ao2_unlock(qe->parent); 02684 02685 (*busies)++; 02686 return 0; 02687 } 02688 02689 ast_channel_lock(tmp->chan); 02690 while (ast_channel_trylock(qe->chan)) { 02691 CHANNEL_DEADLOCK_AVOIDANCE(tmp->chan); 02692 } 02693 02694 if (qe->cancel_answered_elsewhere) { 02695 ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE); 02696 } 02697 tmp->chan->appl = "AppQueue"; 02698 tmp->chan->data = "(Outgoing Line)"; 02699 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup)); 02700 02701 /* If the new channel has no callerid, try to guess what it should be */ 02702 if (ast_strlen_zero(tmp->chan->cid.cid_num)) { 02703 if (!ast_strlen_zero(qe->chan->connected.id.number)) { 02704 ast_set_callerid(tmp->chan, qe->chan->connected.id.number, qe->chan->connected.id.name, qe->chan->connected.ani); 02705 tmp->chan->cid.cid_pres = qe->chan->connected.id.number_presentation; 02706 } else if (!ast_strlen_zero(qe->chan->cid.cid_dnid)) { 02707 ast_set_callerid(tmp->chan, qe->chan->cid.cid_dnid, NULL, NULL); 02708 } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) { 02709 ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL); 02710 } 02711 tmp->update_connectedline = 0; 02712 } 02713 02714 if (tmp->chan->cid.cid_rdnis) 02715 ast_free(tmp->chan->cid.cid_rdnis); 02716 tmp->chan->cid.cid_rdnis = ast_strdup(qe->chan->cid.cid_rdnis); 02717 ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting); 02718 02719 tmp->chan->cid.cid_tns = qe->chan->cid.cid_tns; 02720 02721 ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->cid); 02722 02723 /* Inherit specially named variables from parent channel */ 02724 ast_channel_inherit_variables(qe->chan, tmp->chan); 02725 ast_channel_datastore_inherit(qe->chan, tmp->chan); 02726 02727 /* Presense of ADSI CPE on outgoing channel follows ours */ 02728 tmp->chan->adsicpe = qe->chan->adsicpe; 02729 02730 /* Inherit context and extension */ 02731 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT"); 02732 ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext); 02733 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN"); 02734 if (!ast_strlen_zero(macroexten)) 02735 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten)); 02736 else 02737 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten)); 02738 if (ast_cdr_isset_unanswered()) { 02739 /* they want to see the unanswered dial attempts! */ 02740 /* set up the CDR fields on all the CDRs to give sensical information */ 02741 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name); 02742 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid); 02743 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel); 02744 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src); 02745 strcpy(tmp->chan->cdr->dst, qe->chan->exten); 02746 strcpy(tmp->chan->cdr->dcontext, qe->chan->context); 02747 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp); 02748 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata); 02749 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags; 02750 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode); 02751 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield); 02752 } 02753 02754 /* Place the call, but don't wait on the answer */ 02755 if ((res = ast_call(tmp->chan, location, 0))) { 02756 /* Again, keep going even if there's an error */ 02757 ast_debug(1, "ast call on peer returned %d\n", res); 02758 ast_verb(3, "Couldn't call %s\n", tmp->interface); 02759 ast_channel_unlock(tmp->chan); 02760 ast_channel_unlock(qe->chan); 02761 do_hang(tmp); 02762 (*busies)++; 02763 update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface)); 02764 return 0; 02765 } else if (qe->parent->eventwhencalled) { 02766 char vars[2048]; 02767 02768 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 02769 "Queue: %s\r\n" 02770 "AgentCalled: %s\r\n" 02771 "AgentName: %s\r\n" 02772 "ChannelCalling: %s\r\n" 02773 "DestinationChannel: %s\r\n" 02774 "CallerIDNum: %s\r\n" 02775 "CallerIDName: %s\r\n" 02776 "Context: %s\r\n" 02777 "Extension: %s\r\n" 02778 "Priority: %d\r\n" 02779 "Uniqueid: %s\r\n" 02780 "%s", 02781 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name, 02782 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown", 02783 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown", 02784 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid, 02785 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02786 ast_verb(3, "Called %s\n", tmp->interface); 02787 } 02788 ast_channel_unlock(tmp->chan); 02789 ast_channel_unlock(qe->chan); 02790 02791 update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface)); 02792 return 1; 02793 }
| 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 2821 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().
02822 { 02823 int ret = 0; 02824 02825 while (ret == 0) { 02826 struct callattempt *best = find_best(outgoing); 02827 if (!best) { 02828 ast_debug(1, "Nobody left to try ringing in queue\n"); 02829 break; 02830 } 02831 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) { 02832 struct callattempt *cur; 02833 /* Ring everyone who shares this best metric (for ringall) */ 02834 for (cur = outgoing; cur; cur = cur->q_next) { 02835 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) { 02836 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 02837 ret |= ring_entry(qe, cur, busies); 02838 } 02839 } 02840 } else { 02841 /* Ring just the best channel */ 02842 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric); 02843 ret = ring_entry(qe, best, busies); 02844 } 02845 02846 /* If we have timed out, break out */ 02847 if (qe->expire && (time(NULL) >= qe->expire)) { 02848 ast_debug(1, "Queue timed out while ringing members.\n"); 02849 ret = 0; 02850 break; 02851 } 02852 } 02853 02854 return ret; 02855 }
| 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 2976 of file app_queue.c.
References ast_queue_log(), ast_verb, call_queue::autopause, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, manager_event, ast_channel::name, call_queue::name, queue_ent::parent, QUEUE_EVENT_VARIABLES, set_member_paused(), ast_channel::uniqueid, and vars2manager().
Referenced by wait_for_answer().
02977 { 02978 ast_verb(3, "Nobody picked up in %d ms\n", rnatime); 02979 if (qe->parent->eventwhencalled) { 02980 char vars[2048]; 02981 02982 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer", 02983 "Queue: %s\r\n" 02984 "Uniqueid: %s\r\n" 02985 "Channel: %s\r\n" 02986 "Member: %s\r\n" 02987 "MemberName: %s\r\n" 02988 "Ringtime: %d\r\n" 02989 "%s", 02990 qe->parent->name, 02991 qe->chan->uniqueid, 02992 qe->chan->name, 02993 interface, 02994 membername, 02995 rnatime, 02996 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : ""); 02997 } 02998 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime); 02999 if (qe->parent->autopause && pause) { 03000 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) { 03001 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name); 03002 } else { 03003 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name); 03004 } 03005 } 03006 return; 03007 }
| static int rqm_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
RemoveQueueMember application.
Definition at line 5113 of file app_queue.c.
References AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_NOTICE, LOG_WARNING, ast_channel::name, parse(), pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and ast_channel::uniqueid.
Referenced by load_module().
05114 { 05115 int res=-1; 05116 char *parse, *temppos = NULL; 05117 AST_DECLARE_APP_ARGS(args, 05118 AST_APP_ARG(queuename); 05119 AST_APP_ARG(interface); 05120 AST_APP_ARG(options); 05121 ); 05122 05123 05124 if (ast_strlen_zero(data)) { 05125 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n"); 05126 return -1; 05127 } 05128 05129 parse = ast_strdupa(data); 05130 05131 AST_STANDARD_APP_ARGS(args, parse); 05132 05133 if (ast_strlen_zero(args.interface)) { 05134 args.interface = ast_strdupa(chan->name); 05135 temppos = strrchr(args.interface, '-'); 05136 if (temppos) 05137 *temppos = '\0'; 05138 } 05139 05140 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface); 05141 05142 switch (remove_from_queue(args.queuename, args.interface)) { 05143 case RES_OKAY: 05144 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", ""); 05145 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 05146 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 05147 res = 0; 05148 break; 05149 case RES_EXISTS: 05150 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 05151 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 05152 res = 0; 05153 break; 05154 case RES_NOSUCHQUEUE: 05155 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 05156 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 05157 res = 0; 05158 break; 05159 case RES_NOT_DYNAMIC: 05160 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface); 05161 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC"); 05162 res = 0; 05163 break; 05164 } 05165 05166 return res; 05167 }
| 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 1725 of file app_queue.c.
References ao2_iterator_destroy(), 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, member::rt_uniqueid, and member::state_interface.
Referenced by find_queue_by_name_rt(), and update_realtime_members().
01726 { 01727 struct member *m; 01728 struct ao2_iterator mem_iter; 01729 int penalty = 0; 01730 int paused = 0; 01731 int found = 0; 01732 01733 if (penalty_str) { 01734 penalty = atoi(penalty_str); 01735 if (penalty < 0) 01736 penalty = 0; 01737 } 01738 01739 if (paused_str) { 01740 paused = atoi(paused_str); 01741 if (paused < 0) 01742 paused = 0; 01743 } 01744 01745 /* Find member by realtime uniqueid and update */ 01746 mem_iter = ao2_iterator_init(q->members, 0); 01747 while ((m = ao2_iterator_next(&mem_iter))) { 01748 if (!strcasecmp(m->rt_