Mon Mar 19 11:30:32 2012

Asterisk developer's documentation


app_queue.c File Reference

True call queues with optional send URL on answer. More...

#include "asterisk.h"
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <ctype.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
#include "asterisk/monitor.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/stringfields.h"
#include "asterisk/event.h"
#include "asterisk/astobj2.h"
#include "asterisk/strings.h"
#include "asterisk/global_datastores.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/aoc.h"
#include "asterisk/callerid.h"
#include "asterisk/cel.h"
#include "asterisk/data.h"

Go to the source code of this file.

Data Structures

struct  autopause
struct  call_queue
struct  callattempt
 We define a custom "local user" structure because we use it not only for keeping track of what is in use but also for keeping track of who we're dialing. More...
struct  member
struct  penalty_rule
struct  queue_end_bridge
struct  queue_ent
struct  queue_transfer_ds
struct  rule_list
struct  rule_lists
struct  statechange
struct  strategy

Defines

#define ANNOUNCEHOLDTIME_ALWAYS   1
#define ANNOUNCEHOLDTIME_ONCE   2
#define ANNOUNCEPOSITION_LIMIT   4
#define ANNOUNCEPOSITION_MORE_THAN   3
#define ANNOUNCEPOSITION_NO   2
#define ANNOUNCEPOSITION_YES   1
#define AST_MAX_WATCHERS   256
#define DATA_EXPORT_CALL_QUEUE(MEMBER)
#define DATA_EXPORT_MEMBER(MEMBER)
#define DATA_EXPORT_QUEUE_ENT(MEMBER)
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY   15
#define DEFAULT_RETRY   5
#define DEFAULT_TIMEOUT   15
#define MAX_PERIODIC_ANNOUNCEMENTS   10
#define MAX_QUEUE_BUCKETS   53
#define PM_MAX_LEN   8192
#define QUEUE_EVENT_VARIABLES   3
#define queue_t_ref(a, b)   queue_ref(a)
#define queue_t_unref(a, b)   queue_unref(a)
#define queues_t_link(c, q, tag)   ao2_t_link(c,q,tag)
#define queues_t_unlink(c, q, tag)   ao2_t_unlink(c,q,tag)
#define RECHECK   1
#define RES_EXISTS   (-1)
#define RES_NOSUCHQUEUE   (-3)
#define RES_NOT_DYNAMIC   (-4)
#define RES_OKAY   0
#define RES_OUTOFMEMORY   (-2)

Enumerations

enum  {
  QUEUE_STRATEGY_RINGALL = 0, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_RANDOM,
  QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_WRANDOM, QUEUE_STRATEGY_RRORDERED
}
enum  { QUEUE_AUTOPAUSE_OFF = 0, QUEUE_AUTOPAUSE_ON, QUEUE_AUTOPAUSE_ALL }
enum  agent_complete_reason { CALLER, AGENT, TRANSFER }
enum  empty_conditions {
  QUEUE_EMPTY_PENALTY = (1 << 0), QUEUE_EMPTY_PAUSED = (1 << 1), QUEUE_EMPTY_INUSE = (1 << 2), QUEUE_EMPTY_RINGING = (1 << 3),
  QUEUE_EMPTY_UNAVAILABLE = (1 << 4), QUEUE_EMPTY_INVALID = (1 << 5), QUEUE_EMPTY_UNKNOWN = (1 << 6), QUEUE_EMPTY_WRAPUP = (1 << 7)
}
enum  queue_reload_mask { QUEUE_RELOAD_PARAMETERS = (1 << 0), QUEUE_RELOAD_MEMBER = (1 << 1), QUEUE_RELOAD_RULES = (1 << 2), QUEUE_RESET_STATS = (1 << 3) }
enum  queue_result {
  QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, QUEUE_JOINEMPTY = 2, QUEUE_LEAVEEMPTY = 3,
  QUEUE_JOINUNAVAIL = 4, QUEUE_LEAVEUNAVAIL = 5, QUEUE_FULL = 6, QUEUE_CONTINUE = 7
}
enum  queue_timeout_priority { TIMEOUT_PRIORITY_APP, TIMEOUT_PRIORITY_CONF }

Functions

static char * __queues_show (struct mansession *s, int fd, int argc, const char *const *argv)
 Show queue(s) status and statistics.
static void __reg_module (void)
static void __unreg_module (void)
static int add_to_queue (const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
 Add member to queue.
static struct call_queuealloc_queue (const char *queuename)
static int aqm_exec (struct ast_channel *chan, const char *data)
 AddQueueMember application.
 AST_DATA_STRUCTURE (queue_ent, DATA_EXPORT_QUEUE_ENT)
 AST_DATA_STRUCTURE (member, DATA_EXPORT_MEMBER)
 AST_DATA_STRUCTURE (call_queue, DATA_EXPORT_CALL_QUEUE)
static int attended_transfer_occurred (struct ast_channel *chan)
 mechanism to tell if a queue caller was atxferred by a queue member.
static int autopause2int (const char *autopause)
static int calc_metric (struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
 Calculate the metric of each member in the outgoing callattempts.
static void callattempt_free (struct callattempt *doomed)
static void clear_queue (struct call_queue *q)
static int clear_stats (const char *queuename)
 Facilitates resetting statistics for a queue.
static int compare_weight (struct call_queue *rq, struct member *member)
static char * complete_queue (const char *line, const char *word, int pos, int state)
static char * complete_queue_add_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_pause_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_remove_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_rule_show (const char *line, const char *word, int pos, int state)
static char * complete_queue_set_member_penalty (const char *line, const char *word, int pos, int state)
static char * complete_queue_show (const char *line, const char *word, int pos, int state)
static int compress_char (const char c)
static void copy_rules (struct queue_ent *qe, const char *rulename)
 Copy rule from global list into specified queue.
static struct membercreate_queue_member (const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
 allocate space for new queue member and set fields based on parameters passed
static void destroy_queue (void *obj)
 Free queue's member list then its string fields.
static void device_state_cb (const struct ast_event *event, void *unused)
static void do_hang (struct callattempt *o)
 common hangup actions
static void do_print (struct mansession *s, int fd, const char *str)
 direct ouput to manager or cli with proper terminator
static void dump_queue_members (struct call_queue *pm_queue)
 Dump all members in a specific queue to the database.
static void end_bridge_callback (void *data)
static void end_bridge_callback_data_fixup (struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
static int extension_state_cb (char *context, char *exten, enum ast_extension_states state, void *data)
static int extensionstate2devicestate (int state)
 Helper function which converts from extension state to device state values.
static struct callattemptfind_best (struct callattempt *outgoing)
 find the entry with the best metric, or NULL
static struct call_queuefind_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
 Reload a single queue via realtime.
static void free_members (struct call_queue *q, int all)
 Iterate through queue's member list and delete them.
static int get_member_penalty (char *queuename, char *interface)
static int get_member_status (struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions)
 Check if members are available.
static int get_queue_member_status (struct member *cur)
 Return the current state of a member.
static char * handle_queue_add_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_pause_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_remove_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_reset (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_rule_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_set_member_penalty (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int handle_statechange (void *datap)
 set a member's status based on device state of that member's interface
static void hangupcalls (struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
 Hang up a list of outgoing calls.
static void init_queue (struct call_queue *q)
 Initialize Queue default values.
static void insert_entry (struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
 Insert the 'new' entry after the 'prev' entry of queue 'q'.
static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
 Change queue penalty by adding rule.
static const char * int2strat (int strategy)
static struct memberinterface_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_queueload_realtime_queue (const char *queuename)
static int manager_add_queue_member (struct mansession *s, const struct message *m)
static int manager_pause_queue_member (struct mansession *s, const struct message *m)
static int manager_queue_log_custom (struct mansession *s, const struct message *m)
static int manager_queue_member_penalty (struct mansession *s, const struct message *m)
static int manager_queue_reload (struct mansession *s, const struct message *m)
static int manager_queue_reset (struct mansession *s, const struct message *m)
static int manager_queue_rule_show (struct mansession *s, const struct message *m)
static int manager_queues_show (struct mansession *s, const struct message *m)
static int manager_queues_status (struct mansession *s, const struct message *m)
 Queue status info via AMI.
static int manager_queues_summary (struct mansession *s, const struct message *m)
 Summary of queue info via the AMI.
static int manager_remove_queue_member (struct mansession *s, const struct message *m)
static int mark_dead_and_unfound (void *obj, void *arg, int flags)
static int mark_member_dead (void *obj, void *arg, int flags)
static int member_cmp_fn (void *obj1, void *obj2, int flags)
static int member_hash_fn (const void *obj, const int flags)
static int num_available_members (struct call_queue *q)
 Get the number of members available to accept a call.
static void parse_empty_options (const char *value, enum empty_conditions *empty, int joinempty)
static int play_file (struct ast_channel *chan, const char *filename)
static int pqm_exec (struct ast_channel *chan, const char *data)
 PauseQueueMember application.
static int ql_exec (struct ast_channel *chan, const char *data)
 QueueLog application.
static int queue_cmp_cb (void *obj, void *arg, int flags)
static int queue_exec (struct ast_channel *chan, const char *data)
 The starting point for all queue calls.
static int queue_function_exists (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Check if a given queue exists.
static int queue_function_memberpenalty_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.
static int queue_function_memberpenalty_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.
static int queue_function_qac (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Get number either busy / free / ready or total members of a specific queue.
static int queue_function_qac_dep (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Get the total number of members in a specific queue (Deprecated).
static int queue_function_queuememberlist (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue.
static int queue_function_queuewaitingcount (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue.
static int queue_function_var (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 create interface var with all queue details.
static int queue_hash_cb (const void *obj, const int flags)
static struct call_queuequeue_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_queuequeue_unref (struct call_queue *q)
static int queues_data_provider_get (const struct ast_data_search *search, struct ast_data *data_root)
static void queues_data_provider_get_helper (const struct ast_data_search *search, struct ast_data *data_root, struct call_queue *queue)
static void recalc_holdtime (struct queue_ent *qe, int newholdtime)
static void record_abandoned (struct queue_ent *qe)
 Record that a caller gave up on waiting in queue.
static int reload (void)
static int reload_handler (int reload, struct ast_flags *mask, const char *queuename)
 The command center for all reload operations.
static void reload_queue_members (void)
 Reload dynamic queue members persisted into the astdb.
static int reload_queue_rules (int reload)
 Reload the rules defined in queuerules.conf.
static int reload_queues (int reload, struct ast_flags *mask, const char *queuename)
 reload the queues.conf file
static void reload_single_member (const char *memberdata, struct call_queue *q)
 reload information pertaining to a single member
static void reload_single_queue (struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
 Reload information pertaining to a particular queue.
static int remove_from_queue (const char *queuename, const char *interface)
 Remove member from queue.
static int ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies)
 Part 2 of ring_one.
static int ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies)
 Place a call to a queue member.
static void rna (int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause)
 RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.
static int rqm_exec (struct ast_channel *chan, const char *data)
 RemoveQueueMember application.
static void rt_handle_member_record (struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface)
 Find rt member record to update otherwise create one.
static int say_periodic_announcement (struct queue_ent *qe, int ringing)
 Playback announcement to queued members if period has elapsed.
static int say_position (struct queue_ent *qe, int ringing)
static void send_agent_complete (const struct queue_ent *qe, const char *queuename, const struct ast_channel *peer, const struct member *member, time_t callstart, char *vars, size_t vars_len, enum agent_complete_reason rsn)
 Send out AMI message with member call completion status information.
static int set_member_paused (const char *queuename, const char *interface, const char *reason, int paused)
static int set_member_penalty (const char *queuename, const char *interface, int penalty)
static void set_queue_result (struct ast_channel *chan, enum queue_result res)
 sets the QUEUESTATUS channel variable
static void set_queue_variables (struct call_queue *q, struct ast_channel *chan)
 Set variables of queue.
static struct ast_datastoresetup_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 callattemptwait_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_LOAD_ORDER , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, .nonoptreq = "res_monitor", }
static char * app = "Queue"
static char * app_aqm = "AddQueueMember"
static char * app_pqm = "PauseQueueMember"
static char * app_ql = "QueueLog"
static char * app_rqm = "RemoveQueueMember"
static char * app_upqm = "UnpauseQueueMember"
static struct ast_module_infoast_module_info = &__mod_info
static int autofill_default = 1
 queues.conf [general] option
static struct autopause autopausesmodes []
static struct ast_cli_entry cli_queue []
static struct ast_event_subdevice_state_sub
 Subscription to device state change events.
static struct ast_taskprocessordevicestate_tps
static int montype_default = 0
 queues.conf [general] option
static const char *const pm_family = "Queue/PersistentMembers"
 Persistent Members astdb family.
static const char qpm_cmd_usage []
static const char qsmp_cmd_usage []
static struct ast_data_entry queue_data_providers []
static int queue_persistent_members = 0
 queues.conf [general] option
struct {
   enum queue_result   id
   char *   text
queue_results []
static struct ast_datastore_info queue_transfer_info
 a datastore used to help correctly log attended transfers of queue callers
static struct ast_custom_function queueexists_function
static struct ast_custom_function queuemembercount_dep
static struct ast_custom_function queuemembercount_function
static struct ast_custom_function queuememberlist_function
static struct ast_custom_function queuememberpenalty_function
static struct ao2_containerqueues
static struct ast_data_handler queues_data_provider
static struct ast_custom_function queuevar_function
static struct ast_custom_function queuewaitingcount_function
static const char qum_cmd_usage []
static int shared_lastcall = 1
 queues.conf [general] option
static struct strategy strategies []
static int update_cdr = 0
 queues.conf [general] option
static int use_weight = 0
 queues.conf per-queue weight option


Detailed Description

True call queues with optional send URL on answer.

Author:
Mark Spencer <markster@digium.com>
Development notes
Note:
2004-11-25: Persistent Dynamic Members added by: NetNation Communications (www.netnation.com) Kevin Lindsay <kevinl@netnation.com>
Each dynamic agent in each queue is now stored in the astdb. When asterisk is restarted, each agent will be automatically readded into their recorded queues. This feature can be configured with the 'persistent_members=<1|0>' setting in the '[general]' category in queues.conf. The default is on.

Note:
2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).

These features added by David C. Troy <dave@toad.net>:

Patch Version 1.07 2003-12-24 01

Added servicelevel statistic by Michiel Betel <michiel@betel.nl> Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>

Fixed to work with CVS as of 2004-02-25 and released as 1.07a by Matthew Enger <m.enger@xi.com.au>

Definition in file app_queue.c.


Define Documentation

#define ANNOUNCEHOLDTIME_ALWAYS   1

Definition at line 1062 of file app_queue.c.

Referenced by queue_set_param().

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 1063 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

#define ANNOUNCEPOSITION_LIMIT   4

We not announce position more than <limit>

Definition at line 1078 of file app_queue.c.

Referenced by queue_set_param(), queues_data_provider_get_helper(), and say_position().

#define ANNOUNCEPOSITION_MORE_THAN   3

We say "Currently there are more than <limit>"

Definition at line 1077 of file app_queue.c.

Referenced by queue_set_param(), queues_data_provider_get_helper(), and say_position().

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 1076 of file app_queue.c.

Referenced by queue_set_param(), and queues_data_provider_get_helper().

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 1075 of file app_queue.c.

Referenced by init_queue(), queue_set_param(), queues_data_provider_get_helper(), and say_position().

#define AST_MAX_WATCHERS   256

Definition at line 3409 of file app_queue.c.

#define DATA_EXPORT_CALL_QUEUE ( MEMBER   ) 

Definition at line 7989 of file app_queue.c.

#define DATA_EXPORT_MEMBER ( MEMBER   ) 

Definition at line 8053 of file app_queue.c.

#define DATA_EXPORT_QUEUE_ENT ( MEMBER   ) 

Definition at line 8067 of file app_queue.c.

#define DEFAULT_MIN_ANNOUNCE_FREQUENCY   15

The minimum number of seconds between position announcements \ The default value of 15 provides backwards compatibility

Definition at line 891 of file app_queue.c.

Referenced by init_queue().

#define DEFAULT_RETRY   5

Definition at line 887 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

#define DEFAULT_TIMEOUT   15

Definition at line 888 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 890 of file app_queue.c.

Referenced by destroy_queue(), init_queue(), and queue_set_param().

#define MAX_QUEUE_BUCKETS   53

Definition at line 893 of file app_queue.c.

Referenced by load_module().

#define PM_MAX_LEN   8192

Definition at line 916 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

#define QUEUE_EVENT_VARIABLES   3

Definition at line 1064 of file app_queue.c.

Referenced by queue_set_param(), ring_entry(), rna(), and send_agent_complete().

#define queue_t_ref ( a,
 )     queue_ref(a)

Definition at line 1270 of file app_queue.c.

Referenced by leave_queue().

#define queue_t_unref ( a,
 )     queue_unref(a)

Definition at line 1271 of file app_queue.c.

Referenced by __queues_show(), add_to_queue(), alloc_queue(), clear_stats(), compare_weight(), complete_queue(), complete_queue_remove_member(), end_bridge_callback(), extension_state_cb(), find_queue_by_name_rt(), get_member_penalty(), handle_statechange(), join_queue(), leave_queue(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), queue_function_exists(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), reload_queue_members(), reload_single_queue(), remove_from_queue(), set_member_paused(), set_member_penalty(), unload_module(), and update_queue().

#define queues_t_link ( c,
q,
tag   )     ao2_t_link(c,q,tag)

Definition at line 1272 of file app_queue.c.

#define queues_t_unlink ( c,
q,
tag   )     ao2_t_unlink(c,q,tag)

Definition at line 1273 of file app_queue.c.

Referenced by find_queue_by_name_rt(), leave_queue(), and unload_module().

#define RECHECK   1

Recheck every second to see we we're at the top yet

Definition at line 889 of file app_queue.c.

#define RES_EXISTS   (-1)

Entry already exists

Definition at line 896 of file app_queue.c.

Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().

#define RES_NOSUCHQUEUE   (-3)

No such queue

Definition at line 898 of file app_queue.c.

Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().

#define RES_NOT_DYNAMIC   (-4)

Member is not dynamic

Definition at line 899 of file app_queue.c.

Referenced by handle_queue_add_member(), handle_queue_remove_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().

#define RES_OKAY   0

Action completed

Definition at line 895 of file app_queue.c.

Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().

#define RES_OUTOFMEMORY   (-2)

Out of memory

Definition at line 897 of file app_queue.c.

Referenced by add_to_queue(), aqm_exec(), handle_queue_add_member(), handle_queue_remove_member(), manager_add_queue_member(), manager_remove_queue_member(), and reload_queue_members().


Enumeration Type Documentation

anonymous enum

Please read before modifying this file.
There are three locks which are regularly used throughout this file, the queue list lock, the lock for each individual queue, and the interface list lock. Please be extra careful to always lock in the following order 1) queue list lock 2) individual queue lock 3) interface list lock This order has sort of "evolved" over the lifetime of this application, but it is now in place this way, so please adhere to this order!
Enumerator:
QUEUE_STRATEGY_RINGALL 
QUEUE_STRATEGY_LEASTRECENT 
QUEUE_STRATEGY_FEWESTCALLS 
QUEUE_STRATEGY_RANDOM 
QUEUE_STRATEGY_RRMEMORY 
QUEUE_STRATEGY_LINEAR 
QUEUE_STRATEGY_WRANDOM 
QUEUE_STRATEGY_RRORDERED 

Definition at line 836 of file app_queue.c.

anonymous enum

Enumerator:
QUEUE_AUTOPAUSE_OFF 
QUEUE_AUTOPAUSE_ON 
QUEUE_AUTOPAUSE_ALL 

Definition at line 847 of file app_queue.c.

00847      {
00848      QUEUE_AUTOPAUSE_OFF = 0,
00849      QUEUE_AUTOPAUSE_ON,
00850      QUEUE_AUTOPAUSE_ALL
00851 };

enum agent_complete_reason

Enumerator:
CALLER 
AGENT 
TRANSFER 

Definition at line 4108 of file app_queue.c.

04108                            {
04109    CALLER,
04110    AGENT,
04111    TRANSFER
04112 };

enum empty_conditions

Enumerator:
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 1050 of file app_queue.c.

01050                       {
01051    QUEUE_EMPTY_PENALTY = (1 << 0),
01052    QUEUE_EMPTY_PAUSED = (1 << 1),
01053    QUEUE_EMPTY_INUSE = (1 << 2),
01054    QUEUE_EMPTY_RINGING = (1 << 3),
01055    QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
01056    QUEUE_EMPTY_INVALID = (1 << 5),
01057    QUEUE_EMPTY_UNKNOWN = (1 << 6),
01058    QUEUE_EMPTY_WRAPUP = (1 << 7),
01059 };

enum queue_reload_mask

Enumerator:
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 853 of file app_queue.c.

00853                        {
00854    QUEUE_RELOAD_PARAMETERS = (1 << 0),
00855    QUEUE_RELOAD_MEMBER = (1 << 1),
00856    QUEUE_RELOAD_RULES = (1 << 2),
00857    QUEUE_RESET_STATS = (1 << 3),
00858 };

enum queue_result

Enumerator:
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 

Definition at line 939 of file app_queue.c.

00939                   {
00940    QUEUE_UNKNOWN = 0,
00941    QUEUE_TIMEOUT = 1,
00942    QUEUE_JOINEMPTY = 2,
00943    QUEUE_LEAVEEMPTY = 3,
00944    QUEUE_JOINUNAVAIL = 4,
00945    QUEUE_LEAVEUNAVAIL = 5,
00946    QUEUE_FULL = 6,
00947    QUEUE_CONTINUE = 7,
00948 };

enum queue_timeout_priority

Enumerator:
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 964 of file app_queue.c.

00964                             {
00965    TIMEOUT_PRIORITY_APP,
00966    TIMEOUT_PRIORITY_CONF,
00967 };


Function Documentation

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 6884 of file app_queue.c.

References ao2_container_count(), ao2_iterator_destroy(), AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_category_browse(), ast_check_realtime(), ast_config_destroy(), ast_devstate2str(), ast_load_realtime_multientry(), ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_strlen_zero(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, CLI_SHOWUSAGE, CLI_SUCCESS, call_queue::count, do_print(), member::dynamic, call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, load_realtime_queue(), call_queue::maxlen, member::membername, call_queue::members, ast_channel::name, call_queue::name, queue_ent::next, member::paused, member::penalty, queue_ent::pos, queue_ent::prio, queue_t_unref, queues, member::realtime, call_queue::realtime, SENTINEL, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, call_queue::talktime, and call_queue::weight.

Referenced by manager_queues_show(), and queue_show().

06885 {
06886    struct call_queue *q;
06887    struct ast_str *out = ast_str_alloca(240);
06888    int found = 0;
06889    time_t now = time(NULL);
06890    struct ao2_iterator queue_iter;
06891    struct ao2_iterator mem_iter;
06892 
06893    if (argc != 2 && argc != 3)
06894       return CLI_SHOWUSAGE;
06895 
06896    if (argc == 3) { /* specific queue */
06897       if ((q = load_realtime_queue(argv[2]))) {
06898          queue_t_unref(q, "Done with temporary pointer");
06899       }
06900    } else if (ast_check_realtime("queues")) {
06901       /* This block is to find any queues which are defined in realtime but
06902        * which have not yet been added to the in-core container
06903        */
06904       struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
06905       char *queuename;
06906       if (cfg) {
06907          for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
06908             if ((q = load_realtime_queue(queuename))) {
06909                queue_t_unref(q, "Done with temporary pointer");
06910             }
06911          }
06912          ast_config_destroy(cfg);
06913       }
06914    }
06915 
06916    ao2_lock(queues);
06917    queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
06918    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
06919       float sl;
06920       struct call_queue *realtime_queue = NULL;
06921 
06922       ao2_lock(q);
06923       /* This check is to make sure we don't print information for realtime
06924        * queues which have been deleted from realtime but which have not yet
06925        * been deleted from the in-core container
06926        */
06927       if (q->realtime) {
06928          realtime_queue = load_realtime_queue(q->name);
06929          if (!realtime_queue) {
06930             ao2_unlock(q);
06931             queue_t_unref(q, "Done with iterator");
06932             continue;
06933          }
06934          queue_t_unref(realtime_queue, "Queue is already in memory");
06935       }
06936 
06937       if (argc == 3 && strcasecmp(q->name, argv[2])) {
06938          ao2_unlock(q);
06939          queue_t_unref(q, "Done with iterator");
06940          continue;
06941       }
06942       found = 1;
06943 
06944       ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
06945       if (q->maxlen)
06946          ast_str_append(&out, 0, "%d", q->maxlen);
06947       else
06948          ast_str_append(&out, 0, "unlimited");
06949       sl = 0;
06950       if (q->callscompleted > 0)
06951          sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
06952       ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
06953          int2strat(q->strategy), q->holdtime, q->talktime, q->weight,
06954          q->callscompleted, q->callsabandoned,sl,q->servicelevel);
06955       do_print(s, fd, ast_str_buffer(out));
06956       if (!ao2_container_count(q->members))
06957          do_print(s, fd, "   No Members");
06958       else {
06959          struct member *mem;
06960 
06961          do_print(s, fd, "   Members: ");
06962          mem_iter = ao2_iterator_init(q->members, 0);
06963          while ((mem = ao2_iterator_next(&mem_iter))) {
06964             ast_str_set(&out, 0, "      %s", mem->membername);
06965             if (strcasecmp(mem->membername, mem->interface)) {
06966                ast_str_append(&out, 0, " (%s)", mem->interface);
06967             }
06968             if (mem->penalty)
06969                ast_str_append(&out, 0, " with penalty %d", mem->penalty);
06970             ast_str_append(&out, 0, "%s%s%s (%s)",
06971                mem->dynamic ? " (dynamic)" : "",
06972                mem->realtime ? " (realtime)" : "",
06973                mem->paused ? " (paused)" : "",
06974                ast_devstate2str(mem->status));
06975             if (mem->calls)
06976                ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
06977                   mem->calls, (long) (time(NULL) - mem->lastcall));
06978             else
06979                ast_str_append(&out, 0, " has taken no calls yet");
06980             do_print(s, fd, ast_str_buffer(out));
06981             ao2_ref(mem, -1);
06982          }
06983          ao2_iterator_destroy(&mem_iter);
06984       }
06985       if (!q->head)
06986          do_print(s, fd, "   No Callers");
06987       else {
06988          struct queue_ent *qe;
06989          int pos = 1;
06990 
06991          do_print(s, fd, "   Callers: ");
06992          for (qe = q->head; qe; qe = qe->next) {
06993             ast_str_set(&out, 0, "      %d. %s (wait: %ld:%2.2ld, prio: %d)",
06994                pos++, qe->chan->name, (long) (now - qe->start) / 60,
06995                (long) (now - qe->start) % 60, qe->prio);
06996             do_print(s, fd, ast_str_buffer(out));
06997          }
06998       }
06999       do_print(s, fd, ""); /* blank line between entries */
07000       ao2_unlock(q);
07001       queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
07002    }
07003    ao2_iterator_destroy(&queue_iter);
07004    ao2_unlock(queues);
07005    if (!found) {
07006       if (argc == 3)
07007          ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
07008       else
07009          ast_str_set(&out, 0, "No queues.");
07010       do_print(s, fd, ast_str_buffer(out));
07011    }
07012    return CLI_SUCCESS;
07013 }

static void __reg_module ( void   )  [static]

Definition at line 8393 of file app_queue.c.

static void __unreg_module ( void   )  [static]

Definition at line 8393 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.

Return values:
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

Note:
Ensure the appropriate realtime queue is loaded. Note that this short-circuits if the queue is already in memory.

Definition at line 5219 of file app_queue.c.

References ao2_link, ao2_lock, ao2_ref, ao2_unlock, member::calls, create_queue_member(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, interface_exists(), member::lastcall, load_realtime_queue(), manager_event, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, queue_t_unref, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and member::status.

Referenced by aqm_exec(), handle_queue_add_member(), manager_add_queue_member(), and reload_queue_members().

05220 {
05221    struct call_queue *q;
05222    struct member *new_member, *old_member;
05223    int res = RES_NOSUCHQUEUE;
05224 
05225    /*! \note Ensure the appropriate realtime queue is loaded.  Note that this
05226     * short-circuits if the queue is already in memory. */
05227    if (!(q = load_realtime_queue(queuename)))
05228       return res;
05229 
05230    ao2_lock(q);
05231    if ((old_member = interface_exists(q, interface)) == NULL) {
05232       if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
05233          new_member->dynamic = 1;
05234          ao2_link(q->members, new_member);
05235          manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
05236             "Queue: %s\r\n"
05237             "Location: %s\r\n"
05238             "MemberName: %s\r\n"
05239             "Membership: %s\r\n"
05240             "Penalty: %d\r\n"
05241             "CallsTaken: %d\r\n"
05242             "LastCall: %d\r\n"
05243             "Status: %d\r\n"
05244             "Paused: %d\r\n",
05245             q->name, new_member->interface, new_member->membername,
05246             "dynamic",
05247             new_member->penalty, new_member->calls, (int) new_member->lastcall,
05248             new_member->status, new_member->paused);
05249          
05250          ao2_ref(new_member, -1);
05251          new_member = NULL;
05252 
05253          if (dump)
05254             dump_queue_members(q);
05255          
05256          res = RES_OKAY;
05257       } else {
05258          res = RES_OUTOFMEMORY;
05259       }
05260    } else {
05261       ao2_ref(old_member, -1);
05262       res = RES_EXISTS;
05263    }
05264    ao2_unlock(q);
05265    queue_t_unref(q, "Expiring temporary reference");
05266 
05267    return res;
05268 }

static struct call_queue* alloc_queue ( const char *  queuename  )  [static]

Definition at line 2168 of file app_queue.c.

References ao2_t_alloc, ast_string_field_init, ast_string_field_set, destroy_queue(), and queue_t_unref.

Referenced by find_queue_by_name_rt(), and reload_single_queue().

02169 {
02170    struct call_queue *q;
02171 
02172    if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
02173       if (ast_string_field_init(q, 64)) {
02174          queue_t_unref(q, "String field allocation failed");
02175          return NULL;
02176       }
02177       ast_string_field_set(q, name, queuename);
02178    }
02179    return q;
02180 }

static int aqm_exec ( struct ast_channel chan,
const char *  data 
) [static]

AddQueueMember application.

Definition at line 5651 of file app_queue.c.

References add_to_queue(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::name, parse(), pbx_builtin_setvar_helper(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and ast_channel::uniqueid.

Referenced by load_module().

05652 {
05653    int res=-1;
05654    char *parse, *temppos = NULL;
05655    AST_DECLARE_APP_ARGS(args,
05656       AST_APP_ARG(queuename);
05657       AST_APP_ARG(interface);
05658       AST_APP_ARG(penalty);
05659       AST_APP_ARG(options);
05660       AST_APP_ARG(membername);
05661       AST_APP_ARG(state_interface);
05662    );
05663    int penalty = 0;
05664 
05665    if (ast_strlen_zero(data)) {
05666       ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n");
05667       return -1;
05668    }
05669 
05670    parse = ast_strdupa(data);
05671 
05672    AST_STANDARD_APP_ARGS(args, parse);
05673 
05674    if (ast_strlen_zero(args.interface)) {
05675       args.interface = ast_strdupa(chan->name);
05676       temppos = strrchr(args.interface, '-');
05677       if (temppos)
05678          *temppos = '\0';
05679    }
05680 
05681    if (!ast_strlen_zero(args.penalty)) {
05682       if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
05683          ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
05684          penalty = 0;
05685       }
05686    }
05687 
05688    switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
05689    case RES_OKAY:
05690       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
05691       ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
05692       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
05693       res = 0;
05694       break;
05695    case RES_EXISTS:
05696       ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
05697       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
05698       res = 0;
05699       break;
05700    case RES_NOSUCHQUEUE:
05701       ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
05702       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
05703       res = 0;
05704       break;
05705    case RES_OUTOFMEMORY:
05706       ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
05707       break;
05708    }
05709 
05710    return res;
05711 }

AST_DATA_STRUCTURE ( queue_ent  ,
DATA_EXPORT_QUEUE_ENT   
)

AST_DATA_STRUCTURE ( member  ,
DATA_EXPORT_MEMBER   
)

AST_DATA_STRUCTURE ( call_queue  ,
DATA_EXPORT_CALL_QUEUE   
)

static int attended_transfer_occurred ( struct ast_channel chan  )  [static]

mechanism to tell if a queue caller was atxferred by a queue member.

When a caller is atxferred, then the queue_transfer_info datastore is removed from the channel. If it's still there after the bridge is broken, then the caller was not atxferred.

Note:
Only call this with chan locked

Definition at line 4212 of file app_queue.c.

References ast_channel_datastore_find(), and queue_transfer_info.

04213 {
04214    return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
04215 }

static int autopause2int ( const char *  autopause  )  [static]

Definition at line 1229 of file app_queue.c.

References ARRAY_LEN, ast_strlen_zero(), ast_true(), autopause::autopause, autopausesmodes, QUEUE_AUTOPAUSE_OFF, and QUEUE_AUTOPAUSE_ON.

Referenced by queue_set_param().

01230 {
01231    int x;
01232    /*This 'double check' that default value is OFF */
01233    if (ast_strlen_zero(autopause))
01234       return QUEUE_AUTOPAUSE_OFF;
01235 
01236    /*This 'double check' is to ensure old values works */
01237    if(ast_true(autopause))
01238       return QUEUE_AUTOPAUSE_ON;
01239 
01240    for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
01241       if (!strcasecmp(autopause, autopausesmodes[x].name))
01242          return autopausesmodes[x].autopause;
01243    }
01244 
01245    /*This 'double check' that default value is OFF */
01246    return QUEUE_AUTOPAUSE_OFF;
01247 }

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

Return values:
-1 if penalties are exceeded
0 otherwise

Definition at line 4039 of file app_queue.c.

References ao2_container_count(), ast_debug, ast_log(), ast_random(), member::calls, member::lastcall, queue_ent::linpos, queue_ent::linwrapped, LOG_WARNING, queue_ent::max_penalty, call_queue::members, callattempt::metric, queue_ent::min_penalty, member::penalty, call_queue::penaltymemberslimit, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, QUEUE_STRATEGY_WRANDOM, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.

04040 {
04041    /* disregarding penalty on too few members? */
04042    int membercount = ao2_container_count(q->members);
04043    unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
04044 
04045    if (usepenalty) {
04046       if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) ||
04047          (qe->min_penalty && (mem->penalty < qe->min_penalty))) {
04048          return -1;
04049       }
04050    } else {
04051       ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
04052            membercount, q->penaltymemberslimit);
04053    }
04054 
04055    switch (q->strategy) {
04056    case QUEUE_STRATEGY_RINGALL:
04057       /* Everyone equal, except for penalty */
04058       tmp->metric = mem->penalty * 1000000 * usepenalty;
04059       break;
04060    case QUEUE_STRATEGY_LINEAR:
04061       if (pos < qe->linpos) {
04062          tmp->metric = 1000 + pos;
04063       } else {
04064          if (pos > qe->linpos)
04065             /* Indicate there is another priority */
04066             qe->linwrapped = 1;
04067          tmp->metric = pos;
04068       }
04069       tmp->metric += mem->penalty * 1000000 * usepenalty;
04070       break;
04071    case QUEUE_STRATEGY_RRORDERED:
04072    case QUEUE_STRATEGY_RRMEMORY:
04073       if (pos < q->rrpos) {
04074          tmp->metric = 1000 + pos;
04075       } else {
04076          if (pos > q->rrpos)
04077             /* Indicate there is another priority */
04078             q->wrapped = 1;
04079          tmp->metric = pos;
04080       }
04081       tmp->metric += mem->penalty * 1000000 * usepenalty;
04082       break;
04083    case QUEUE_STRATEGY_RANDOM:
04084       tmp->metric = ast_random() % 1000;
04085       tmp->metric += mem->penalty * 1000000 * usepenalty;
04086       break;
04087    case QUEUE_STRATEGY_WRANDOM:
04088       tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
04089       break;
04090    case QUEUE_STRATEGY_FEWESTCALLS:
04091       tmp->metric = mem->calls;
04092       tmp->metric += mem->penalty * 1000000 * usepenalty;
04093       break;
04094    case QUEUE_STRATEGY_LEASTRECENT:
04095       if (!mem->lastcall)
04096          tmp->metric = 0;
04097       else
04098          tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
04099       tmp->metric += mem->penalty * 1000000 * usepenalty;
04100       break;
04101    default:
04102       ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
04103       break;
04104    }
04105    return 0;
04106 }

static void callattempt_free ( struct callattempt doomed  )  [static]

Definition at line 2819 of file app_queue.c.

References ao2_ref, ast_free, ast_party_connected_line_free(), callattempt::connected, and callattempt::member.

Referenced by hangupcalls().

02820 {
02821    if (doomed->member) {
02822       ao2_ref(doomed->member, -1);
02823    }
02824    ast_party_connected_line_free(&doomed->connected);
02825    ast_free(doomed);
02826 }

static void clear_queue ( struct call_queue q  )  [static]

Definition at line 1735 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::holdtime, member::lastcall, call_queue::members, and call_queue::talktime.

Referenced by clear_stats(), and find_queue_by_name_rt().

01736 {
01737    q->holdtime = 0;
01738    q->callscompleted = 0;
01739    q->callsabandoned = 0;
01740    q->callscompletedinsl = 0;
01741    q->talktime = 0;
01742 
01743    if (q->members) {
01744       struct member *mem;
01745       struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
01746       while ((mem = ao2_iterator_next(&mem_iter))) {
01747          mem->calls = 0;
01748          mem->lastcall = 0;
01749          ao2_ref(mem, -1);
01750       }
01751       ao2_iterator_destroy(&mem_iter);
01752    }
01753 }

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.

Parameters:
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
Return values:
void 

Definition at line 6823 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_t_iterator_next, ao2_unlock, ast_strlen_zero(), clear_queue(), call_queue::name, queue_t_unref, and queues.

Referenced by reload_handler().

06824 {
06825    struct call_queue *q;
06826    struct ao2_iterator queue_iter;
06827 
06828    queue_iter = ao2_iterator_init(queues, 0);
06829    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
06830       ao2_lock(q);
06831       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
06832          clear_queue(q);
06833       ao2_unlock(q);
06834       queue_t_unref(q, "Done with iterator");
06835    }
06836    ao2_iterator_destroy(&queue_iter);
06837    return 0;
06838 }

static int compare_weight ( struct call_queue rq,
struct member member 
) [static]

Definition at line 2899 of file app_queue.c.

References ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_debug, call_queue::count, member::interface, call_queue::members, call_queue::name, num_available_members(), OBJ_POINTER, queue_t_unref, queues, and call_queue::weight.

Referenced by ring_entry().

02900 {
02901    struct call_queue *q;
02902    struct member *mem;
02903    int found = 0;
02904    struct ao2_iterator queue_iter;
02905 
02906    queue_iter = ao2_iterator_init(queues, 0);
02907    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
02908       if (q == rq) { /* don't check myself, could deadlock */
02909          queue_t_unref(q, "Done with iterator");
02910          continue;
02911       }
02912       ao2_lock(q);
02913       if (q->count && q->members) {
02914          if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
02915             ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
02916             if (q->weight > rq->weight && q->count >= num_available_members(q)) {
02917                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);
02918                found = 1;
02919             }
02920             ao2_ref(mem, -1);
02921          }
02922       }
02923       ao2_unlock(q);
02924       queue_t_unref(q, "Done with iterator");
02925       if (found) {
02926          break;
02927       }
02928    }
02929    ao2_iterator_destroy(&queue_iter);
02930    return found;
02931 }

static char* complete_queue ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 7015 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_strdup, call_queue::name, queue_t_unref, and queues.

Referenced by complete_queue_add_member(), complete_queue_pause_member(), complete_queue_remove_member(), complete_queue_set_member_penalty(), complete_queue_show(), handle_queue_reload(), and handle_queue_reset().

07016 {
07017    struct call_queue *q;
07018    char *ret = NULL;
07019    int which = 0;
07020    int wordlen = strlen(word);
07021    struct ao2_iterator queue_iter;
07022 
07023    queue_iter = ao2_iterator_init(queues, 0);
07024    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07025       if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
07026          ret = ast_strdup(q->name);
07027          queue_t_unref(q, "Done with iterator");
07028          break;
07029       }
07030       queue_t_unref(q, "Done with iterator");
07031    }
07032    ao2_iterator_destroy(&queue_iter);
07033 
07034    return ret;
07035 }

static char* complete_queue_add_member ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 7461 of file app_queue.c.

References ast_malloc, ast_strdup, and complete_queue().

Referenced by handle_queue_add_member().

07462 {
07463    /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
07464    switch (pos) {
07465    case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
07466       return NULL;
07467    case 4: /* only one possible match, "to" */
07468       return state == 0 ? ast_strdup("to") : NULL;
07469    case 5: /* <queue> */
07470       return complete_queue(line, word, pos, state);
07471    case 6: /* only one possible match, "penalty" */
07472       return state == 0 ? ast_strdup("penalty") : NULL;
07473    case 7:
07474       if (state < 100) {      /* 0-99 */
07475          char *num;
07476          if ((num = ast_malloc(3))) {
07477             sprintf(num, "%d", state);
07478          }
07479          return num;
07480       } else {
07481          return NULL;
07482       }
07483    case 8: /* only one possible match, "as" */
07484       return state == 0 ? ast_strdup("as") : NULL;
07485    case 9: /* Don't attempt to complete name of member (infinite possibilities) */
07486       return NULL;
07487    default:
07488       return NULL;
07489    }
07490 }

static char* complete_queue_pause_member ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 7682 of file app_queue.c.

References ast_strdup, and complete_queue().

Referenced by handle_queue_pause_member().

07683 {
07684    /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
07685    switch (pos) {
07686    case 3:  /* Don't attempt to complete name of interface (infinite possibilities) */
07687       return NULL;
07688    case 4:  /* only one possible match, "queue" */
07689       return state == 0 ? ast_strdup("queue") : NULL;
07690    case 5:  /* <queue> */
07691       return complete_queue(line, word, pos, state);
07692    case 6: /* "reason" */
07693       return state == 0 ? ast_strdup("reason") : NULL;
07694    case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
07695       return NULL;
07696    default:
07697       return NULL;
07698    }
07699 }

static char* complete_queue_remove_member ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 7591 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_strdup, complete_queue(), member::interface, member::membername, call_queue::members, queue_t_unref, and queues.

Referenced by handle_queue_remove_member().

07592 {
07593    int which = 0;
07594    struct call_queue *q;
07595    struct member *m;
07596    struct ao2_iterator queue_iter;
07597    struct ao2_iterator mem_iter;
07598    int wordlen = strlen(word);
07599 
07600    /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
07601    if (pos > 5 || pos < 3)
07602       return NULL;
07603    if (pos == 4)   /* only one possible match, 'from' */
07604       return (state == 0 ? ast_strdup("from") : NULL);
07605 
07606    if (pos == 5)   /* No need to duplicate code */
07607       return complete_queue(line, word, pos, state);
07608 
07609    /* here is the case for 3, <member> */
07610    queue_iter = ao2_iterator_init(queues, 0);
07611    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07612       ao2_lock(q);
07613       mem_iter = ao2_iterator_init(q->members, 0);
07614       while ((m = ao2_iterator_next(&mem_iter))) {
07615          if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
07616             char *tmp;
07617             tmp = ast_strdup(m->interface);
07618             ao2_ref(m, -1);
07619             ao2_iterator_destroy(&mem_iter);
07620             ao2_unlock(q);
07621             queue_t_unref(q, "Done with iterator, returning interface name");
07622             ao2_iterator_destroy(&queue_iter);
07623             return tmp;
07624          }
07625          ao2_ref(m, -1);
07626       }
07627       ao2_iterator_destroy(&mem_iter);
07628       ao2_unlock(q);
07629       queue_t_unref(q, "Done with iterator");
07630    }
07631    ao2_iterator_destroy(&queue_iter);
07632 
07633    return NULL;
07634 }

static char* complete_queue_rule_show ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 7815 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, rule_list::list, and rule_list::name.

Referenced by handle_queue_rule_show().

07816 {
07817    int which = 0;
07818    struct rule_list *rl_iter;
07819    int wordlen = strlen(word);
07820    char *ret = NULL;
07821    if (pos != 3) /* Wha? */ {
07822       return NULL;
07823    }
07824 
07825    AST_LIST_LOCK(&rule_lists);
07826    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
07827       if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
07828          ret = ast_strdup(rl_iter->name);
07829          break;
07830       }
07831    }
07832    AST_LIST_UNLOCK(&rule_lists);
07833 
07834    return ret;
07835 }

static char* complete_queue_set_member_penalty ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 7752 of file app_queue.c.

References ast_strdup, and complete_queue().

Referenced by handle_queue_set_member_penalty().

07753 {
07754    /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
07755    switch (pos) {
07756    case 4:
07757       if (state == 0) {
07758          return ast_strdup("on");
07759       } else {
07760          return NULL;
07761       }
07762    case 6:
07763       if (state == 0) {
07764          return ast_strdup("in");
07765       } else {
07766          return NULL;
07767       }
07768    case 7:
07769       return complete_queue(line, word, pos, state);
07770    default:
07771       return NULL;
07772    }
07773 }

static char* complete_queue_show ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 7037 of file app_queue.c.

References complete_queue().

Referenced by queue_show().

07038 {
07039    if (pos == 2)
07040       return complete_queue(line, word, pos, state);
07041    return NULL;
07042 }

static int compress_char ( const char  c  )  [static]

Definition at line 1627 of file app_queue.c.

Referenced by member_hash_fn().

01628 {
01629    if (c < 32)
01630       return 0;
01631    else if (c > 96)
01632       return c - 64;
01633    else
01634       return c - 32;
01635 }

static void copy_rules ( struct queue_ent qe,
const char *  rulename 
) [static]

Copy rule from global list into specified queue.

Definition at line 5748 of file app_queue.c.

References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), call_queue::defaultrule, penalty_rule::list, rule_list::list, LOG_ERROR, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, queue_ent::parent, queue_ent::qe_rules, rule_list::rules, and penalty_rule::time.

Referenced by queue_exec().

05749 {
05750    struct penalty_rule *pr_iter;
05751    struct rule_list *rl_iter;
05752    const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
05753    AST_LIST_LOCK(&rule_lists);
05754    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
05755       if (!strcasecmp(rl_iter->name, tmp))
05756          break;
05757    }
05758    if (rl_iter) {
05759       AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
05760          struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
05761          if (!new_pr) {
05762             ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
05763             break;
05764          }
05765          new_pr->time = pr_iter->time;
05766          new_pr->max_value = pr_iter->max_value;
05767          new_pr->min_value = pr_iter->min_value;
05768          new_pr->max_relative = pr_iter->max_relative;
05769          new_pr->min_relative = pr_iter->min_relative;
05770          AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
05771       }
05772    }
05773    AST_LIST_UNLOCK(&rule_lists);
05774 }

static struct member* create_queue_member ( const char *  interface,
const char *  membername,
int  penalty,
int  paused,
const char *  state_interface 
) [static]

allocate space for new queue member and set fields based on parameters passed

Definition at line 1595 of file app_queue.c.

References ao2_alloc, ast_copy_string(), ast_log(), ast_strdupa, ast_strlen_zero(), queue_ent::context, exten, get_queue_member_status(), LOG_WARNING, member::penalty, S_OR, and strsep().

Referenced by add_to_queue(), reload_single_member(), and rt_handle_member_record().

01596 {
01597    struct member *cur;
01598    
01599    if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
01600       cur->penalty = penalty;
01601       cur->paused = paused;
01602       ast_copy_string(cur->interface, interface, sizeof(cur->interface));
01603       if (!ast_strlen_zero(state_interface))
01604          ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
01605       else
01606          ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
01607       if (!ast_strlen_zero(membername))
01608          ast_copy_string(cur->membername, membername, sizeof(cur->membername));
01609       else
01610          ast_copy_string(cur->membername, interface, sizeof(cur->membername));
01611       if (!strchr(cur->interface, '/'))
01612          ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
01613       if (!strncmp(cur->state_interface, "hint:", 5)) {
01614          char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
01615          char *exten = strsep(&context, "@") + 5;
01616 
01617          ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
01618          ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
01619       }
01620       cur->status = get_queue_member_status(cur);
01621    }
01622 
01623    return cur;
01624 }

static void destroy_queue ( void *  obj  )  [static]

Free queue's member list then its string fields.

Definition at line 2154 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().

02155 {
02156    struct call_queue *q = obj;
02157    int i;
02158 
02159    free_members(q, 1);
02160    ast_string_field_free_memory(q);
02161    for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
02162       if (q->sound_periodicannounce[i])
02163          free(q->sound_periodicannounce[i]);
02164    }
02165    ao2_ref(q->members, -1);
02166 }

static void device_state_cb ( const struct ast_event event,
void *  unused 
) [static]

Definition at line 1493 of file app_queue.c.

References ast_calloc, ast_device_state(), ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_STATE, ast_free, ast_log(), ast_strlen_zero(), ast_taskprocessor_push(), statechange::dev, devicestate_tps, handle_statechange(), LOG_ERROR, and statechange::state.

Referenced by load_module(), and load_pbx().

01494 {
01495    enum ast_device_state state;
01496    const char *device;
01497    struct statechange *sc;
01498    size_t datapsize;
01499 
01500    state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
01501    device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
01502 
01503    if (ast_strlen_zero(device)) {
01504       ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
01505       return;
01506    }
01507    datapsize = sizeof(*sc) + strlen(device) + 1;
01508    if (!(sc = ast_calloc(1, datapsize))) {
01509       ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
01510       return;
01511    }
01512    sc->state = state;
01513    strcpy(sc->dev, device);
01514    if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
01515       ast_free(sc);
01516    }
01517 }

static void do_hang ( struct callattempt o  )  [static]

common hangup actions

Definition at line 2934 of file app_queue.c.

References ast_hangup(), callattempt::chan, and callattempt::stillgoing.

Referenced by ring_entry().

02935 {
02936    o->stillgoing = 0;
02937    ast_hangup(o->chan);
02938    o->chan = NULL;
02939 }

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 6870 of file app_queue.c.

References ast_cli(), and astman_append().

Referenced by __queues_show().

06871 {
06872    if (s)
06873       astman_append(s, "%s\r\n", str);
06874    else
06875       ast_cli(fd, "%s\n", str);
06876 }

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 5124 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().

05125 {
05126    struct member *cur_member;
05127    char value[PM_MAX_LEN];
05128    int value_len = 0;
05129    int res;
05130    struct ao2_iterator mem_iter;
05131 
05132    memset(value, 0, sizeof(value));
05133 
05134    if (!pm_queue)
05135       return;
05136 
05137    mem_iter = ao2_iterator_init(pm_queue->members, 0);
05138    while ((cur_member = ao2_iterator_next(&mem_iter))) {
05139       if (!cur_member->dynamic) {
05140          ao2_ref(cur_member, -1);
05141          continue;
05142       }
05143 
05144       res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s",
05145          value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface);
05146 
05147       ao2_ref(cur_member, -1);
05148 
05149       if (res != strlen(value + value_len)) {
05150          ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
05151          break;
05152       }
05153       value_len += res;
05154    }
05155    ao2_iterator_destroy(&mem_iter);
05156    
05157    if (value_len && !cur_member) {
05158       if (ast_db_put(pm_family, pm_queue->name, value))
05159          ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
05160    } else
05161       /* Delete the entry if the queue is empty or there is an error */
05162       ast_db_del(pm_family, pm_queue->name);
05163 }

static void end_bridge_callback ( void *  data  )  [static]

Definition at line 4259 of file app_queue.c.

References ao2_ref, queue_end_bridge::chan, queue_end_bridge::q, queue_t_unref, and set_queue_variables().

04260 {
04261    struct queue_end_bridge *qeb = data;
04262    struct call_queue *q = qeb->q;
04263    struct ast_channel *chan = qeb->chan;
04264 
04265    if (ao2_ref(qeb, -1) == 1) {
04266       set_queue_variables(q, chan);
04267       /* This unrefs the reference we made in try_calling when we allocated qeb */
04268       queue_t_unref(q, "Expire bridge_config reference");
04269    }
04270 }

static void end_bridge_callback_data_fixup ( struct ast_bridge_config bconfig,
struct ast_channel originator,
struct ast_channel terminator 
) [static]

Definition at line 4252 of file app_queue.c.

References ao2_ref, queue_end_bridge::chan, and ast_bridge_config::end_bridge_callback_data.

04253 {
04254    struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
04255    ao2_ref(qeb, +1);
04256    qeb->chan = originator;
04257 }

static int extension_state_cb ( char *  context,
char *  exten,
enum ast_extension_states  state,
void *  data 
) [static]

Definition at line 1551 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_debug, ast_devstate2str(), extensionstate2devicestate(), call_queue::found, call_queue::members, queue_t_unref, queues, member::state_context, member::state_exten, and update_status().

Referenced by load_module(), and unload_module().

01552 {
01553    struct ao2_iterator miter, qiter;
01554    struct member *m;
01555    struct call_queue *q;
01556    int found = 0, device_state = extensionstate2devicestate(state);
01557 
01558    qiter = ao2_iterator_init(queues, 0);
01559    while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
01560       ao2_lock(q);
01561 
01562       miter = ao2_iterator_init(q->members, 0);
01563       for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
01564          if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
01565             update_status(q, m, device_state);
01566             ao2_ref(m, -1);
01567             found = 1;
01568             break;
01569          }
01570       }
01571       ao2_iterator_destroy(&miter);
01572 
01573       ao2_unlock(q);
01574       queue_t_unref(q, "Done with iterator");
01575    }
01576    ao2_iterator_destroy(&qiter);
01577 
01578         if (found) {
01579       ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
01580    } else {
01581       ast_debug(3, "Extension '%s@%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n",
01582            exten, context, device_state, ast_devstate2str(device_state));
01583    }
01584 
01585    return 0;
01586 }

static int extensionstate2devicestate ( int  state  )  [static]

Helper function which converts from extension state to device state values.

Definition at line 1520 of file app_queue.c.

References AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_UNAVAILABLE, AST_EXTENSION_BUSY, AST_EXTENSION_DEACTIVATED, AST_EXTENSION_INUSE, AST_EXTENSION_NOT_INUSE, AST_EXTENSION_ONHOLD, AST_EXTENSION_REMOVED, AST_EXTENSION_RINGING, and AST_EXTENSION_UNAVAILABLE.

Referenced by extension_state_cb(), and get_queue_member_status().

01521 {
01522    switch (state) {
01523    case AST_EXTENSION_NOT_INUSE:
01524       state = AST_DEVICE_NOT_INUSE;
01525       break;
01526    case AST_EXTENSION_INUSE:
01527       state = AST_DEVICE_INUSE;
01528       break;
01529    case AST_EXTENSION_BUSY:
01530       state = AST_DEVICE_BUSY;
01531       break;
01532    case AST_EXTENSION_RINGING:
01533       state = AST_DEVICE_RINGING;
01534       break;
01535    case AST_EXTENSION_ONHOLD:
01536       state = AST_DEVICE_ONHOLD;
01537       break;
01538    case AST_EXTENSION_UNAVAILABLE:
01539       state = AST_DEVICE_UNAVAILABLE;
01540       break;
01541    case AST_EXTENSION_REMOVED:
01542    case AST_EXTENSION_DEACTIVATED:
01543    default:
01544       state = AST_DEVICE_INVALID;
01545       break;
01546    }
01547 
01548    return state;
01549 }

static struct callattempt* find_best ( struct callattempt outgoing  )  [static]

find the entry with the best metric, or NULL

Definition at line 3174 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().

03175 {
03176    struct callattempt *best = NULL, *cur;
03177 
03178    for (cur = outgoing; cur; cur = cur->q_next) {
03179       if (cur->stillgoing &&              /* Not already done */
03180          !cur->chan &&              /* Isn't already going */
03181          (!best || cur->metric < best->metric)) {     /* We haven't found one yet, or it's better */
03182          best = cur;
03183       }
03184    }
03185 
03186    return best;
03187 }

static struct call_queue* find_queue_by_name_rt ( const char *  queuename,
struct ast_variable queue_vars,
struct ast_config member_config 
) [static]

Reload a single queue via realtime.

Check for statically defined queue first, check if deleted RT queue, check for new RT queue, if queue vars are not defined init them with defaults. reload RT queue vars, set RT queue members dead and reload them, return finished queue.

Return values:
the queue,
NULL if it doesn't exist.
Note:
Should be called with the "queues" container locked.

Note:
Hmm, can't seem to distinguish a DB failure from a not found condition... So we might delete an in-core queue in case of DB failure.

Definition at line 2192 of file app_queue.c.

References alloc_queue(), ao2_lock, ao2_t_find, ao2_unlock, ast_debug, ast_log(), clear_queue(), call_queue::dead, LOG_WARNING, ast_variable::name, call_queue::name, ast_variable::next, OBJ_POINTER, QUEUE_STRATEGY_RINGALL, queue_t_unref, queues, queues_t_unlink, call_queue::realtime, strat2int(), call_queue::strategy, and ast_variable::value.

Referenced by load_realtime_queue().

02193 {
02194    struct ast_variable *v;
02195    struct call_queue *q, tmpq = {
02196       .name = queuename,   
02197    };
02198    struct member *m;
02199    struct ao2_iterator mem_iter;
02200    char *interface = NULL;
02201    const char *tmp_name;
02202    char *tmp;
02203    char tmpbuf[64];  /* Must be longer than the longest queue param name. */
02204 
02205    /* Static queues override realtime. */
02206    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
02207       ao2_lock(q);
02208       if (!q->realtime) {
02209          if (q->dead) {
02210             ao2_unlock(q);
02211             queue_t_unref(q, "Queue is dead; can't return it");
02212             return NULL;
02213          } else {
02214             ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
02215             ao2_unlock(q);
02216             return q;
02217          }
02218       }
02219    } else if (!member_config)
02220       /* Not found in the list, and it's not realtime ... */
02221       return NULL;
02222 
02223    /* Check if queue is defined in realtime. */
02224    if (!queue_vars) {
02225       /* Delete queue from in-core list if it has been deleted in realtime. */
02226       if (q) {
02227          /*! \note Hmm, can't seem to distinguish a DB failure from a not
02228             found condition... So we might delete an in-core queue
02229             in case of DB failure. */
02230          ast_debug(1, "Queue %s not found in realtime.\n", queuename);
02231 
02232          q->dead = 1;
02233          /* Delete if unused (else will be deleted when last caller leaves). */
02234          queues_t_unlink(queues, q, "Unused; removing from container");
02235          ao2_unlock(q);
02236          queue_t_unref(q, "Queue is dead; can't return it");
02237       }
02238       return NULL;
02239    }
02240 
02241    /* Create a new queue if an in-core entry does not exist yet. */
02242    if (!q) {
02243       struct ast_variable *tmpvar = NULL;
02244       if (!(q = alloc_queue(queuename)))
02245          return NULL;
02246       ao2_lock(q);
02247       clear_queue(q);
02248       q->realtime = 1;
02249       /*Before we initialize the queue, we need to set the strategy, so that linear strategy
02250        * will allocate the members properly
02251        */
02252       for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
02253          if (!strcasecmp(tmpvar->name, "strategy")) {
02254             q->strategy = strat2int(tmpvar->value);
02255             if (q->strategy < 0) {
02256                ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
02257                tmpvar->value, q->name);
02258                q->strategy = QUEUE_STRATEGY_RINGALL;
02259             }
02260             break;
02261          }
02262       }
02263       /* We traversed all variables and didn't find a strategy */
02264       if (!tmpvar)
02265          q->strategy = QUEUE_STRATEGY_RINGALL;
02266       queues_t_link(queues, q, "Add queue to container");
02267    }
02268    init_queue(q);    /* Ensure defaults for all parameters not set explicitly. */
02269 
02270    memset(tmpbuf, 0, sizeof(tmpbuf));
02271    for (v = queue_vars; v; v = v->next) {
02272       /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
02273       if ((tmp = strchr(v->name, '_'))) {
02274          ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
02275          tmp_name = tmpbuf;
02276          tmp = tmpbuf;
02277          while ((tmp = strchr(tmp, '_')))
02278             *tmp++ = '-';
02279       } else
02280          tmp_name = v->name;
02281 
02282       /* NULL values don't get returned from realtime; blank values should
02283        * still get set.  If someone doesn't want a value to be set, they
02284        * should set the realtime column to NULL, not blank. */
02285       queue_set_param(q, tmp_name, v->value, -1, 0);
02286    }
02287 
02288    /* Temporarily set realtime members dead so we can detect deleted ones. */
02289    mem_iter = ao2_iterator_init(q->members, 0);
02290    while ((m = ao2_iterator_next(&mem_iter))) {
02291       if (m->realtime)
02292          m->dead = 1;
02293       ao2_ref(m, -1);
02294    }
02295    ao2_iterator_destroy(&mem_iter);
02296 
02297    while ((interface = ast_category_browse(member_config, interface))) {
02298       rt_handle_member_record(q, interface,
02299          ast_variable_retrieve(member_config, interface, "uniqueid"),
02300          S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
02301          ast_variable_retrieve(member_config, interface, "penalty"),
02302          ast_variable_retrieve(member_config, interface, "paused"),
02303          S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
02304    }
02305 
02306    /* Delete all realtime members that have been deleted in DB. */
02307    mem_iter = ao2_iterator_init(q->members, 0);
02308    while ((m = ao2_iterator_next(&mem_iter))) {
02309       if (m->dead) {
02310          ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
02311          ao2_unlink(q->members, m);
02312       }
02313       ao2_ref(m, -1);
02314    }
02315    ao2_iterator_destroy(&mem_iter);
02316 
02317    ao2_unlock(q);
02318 
02319    return q;
02320 }

static void free_members ( struct call_queue q,
int  all 
) [static]

Iterate through queue's member list and delete them.

Definition at line 2138 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ao2_unlink, member::dynamic, and call_queue::members.

Referenced by destroy_queue().

02139 {
02140    /* Free non-dynamic members */
02141    struct member *cur;
02142    struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
02143 
02144    while ((cur = ao2_iterator_next(&mem_iter))) {
02145       if (all || !cur->dynamic) {
02146          ao2_unlink(q->members, cur);
02147       }
02148       ao2_ref(cur, -1);
02149    }
02150    ao2_iterator_destroy(&mem_iter);
02151 }

static int get_member_penalty ( char *  queuename,
char *  interface 
) [static]

Definition at line 5396 of file app_queue.c.

References ao2_lock, ao2_ref, ao2_t_find, ao2_unlock, ast_log(), interface_exists(), LOG_ERROR, OBJ_POINTER, member::penalty, queue_t_unref, queues, and RESULT_FAILURE.

Referenced by queue_function_memberpenalty_read().

05397 {
05398    int foundqueue = 0, penalty;
05399    struct call_queue *q, tmpq = {
05400       .name = queuename,   
05401    };
05402    struct member *mem;
05403    
05404    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) {
05405       foundqueue = 1;
05406       ao2_lock(q);
05407       if ((mem = interface_exists(q, interface))) {
05408          penalty = mem->penalty;
05409          ao2_ref(mem, -1);
05410          ao2_unlock(q);
05411          queue_t_unref(q, "Search complete");
05412          return penalty;
05413       }
05414       ao2_unlock(q);
05415       queue_t_unref(q, "Search complete");
05416    }
05417 
05418    /* some useful debuging */
05419    if (foundqueue) 
05420       ast_log (LOG_ERROR, "Invalid queuename\n");
05421    else 
05422       ast_log (LOG_ERROR, "Invalid interface\n");
05423 
05424    return RESULT_FAILURE;
05425 }

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 1343 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_RINGING, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, member::lastcall, member::membername, call_queue::members, member::paused, member::penalty, QUEUE_EMPTY_INUSE, QUEUE_EMPTY_INVALID, QUEUE_EMPTY_PAUSED, QUEUE_EMPTY_PENALTY, QUEUE_EMPTY_RINGING, QUEUE_EMPTY_UNAVAILABLE, QUEUE_EMPTY_UNKNOWN, QUEUE_EMPTY_WRAPUP, member::status, and call_queue::wrapuptime.

Referenced by join_queue(), queue_exec(), and wait_our_turn().

01344 {
01345    struct member *member;
01346    struct ao2_iterator mem_iter;
01347 
01348    ao2_lock(q);
01349    mem_iter = ao2_iterator_init(q->members, 0);
01350    for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
01351       if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
01352          if (conditions & QUEUE_EMPTY_PENALTY) {
01353             ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
01354             continue;
01355          }
01356       }
01357 
01358       switch (member->status) {
01359       case AST_DEVICE_INVALID:
01360          if (conditions & QUEUE_EMPTY_INVALID) {
01361             ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
01362             break;
01363          }
01364          goto default_case;
01365       case AST_DEVICE_UNAVAILABLE:
01366          if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
01367             ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
01368             break;
01369          }
01370          goto default_case;
01371       case AST_DEVICE_INUSE:
01372          if (conditions & QUEUE_EMPTY_INUSE) {
01373             ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
01374             break;
01375          }
01376          goto default_case;
01377       case AST_DEVICE_RINGING:
01378          if (conditions & QUEUE_EMPTY_RINGING) {
01379             ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
01380             break;
01381          }
01382          goto default_case;
01383       case AST_DEVICE_UNKNOWN:
01384          if (conditions & QUEUE_EMPTY_UNKNOWN) {
01385             ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
01386             break;
01387          }
01388          /* Fall-through */
01389       default:
01390       default_case:
01391          if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
01392             ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
01393             break;
01394          } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
01395             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);
01396             break;
01397          } else {
01398             ao2_ref(member, -1);
01399             ao2_iterator_destroy(&mem_iter);
01400             ao2_unlock(q);
01401             ast_debug(4, "%s is available.\n", member->membername);
01402             return 0;
01403          }
01404          break;
01405       }
01406    }
01407    ao2_iterator_destroy(&mem_iter);
01408 
01409    ao2_unlock(q);
01410    return -1;
01411 }

static int get_queue_member_status ( struct member cur  )  [static]

Return the current state of a member.

Definition at line 1589 of file app_queue.c.

References ast_device_state(), ast_extension_state(), ast_strlen_zero(), extensionstate2devicestate(), member::state_context, member::state_exten, and member::state_interface.

Referenced by create_queue_member(), kill_dead_members(), and ring_entry().

01590 {
01591    return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
01592 }

static char* handle_queue_add_member ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7517 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.

07518 {
07519    const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
07520    int penalty;
07521 
07522    switch ( cmd ) {
07523    case CLI_INIT:
07524       e->command = "queue add member";
07525       e->usage =
07526          "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"
07527          "       Add a channel to a queue with optionally:  a penalty, membername and a state_interface\n";
07528       return NULL;
07529    case CLI_GENERATE:
07530       return complete_queue_add_member(a->line, a->word, a->pos, a->n);
07531    }
07532 
07533    if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
07534       return CLI_SHOWUSAGE;
07535    } else if (strcmp(a->argv[4], "to")) {
07536       return CLI_SHOWUSAGE;
07537    } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
07538       return CLI_SHOWUSAGE;
07539    } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
07540       return CLI_SHOWUSAGE;
07541    } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
07542       return CLI_SHOWUSAGE;
07543    }
07544 
07545    queuename = a->argv[5];
07546    interface = a->argv[3];
07547    if (a->argc >= 8) {
07548       if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
07549          if (penalty < 0) {
07550             ast_cli(a->fd, "Penalty must be >= 0\n");
07551             penalty = 0;
07552          }
07553       } else {
07554          ast_cli(a->fd, "Penalty must be an integer >= 0\n");
07555          penalty = 0;
07556       }
07557    } else {
07558       penalty = 0;
07559    }
07560 
07561    if (a->argc >= 10) {
07562       membername = a->argv[9];
07563    }
07564 
07565    if (a->argc >= 12) {
07566       state_interface = a->argv[11];
07567    }
07568 
07569    switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
07570    case RES_OKAY:
07571       ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
07572       ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
07573       return CLI_SUCCESS;
07574    case RES_EXISTS:
07575       ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
07576       return CLI_FAILURE;
07577    case RES_NOSUCHQUEUE:
07578       ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
07579       return CLI_FAILURE;
07580    case RES_OUTOFMEMORY:
07581       ast_cli(a->fd, "Out of memory\n");
07582       return CLI_FAILURE;
07583    case RES_NOT_DYNAMIC:
07584       ast_cli(a->fd, "Member not dynamic\n");
07585       return CLI_FAILURE;
07586    default:
07587       return CLI_FAILURE;
07588    }
07589 }

static char* handle_queue_pause_member ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7701 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.

07702 {
07703    const char *queuename, *interface, *reason;
07704    int paused;
07705 
07706    switch (cmd) {
07707    case CLI_INIT:
07708       e->command = "queue {pause|unpause} member";
07709       e->usage = 
07710          "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
07711          "  Pause or unpause a queue member. Not specifying a particular queue\n"
07712          "  will pause or unpause a member across all queues to which the member\n"
07713          "  belongs.\n";
07714       return NULL;
07715    case CLI_GENERATE:
07716       return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
07717    }
07718 
07719    if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
07720       return CLI_SHOWUSAGE;
07721    } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
07722       return CLI_SHOWUSAGE;
07723    } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
07724       return CLI_SHOWUSAGE;
07725    }
07726 
07727 
07728    interface = a->argv[3];
07729    queuename = a->argc >= 6 ? a->argv[5] : NULL;
07730    reason = a->argc == 8 ? a->argv[7] : NULL;
07731    paused = !strcasecmp(a->argv[1], "pause");
07732 
07733    if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
07734       ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
07735       if (!ast_strlen_zero(queuename))
07736          ast_cli(a->fd, " in queue '%s'", queuename);
07737       if (!ast_strlen_zero(reason))
07738          ast_cli(a->fd, " for reason '%s'", reason);
07739       ast_cli(a->fd, "\n");
07740       return CLI_SUCCESS;
07741    } else {
07742       ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
07743       if (!ast_strlen_zero(queuename))
07744          ast_cli(a->fd, " in queue '%s'", queuename);
07745       if (!ast_strlen_zero(reason))
07746          ast_cli(a->fd, " for reason '%s'", reason);
07747       ast_cli(a->fd, "\n");
07748       return CLI_FAILURE;
07749    }
07750 }

static char* handle_queue_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7910 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.

07911 {
07912    struct ast_flags mask = {0,};
07913    int i;
07914 
07915    switch (cmd) {
07916       case CLI_INIT:
07917          e->command = "queue reload {parameters|members|rules|all}";
07918          e->usage =
07919             "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
07920             "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
07921             "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
07922             "specified in order to know what information to reload. Below is an explanation\n"
07923             "of each of these qualifiers.\n"
07924             "\n"
07925             "\t'members' - reload queue members from queues.conf\n"
07926             "\t'parameters' - reload all queue options except for queue members\n"
07927             "\t'rules' - reload the queuerules.conf file\n"
07928             "\t'all' - reload queue rules, parameters, and members\n"
07929             "\n"
07930             "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
07931             "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
07932             "one queue is specified when using this command, reloading queue rules may cause\n"
07933             "other queues to be affected\n";
07934          return NULL;
07935       case CLI_GENERATE:
07936          if (a->pos >= 3) {
07937             return complete_queue(a->line, a->word, a->pos, a->n);
07938          } else {
07939             return NULL;
07940          }
07941    }
07942 
07943    if (a->argc < 3)
07944       return CLI_SHOWUSAGE;
07945 
07946    if (!strcasecmp(a->argv[2], "rules")) {
07947       ast_set_flag(&mask, QUEUE_RELOAD_RULES);
07948    } else if (!strcasecmp(a->argv[2], "members")) {
07949       ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
07950    } else if (!strcasecmp(a->argv[2], "parameters")) {
07951       ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
07952    } else if (!strcasecmp(a->argv[2], "all")) {
07953       ast_set_flag(&mask, AST_FLAGS_ALL);
07954    }
07955 
07956    if (a->argc == 3) {
07957       reload_handler(1, &mask, NULL);
07958       return CLI_SUCCESS;
07959    }
07960 
07961    for (i = 3; i < a->argc; ++i) {
07962       reload_handler(1, &mask, a->argv[i]);
07963    }
07964 
07965    return CLI_SUCCESS;
07966 }

static char* handle_queue_remove_member ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7636 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.

07637 {
07638    const char *queuename, *interface;
07639 
07640    switch (cmd) {
07641    case CLI_INIT:
07642       e->command = "queue remove member";
07643       e->usage = 
07644          "Usage: queue remove member <channel> from <queue>\n"
07645          "       Remove a specific channel from a queue.\n";
07646       return NULL;
07647    case CLI_GENERATE:
07648       return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
07649    }
07650 
07651    if (a->argc != 6) {
07652       return CLI_SHOWUSAGE;
07653    } else if (strcmp(a->argv[4], "from")) {
07654       return CLI_SHOWUSAGE;
07655    }
07656 
07657    queuename = a->argv[5];
07658    interface = a->argv[3];
07659 
07660    switch (remove_from_queue(queuename, interface)) {
07661    case RES_OKAY:
07662       ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
07663       ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
07664       return CLI_SUCCESS;
07665    case RES_EXISTS:
07666       ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
07667       return CLI_FAILURE;
07668    case RES_NOSUCHQUEUE:
07669       ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
07670       return CLI_FAILURE;
07671    case RES_OUTOFMEMORY:
07672       ast_cli(a->fd, "Out of memory\n");
07673       return CLI_FAILURE;
07674    case RES_NOT_DYNAMIC:
07675       ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
07676       return CLI_FAILURE;
07677    default:
07678       return CLI_FAILURE;
07679    }
07680 }

static char* handle_queue_reset ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7871 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.

07872 {
07873    struct ast_flags mask = {QUEUE_RESET_STATS,};
07874    int i;
07875 
07876    switch (cmd) {
07877       case CLI_INIT:
07878          e->command = "queue reset stats";
07879          e->usage =
07880             "Usage: queue reset stats [<queuenames>]\n"
07881             "\n"
07882             "Issuing this command will reset statistics for\n"
07883             "<queuenames>, or for all queues if no queue is\n"
07884             "specified.\n";
07885          return NULL;
07886       case CLI_GENERATE:
07887          if (a->pos >= 3) {
07888             return complete_queue(a->line, a->word, a->pos, a->n);
07889          } else {
07890             return NULL;
07891          }
07892    }
07893 
07894    if (a->argc < 3) {
07895       return CLI_SHOWUSAGE;
07896    }
07897 
07898    if (a->argc == 3) {
07899       reload_handler(1, &mask, NULL);
07900       return CLI_SUCCESS;
07901    }
07902 
07903    for (i = 3; i < a->argc; ++i) {
07904       reload_handler(1, &mask, a->argv[i]);
07905    }
07906 
07907    return CLI_SUCCESS;
07908 }

static char* handle_queue_rule_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7837 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_rule_show(), ast_cli_args::fd, ast_cli_args::line, penalty_rule::list, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, ast_cli_args::n, rule_list::name, ast_cli_args::pos, rule_list::rules, penalty_rule::time, ast_cli_entry::usage, and ast_cli_args::word.

07838 {
07839    const char *rule;
07840    struct rule_list *rl_iter;
07841    struct penalty_rule *pr_iter;
07842    switch (cmd) {
07843    case CLI_INIT:
07844       e->command = "queue show rules";
07845       e->usage =
07846       "Usage: queue show rules [rulename]\n"
07847       "  Show the list of rules associated with rulename. If no\n"
07848       "  rulename is specified, list all rules defined in queuerules.conf\n";
07849       return NULL;
07850    case CLI_GENERATE:
07851       return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
07852    }
07853 
07854    if (a->argc != 3 && a->argc != 4)
07855       return CLI_SHOWUSAGE;
07856 
07857    rule = a->argc == 4 ? a->argv[3] : "";
07858    AST_LIST_LOCK(&rule_lists);
07859    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
07860       if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
07861          ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
07862          AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
07863             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);
07864          }
07865       }
07866    }
07867    AST_LIST_UNLOCK(&rule_lists);
07868    return CLI_SUCCESS; 
07869 }

static char* handle_queue_set_member_penalty ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7775 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.

07776 {
07777    const char *queuename = NULL, *interface;
07778    int penalty = 0;
07779 
07780    switch (cmd) {
07781    case CLI_INIT:
07782       e->command = "queue set penalty";
07783       e->usage = 
07784       "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
07785       "  Set a member's penalty in the queue specified. If no queue is specified\n"
07786       "  then that interface's penalty is set in all queues to which that interface is a member\n";
07787       return NULL;
07788    case CLI_GENERATE:
07789       return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n);
07790    }
07791 
07792    if (a->argc != 6 && a->argc != 8) {
07793       return CLI_SHOWUSAGE;
07794    } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
07795       return CLI_SHOWUSAGE;
07796    }
07797 
07798    if (a->argc == 8)
07799       queuename = a->argv[7];
07800    interface = a->argv[5];
07801    penalty = atoi(a->argv[3]);
07802 
07803    switch (set_member_penalty(queuename, interface, penalty)) {
07804    case RESULT_SUCCESS:
07805       ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
07806       return CLI_SUCCESS;
07807    case RESULT_FAILURE:
07808       ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
07809       return CLI_FAILURE;
07810    default:
07811       return CLI_FAILURE;
07812    }
07813 }

static int handle_statechange ( void *  datap  )  [static]

set a member's status based on device state of that member's interface

Definition at line 1449 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_copy_string(), ast_debug, ast_devstate2str(), ast_free, statechange::dev, call_queue::found, call_queue::members, queue_t_unref, queues, statechange::state, member::state_interface, and update_status().

Referenced by device_state_cb().

01450 {
01451    struct statechange *sc = datap;
01452    struct ao2_iterator miter, qiter;
01453    struct member *m;
01454    struct call_queue *q;
01455    char interface[80], *slash_pos;
01456    int found = 0;
01457 
01458    qiter = ao2_iterator_init(queues, 0);
01459    while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
01460       ao2_lock(q);
01461 
01462       miter = ao2_iterator_init(q->members, 0);
01463       for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
01464          ast_copy_string(interface, m->state_interface, sizeof(interface));
01465 
01466          if ((slash_pos = strchr(interface, '/')))
01467             if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/')))
01468                *slash_pos = '\0';
01469 
01470          if (!strcasecmp(interface, sc->dev)) {
01471             found = 1;
01472             update_status(q, m, sc->state);
01473             ao2_ref(m, -1);
01474             break;
01475          }
01476       }
01477       ao2_iterator_destroy(&miter);
01478 
01479       ao2_unlock(q);
01480       queue_t_unref(q, "Done with iterator");
01481    }
01482    ao2_iterator_destroy(&qiter);
01483 
01484    if (found)
01485       ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
01486    else
01487       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));
01488 
01489    ast_free(sc);
01490    return 0;
01491 }

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 2829 of file app_queue.c.

References callattempt::aoc_s_rate_list, ast_aoc_destroy_decoded(), AST_FLAG_ANSWERED_ELSEWHERE, ast_hangup(), ast_set_flag, callattempt_free(), callattempt::chan, and callattempt::q_next.

02830 {
02831    struct callattempt *oo;
02832 
02833    while (outgoing) {
02834       /* If someone else answered the call we should indicate this in the CANCEL */
02835       /* Hangup any existing lines we have open */
02836       if (outgoing->chan && (outgoing->chan != exception)) {
02837          if (exception || cancel_answered_elsewhere)
02838             ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
02839          ast_hangup(outgoing->chan);
02840       }
02841       oo = outgoing;
02842       outgoing = outgoing->q_next;
02843       ast_aoc_destroy_decoded(oo->aoc_s_rate_list);
02844       callattempt_free(oo);
02845    }
02846 }

static void init_queue ( struct call_queue q  )  [static]

Initialize Queue default values.

Note:
the queue's lock must be held before executing this function

Definition at line 1659 of file app_queue.c.

References call_queue::announcefrequency, call_queue::announceholdtime, call_queue::announceposition, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, ao2_container_alloc, ast_free, AST_LIST_REMOVE_HEAD, ast_str_create(), ast_str_set(), ast_string_field_set, call_queue::autofill, call_queue::autopause, call_queue::dead, DEFAULT_MIN_ANNOUNCE_FREQUENCY, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::eventwhencalled, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, penalty_rule::list, call_queue::maskmemberstatus, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, member_cmp_fn(), member_hash_fn(), call_queue::memberdelay, call_queue::members, call_queue::minannouncefrequency, call_queue::monfmt, call_queue::montype, call_queue::numperiodicannounce, call_queue::penaltymemberslimit, call_queue::periodicannouncefrequency, QUEUE_AUTOPAUSE_OFF, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRORDERED, call_queue::randomperiodicannounce, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::roundingseconds, call_queue::rules, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::setqueueentryvar, call_queue::setqueuevar, call_queue::sound_periodicannounce, call_queue::strategy, call_queue::timeout, TIMEOUT_PRIORITY_APP, call_queue::timeoutpriority, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.

Referenced by reload_single_queue().

01660 {
01661    int i;
01662    struct penalty_rule *pr_iter;
01663 
01664    q->dead = 0;
01665    q->retry = DEFAULT_RETRY;
01666    q->timeout = DEFAULT_TIMEOUT;
01667    q->maxlen = 0;
01668    q->announcefrequency = 0;
01669    q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
01670    q->announceholdtime = 1;
01671    q->announcepositionlimit = 10; /* Default 10 positions */
01672    q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
01673    q->roundingseconds = 0; /* Default - don't announce seconds */
01674    q->servicelevel = 0;
01675    q->ringinuse = 1;
01676    q->setinterfacevar = 0;
01677    q->setqueuevar = 0;
01678    q->setqueueentryvar = 0;
01679    q->autofill = autofill_default;
01680    q->montype = montype_default;
01681    q->monfmt[0] = '\0';
01682    q->reportholdtime = 0;
01683    q->wrapuptime = 0;
01684    q->penaltymemberslimit = 0;
01685    q->joinempty = 0;
01686    q->leavewhenempty = 0;
01687    q->memberdelay = 0;
01688    q->maskmemberstatus = 0;
01689    q->eventwhencalled = 0;
01690    q->weight = 0;
01691    q->timeoutrestart = 0;
01692    q->periodicannouncefrequency = 0;
01693    q->randomperiodicannounce = 0;
01694    q->numperiodicannounce = 0;
01695    q->autopause = QUEUE_AUTOPAUSE_OFF;
01696    q->timeoutpriority = TIMEOUT_PRIORITY_APP;
01697    if (!q->members) {
01698       if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED)
01699          /* linear strategy depends on order, so we have to place all members in a single bucket */
01700          q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
01701       else
01702          q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
01703    }
01704    q->found = 1;
01705 
01706    ast_string_field_set(q, sound_next, "queue-youarenext");
01707    ast_string_field_set(q, sound_thereare, "queue-thereare");
01708    ast_string_field_set(q, sound_calls, "queue-callswaiting");
01709    ast_string_field_set(q, queue_quantity1, "queue-quantity1");
01710    ast_string_field_set(q, queue_quantity2, "queue-quantity2");
01711    ast_string_field_set(q, sound_holdtime, "queue-holdtime");
01712    ast_string_field_set(q, sound_minutes, "queue-minutes");
01713    ast_string_field_set(q, sound_minute, "queue-minute");
01714    ast_string_field_set(q, sound_seconds, "queue-seconds");
01715    ast_string_field_set(q, sound_thanks, "queue-thankyou");
01716    ast_string_field_set(q, sound_reporthold, "queue-reporthold");
01717 
01718    if (!q->sound_periodicannounce[0]) {
01719       q->sound_periodicannounce[0] = ast_str_create(32);
01720    }
01721 
01722    if (q->sound_periodicannounce[0]) {
01723       ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
01724    }
01725 
01726    for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
01727       if (q->sound_periodicannounce[i])
01728          ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
01729    }
01730 
01731    while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list)))
01732       ast_free(pr_iter);
01733 }

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 1313 of file app_queue.c.

References call_queue::head, queue_ent::next, and queue_ref().

Referenced by join_queue().

01314 {
01315    struct queue_ent *cur;
01316 
01317    if (!q || !new)
01318       return;
01319    if (prev) {
01320       cur = prev->next;
01321       prev->next = new;
01322    } else {
01323       cur = q->head;
01324       q->head = new;
01325    }
01326    new->next = cur;
01327 
01328    /* every queue_ent must have a reference to it's parent call_queue, this
01329     * reference does not go away until the end of the queue_ent's life, meaning
01330     * that even when the queue_ent leaves the call_queue this ref must remain. */
01331    queue_ref(q);
01332    new->parent = q;
01333    new->pos = ++(*pos);
01334    new->opos = *pos;
01335 }

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.

Return values:
-1 on failure
0 on success
Note:
Call this with the rule_lists locked

Definition at line 1764 of file app_queue.c.

References ast_calloc, ast_free, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_strdupa, ast_strlen_zero(), rule_list::list, LOG_WARNING, rule_list::name, and rule_list::rules.

Referenced by reload_queue_rules().

01765 {
01766    char *timestr, *maxstr, *minstr, *contentdup;
01767    struct penalty_rule *rule = NULL, *rule_iter;
01768    struct rule_list *rl_iter;
01769    int penaltychangetime, inserted = 0;
01770 
01771    if (!(rule = ast_calloc(1, sizeof(*rule)))) {
01772       return -1;
01773    }
01774 
01775    contentdup = ast_strdupa(content);
01776    
01777    if (!(maxstr = strchr(contentdup, ','))) {
01778       ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
01779       ast_free(rule);
01780       return -1;
01781    }
01782 
01783    *maxstr++ = '\0';
01784    timestr = contentdup;
01785 
01786    if ((penaltychangetime = atoi(timestr)) < 0) {
01787       ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
01788       ast_free(rule);
01789       return -1;
01790    }
01791 
01792    rule->time = penaltychangetime;
01793 
01794    if ((minstr = strchr(maxstr,',')))
01795       *minstr++ = '\0';
01796    
01797    /* The last check will evaluate true if either no penalty change is indicated for a given rule
01798     * OR if a min penalty change is indicated but no max penalty change is */
01799    if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
01800       rule->max_relative = 1;
01801    }
01802 
01803    rule->max_value = atoi(maxstr);
01804 
01805    if (!ast_strlen_zero(minstr)) {
01806       if (*minstr == '+' || *minstr == '-')
01807          rule->min_relative = 1;
01808       rule->min_value = atoi(minstr);
01809    } else /*there was no minimum specified, so assume this means no change*/
01810       rule->min_relative = 1;
01811 
01812    /*We have the rule made, now we need to insert it where it belongs*/
01813    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
01814       if (strcasecmp(rl_iter->name, list_name))
01815          continue;
01816 
01817       AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
01818          if (rule->time < rule_iter->time) {
01819             AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
01820             inserted = 1;
01821             break;
01822          }
01823       }
01824       AST_LIST_TRAVERSE_SAFE_END;
01825    
01826       if (!inserted) {
01827          AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
01828       }
01829    }
01830 
01831    return 0;
01832 }

static const char* int2strat ( int  strategy  )  [static]

Definition at line 1205 of file app_queue.c.

References ARRAY_LEN, strategy::name, and strategies.

Referenced by __queues_show(), manager_queues_status(), queue_function_var(), queues_data_provider_get_helper(), and set_queue_variables().

01206 {
01207    int x;
01208 
01209    for (x = 0; x < ARRAY_LEN(strategies); x++) {
01210       if (strategy == strategies[x].strategy)
01211          return strategies[x].name;
01212    }
01213 
01214    return "<unknown>";
01215 }

static struct member* interface_exists ( struct call_queue q,
const char *  interface 
) [static]

Definition at line 5098 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().

05099 {
05100    struct member *mem;
05101    struct ao2_iterator mem_iter;
05102 
05103    if (!q)
05104       return NULL;
05105 
05106    mem_iter = ao2_iterator_init(q->members, 0);
05107    while ((mem = ao2_iterator_next(&mem_iter))) {
05108       if (!strcasecmp(interface, mem->interface)) {
05109          ao2_iterator_destroy(&mem_iter);
05110          return mem;
05111       }
05112       ao2_ref(mem, -1);
05113    }
05114    ao2_iterator_destroy(&mem_iter);
05115 
05116    return NULL;
05117 }

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.

Parameters:
[in] qe The caller who wants to know if it is his turn
Return values:
0 It is not our turn
1 It is our turn

Definition at line 3840 of file app_queue.c.

References ao2_lock, ao2_unlock, ast_debug, call_queue::autofill, queue_ent::chan, call_queue::head, ast_channel::name, queue_ent::next, num_available_members(), queue_ent::parent, queue_ent::pending, and queue_ent::pos.

Referenced by queue_exec(), and wait_our_turn().

03841 {
03842    struct queue_ent *ch;
03843    int res;
03844    int avl;
03845    int idx = 0;
03846    /* This needs a lock. How many members are available to be served? */
03847    ao2_lock(qe->parent);
03848 
03849    avl = num_available_members(qe->parent);
03850 
03851    ch = qe->parent->head;
03852 
03853    ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
03854 
03855    while ((idx < avl) && (ch) && (ch != qe)) {
03856       if (!ch->pending)
03857          idx++;
03858       ch = ch->next;       
03859    }
03860 
03861    ao2_unlock(qe->parent);
03862    /* If the queue entry is within avl [the number of available members] calls from the top ... 
03863     * Autofill and position check added to support autofill=no (as only calls
03864     * from the front of the queue are valid when autofill is disabled)
03865     */
03866    if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
03867       ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
03868       res = 1;
03869    } else {
03870       ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
03871       res = 0;
03872    }
03873 
03874    return res;
03875 }

static int join_queue ( char *  queuename,
struct queue_ent qe,
enum queue_result reason,
int  position 
) [static]

Definition at line 2439 of file app_queue.c.

References queue_ent::announce, ao2_lock, ao2_unlock, ast_copy_string(), ast_debug, ast_log(), ast_manager_event, ast_channel::caller, queue_ent::chan, ast_channel::connected, queue_ent::context, call_queue::count, EVENT_FLAG_CALL, get_member_status(), call_queue::head, ast_party_connected_line::id, ast_party_caller::id, insert_entry(), call_queue::joinempty, load_realtime_queue(), LOG_NOTICE, queue_ent::max_penalty, call_queue::maxlen, queue_ent::min_penalty, queue_ent::moh, ast_party_id::name, ast_channel::name, queue_ent::next, ast_party_id::number, queue_ent::pos, queue_ent::prio, QUEUE_FULL, QUEUE_JOINEMPTY, queue_t_unref, QUEUE_UNKNOWN, S_COR, status, ast_party_name::str, ast_party_number::str, ast_channel::uniqueid, ast_party_name::valid, and ast_party_number::valid.

Referenced by queue_exec().

02440 {
02441    struct call_queue *q;
02442    struct queue_ent *cur, *prev = NULL;
02443    int res = -1;
02444    int pos = 0;
02445    int inserted = 0;
02446 
02447    if (!(q = load_realtime_queue(queuename)))
02448       return res;
02449 
02450    ao2_lock(q);
02451 
02452    /* This is our one */
02453    if (q->joinempty) {
02454       int status = 0;
02455       if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) {
02456          *reason = QUEUE_JOINEMPTY;
02457          ao2_unlock(q);
02458          queue_t_unref(q, "Done with realtime queue");
02459          return res;
02460       }
02461    }
02462    if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen))
02463       *reason = QUEUE_FULL;
02464    else if (*reason == QUEUE_UNKNOWN) {
02465       /* There's space for us, put us at the right position inside
02466        * the queue.
02467        * Take into account the priority of the calling user */
02468       inserted = 0;
02469       prev = NULL;
02470       cur = q->head;
02471       while (cur) {
02472          /* We have higher priority than the current user, enter
02473           * before him, after all the other users with priority
02474           * higher or equal to our priority. */
02475          if ((!inserted) && (qe->prio > cur->prio)) {
02476             insert_entry(q, prev, qe, &pos);
02477             inserted = 1;
02478          }
02479          /* <= is necessary for the position comparison because it may not be possible to enter
02480           * at our desired position since higher-priority callers may have taken the position we want
02481           */
02482          if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
02483             insert_entry(q, prev, qe, &pos);
02484             /*pos is incremented inside insert_entry, so don't need to add 1 here*/
02485             if (position < pos) {
02486                ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
02487             }
02488             inserted = 1;
02489          }
02490          cur->pos = ++pos;
02491          prev = cur;
02492          cur = cur->next;
02493       }
02494       /* No luck, join at the end of the queue */
02495       if (!inserted)
02496          insert_entry(q, prev, qe, &pos);
02497       ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
02498       ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
02499       ast_copy_string(qe->context, q->context, sizeof(qe->context));
02500       q->count++;
02501       res = 0;
02502       ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
02503          "Channel: %s\r\n"
02504          "CallerIDNum: %s\r\n"
02505          "CallerIDName: %s\r\n"
02506          "ConnectedLineNum: %s\r\n"
02507          "ConnectedLineName: %s\r\n"
02508          "Queue: %s\r\n"
02509          "Position: %d\r\n"
02510          "Count: %d\r\n"
02511          "Uniqueid: %s\r\n",
02512          qe->chan->name,
02513          S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
02514          S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
02515          S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
02516          S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
02517          q->name, qe->pos, q->count, qe->chan->uniqueid );
02518       ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
02519    }
02520    ao2_unlock(q);
02521    queue_t_unref(q, "Done with realtime queue");
02522 
02523    return res;
02524 }

static int kill_dead_members ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 6611 of file app_queue.c.

References CMP_MATCH, member::delme, get_queue_member_status(), and member::status.

06612 {
06613    struct member *member = obj;
06614 
06615    if (!member->delme) {
06616       member->status = get_queue_member_status(member);
06617       return 0;
06618    } else {
06619       return CMP_MATCH;
06620    }
06621 }

static int kill_dead_queues ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 6740 of file app_queue.c.

References ast_strlen_zero(), CMP_MATCH, call_queue::dead, and call_queue::name.

Referenced by reload_queues().

06741 {
06742    struct call_queue *q = obj;
06743    char *queuename = arg;
06744    if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
06745       return CMP_MATCH;
06746    } else {
06747       return 0;
06748    }
06749 }

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 2751 of file app_queue.c.

References ao2_lock, ao2_unlock, ast_debug, ast_free, AST_LIST_REMOVE_HEAD, ast_load_realtime(), ast_manager_event, ast_variables_destroy(), queue_ent::chan, call_queue::count, call_queue::dead, EVENT_FLAG_CALL, call_queue::head, penalty_rule::list, call_queue::name, ast_channel::name, queue_ent::next, queue_ent::parent, pbx_builtin_setvar_helper(), queue_ent::pos, queue_ent::qe_rules, queue_t_ref, queue_t_unref, queues, queues_t_unlink, call_queue::realtime, SENTINEL, ast_channel::uniqueid, and var.

Referenced by wait_our_turn().

02752 {
02753    struct call_queue *q;
02754    struct queue_ent *current, *prev = NULL;
02755    struct penalty_rule *pr_iter;
02756    int pos = 0;
02757 
02758    if (!(q = qe->parent))
02759       return;
02760    queue_t_ref(q, "Copy queue pointer from queue entry");
02761    ao2_lock(q);
02762 
02763    prev = NULL;
02764    for (current = q->head; current; current = current->next) {
02765       if (current == qe) {
02766          char posstr[20];
02767          q->count--;
02768 
02769          /* Take us out of the queue */
02770          ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave",
02771             "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
02772             qe->chan->name, q->name,  q->count, qe->pos, qe->chan->uniqueid);
02773          ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
02774          /* Take us out of the queue */
02775          if (prev)
02776             prev->next = current->next;
02777          else
02778             q->head = current->next;
02779          /* Free penalty rules */
02780          while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
02781             ast_free(pr_iter);
02782          snprintf(posstr, sizeof(posstr), "%d", qe->pos);
02783          pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
02784       } else {
02785          /* Renumber the people after us in the queue based on a new count */
02786          current->pos = ++pos;
02787          prev = current;
02788       }
02789    }
02790    ao2_unlock(q);
02791 
02792    /*If the queue is a realtime queue, check to see if it's still defined in real time*/
02793    if (q->realtime) {
02794       struct ast_variable *var;
02795       if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
02796          q->dead = 1;
02797       } else {
02798          ast_variables_destroy(var);
02799       }
02800    }
02801 
02802    if (q->dead) { 
02803       /* It's dead and nobody is in it, so kill it */
02804       queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
02805    }
02806    /* unref the explicit ref earlier in the function */
02807    queue_t_unref(q, "Expire copied reference");
02808 }

static int load_module ( void   )  [static]

Definition at line 8313 of file app_queue.c.

References ao2_container_alloc, aqm_exec(), ARRAY_LEN, ast_add_extension2(), ast_cli_register_multiple(), ast_context_find_or_create(), ast_custom_function_register, ast_data_register_multiple, AST_EVENT_DEVICE_STATE, AST_EVENT_IE_END, ast_event_subscribe(), ast_extension_state_add(), AST_FLAGS_ALL, ast_free_ptr, ast_log(), ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, ast_realtime_require_field(), ast_register_application_xml, ast_strdup, ast_taskprocessor_get(), cli_queue, device_state_cb(), device_state_sub, devicestate_tps, EVENT_FLAG_AGENT, extension_state_cb(), LOG_ERROR, LOG_WARNING, manager_add_queue_member(), manager_pause_queue_member(), manager_queue_log_custom(), manager_queue_member_penalty(), manager_queue_reload(), manager_queue_reset(), manager_queue_rule_show(), manager_queues_show(), manager_queues_status(), manager_queues_summary(), manager_remove_queue_member(), MAX_QUEUE_BUCKETS, pqm_exec(), ql_exec(), queue_cmp_cb(), queue_data_providers, queue_exec(), queue_hash_cb(), queueexists_function, queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queuevar_function, queuewaitingcount_function, reload_handler(), reload_queue_members(), RQ_INTEGER1, RQ_UINTEGER2, rqm_exec(), SENTINEL, and upqm_exec().

08314 {
08315    int res;
08316    struct ast_context *con;
08317    struct ast_flags mask = {AST_FLAGS_ALL, };
08318 
08319    queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
08320 
08321    use_weight = 0;
08322 
08323    if (reload_handler(0, &mask, NULL))
08324       return AST_MODULE_LOAD_DECLINE;
08325 
08326    con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
08327    if (!con)
08328       ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n");
08329    else
08330       ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue");
08331 
08332    if (queue_persistent_members)
08333       reload_queue_members();
08334 
08335    ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers));
08336 
08337    ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue));
08338    res = ast_register_application_xml(app, queue_exec);
08339    res |= ast_register_application_xml(app_aqm, aqm_exec);
08340    res |= ast_register_application_xml(app_rqm, rqm_exec);
08341    res |= ast_register_application_xml(app_pqm, pqm_exec);
08342    res |= ast_register_application_xml(app_upqm, upqm_exec);
08343    res |= ast_register_application_xml(app_ql, ql_exec);
08344    res |= ast_manager_register_xml("Queues", 0, manager_queues_show);
08345    res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
08346    res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
08347    res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member);
08348    res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member);
08349    res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member);
08350    res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom);
08351    res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty);
08352    res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
08353    res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
08354    res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
08355    res |= ast_custom_function_register(&queuevar_function);
08356    res |= ast_custom_function_register(&queueexists_function);
08357    res |= ast_custom_function_register(&queuemembercount_function);
08358    res |= ast_custom_function_register(&queuemembercount_dep);
08359    res |= ast_custom_function_register(&queuememberlist_function);
08360    res |= ast_custom_function_register(&queuewaitingcount_function);
08361    res |= ast_custom_function_register(&queuememberpenalty_function);
08362 
08363    if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) {
08364       ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
08365    }
08366 
08367    /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
08368    if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) {
08369       res = -1;
08370    }
08371 
08372    ast_extension_state_add(NULL, NULL, extension_state_cb, NULL);
08373 
08374    ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
08375 
08376    return res ? AST_MODULE_LOAD_DECLINE : 0;
08377 }

static struct call_queue* load_realtime_queue ( const char *  queuename  )  [static]

Note:
Returns a reference to the loaded realtime queue.

Note:
Load from realtime before taking the "queues" container lock, to avoid blocking all queue operations while waiting for the DB.
This will be two separate database transactions, so we might see queue parameters as they were before another process changed the queue and member list as it was after the change. Thus we might see an empty member list when a queue is deleted. In practise, this is unlikely to cause a problem.

Definition at line 2323 of file app_queue.c.

References ao2_t_find, ast_atomic_fetchadd_int(), ast_config_destroy(), ast_config_new(), ast_debug, ast_load_realtime(), ast_load_realtime_multientry(), ast_variables_destroy(), find_queue_by_name_rt(), call_queue::name, OBJ_POINTER, queue_t_unref, queues, call_queue::realtime, SENTINEL, update_realtime_members(), and call_queue::weight.

Referenced by __queues_show(), add_to_queue(), join_queue(), queue_function_exists(), queue_function_qac(), queue_function_qac_dep(), queues_data_provider_get(), and reload_queue_members().

02324 {
02325    struct ast_variable *queue_vars;
02326    struct ast_config *member_config = NULL;
02327    struct call_queue *q = NULL, tmpq = {
02328       .name = queuename,   
02329    };
02330    int prev_weight = 0;
02331 
02332    /* Find the queue in the in-core list first. */
02333    q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
02334 
02335    if (!q || q->realtime) {
02336       /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
02337          queue operations while waiting for the DB.
02338 
02339          This will be two separate database transactions, so we might
02340          see queue parameters as they were before another process
02341          changed the queue and member list as it was after the change.
02342          Thus we might see an empty member list when a queue is
02343          deleted. In practise, this is unlikely to cause a problem. */
02344 
02345       queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
02346       if (queue_vars) {
02347          member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
02348          if (!member_config) {
02349             ast_debug(1, "No queue_members defined in config extconfig.conf\n");
02350             member_config = ast_config_new();
02351          }
02352       }
02353       if (q) {
02354          prev_weight = q->weight ? 1 : 0;
02355          queue_t_unref(q, "Need to find realtime queue");
02356       }
02357 
02358       q = find_queue_by_name_rt(queuename, queue_vars, member_config);
02359       ast_config_destroy(member_config);
02360       ast_variables_destroy(queue_vars);
02361 
02362       /* update the use_weight value if the queue's has gained or lost a weight */
02363       if (q) {
02364          if (!q->weight && prev_weight) {
02365             ast_atomic_fetchadd_int(&use_weight, -1);
02366          }
02367          if (q->weight && !prev_weight) {
02368             ast_atomic_fetchadd_int(&use_weight, +1);
02369          }
02370       }
02371       /* Other cases will end up with the proper value for use_weight */
02372    } else {
02373       update_realtime_members(q);
02374    }
02375    return q;
02376 }

static int manager_add_queue_member ( struct mansession s,
const struct message m 
) [static]

Definition at line 7284 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().

07285 {
07286    const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
07287    int paused, penalty = 0;
07288 
07289    queuename = astman_get_header(m, "Queue");
07290    interface = astman_get_header(m, "Interface");
07291    penalty_s = astman_get_header(m, "Penalty");
07292    paused_s = astman_get_header(m, "Paused");
07293    membername = astman_get_header(m, "MemberName");
07294    state_interface = astman_get_header(m, "StateInterface");
07295 
07296    if (ast_strlen_zero(queuename)) {
07297       astman_send_error(s, m, "'Queue' not specified.");
07298       return 0;
07299    }
07300 
07301    if (ast_strlen_zero(interface)) {
07302       astman_send_error(s, m, "'Interface' not specified.");
07303       return 0;
07304    }
07305 
07306    if (ast_strlen_zero(penalty_s))
07307       penalty = 0;
07308    else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0)
07309       penalty = 0;
07310 
07311    if (ast_strlen_zero(paused_s))
07312       paused = 0;
07313    else
07314       paused = abs(ast_true(paused_s));
07315 
07316    switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
07317    case RES_OKAY:
07318       ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
07319       astman_send_ack(s, m, "Added interface to queue");
07320       break;
07321    case RES_EXISTS:
07322       astman_send_error(s, m, "Unable to add interface: Already there");
07323       break;
07324    case RES_NOSUCHQUEUE:
07325       astman_send_error(s, m, "Unable to add interface to queue: No such queue");
07326       break;
07327    case RES_OUTOFMEMORY:
07328       astman_send_error(s, m, "Out of memory");
07329       break;
07330    }
07331 
07332    return 0;
07333 }

static int manager_pause_queue_member ( struct mansession s,
const struct message m 
) [static]

Definition at line 7369 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().

07370 {
07371    const char *queuename, *interface, *paused_s, *reason;
07372    int paused;
07373 
07374    interface = astman_get_header(m, "Interface");
07375    paused_s = astman_get_header(m, "Paused");
07376    queuename = astman_get_header(m, "Queue");      /* Optional - if not supplied, pause the given Interface in all queues */
07377    reason = astman_get_header(m, "Reason");        /* Optional - Only used for logging purposes */
07378 
07379    if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
07380       astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
07381       return 0;
07382    }
07383 
07384    paused = abs(ast_true(paused_s));
07385 
07386    if (set_member_paused(queuename, interface, reason, paused))
07387       astman_send_error(s, m, "Interface not found");
07388    else
07389       astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
07390    return 0;
07391 }

static int manager_queue_log_custom ( struct mansession s,
const struct message m 
) [static]

Definition at line 7393 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().

07394 {
07395    const char *queuename, *event, *message, *interface, *uniqueid;
07396 
07397    queuename = astman_get_header(m, "Queue");
07398    uniqueid = astman_get_header(m, "UniqueId");
07399    interface = astman_get_header(m, "Interface");
07400    event = astman_get_header(m, "Event");
07401    message = astman_get_header(m, "Message");
07402 
07403    if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
07404       astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
07405       return 0;
07406    }
07407 
07408    ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
07409    astman_send_ack(s, m, "Event added successfully");
07410 
07411    return 0;
07412 }

static int manager_queue_member_penalty ( struct mansession s,
const struct message m 
) [static]

Definition at line 7492 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().

07493 {
07494    const char *queuename, *interface, *penalty_s;
07495    int penalty;
07496 
07497    interface = astman_get_header(m, "Interface");
07498    penalty_s = astman_get_header(m, "Penalty");
07499    /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
07500    queuename = astman_get_header(m, "Queue");
07501 
07502    if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
07503       astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
07504       return 0;
07505    }
07506  
07507    penalty = atoi(penalty_s);
07508 
07509    if (set_member_penalty((char *)queuename, (char *)interface, penalty))
07510       astman_send_error(s, m, "Invalid interface, queuename or penalty");
07511    else
07512       astman_send_ack(s, m, "Interface penalty set successfully");
07513 
07514    return 0;
07515 }

static int manager_queue_reload ( struct mansession s,
const struct message m 
) [static]

Definition at line 7414 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().

07415 {
07416    struct ast_flags mask = {0,};
07417    const char *queuename = NULL;
07418    int header_found = 0;
07419 
07420    queuename = astman_get_header(m, "Queue");
07421    if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
07422       ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
07423       header_found = 1;
07424    }
07425    if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
07426       ast_set_flag(&mask, QUEUE_RELOAD_RULES);
07427       header_found = 1;
07428    }
07429    if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
07430       ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
07431       header_found = 1;
07432    }
07433 
07434    if (!header_found) {
07435       ast_set_flag(&mask, AST_FLAGS_ALL);
07436    }
07437 
07438    if (!reload_handler(1, &mask, queuename)) {
07439       astman_send_ack(s, m, "Queue reloaded successfully");
07440    } else {
07441       astman_send_error(s, m, "Error encountered while reloading queue");
07442    }
07443    return 0;
07444 }

static int manager_queue_reset ( struct mansession s,
const struct message m 
) [static]

Definition at line 7446 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().

07447 {
07448    const char *queuename = NULL;
07449    struct ast_flags mask = {QUEUE_RESET_STATS,};
07450    
07451    queuename = astman_get_header(m, "Queue");
07452 
07453    if (!reload_handler(1, &mask, queuename)) {
07454       astman_send_ack(s, m, "Queue stats reset successfully");
07455    } else {
07456       astman_send_error(s, m, "Error encountered while resetting queue stats");
07457    }
07458    return 0;
07459 }

static int manager_queue_rule_show ( struct mansession s,
const struct message m 
) [static]

Definition at line 7073 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), penalty_rule::list, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, RESULT_SUCCESS, rule_list::rules, and penalty_rule::time.

Referenced by load_module().

07074 {
07075    const char *rule = astman_get_header(m, "Rule");
07076    const char *id = astman_get_header(m, "ActionID");
07077    struct rule_list *rl_iter;
07078    struct penalty_rule *pr_iter;
07079 
07080    astman_append(s, "Response: Success\r\n");
07081    if (!ast_strlen_zero(id)) {
07082       astman_append(s, "ActionID: %s\r\n", id);
07083    }
07084 
07085    AST_LIST_LOCK(&rule_lists);
07086    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
07087       if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
07088          astman_append(s, "RuleList: %s\r\n", rl_iter->name);
07089          AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
07090             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 );
07091          }
07092          if (!ast_strlen_zero(rule))
07093             break;
07094       }
07095    }
07096    AST_LIST_UNLOCK(&rule_lists);
07097 
07098    /*
07099     * Two blank lines instead of one because the Response and
07100     * ActionID headers used to not be present.
07101     */
07102    astman_append(s, "\r\n\r\n");
07103 
07104    return RESULT_SUCCESS;
07105 }

static int manager_queues_show ( struct mansession s,
const struct message m 
) [static]

Definition at line 7063 of file app_queue.c.

References __queues_show(), astman_append(), and RESULT_SUCCESS.

Referenced by load_module().

07064 {
07065    static const char * const a[] = { "queue", "show" };
07066 
07067    __queues_show(s, -1, 2, a);
07068    astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
07069 
07070    return RESULT_SUCCESS;
07071 }

static int manager_queues_status ( struct mansession s,
const struct message m 
) [static]

Queue status info via AMI.

Definition at line 7183 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), ast_channel::caller, member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, ast_channel::connected, call_queue::count, member::dynamic, call_queue::head, call_queue::holdtime, ast_party_connected_line::id, ast_party_caller::id, int2strat(), member::interface, member::lastcall, call_queue::maxlen, member::membername, call_queue::members, ast_party_id::name, ast_channel::name, call_queue::name, queue_ent::next, ast_party_id::number, member::paused, member::penalty, queue_t_unref, queues, RESULT_SUCCESS, S_COR, call_queue::servicelevel, queue_ent::start, member::status, ast_party_name::str, ast_party_number::str, call_queue::strategy, call_queue::talktime, ast_channel::uniqueid, ast_party_name::valid, ast_party_number::valid, and call_queue::weight.

Referenced by load_module().

07184 {
07185    time_t now;
07186    int pos;
07187    const char *id = astman_get_header(m,"ActionID");
07188    const char *queuefilter = astman_get_header(m,"Queue");
07189    const char *memberfilter = astman_get_header(m,"Member");
07190    char idText[256] = "";
07191    struct call_queue *q;
07192    struct queue_ent *qe;
07193    float sl = 0;
07194    struct member *mem;
07195    struct ao2_iterator queue_iter;
07196    struct ao2_iterator mem_iter;
07197 
07198    astman_send_ack(s, m, "Queue status will follow");
07199    time(&now);
07200    if (!ast_strlen_zero(id))
07201       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
07202 
07203    queue_iter = ao2_iterator_init(queues, 0);
07204    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07205       ao2_lock(q);
07206 
07207       /* List queue properties */
07208       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
07209          sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
07210          astman_append(s, "Event: QueueParams\r\n"
07211             "Queue: %s\r\n"
07212             "Max: %d\r\n"
07213             "Strategy: %s\r\n"
07214             "Calls: %d\r\n"
07215             "Holdtime: %d\r\n"
07216             "TalkTime: %d\r\n"
07217             "Completed: %d\r\n"
07218             "Abandoned: %d\r\n"
07219             "ServiceLevel: %d\r\n"
07220             "ServicelevelPerf: %2.1f\r\n"
07221             "Weight: %d\r\n"
07222             "%s"
07223             "\r\n",
07224             q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
07225             q->callsabandoned, q->servicelevel, sl, q->weight, idText);
07226          /* List Queue Members */
07227          mem_iter = ao2_iterator_init(q->members, 0);
07228          while ((mem = ao2_iterator_next(&mem_iter))) {
07229             if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
07230                astman_append(s, "Event: QueueMember\r\n"
07231                   "Queue: %s\r\n"
07232                   "Name: %s\r\n"
07233                   "Location: %s\r\n"
07234                   "Membership: %s\r\n"
07235                   "Penalty: %d\r\n"
07236                   "CallsTaken: %d\r\n"
07237                   "LastCall: %d\r\n"
07238                   "Status: %d\r\n"
07239                   "Paused: %d\r\n"
07240                   "%s"
07241                   "\r\n",
07242                   q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
07243                   mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
07244             }
07245             ao2_ref(mem, -1);
07246          }
07247          ao2_iterator_destroy(&mem_iter);
07248          /* List Queue Entries */
07249          pos = 1;
07250          for (qe = q->head; qe; qe = qe->next) {
07251             astman_append(s, "Event: QueueEntry\r\n"
07252                "Queue: %s\r\n"
07253                "Position: %d\r\n"
07254                "Channel: %s\r\n"
07255                "Uniqueid: %s\r\n"
07256                "CallerIDNum: %s\r\n"
07257                "CallerIDName: %s\r\n"
07258                "ConnectedLineNum: %s\r\n"
07259                "ConnectedLineName: %s\r\n"
07260                "Wait: %ld\r\n"
07261                "%s"
07262                "\r\n",
07263                q->name, pos++, qe->chan->name, qe->chan->uniqueid,
07264                S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
07265                S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
07266                S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),
07267                S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
07268                (long) (now - qe->start), idText);
07269          }
07270       }
07271       ao2_unlock(q);
07272       queue_t_unref(q, "Done with iterator");
07273    }
07274    ao2_iterator_destroy(&queue_iter);
07275 
07276    astman_append(s,
07277       "Event: QueueStatusComplete\r\n"
07278       "%s"
07279       "\r\n",idText);
07280 
07281    return RESULT_SUCCESS;
07282 }

static int manager_queues_summary ( struct mansession s,
const struct message m 
) [static]

Summary of queue info via the AMI.

Definition at line 7108 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), call_queue::head, call_queue::holdtime, call_queue::members, call_queue::name, queue_ent::next, member::paused, queue_t_unref, queues, RESULT_SUCCESS, queue_ent::start, member::status, and call_queue::talktime.

Referenced by load_module().

07109 {
07110    time_t now;
07111    int qmemcount = 0;
07112    int qmemavail = 0;
07113    int qchancount = 0;
07114    int qlongestholdtime = 0;
07115    const char *id = astman_get_header(m, "ActionID");
07116    const char *queuefilter = astman_get_header(m, "Queue");
07117    char idText[256] = "";
07118    struct call_queue *q;
07119    struct queue_ent *qe;
07120    struct member *mem;
07121    struct ao2_iterator queue_iter;
07122    struct ao2_iterator mem_iter;
07123 
07124    astman_send_ack(s, m, "Queue summary will follow");
07125    time(&now);
07126    if (!ast_strlen_zero(id))
07127       snprintf(idText, 256, "ActionID: %s\r\n", id);
07128    queue_iter = ao2_iterator_init(queues, 0);
07129    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07130       ao2_lock(q);
07131 
07132       /* List queue properties */
07133       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
07134          /* Reset the necessary local variables if no queuefilter is set*/
07135          qmemcount = 0;
07136          qmemavail = 0;
07137          qchancount = 0;
07138          qlongestholdtime = 0;
07139 
07140          /* List Queue Members */
07141          mem_iter = ao2_iterator_init(q->members, 0);
07142          while ((mem = ao2_iterator_next(&mem_iter))) {
07143             if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
07144                ++qmemcount;
07145                if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) {
07146                   ++qmemavail;
07147                }
07148             }
07149             ao2_ref(mem, -1);
07150          }
07151          ao2_iterator_destroy(&mem_iter);
07152          for (qe = q->head; qe; qe = qe->next) {
07153             if ((now - qe->start) > qlongestholdtime) {
07154                qlongestholdtime = now - qe->start;
07155             }
07156             ++qchancount;
07157          }
07158          astman_append(s, "Event: QueueSummary\r\n"
07159             "Queue: %s\r\n"
07160             "LoggedIn: %d\r\n"
07161             "Available: %d\r\n"
07162             "Callers: %d\r\n" 
07163             "HoldTime: %d\r\n"
07164             "TalkTime: %d\r\n"
07165             "LongestHoldTime: %d\r\n"
07166             "%s"
07167             "\r\n",
07168             q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
07169       }
07170       ao2_unlock(q);
07171       queue_t_unref(q, "Done with iterator");
07172    }
07173    ao2_iterator_destroy(&queue_iter);
07174    astman_append(s,
07175       "Event: QueueSummaryComplete\r\n"
07176       "%s"
07177       "\r\n", idText);
07178 
07179    return RESULT_SUCCESS;
07180 }

static int manager_remove_queue_member ( struct mansession s,
const struct message m 
) [static]

Definition at line 7335 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().

07336 {
07337    const char *queuename, *interface;
07338 
07339    queuename = astman_get_header(m, "Queue");
07340    interface = astman_get_header(m, "Interface");
07341 
07342    if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
07343       astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
07344       return 0;
07345    }
07346 
07347    switch (remove_from_queue(queuename, interface)) {
07348    case RES_OKAY:
07349       ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
07350       astman_send_ack(s, m, "Removed interface from queue");
07351       break;
07352    case RES_EXISTS:
07353       astman_send_error(s, m, "Unable to remove interface: Not there");
07354       break;
07355    case RES_NOSUCHQUEUE:
07356       astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
07357       break;
07358    case RES_OUTOFMEMORY:
07359       astman_send_error(s, m, "Out of memory");
07360       break;
07361    case RES_NOT_DYNAMIC:
07362       astman_send_error(s, m, "Member not dynamic");
07363       break;
07364    }
07365 
07366    return 0;
07367 }

static int mark_dead_and_unfound ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 6729 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().

06730 {
06731    struct call_queue *q = obj;
06732    char *queuename = arg;
06733    if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
06734       q->dead = 1;
06735       q->found = 0;
06736    }
06737    return 0;
06738 }

static int mark_member_dead ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 6602 of file app_queue.c.

References member::delme, and member::dynamic.

Referenced by reload_single_queue().

06603 {
06604    struct member *member = obj;
06605    if (!member->dynamic) {
06606       member->delme = 1;
06607    }
06608    return 0;
06609 }

static int member_cmp_fn ( void *  obj1,
void *  obj2,
int  flags 
) [static]

Definition at line 1649 of file app_queue.c.

References CMP_MATCH, CMP_STOP, and member::interface.

Referenced by init_queue().

01650 {
01651    struct member *mem1 = obj1, *mem2 = obj2;
01652    return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
01653 }

static int member_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 1637 of file app_queue.c.

References compress_char(), and member::interface.

Referenced by init_queue().

01638 {
01639    const struct member *mem = obj;
01640    const char *chname = strchr(mem->interface, '/');
01641    int ret = 0, i;
01642    if (!chname)
01643       chname = mem->interface;
01644    for (i = 0; i < 5 && chname[i]; i++)
01645       ret += compress_char(chname[i]) << (i * 6);
01646    return ret;
01647 }

static int num_available_members ( struct call_queue q  )  [static]

Get the number of members available to accept a call.

Note:
The queue passed in should be locked prior to this function call
Parameters:
[in] q The queue for which we are couting the number of available members
Returns:
Return the number of available members in queue q

Definition at line 2856 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().

02857 {
02858    struct member *mem;
02859    int avl = 0;
02860    struct ao2_iterator mem_iter;
02861 
02862    mem_iter = ao2_iterator_init(q->members, 0);
02863    while ((mem = ao2_iterator_next(&mem_iter))) {
02864       switch (mem->status) {
02865       case AST_DEVICE_INUSE:
02866          if (!q->ringinuse)
02867             break;
02868          /* else fall through */
02869       case AST_DEVICE_NOT_INUSE:
02870       case AST_DEVICE_UNKNOWN:
02871          if (!mem->paused) {
02872             avl++;
02873          }
02874          break;
02875       }
02876       ao2_ref(mem, -1);
02877 
02878       /* If autofill is not enabled or if the queue's strategy is ringall, then
02879        * we really don't care about the number of available members so much as we
02880        * do that there is at least one available.
02881        *
02882        * In fact, we purposely will return from this function stating that only
02883        * one member is available if either of those conditions hold. That way,
02884        * functions which determine what action to take based on the number of available
02885        * members will operate properly. The reasoning is that even if multiple
02886        * members are available, only the head caller can actually be serviced.
02887        */
02888       if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
02889          break;
02890       }
02891    }
02892    ao2_iterator_destroy(&mem_iter);
02893 
02894    return avl;
02895 }

static void parse_empty_options ( const char *  value,
enum empty_conditions empty,
int  joinempty 
) [static]

Definition at line 1834 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().

01835 {
01836    char *value_copy = ast_strdupa(value);
01837    char *option = NULL;
01838    while ((option = strsep(&value_copy, ","))) {
01839       if (!strcasecmp(option, "paused")) {
01840          *empty |= QUEUE_EMPTY_PAUSED;
01841       } else if (!strcasecmp(option, "penalty")) {
01842          *empty |= QUEUE_EMPTY_PENALTY;
01843       } else if (!strcasecmp(option, "inuse")) {
01844          *empty |= QUEUE_EMPTY_INUSE;
01845       } else if (!strcasecmp(option, "ringing")) {
01846          *empty |= QUEUE_EMPTY_RINGING;
01847       } else if (!strcasecmp(option, "invalid")) {
01848          *empty |= QUEUE_EMPTY_INVALID;
01849       } else if (!strcasecmp(option, "wrapup")) {
01850          *empty |= QUEUE_EMPTY_WRAPUP;
01851       } else if (!strcasecmp(option, "unavailable")) {
01852          *empty |= QUEUE_EMPTY_UNAVAILABLE;
01853       } else if (!strcasecmp(option, "unknown")) {
01854          *empty |= QUEUE_EMPTY_UNKNOWN;
01855       } else if (!strcasecmp(option, "loose")) {
01856          *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID);
01857       } else if (!strcasecmp(option, "strict")) {
01858          *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE);
01859       } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
01860          *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED);
01861       } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
01862          *empty = 0;
01863       } else {
01864          ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
01865       }
01866    }
01867 }

static int play_file ( struct ast_channel chan,
const char *  filename 
) [static]

Definition at line 2526 of file app_queue.c.

References AST_DIGIT_ANY, ast_fileexists(), ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_waitstream(), queue_ent::chan, and ast_channel::language.

Referenced by say_periodic_announcement(), and say_position().

02527 {
02528    int res;
02529 
02530    if (ast_strlen_zero(filename)) {
02531       return 0;
02532    }
02533 
02534    if (!ast_fileexists(filename, NULL, chan->language)) {
02535       return 0;
02536    }
02537 
02538    ast_stopstream(chan);
02539 
02540    res = ast_streamfile(chan, filename, chan->language);
02541    if (!res)
02542       res = ast_waitstream(chan, AST_DIGIT_ANY);
02543 
02544    ast_stopstream(chan);
02545 
02546    return res;
02547 }

static int pqm_exec ( struct ast_channel chan,
const char *  data 
) [static]

PauseQueueMember application.

Definition at line 5522 of file app_queue.c.

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, parse(), pbx_builtin_setvar_helper(), and set_member_paused().

Referenced by load_module().

05523 {
05524    char *parse;
05525    AST_DECLARE_APP_ARGS(args,
05526       AST_APP_ARG(queuename);
05527       AST_APP_ARG(interface);
05528       AST_APP_ARG(options);
05529       AST_APP_ARG(reason);
05530    );
05531 
05532    if (ast_strlen_zero(data)) {
05533       ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
05534       return -1;
05535    }
05536 
05537    parse = ast_strdupa(data);
05538 
05539    AST_STANDARD_APP_ARGS(args, parse);
05540 
05541    if (ast_strlen_zero(args.interface)) {
05542       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
05543       return -1;
05544    }
05545 
05546    if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
05547       ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
05548       pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
05549       return 0;
05550    }
05551 
05552    pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
05553 
05554    return 0;
05555 }

static int ql_exec ( struct ast_channel chan,
const char *  data 
) [static]

QueueLog application.

Definition at line 5714 of file app_queue.c.

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, and parse().

Referenced by load_module().

05715 {
05716    char *parse;
05717 
05718    AST_DECLARE_APP_ARGS(args,
05719       AST_APP_ARG(queuename);
05720       AST_APP_ARG(uniqueid);
05721       AST_APP_ARG(membername);
05722       AST_APP_ARG(event);
05723       AST_APP_ARG(params);
05724    );
05725 
05726    if (ast_strlen_zero(data)) {
05727       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
05728       return -1;
05729    }
05730 
05731    parse = ast_strdupa(data);
05732 
05733    AST_STANDARD_APP_ARGS(args, parse);
05734 
05735    if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
05736        || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
05737       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
05738       return -1;
05739    }
05740 
05741    ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 
05742       "%s", args.params ? args.params : "");
05743 
05744    return 0;
05745 }

static int queue_cmp_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1256 of file app_queue.c.

References CMP_MATCH, CMP_STOP, and call_queue::name.

Referenced by load_module().

01257 {
01258    struct call_queue *q = obj, *q2 = arg;
01259    return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
01260 }

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 5788 of file app_queue.c.

References call_queue::announcefrequency, ao2_container_count(), args, AST_APP_ARG, ast_channel_lock, ast_channel_unlock, AST_CONTROL_RINGING, ast_debug, AST_DECLARE_APP_ARGS, ast_indicate(), AST_LIST_FIRST, ast_log(), ast_moh_start(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::caller, queue_ent::chan, copy_rules(), queue_ent::expire, get_member_status(), ast_party_caller::id, is_our_turn(), join_queue(), queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::last_pos, queue_ent::last_pos_said, call_queue::leavewhenempty, LOG_WARNING, queue_ent::max_penalty, call_queue::members, queue_ent::min_penalty, queue_ent::moh, call_queue::name, ast_channel::name, ast_party_id::number, queue_ent::opos, queue_ent::parent, parse(), pbx_builtin_getvar_helper(), call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::pr, queue_ent::prio, queue_ent::qe_rules, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), queue_ent::ring_when_ringing, S_COR, S_OR, say_periodic_announcement(), say_position(), set_queue_result(), queue_ent::start, status, stop, ast_party_number::str, penalty_rule::time, try_calling(), ast_channel::uniqueid, update_qe_rule(), update_realtime_members(), url, ast_party_number::valid, queue_ent::valid_digits, wait_a_bit(), and wait_our_turn().

Referenced by load_module().

05789 {
05790    int res=-1;
05791    int ringing=0;
05792    const char *user_priority;
05793    const char *max_penalty_str;
05794    const char *min_penalty_str;
05795    int prio;
05796    int qcontinue = 0;
05797    int max_penalty, min_penalty;
05798    enum queue_result reason = QUEUE_UNKNOWN;
05799    /* whether to exit Queue application after the timeout hits */
05800    int tries = 0;
05801    int noption = 0;
05802    char *parse;
05803    int makeannouncement = 0;
05804    int position = 0;
05805    AST_DECLARE_APP_ARGS(args,
05806       AST_APP_ARG(queuename);
05807       AST_APP_ARG(options);
05808       AST_APP_ARG(url);
05809       AST_APP_ARG(announceoverride);
05810       AST_APP_ARG(queuetimeoutstr);
05811       AST_APP_ARG(agi);
05812       AST_APP_ARG(macro);
05813       AST_APP_ARG(gosub);
05814       AST_APP_ARG(rule);
05815       AST_APP_ARG(position);
05816    );
05817    /* Our queue entry */
05818    struct queue_ent qe = { 0 };
05819    
05820    if (ast_strlen_zero(data)) {
05821       ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
05822       return -1;
05823    }
05824    
05825    parse = ast_strdupa(data);
05826    AST_STANDARD_APP_ARGS(args, parse);
05827 
05828    /* Setup our queue entry */
05829    qe.start = time(NULL);
05830 
05831    /* set the expire time based on the supplied timeout; */
05832    if (!ast_strlen_zero(args.queuetimeoutstr))
05833       qe.expire = qe.start + atoi(args.queuetimeoutstr);
05834    else
05835       qe.expire = 0;
05836 
05837    /* Get the priority from the variable ${QUEUE_PRIO} */
05838    ast_channel_lock(chan);
05839    user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
05840    if (user_priority) {
05841       if (sscanf(user_priority, "%30d", &prio) == 1) {
05842          ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio);
05843       } else {
05844          ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
05845             user_priority, chan->name);
05846          prio = 0;
05847       }
05848    } else {
05849       ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
05850       prio = 0;
05851    }
05852 
05853    /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
05854 
05855    if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
05856       if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
05857          ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty);
05858       } else {
05859          ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
05860             max_penalty_str, chan->name);
05861          max_penalty = 0;
05862       }
05863    } else {
05864       max_penalty = 0;
05865    }
05866 
05867    if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
05868       if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
05869          ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty);
05870       } else {
05871          ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
05872             min_penalty_str, chan->name);
05873          min_penalty = 0;
05874       }
05875    } else {
05876       min_penalty = 0;
05877    }
05878    ast_channel_unlock(chan);
05879 
05880    if (args.options && (strchr(args.options, 'r')))
05881       ringing = 1;
05882 
05883    if (ringing != 1 && args.options && (strchr(args.options, 'R'))) {
05884       qe.ring_when_ringing = 1;
05885    }
05886 
05887    if (args.options && (strchr(args.options, 'c')))
05888       qcontinue = 1;
05889 
05890    if (args.position) {
05891       position = atoi(args.position);
05892       if (position < 0) {
05893          ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
05894          position = 0;
05895       }
05896    }
05897 
05898    ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
05899       args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
05900 
05901    qe.chan = chan;
05902    qe.prio = prio;
05903    qe.max_penalty = max_penalty;
05904    qe.min_penalty = min_penalty;
05905    qe.last_pos_said = 0;
05906    qe.last_pos = 0;
05907    qe.last_periodic_announce_time = time(NULL);
05908    qe.last_periodic_announce_sound = 0;
05909    qe.valid_digits = 0;
05910    if (join_queue(args.queuename, &qe, &reason, position)) {
05911       ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
05912       set_queue_result(chan, reason);
05913       return 0;
05914    }
05915    ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d",
05916       S_OR(args.url, ""),
05917       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
05918       qe.opos);
05919    copy_rules(&qe, args.rule);
05920    qe.pr = AST_LIST_FIRST(&qe.qe_rules);
05921 check_turns:
05922    if (ringing) {
05923       ast_indicate(chan, AST_CONTROL_RINGING);
05924    } else {
05925       ast_moh_start(chan, qe.moh, NULL);
05926    }
05927 
05928    /* This is the wait loop for callers 2 through maxlen */
05929    res = wait_our_turn(&qe, ringing, &reason);
05930    if (res) {
05931       goto stop;
05932    }
05933 
05934    makeannouncement = 0;
05935 
05936    for (;;) {
05937       /* This is the wait loop for the head caller*/
05938       /* To exit, they may get their call answered; */
05939       /* they may dial a digit from the queue context; */
05940       /* or, they may timeout. */
05941 
05942       /* Leave if we have exceeded our queuetimeout */
05943       if (qe.expire && (time(NULL) >= qe.expire)) {
05944          record_abandoned(&qe);
05945          reason = QUEUE_TIMEOUT;
05946          res = 0;
05947          ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 
05948             qe.pos, qe.opos, (long) time(NULL) - qe.start);
05949          break;
05950       }
05951 
05952       if (makeannouncement) {
05953          /* Make a position announcement, if enabled */
05954          if (qe.parent->announcefrequency)
05955             if ((res = say_position(&qe,ringing)))
05956                goto stop;
05957       }
05958       makeannouncement = 1;
05959 
05960       /* Make a periodic announcement, if enabled */
05961       if (qe.parent->periodicannouncefrequency)
05962          if ((res = say_periodic_announcement(&qe,ringing)))
05963             goto stop;
05964    
05965       /* Leave if we have exceeded our queuetimeout */
05966       if (qe.expire && (time(NULL) >= qe.expire)) {
05967          record_abandoned(&qe);
05968          reason = QUEUE_TIMEOUT;
05969          res = 0;
05970          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
05971          break;
05972       }
05973 
05974       /* see if we need to move to the next penalty level for this queue */
05975       while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
05976          update_qe_rule(&qe);
05977       }
05978 
05979       /* Try calling all queue members for 'timeout' seconds */
05980       res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
05981       if (res) {
05982          goto stop;
05983       }
05984 
05985       if (qe.parent->leavewhenempty) {
05986          int status = 0;
05987          if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty))) {
05988             record_abandoned(&qe);
05989             reason = QUEUE_LEAVEEMPTY;
05990             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
05991             res = 0;
05992             break;
05993          }
05994       }
05995 
05996       /* exit after 'timeout' cycle if 'n' option enabled */
05997       if (noption && tries >= ao2_container_count(qe.parent->members)) {
05998          ast_verb(3, "Exiting on time-out cycle\n");
05999          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
06000          record_abandoned(&qe);
06001          reason = QUEUE_TIMEOUT;
06002          res = 0;
06003          break;
06004       }
06005 
06006       
06007       /* Leave if we have exceeded our queuetimeout */
06008       if (qe.expire && (time(NULL) >= qe.expire)) {
06009          record_abandoned(&qe);
06010          reason = QUEUE_TIMEOUT;
06011          res = 0;
06012          ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start);
06013          break;
06014       }
06015 
06016       /* If using dynamic realtime members, we should regenerate the member list for this queue */
06017       update_realtime_members(qe.parent);
06018       /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
06019       res = wait_a_bit(&qe);
06020       if (res)
06021          goto stop;
06022 
06023       /* Since this is a priority queue and
06024        * it is not sure that we are still at the head
06025        * of the queue, go and check for our turn again.
06026        */
06027       if (!is_our_turn(&qe)) {
06028          ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name);
06029          goto check_turns;
06030       }
06031    }
06032 
06033 stop:
06034    if (res) {
06035       if (res < 0) {
06036          if (!qe.handled) {
06037             record_abandoned(&qe);
06038             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
06039                "%d|%d|%ld", qe.pos, qe.opos,
06040                (long) time(NULL) - qe.start);
06041             res = -1;
06042          } else if (qcontinue) {
06043             reason = QUEUE_CONTINUE;
06044             res = 0;
06045          }
06046       } else if (qe.valid_digits) {
06047          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
06048             "%s|%d", qe.digits, qe.pos);
06049       }
06050    }
06051 
06052    /* Don't allow return code > 0 */
06053    if (res >= 0) {
06054       res = 0; 
06055       if (ringing) {
06056          ast_indicate(chan, -1);
06057       } else {
06058          ast_moh_stop(chan);
06059       }        
06060       ast_stopstream(chan);
06061    }
06062 
06063    set_queue_variables(qe.parent, qe.chan);
06064 
06065    leave_queue(&qe);
06066    if (reason != QUEUE_UNKNOWN)
06067       set_queue_result(chan, reason);
06068 
06069    if (qe.parent) {
06070       /* every queue_ent is given a reference to it's parent call_queue when it joins the queue.
06071        * This ref must be taken away right before the queue_ent is destroyed.  In this case
06072        * the queue_ent is about to be returned on the stack */
06073       qe.parent = queue_unref(qe.parent);
06074    }
06075 
06076    return res;
06077 }

static int queue_function_exists ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Check if a given queue exists.

Definition at line 6131 of file app_queue.c.

References ast_log(), ast_strlen_zero(), load_realtime_queue(), LOG_ERROR, and queue_t_unref.

06132 {
06133    struct call_queue *q;
06134 
06135    buf[0] = '\0';
06136 
06137    if (ast_strlen_zero(data)) {
06138       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06139       return -1;
06140    }
06141    q = load_realtime_queue(data);
06142    snprintf(buf, len, "%d", q != NULL? 1 : 0);
06143    if (q) {
06144       queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
06145    }
06146 
06147    return 0;
06148 }

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 6350 of file app_queue.c.

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), get_member_penalty(), and LOG_ERROR.

06351 {
06352    int penalty;
06353    AST_DECLARE_APP_ARGS(args,
06354       AST_APP_ARG(queuename);
06355       AST_APP_ARG(interface);
06356    );
06357    /* Make sure the returned value on error is NULL. */
06358    buf[0] = '\0';
06359 
06360    if (ast_strlen_zero(data)) {
06361       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06362       return -1;
06363    }
06364 
06365    AST_STANDARD_APP_ARGS(args, data);
06366 
06367    if (args.argc < 2) {
06368       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06369       return -1;
06370    }
06371 
06372    penalty = get_member_penalty (args.queuename, args.interface);
06373    
06374    if (penalty >= 0) /* remember that buf is already '\0' */
06375       snprintf (buf, len, "%d", penalty);
06376 
06377    return 0;
06378 }

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 6381 of file app_queue.c.

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), LOG_ERROR, and set_member_penalty().

06382 {
06383    int penalty;
06384    AST_DECLARE_APP_ARGS(args,
06385       AST_APP_ARG(queuename);
06386       AST_APP_ARG(interface);
06387    );
06388 
06389    if (ast_strlen_zero(data)) {
06390       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06391       return -1;
06392    }
06393 
06394    AST_STANDARD_APP_ARGS(args, data);
06395 
06396    if (args.argc < 2) {
06397       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06398       return -1;
06399    }
06400 
06401    penalty = atoi(value);
06402 
06403    if (ast_strlen_zero(args.interface)) {
06404       ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
06405       return -1;
06406    }
06407 
06408    /* if queuename = NULL then penalty will be set for interface in all the queues. */
06409    if (set_member_penalty(args.queuename, args.interface, penalty)) {
06410       ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
06411       return -1;
06412    }
06413 
06414    return 0;
06415 }

static int queue_function_qac ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Get number either busy / free / ready or total members of a specific queue.

Return values:
number of members (busy / free / ready / total)
-1 on error

Definition at line 6155 of file app_queue.c.

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_log(), ast_strlen_zero(), call_queue::count, member::lastcall, load_realtime_queue(), LOG_ERROR, LOG_WARNING, member::paused, queue_t_unref, and member::status.

06156 {
06157    int count = 0;
06158    struct member *m;
06159    struct ao2_iterator mem_iter;
06160    struct call_queue *q;
06161    char *option;
06162 
06163    if (ast_strlen_zero(data)) {
06164       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06165       return -1;
06166    }
06167 
06168    if ((option = strchr(data, ',')))
06169       *option++ = '\0';
06170    else
06171       option = "logged";
06172    if ((q = load_realtime_queue(data))) {
06173       ao2_lock(q);
06174       if (!strcasecmp(option, "logged")) {
06175          mem_iter = ao2_iterator_init(q->members, 0);
06176          while ((m = ao2_iterator_next(&mem_iter))) {
06177             /* Count the agents who are logged in and presently answering calls */
06178             if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
06179                count++;
06180             }
06181             ao2_ref(m, -1);
06182          }
06183          ao2_iterator_destroy(&mem_iter);
06184       } else if (!strcasecmp(option, "free")) {
06185          mem_iter = ao2_iterator_init(q->members, 0);
06186          while ((m = ao2_iterator_next(&mem_iter))) {
06187             /* Count the agents who are logged in and presently answering calls */
06188             if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
06189                count++;
06190             }
06191             ao2_ref(m, -1);
06192          }
06193          ao2_iterator_destroy(&mem_iter);
06194       } else if (!strcasecmp(option, "ready")) {
06195          time_t now;
06196          time(&now);
06197          mem_iter = ao2_iterator_init(q->members, 0);
06198          while ((m = ao2_iterator_next(&mem_iter))) {
06199             /* Count the agents who are logged in, not paused and not wrapping up */
06200             if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
06201                   !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) {
06202                count++;
06203             }
06204             ao2_ref(m, -1);
06205          }
06206          ao2_iterator_destroy(&mem_iter);
06207       } else /* must be "count" */
06208          count = ao2_container_count(q->members);
06209       ao2_unlock(q);
06210       queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
06211    } else
06212       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06213 
06214    snprintf(buf, len, "%d", count);
06215 
06216    return 0;
06217 }

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).

Return values:
number of members
-1 on error

Definition at line 6224 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, ast_log(), ast_strlen_zero(), call_queue::count, load_realtime_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, queue_t_unref, and member::status.

06225 {
06226    int count = 0;
06227    struct member *m;
06228    struct call_queue *q;
06229    struct ao2_iterator mem_iter;
06230    static int depflag = 1;
06231 
06232    if (depflag) {
06233       depflag = 0;
06234       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");
06235    }
06236 
06237    if (ast_strlen_zero(data)) {
06238       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06239       return -1;
06240    }
06241    
06242    if ((q = load_realtime_queue(data))) {
06243       ao2_lock(q);
06244       mem_iter = ao2_iterator_init(q->members, 0);
06245       while ((m = ao2_iterator_next(&mem_iter))) {
06246          /* Count the agents who are logged in and presently answering calls */
06247          if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
06248             count++;
06249          }
06250          ao2_ref(m, -1);
06251       }
06252       ao2_iterator_destroy(&mem_iter);
06253       ao2_unlock(q);
06254       queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
06255    } else
06256       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06257 
06258    snprintf(buf, len, "%d", count);
06259 
06260    return 0;
06261 }

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 6300 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_t_find, ao2_unlock, ast_log(), ast_strlen_zero(), member::interface, LOG_ERROR, LOG_WARNING, call_queue::members, OBJ_POINTER, queue_t_unref, and queues.

06301 {
06302    struct call_queue *q, tmpq = {
06303       .name = data,  
06304    };
06305    struct member *m;
06306 
06307    /* Ensure an otherwise empty list doesn't return garbage */
06308    buf[0] = '\0';
06309 
06310    if (ast_strlen_zero(data)) {
06311       ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
06312       return -1;
06313    }
06314 
06315    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) {
06316       int buflen = 0, count = 0;
06317       struct ao2_iterator mem_iter;
06318 
06319       ao2_lock(q);
06320       mem_iter = ao2_iterator_init(q->members, 0);
06321       while ((m = ao2_iterator_next(&mem_iter))) {
06322          /* strcat() is always faster than printf() */
06323          if (count++) {
06324             strncat(buf + buflen, ",", len - buflen - 1);
06325             buflen++;
06326          }
06327          strncat(buf + buflen, m->interface, len - buflen - 1);
06328          buflen += strlen(m->interface);
06329          /* Safeguard against overflow (negative length) */
06330          if (buflen >= len - 2) {
06331             ao2_ref(m, -1);
06332             ast_log(LOG_WARNING, "Truncating list\n");
06333             break;
06334          }
06335          ao2_ref(m, -1);
06336       }
06337       ao2_iterator_destroy(&mem_iter);
06338       ao2_unlock(q);
06339       queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
06340    } else
06341       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06342 
06343    /* We should already be terminated, but let's make sure. */
06344    buf[len - 1] = '\0';
06345 
06346    return 0;
06347 }

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 6264 of file app_queue.c.

References ao2_lock, ao2_t_find, ao2_unlock, ast_load_realtime(), ast_log(), ast_strlen_zero(), ast_variables_destroy(), call_queue::count, LOG_ERROR, LOG_WARNING, OBJ_POINTER, queue_t_unref, queues, SENTINEL, and var.

06265 {
06266    int count = 0;
06267    struct call_queue *q, tmpq = {
06268       .name = data,  
06269    };
06270    struct ast_variable *var = NULL;
06271 
06272    buf[0] = '\0';
06273    
06274    if (ast_strlen_zero(data)) {
06275       ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
06276       return -1;
06277    }
06278 
06279    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
06280       ao2_lock(q);
06281       count = q->count;
06282       ao2_unlock(q);
06283       queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
06284    } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
06285       /* if the queue is realtime but was not found in memory, this
06286        * means that the queue had been deleted from memory since it was 
06287        * "dead." This means it has a 0 waiting count
06288        */
06289       count = 0;
06290       ast_variables_destroy(var);
06291    } else
06292       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06293 
06294    snprintf(buf, len, "%d", count);
06295 
06296    return 0;
06297 }

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.

Return values:
0 on success
-1 on error

Definition at line 6084 of file app_queue.c.

References ao2_lock, ao2_t_find, ao2_unlock, ast_log(), ast_strlen_zero(), call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::count, call_queue::holdtime, int2strat(), LOG_ERROR, LOG_WARNING, call_queue::maxlen, OBJ_POINTER, pbx_builtin_setvar_multiple(), queue_t_unref, queues, call_queue::servicelevel, call_queue::setqueuevar, call_queue::strategy, and call_queue::talktime.

06085 {
06086    int res = -1;
06087    struct call_queue *q, tmpq = {
06088       .name = data,  
06089    };
06090 
06091    char interfacevar[256] = "";
06092    float sl = 0;
06093 
06094    if (ast_strlen_zero(data)) {
06095       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06096       return -1;
06097    }
06098 
06099    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) {
06100       ao2_lock(q);
06101       if (q->setqueuevar) {
06102          sl = 0;
06103          res = 0;
06104 
06105          if (q->callscompleted > 0) {
06106             sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
06107          }
06108 
06109          snprintf(interfacevar, sizeof(interfacevar),
06110             "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
06111             q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned,  q->servicelevel, sl);
06112 
06113          pbx_builtin_setvar_multiple(chan, interfacevar);
06114       }
06115 
06116       ao2_unlock(q);
06117       queue_t_unref(q, "Done with QUEUE() function");
06118    } else {
06119       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06120    }
06121 
06122    snprintf(buf, len, "%d", res);
06123 
06124    return 0;
06125 }

static int queue_hash_cb ( const void *  obj,
const int  flags 
) [static]

Definition at line 1249 of file app_queue.c.

References ast_str_case_hash(), and call_queue::name.

Referenced by load_module().

01250 {
01251    const struct call_queue *q = obj;
01252 
01253    return ast_str_case_hash(q->name);
01254 }

static struct call_queue* queue_ref ( struct call_queue q  )  [inline, static]

Definition at line 1274 of file app_queue.c.

References ao2_ref.

Referenced by insert_entry().

01275 {
01276    ao2_ref(q, 1);
01277    return q;
01278 }

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 6508 of file app_queue.c.

References ast_true(), and ast_variable_retrieve().

Referenced by reload_queues().

06509 {
06510    const char *general_val = NULL;
06511    queue_persistent_members = 0;
06512    if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
06513       queue_persistent_members = ast_true(general_val);
06514    autofill_default = 0;
06515    if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
06516       autofill_default = ast_true(general_val);
06517    montype_default = 0;
06518    if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
06519       if (!strcasecmp(general_val, "mixmonitor"))
06520          montype_default = 1;
06521    }
06522    update_cdr = 0;
06523    if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
06524       update_cdr = ast_true(general_val);
06525    shared_lastcall = 0;
06526    if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
06527       shared_lastcall = ast_true(general_val);
06528 }

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.

Note:
For error reporting, line number is passed for .conf static configuration, for Realtime queues, linenum is -1.

Definition at line 1877 of file app_queue.c.

References queue_ent::announce, call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_NO, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, ast_copy_string(), ast_debug, ast_log(), ast_str_create(), ast_str_set(), ast_strdupa, ast_string_field_set, ast_true(), call_queue::autofill, call_queue::autopause, autopause2int(), queue_ent::context, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::eventwhencalled, call_queue::joinempty, call_queue::leavewhenempty, LOG_WARNING, call_queue::maskmemberstatus, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, call_queue::memberdelay, call_queue::minannouncefrequency, call_queue::monfmt, call_queue::montype, call_queue::name, call_queue::numperiodicannounce, parse_empty_options(), call_queue::penaltymemberslimit, call_queue::periodicannouncefrequency, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RINGALL, call_queue::randomperiodicannounce, call_queue::relativeperiodicannounce, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::roundingseconds, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::setqueueentryvar, call_queue::setqueuevar, call_queue::sound_periodicannounce, strat2int(), call_queue::strategy, strsep(), call_queue::timeout, TIMEOUT_PRIORITY_APP, TIMEOUT_PRIORITY_CONF, call_queue::timeoutpriority, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.

Referenced by reload_single_queue().

01878 {
01879    if (!strcasecmp(param, "musicclass") || 
01880       !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
01881       ast_string_field_set(q, moh, val);
01882    } else if (!strcasecmp(param, "announce")) {
01883       ast_string_field_set(q, announce, val);
01884    } else if (!strcasecmp(param, "context")) {
01885       ast_string_field_set(q, context, val);
01886    } else if (!strcasecmp(param, "timeout")) {
01887       q->timeout = atoi(val);
01888       if (q->timeout < 0)
01889          q->timeout = DEFAULT_TIMEOUT;
01890    } else if (!strcasecmp(param, "ringinuse")) {
01891       q->ringinuse = ast_true(val);
01892    } else if (!strcasecmp(param, "setinterfacevar")) {
01893       q->setinterfacevar = ast_true(val);
01894    } else if (!strcasecmp(param, "setqueuevar")) {
01895       q->setqueuevar = ast_true(val);
01896    } else if (!strcasecmp(param, "setqueueentryvar")) {
01897       q->setqueueentryvar = ast_true(val);
01898    } else if (!strcasecmp(param, "monitor-format")) {
01899       ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
01900    } else if (!strcasecmp(param, "membermacro")) {
01901       ast_string_field_set(q, membermacro, val);
01902    } else if (!strcasecmp(param, "membergosub")) {
01903       ast_string_field_set(q, membergosub, val);
01904    } else if (!strcasecmp(param, "queue-youarenext")) {
01905       ast_string_field_set(q, sound_next, val);
01906    } else if (!strcasecmp(param, "queue-thereare")) {
01907       ast_string_field_set(q, sound_thereare, val);
01908    } else if (!strcasecmp(param, "queue-callswaiting")) {
01909       ast_string_field_set(q, sound_calls, val);
01910    } else if (!strcasecmp(param, "queue-quantity1")) {
01911       ast_string_field_set(q, queue_quantity1, val);
01912    } else if (!strcasecmp(param, "queue-quantity2")) {
01913       ast_string_field_set(q, queue_quantity2, val);
01914    } else if (!strcasecmp(param, "queue-holdtime")) {
01915       ast_string_field_set(q, sound_holdtime, val);
01916    } else if (!strcasecmp(param, "queue-minutes")) {
01917       ast_string_field_set(q, sound_minutes, val);
01918    } else if (!strcasecmp(param, "queue-minute")) {
01919       ast_string_field_set(q, sound_minute, val);
01920    } else if (!strcasecmp(param, "queue-seconds")) {
01921       ast_string_field_set(q, sound_seconds, val);
01922    } else if (!strcasecmp(param, "queue-thankyou")) {
01923       ast_string_field_set(q, sound_thanks, val);
01924    } else if (!strcasecmp(param, "queue-callerannounce")) {
01925       ast_string_field_set(q, sound_callerannounce, val);
01926    } else if (!strcasecmp(param, "queue-reporthold")) {
01927       ast_string_field_set(q, sound_reporthold, val);
01928    } else if (!strcasecmp(param, "announce-frequency")) {
01929       q->announcefrequency = atoi(val);
01930    } else if (!strcasecmp(param, "min-announce-frequency")) {
01931       q->minannouncefrequency = atoi(val);
01932       ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
01933    } else if (!strcasecmp(param, "announce-round-seconds")) {
01934       q->roundingseconds = atoi(val);
01935       /* Rounding to any other values just doesn't make sense... */
01936       if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
01937          || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
01938          if (linenum >= 0) {
01939             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01940                "using 0 instead for queue '%s' at line %d of queues.conf\n",
01941                val, param, q->name, linenum);
01942          } else {
01943             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01944                "using 0 instead for queue '%s'\n", val, param, q->name);
01945          }
01946          q->roundingseconds=0;
01947       }
01948    } else if (!strcasecmp(param, "announce-holdtime")) {
01949       if (!strcasecmp(val, "once"))
01950          q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
01951       else if (ast_true(val))
01952          q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
01953       else
01954          q->announceholdtime = 0;
01955    } else if (!strcasecmp(param, "announce-position")) {
01956       if (!strcasecmp(val, "limit"))
01957          q->announceposition = ANNOUNCEPOSITION_LIMIT;
01958       else if (!strcasecmp(val, "more"))
01959          q->announceposition = ANNOUNCEPOSITION_MORE_THAN;
01960       else if (ast_true(val))
01961          q->announceposition = ANNOUNCEPOSITION_YES;
01962       else
01963          q->announceposition = ANNOUNCEPOSITION_NO;
01964    } else if (!strcasecmp(param, "announce-position-limit")) {
01965       q->announcepositionlimit = atoi(val);
01966    } else if (!strcasecmp(param, "periodic-announce")) {
01967       if (strchr(val, ',')) {
01968          char *s, *buf = ast_strdupa(val);
01969          unsigned int i = 0;
01970 
01971          while ((s = strsep(&buf, ",|"))) {
01972             if (!q->sound_periodicannounce[i])
01973                q->sound_periodicannounce[i] = ast_str_create(16);
01974             ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
01975             i++;
01976             if (i == MAX_PERIODIC_ANNOUNCEMENTS)
01977                break;
01978          }
01979          q->numperiodicannounce = i;
01980       } else {
01981          ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
01982          q->numperiodicannounce = 1;
01983       }
01984    } else if (!strcasecmp(param, "periodic-announce-frequency")) {
01985       q->periodicannouncefrequency = atoi(val);
01986    } else if (!strcasecmp(param, "relative-periodic-announce")) {
01987       q->relativeperiodicannounce = ast_true(val);
01988    } else if (!strcasecmp(param, "random-periodic-announce")) {
01989       q->randomperiodicannounce = ast_true(val);
01990    } else if (!strcasecmp(param, "retry")) {
01991       q->retry = atoi(val);
01992       if (q->retry <= 0)
01993          q->retry = DEFAULT_RETRY;
01994    } else if (!strcasecmp(param, "wrapuptime")) {
01995       q->wrapuptime = atoi(val);
01996    } else if (!strcasecmp(param, "penaltymemberslimit")) {
01997       if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
01998          q->penaltymemberslimit = 0;
01999       }
02000    } else if (!strcasecmp(param, "autofill")) {
02001       q->autofill = ast_true(val);
02002    } else if (!strcasecmp(param, "monitor-type")) {
02003       if (!strcasecmp(val, "mixmonitor"))
02004          q->montype = 1;
02005    } else if (!strcasecmp(param, "autopause")) {
02006       q->autopause = autopause2int(val);
02007    } else if (!strcasecmp(param, "maxlen")) {
02008       q->maxlen = atoi(val);
02009       if (q->maxlen < 0)
02010          q->maxlen = 0;
02011    } else if (!strcasecmp(param, "servicelevel")) {
02012       q->servicelevel= atoi(val);
02013    } else if (!strcasecmp(param, "strategy")) {
02014       int strategy;
02015 
02016       /* We are a static queue and already have set this, no need to do it again */
02017       if (failunknown) {
02018          return;
02019       }
02020       strategy = strat2int(val);
02021       if (strategy < 0) {
02022          ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
02023             val, q->name);
02024          q->strategy = QUEUE_STRATEGY_RINGALL;
02025       }
02026       if (strategy == q->strategy) {
02027          return;
02028       }
02029       if (strategy == QUEUE_STRATEGY_LINEAR) {
02030          ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
02031          return;
02032       }
02033       q->strategy = strategy;
02034    } else if (!strcasecmp(param, "joinempty")) {
02035       parse_empty_options(val, &q->joinempty, 1);
02036    } else if (!strcasecmp(param, "leavewhenempty")) {
02037       parse_empty_options(val, &q->leavewhenempty, 0);
02038    } else if (!strcasecmp(param, "eventmemberstatus")) {
02039       q->maskmemberstatus = !ast_true(val);
02040    } else if (!strcasecmp(param, "eventwhencalled")) {
02041       if (!strcasecmp(val, "vars")) {
02042          q->eventwhencalled = QUEUE_EVENT_VARIABLES;
02043       } else {
02044          q->eventwhencalled = ast_true(val) ? 1 : 0;
02045       }
02046    } else if (!strcasecmp(param, "reportholdtime")) {
02047       q->reportholdtime = ast_true(val);
02048    } else if (!strcasecmp(param, "memberdelay")) {
02049       q->memberdelay = atoi(val);
02050    } else if (!strcasecmp(param, "weight")) {
02051       q->weight = atoi(val);
02052    } else if (!strcasecmp(param, "timeoutrestart")) {
02053       q->timeoutrestart = ast_true(val);
02054    } else if (!strcasecmp(param, "defaultrule")) {
02055       ast_string_field_set(q, defaultrule, val);
02056    } else if (!strcasecmp(param, "timeoutpriority")) {
02057       if (!strcasecmp(val, "conf")) {
02058          q->timeoutpriority = TIMEOUT_PRIORITY_CONF;
02059       } else {
02060          q->timeoutpriority = TIMEOUT_PRIORITY_APP;
02061       }
02062    } else if (failunknown) {
02063       if (linenum >= 0) {
02064          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
02065             q->name, param, linenum);
02066       } else {
02067          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
02068       }
02069    }
02070 }

static char* queue_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 7044 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.

07045 {
07046    switch ( cmd ) {
07047    case CLI_INIT:
07048       e->command = "queue show";
07049       e->usage =
07050          "Usage: queue show\n"
07051          "       Provides summary information on a specified queue.\n";
07052       return NULL;
07053    case CLI_GENERATE:
07054       return complete_queue_show(a->line, a->word, a->pos, a->n); 
07055    }
07056 
07057    return __queues_show(NULL, a->fd, a->argc, a->argv);
07058 }

static void queue_transfer_destroy ( void *  data  )  [static]

Definition at line 4158 of file app_queue.c.

References ast_free.

04159 {
04160    struct queue_transfer_ds *qtds = data;
04161    ast_free(qtds);
04162 }

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 4181 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().

04182 {
04183    struct queue_transfer_ds *qtds = data;
04184    struct queue_ent *qe = qtds->qe;
04185    struct member *member = qtds->member;
04186    time_t callstart = qtds->starttime;
04187    int callcompletedinsl = qtds->callcompletedinsl;
04188    struct ast_datastore *datastore;
04189 
04190    ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
04191             new_chan->exten, new_chan->context, (long) (callstart - qe->start),
04192             (long) (time(NULL) - callstart), qe->opos);
04193 
04194    update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
04195    
04196    /* No need to lock the channels because they are already locked in ast_do_masquerade */
04197    if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
04198       ast_channel_datastore_remove(old_chan, datastore);
04199    } else {
04200       ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
04201    }
04202 }

static struct call_queue* queue_unref ( struct call_queue q  )  [inline, static]

Definition at line 1280 of file app_queue.c.

References ao2_ref.

Referenced by queues_data_provider_get().

01281 {
01282    ao2_ref(q, -1);
01283    return NULL;
01284 }

static int queues_data_provider_get ( const struct ast_data_search search,
struct ast_data data_root 
) [static]

Definition at line 8205 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_unlock, ast_category_browse(), ast_config_destroy(), ast_load_realtime_multientry(), ast_strlen_zero(), load_realtime_queue(), queue_unref(), queues, queues_data_provider_get_helper(), and SENTINEL.

08207 {
08208    struct ao2_iterator i;
08209    struct call_queue *queue, *queue_realtime = NULL;
08210    struct ast_config *cfg;
08211    char *queuename;
08212 
08213    /* load realtime queues. */
08214    cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
08215    if (cfg) {
08216       for (queuename = ast_category_browse(cfg, NULL);
08217             !ast_strlen_zero(queuename);
08218             queuename = ast_category_browse(cfg, queuename)) {
08219          if ((queue = load_realtime_queue(queuename))) {
08220             queue_unref(queue);
08221          }
08222       }
08223       ast_config_destroy(cfg);
08224    }
08225 
08226    /* static queues. */
08227    i = ao2_iterator_init(queues, 0);
08228    while ((queue = ao2_iterator_next(&i))) {
08229       ao2_lock(queue);
08230       if (queue->realtime) {
08231          queue_realtime = load_realtime_queue(queue->name);
08232          if (!queue_realtime) {
08233             ao2_unlock(queue);
08234             queue_unref(queue);
08235             continue;
08236          }
08237          queue_unref(queue_realtime);
08238       }
08239 
08240       queues_data_provider_get_helper(search, data_root, queue);
08241       ao2_unlock(queue);
08242       queue_unref(queue);
08243    }
08244    ao2_iterator_destroy(&i);
08245 
08246    return 0;
08247 }

static void queues_data_provider_get_helper ( const struct ast_data_search search,
struct ast_data data_root,
struct call_queue queue 
) [static]

Definition at line 8099 of file app_queue.c.

References call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_NO, ANNOUNCEPOSITION_YES, ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_data_add_structure(), ast_data_add_int(), ast_data_add_node(), ast_data_add_str(), ast_data_add_structure, ast_data_remove_node(), ast_data_search_match(), queue_ent::chan, call_queue::head, int2strat(), call_queue::members, queue_ent::next, and call_queue::strategy.

Referenced by queues_data_provider_get().

08101 {
08102    struct ao2_iterator im;
08103    struct member *member;
08104    struct queue_ent *qe;
08105    struct ast_data *data_queue, *data_members = NULL, *enum_node;
08106    struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel;
08107 
08108    data_queue = ast_data_add_node(data_root, "queue");
08109    if (!data_queue) {
08110       return;
08111    }
08112 
08113    ast_data_add_structure(call_queue, data_queue, queue);
08114 
08115    ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy));
08116    ast_data_add_int(data_queue, "membercount", ao2_container_count(queue->members));
08117 
08118    /* announce position */
08119    enum_node = ast_data_add_node(data_queue, "announceposition");
08120    if (!enum_node) {
08121       return;
08122    }
08123    switch (queue->announceposition) {
08124    case ANNOUNCEPOSITION_LIMIT:
08125       ast_data_add_str(enum_node, "text", "limit");
08126       break;
08127    case ANNOUNCEPOSITION_MORE_THAN:
08128       ast_data_add_str(enum_node, "text", "more");
08129       break;
08130    case ANNOUNCEPOSITION_YES:
08131       ast_data_add_str(enum_node, "text", "yes");
08132       break;
08133    case ANNOUNCEPOSITION_NO:
08134       ast_data_add_str(enum_node, "text", "no");
08135       break;
08136    default:
08137       ast_data_add_str(enum_node, "text", "unknown");
08138       break;
08139    }
08140    ast_data_add_int(enum_node, "value", queue->announceposition);
08141 
08142    /* add queue members */
08143    im = ao2_iterator_init(queue->members, 0);
08144    while ((member = ao2_iterator_next(&im))) {
08145       if (!data_members) {
08146          data_members = ast_data_add_node(data_queue, "members");
08147          if (!data_members) {
08148             ao2_ref(member, -1);
08149             continue;
08150          }
08151       }
08152 
08153       data_member = ast_data_add_node(data_members, "member");
08154       if (!data_member) {
08155          ao2_ref(member, -1);
08156          continue;
08157       }
08158 
08159       ast_data_add_structure(member, data_member, member);
08160 
08161       ao2_ref(member, -1);
08162    }
08163    ao2_iterator_destroy(&im);
08164 
08165    /* include the callers inside the result. */
08166    if (queue->head) {
08167       for (qe = queue->head; qe; qe = qe->next) {
08168          if (!data_callers) {
08169             data_callers = ast_data_add_node(data_queue, "callers");
08170             if (!data_callers) {
08171                continue;
08172             }
08173          }
08174 
08175          data_caller = ast_data_add_node(data_callers, "caller");
08176          if (!data_caller) {
08177             continue;
08178          }
08179 
08180          ast_data_add_structure(queue_ent, data_caller, qe);
08181 
08182          /* add the caller channel. */
08183          data_caller_channel = ast_data_add_node(data_caller, "channel");
08184          if (!data_caller_channel) {
08185             continue;
08186          }
08187 
08188          ast_channel_data_add_structure(data_caller_channel, qe->chan, 1);
08189       }
08190    }
08191 
08192    /* if this queue doesn't match remove the added queue. */
08193    if (!ast_data_search_match(search, data_queue)) {
08194       ast_data_remove_node(data_root, data_queue);
08195    }
08196 }

static void recalc_holdtime ( struct queue_ent qe,
int  newholdtime 
) [static]

Definition at line 2732 of file app_queue.c.

References ao2_lock, ao2_unlock, call_queue::holdtime, and queue_ent::parent.

02733 {
02734    int oldvalue;
02735 
02736    /* Calculate holdtime using an exponential average */
02737    /* Thanks to SRT for this contribution */
02738    /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
02739 
02740    ao2_lock(qe->parent);
02741    oldvalue = qe->parent->holdtime;
02742    qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
02743    ao2_unlock(qe->parent);
02744 }

static void record_abandoned ( struct queue_ent qe  )  [static]

Record that a caller gave up on waiting in queue.

Definition at line 3340 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().

03341 {
03342    set_queue_variables(qe->parent, qe->chan);
03343    ao2_lock(qe->parent);
03344    manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
03345       "Queue: %s\r\n"
03346       "Uniqueid: %s\r\n"
03347       "Position: %d\r\n"
03348       "OriginalPosition: %d\r\n"
03349       "HoldTime: %d\r\n",
03350       qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
03351 
03352    qe->parent->callsabandoned++;
03353    ao2_unlock(qe->parent);
03354 }

static int reload ( void   )  [static]

Definition at line 8379 of file app_queue.c.

References AST_FLAGS_ALL, ast_unload_realtime(), QUEUE_RESET_STATS, and reload_handler().

08380 {
08381    struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
08382    ast_unload_realtime("queue_members");
08383    reload_handler(1, &mask, NULL);
08384    return 0;
08385 }

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.

Parameters:
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
Return values:
0 All reloads were successful
non-zero There was a failure

Definition at line 6853 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().

06854 {
06855    int res = 0;
06856 
06857    if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
06858       res |= reload_queue_rules(reload);
06859    }
06860    if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
06861       res |= clear_stats(queuename);
06862    }
06863    if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) {
06864       res |= reload_queues(reload, mask, queuename);
06865    }
06866    return res;
06867 }

static void reload_queue_members ( void   )  [static]

Reload dynamic queue members persisted into the astdb.

Definition at line 5428 of file app_queue.c.

References add_to_queue(), ao2_t_find, ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), ast_debug, ast_log(), ast_strlen_zero(), errno, member::interface, ast_db_entry::key, load_realtime_queue(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, member::membername, call_queue::name, ast_db_entry::next, OBJ_POINTER, member::paused, member::penalty, PM_MAX_LEN, queue_t_unref, queues, RES_OUTOFMEMORY, member::state_interface, and strsep().

Referenced by load_module().

05429 {
05430    char *cur_ptr;
05431    const char *queue_name;
05432    char *member;
05433    char *interface;
05434    char *membername = NULL;
05435    char *state_interface;
05436    char *penalty_tok;
05437    int penalty = 0;
05438    char *paused_tok;
05439    int paused = 0;
05440    struct ast_db_entry *db_tree;
05441    struct ast_db_entry *entry;
05442    struct call_queue *cur_queue;
05443    char queue_data[PM_MAX_LEN];
05444 
05445    /* Each key in 'pm_family' is the name of a queue */
05446    db_tree = ast_db_gettree(pm_family, NULL);
05447    for (entry = db_tree; entry; entry = entry->next) {
05448 
05449       queue_name = entry->key + strlen(pm_family) + 2;
05450 
05451       {
05452          struct call_queue tmpq = {
05453             .name = queue_name,
05454          };
05455          cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
05456       }  
05457 
05458       if (!cur_queue)
05459          cur_queue = load_realtime_queue(queue_name);
05460 
05461       if (!cur_queue) {
05462          /* If the queue no longer exists, remove it from the
05463           * database */
05464          ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
05465          ast_db_del(pm_family, queue_name);
05466          continue;
05467       } 
05468 
05469       if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) {
05470          queue_t_unref(cur_queue, "Expire reload reference");
05471          continue;
05472       }
05473 
05474       cur_ptr = queue_data;
05475       while ((member = strsep(&cur_ptr, ",|"))) {
05476          if (ast_strlen_zero(member))
05477             continue;
05478 
05479          interface = strsep(&member, ";");
05480          penalty_tok = strsep(&member, ";");
05481          paused_tok = strsep(&member, ";");
05482          membername = strsep(&member, ";");
05483          state_interface = strsep(&member, ";");
05484 
05485          if (!penalty_tok) {
05486             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
05487             break;
05488          }
05489          penalty = strtol(penalty_tok, NULL, 10);
05490          if (errno == ERANGE) {
05491             ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
05492             break;
05493          }
05494          
05495          if (!paused_tok) {
05496             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
05497             break;
05498          }
05499          paused = strtol(paused_tok, NULL, 10);
05500          if ((errno == ERANGE) || paused < 0 || paused > 1) {
05501             ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
05502             break;
05503          }
05504 
05505          ast_debug(1, "Reload Members: Queue: %s  Member: %s  Name: %s  Penalty: %d  Paused: %d\n", queue_name, interface, membername, penalty, paused);
05506          
05507          if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
05508             ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
05509             break;
05510          }
05511       }
05512       queue_t_unref(cur_queue, "Expire reload reference");
05513    }
05514 
05515    if (db_tree) {
05516       ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
05517       ast_db_freetree(db_tree);
05518    }
05519 }

static int reload_queue_rules ( int  reload  )  [static]

Reload the rules defined in queuerules.conf.

Parameters:
reload If 1, then only process queuerules.conf if the file has changed since the last time we inspected it.
Returns:
Always returns AST_MODULE_LOAD_SUCCESS

Definition at line 6459 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_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, insert_penaltychange(), ast_variable::lineno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_variable::name, ast_variable::next, rule_list::rules, and ast_variable::value.

Referenced by reload_handler().

06460 {
06461    struct ast_config *cfg;
06462    struct rule_list *rl_iter, *new_rl;
06463    struct penalty_rule *pr_iter;
06464    char *rulecat = NULL;
06465    struct ast_variable *rulevar = NULL;
06466    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06467    
06468    if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
06469       ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
06470       return AST_MODULE_LOAD_SUCCESS;
06471    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06472       ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
06473       return AST_MODULE_LOAD_SUCCESS;
06474    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06475       ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format.  Aborting.\n");
06476       return AST_MODULE_LOAD_SUCCESS;
06477    }
06478 
06479    AST_LIST_LOCK(&rule_lists);
06480    while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
06481       while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
06482          ast_free(pr_iter);
06483       ast_free(rl_iter);
06484    }
06485    while ((rulecat = ast_category_browse(cfg, rulecat))) {
06486       if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
06487          AST_LIST_UNLOCK(&rule_lists);
06488          ast_config_destroy(cfg);
06489          return AST_MODULE_LOAD_FAILURE;
06490       } else {
06491          ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
06492          AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
06493          for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
06494             if(!strcasecmp(rulevar->name, "penaltychange"))
06495                insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
06496             else
06497                ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
06498       }
06499    }
06500    AST_LIST_UNLOCK(&rule_lists);
06501 
06502    ast_config_destroy(cfg);
06503 
06504    return AST_MODULE_LOAD_SUCCESS;
06505 }

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.

Parameters:
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
Return values:
-1 Failure occurred
0 All clear!

Definition at line 6763 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_flags, 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().

06764 {
06765    struct ast_config *cfg;
06766    char *cat;
06767    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06768    const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
06769 
06770    if (!(cfg = ast_config_load("queues.conf", config_flags))) {
06771       ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
06772       return -1;
06773    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06774       return 0;
06775    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06776       ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format.  Aborting.\n");
06777       return -1;
06778    }
06779 
06780    /* We've made it here, so it looks like we're doing operations on all queues. */
06781    ao2_lock(queues);
06782 
06783    /* Mark all queues as dead for the moment if we're reloading queues.
06784     * For clarity, we could just be reloading members, in which case we don't want to mess
06785     * with the other queue parameters at all*/
06786    if (queue_reload) {
06787       ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename);
06788    }
06789 
06790    /* Chug through config file */
06791    cat = NULL;
06792    while ((cat = ast_category_browse(cfg, cat)) ) {
06793       if (!strcasecmp(cat, "general") && queue_reload) {
06794          queue_set_global_params(cfg);
06795          continue;
06796       }
06797       if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
06798          reload_single_queue(cfg, mask, cat);
06799    }
06800 
06801    ast_config_destroy(cfg);
06802    /* Unref all the dead queues if we were reloading queues */
06803    if (queue_reload) {
06804       ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename);
06805    }
06806    ao2_unlock(queues);
06807    return 0;
06808 }

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.

Parameters:
memberdata The part after member = in the config file
q The queue to which this member belongs

Definition at line 6538 of file app_queue.c.

References ao2_find, ao2_link, ao2_ref, args, AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strip(), ast_strlen_zero(), create_queue_member(), member::interface, LOG_WARNING, call_queue::members, OBJ_POINTER, OBJ_UNLINK, parse(), member::paused, and member::penalty.

Referenced by reload_single_queue().

06539 {
06540    char *membername, *interface, *state_interface, *tmp;
06541    char *parse;
06542    struct member *cur, *newm;
06543    struct member tmpmem;
06544    int penalty;
06545    AST_DECLARE_APP_ARGS(args,
06546       AST_APP_ARG(interface);
06547       AST_APP_ARG(penalty);
06548       AST_APP_ARG(membername);
06549       AST_APP_ARG(state_interface);
06550    );
06551 
06552    if (ast_strlen_zero(memberdata)) {
06553       ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
06554       return;
06555    }
06556 
06557    /* Add a new member */
06558    parse = ast_strdupa(memberdata);
06559             
06560    AST_STANDARD_APP_ARGS(args, parse);
06561 
06562    interface = args.interface;
06563    if (!ast_strlen_zero(args.penalty)) {
06564       tmp = args.penalty;
06565       ast_strip(tmp);
06566       penalty = atoi(tmp);
06567       if (penalty < 0) {
06568          penalty = 0;
06569       }
06570    } else {
06571       penalty = 0;
06572    }
06573 
06574    if (!ast_strlen_zero(args.membername)) {
06575       membername = args.membername;
06576       ast_strip(membername);
06577    } else {
06578       membername = interface;
06579    }
06580 
06581    if (!ast_strlen_zero(args.state_interface)) {
06582       state_interface = args.state_interface;
06583       ast_strip(state_interface);
06584    } else {
06585       state_interface = interface;
06586    }
06587 
06588    /* Find the old position in the list */
06589    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
06590    cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
06591    if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) {
06592       ao2_link(q->members, newm);
06593       ao2_ref(newm, -1);
06594    }
06595    newm = NULL;
06596 
06597    if (cur) {
06598       ao2_ref(cur, -1);
06599    }
06600 }

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

Parameters:
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
Return values:
void 

Definition at line 6634 of file app_queue.c.

References alloc_queue(), ao2_callback, ao2_lock, ao2_t_find, ao2_unlock, ast_log(), ast_test_flag, ast_variable_browse(), ast_variable_retrieve(), call_queue::found, init_queue(), LOG_WARNING, mark_member_dead(), call_queue::members, call_queue::name, OBJ_NODATA, OBJ_POINTER, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_t_unref, queues, reload_single_member(), strat2int(), call_queue::strategy, and var.

Referenced by reload_queues().

06635 {
06636    int new;
06637    struct call_queue *q = NULL;
06638    /*We're defining a queue*/
06639    struct call_queue tmpq = {
06640       .name = queuename,
06641    };
06642    const char *tmpvar;
06643    const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
06644    const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
06645    int prev_weight = 0;
06646    struct ast_variable *var;
06647    if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
06648       if (queue_reload) {
06649          /* Make one then */
06650          if (!(q = alloc_queue(queuename))) {
06651             return;
06652          }
06653       } else {
06654          /* Since we're not reloading queues, this means that we found a queue
06655           * in the configuration file which we don't know about yet. Just return.
06656           */
06657          return;
06658       }
06659       new = 1;
06660    } else {
06661       new = 0;
06662    }
06663    
06664    if (!new) {
06665       ao2_lock(q);
06666       prev_weight = q->weight ? 1 : 0;
06667    }
06668    /* Check if we already found a queue with this name in the config file */
06669    if (q->found) {
06670       ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
06671       if (!new) {
06672          /* It should be impossible to *not* hit this case*/
06673          ao2_unlock(q);
06674       }
06675       queue_t_unref(q, "We exist! Expiring temporary pointer");
06676       return;
06677    }
06678    /* Due to the fact that the "linear" strategy will have a different allocation
06679     * scheme for queue members, we must devise the queue's strategy before other initializations.
06680     * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
06681     * container used will have only a single bucket instead of the typical number.
06682     */
06683    if (queue_reload) {
06684       if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
06685          q->strategy = strat2int(tmpvar);
06686          if (q->strategy < 0) {
06687             ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
06688             tmpvar, q->name);
06689             q->strategy = QUEUE_STRATEGY_RINGALL;
06690          }
06691       } else {
06692          q->strategy = QUEUE_STRATEGY_RINGALL;
06693       }
06694       init_queue(q);
06695    }
06696    if (member_reload) {
06697       ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL);
06698    }
06699    for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
06700       if (member_reload && !strcasecmp(var->name, "member")) {
06701          reload_single_member(var->value, q);
06702       } else if (queue_reload) {
06703          queue_set_param(q, var->name, var->value, var->lineno, 1);
06704       }
06705    }
06706    /* At this point, we've determined if the queue has a weight, so update use_weight
06707     * as appropriate
06708     */
06709    if (!q->weight && prev_weight) {
06710       ast_atomic_fetchadd_int(&use_weight, -1);
06711    }
06712    else if (q->weight && !prev_weight) {
06713       ast_atomic_fetchadd_int(&use_weight, +1);
06714    }
06715 
06716    /* Free remaining members marked as delme */
06717    if (member_reload) {
06718       ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q);
06719    }
06720 
06721    if (new) {
06722       queues_t_link(queues, q, "Add queue to container");
06723    } else {
06724       ao2_unlock(q);
06725    }
06726    queue_t_unref(q, "Expiring creation reference");
06727 }

static int remove_from_queue ( const char *  queuename,
const char *  interface 
) [static]

Remove member from queue.

Return values:
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 5171 of file app_queue.c.

References ao2_find, ao2_lock, ao2_ref, ao2_t_find, ao2_unlink, ao2_unlock, ast_copy_string(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, manager_event, member::membername, call_queue::members, call_queue::name, OBJ_POINTER, queue_t_unref, queues, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, and RES_OKAY.

Referenced by attempt_thread(), handle_queue_remove_member(), manager_remove_queue_member(), rqm_exec(), and scan_service().

05172 {
05173    struct call_queue *q, tmpq = {
05174       .name = queuename,   
05175    };
05176    struct member *mem, tmpmem;
05177    int res = RES_NOSUCHQUEUE;
05178 
05179    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
05180    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
05181       ao2_lock(q);
05182       if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
05183          /* XXX future changes should beware of this assumption!! */
05184          if (!mem->dynamic) {
05185             ao2_ref(mem, -1);
05186             ao2_unlock(q);
05187             queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
05188             return RES_NOT_DYNAMIC;
05189          }
05190          manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
05191             "Queue: %s\r\n"
05192             "Location: %s\r\n"
05193             "MemberName: %s\r\n",
05194             q->name, mem->interface, mem->membername);
05195          ao2_unlink(q->members, mem);
05196          ao2_ref(mem, -1);
05197 
05198          if (queue_persistent_members)
05199             dump_queue_members(q);
05200          
05201          res = RES_OKAY;
05202       } else {
05203          res = RES_EXISTS;
05204       }
05205       ao2_unlock(q);
05206       queue_t_unref(q, "Expiring temporary reference");
05207    }
05208 
05209    return res;
05210 }

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:

Return values:
1 on success to reach a free agent
0 on failure to get agent.

Definition at line 2993 of file app_queue.c.

References ast_cdr::accountcode, ast_channel::adsicpe, ast_cdr::amaflags, ast_party_connected_line::ani, ast_party_caller::ani, ao2_lock, ao2_unlock, ast_channel::appl, ast_call(), ast_cdr_busy(), ast_cdr_isset_unanswered(), ast_cdr_setdestchan(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_lock_both, ast_channel_set_caller_event(), ast_channel_unlock, ast_connected_line_copy_from_caller(), ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, AST_FLAG_ANSWERED_ELSEWHERE, ast_party_caller_set_init(), ast_party_redirecting_copy(), ast_request(), ast_set_callerid(), ast_set_flag, ast_string_field_set, ast_strlen_zero(), ast_verb, ast_channel::caller, queue_ent::cancel_answered_elsewhere, ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_cdr::channel, ast_cdr::clid, compare_weight(), ast_channel::connected, ast_channel::context, ast_channel::data, ast_cdr::dcontext, callattempt::dial_callerid_absent, dialcontext, ast_channel::dialed, do_hang(), ast_cdr::dst, EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, get_queue_member_status(), ast_party_connected_line::id, ast_party_caller::id, callattempt::interface, ast_cdr::lastapp, callattempt::lastcall, ast_cdr::lastdata, callattempt::lastqueue, queue_ent::linpos, ast_channel::macroexten, manager_event, callattempt::member, member::membername, ast_party_id::name, ast_channel::name, call_queue::name, ast_channel::nativeformats, ast_party_dialed::number, ast_party_id::number, queue_ent::parent, member::paused, pbx_builtin_getvar_helper(), ast_channel::priority, QUEUE_EVENT_VARIABLES, ast_channel::redirecting, call_queue::ringinuse, call_queue::rrpos, S_COR, S_OR, ast_cdr::src, member::status, status, callattempt::stillgoing, ast_party_name::str, ast_party_number::str, ast_party_dialed::str, ast_party_dialed::transit_network_select, ast_channel::uniqueid, update_status(), ast_cdr::userfield, ast_party_name::valid, ast_party_number::valid, vars2manager(), ast_channel::whentohangup, and call_queue::wrapuptime.

Referenced by ring_one().

02994 {
02995    int res;
02996    int status;
02997    char tech[256];
02998    char *location;
02999    const char *macrocontext, *macroexten;
03000 
03001    /* on entry here, we know that tmp->chan == NULL */
03002    if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
03003       (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
03004       ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 
03005             (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
03006       if (qe->chan->cdr)
03007          ast_cdr_busy(qe->chan->cdr);
03008       tmp->stillgoing = 0;
03009       (*busies)++;
03010       return 0;
03011    }
03012 
03013    if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
03014       ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
03015       if (qe->chan->cdr)
03016          ast_cdr_busy(qe->chan->cdr);
03017       tmp->stillgoing = 0;
03018       return 0;
03019    }
03020 
03021    if (tmp->member->paused) {
03022       ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
03023       if (qe->chan->cdr)
03024          ast_cdr_busy(qe->chan->cdr);
03025       tmp->stillgoing = 0;
03026       return 0;
03027    }
03028    if (use_weight && compare_weight(qe->parent,tmp->member)) {
03029       ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
03030       if (qe->chan->cdr)
03031          ast_cdr_busy(qe->chan->cdr);
03032       tmp->stillgoing = 0;
03033       (*busies)++;
03034       return 0;
03035    }
03036 
03037    ast_copy_string(tech, tmp->interface, sizeof(tech));
03038    if ((location = strchr(tech, '/')))
03039       *location++ = '\0';
03040    else
03041       location = "";
03042 
03043    /* Request the peer */
03044    tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
03045    if (!tmp->chan) {       /* If we can't, just go on to the next call */
03046       if (qe->chan->cdr)
03047          ast_cdr_busy(qe->chan->cdr);
03048       tmp->stillgoing = 0; 
03049 
03050       ao2_lock(qe->parent);
03051       update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
03052       qe->parent->rrpos++;
03053       qe->linpos++;
03054       ao2_unlock(qe->parent);
03055 
03056       (*busies)++;
03057       return 0;
03058    }
03059 
03060    ast_channel_lock_both(tmp->chan, qe->chan);
03061 
03062    if (qe->cancel_answered_elsewhere) {
03063       ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE);
03064    }
03065    tmp->chan->appl = "AppQueue";
03066    tmp->chan->data = "(Outgoing Line)";
03067    memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
03068 
03069    /* If the new channel has no callerid, try to guess what it should be */
03070    if (!tmp->chan->caller.id.number.valid) {
03071       if (qe->chan->connected.id.number.valid) {
03072          struct ast_party_caller caller;
03073 
03074          ast_party_caller_set_init(&caller, &tmp->chan->caller);
03075          caller.id = qe->chan->connected.id;
03076          caller.ani = qe->chan->connected.ani;
03077          ast_channel_set_caller_event(tmp->chan, &caller, NULL);
03078       } else if (!ast_strlen_zero(qe->chan->dialed.number.str)) {
03079          ast_set_callerid(tmp->chan, qe->chan->dialed.number.str, NULL, NULL);
03080       } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
03081          ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL); 
03082       }
03083       tmp->dial_callerid_absent = 1;
03084    }
03085 
03086    ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
03087 
03088    tmp->chan->dialed.transit_network_select = qe->chan->dialed.transit_network_select;
03089 
03090    ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->caller);
03091 
03092    /* Inherit specially named variables from parent channel */
03093    ast_channel_inherit_variables(qe->chan, tmp->chan);
03094    ast_channel_datastore_inherit(qe->chan, tmp->chan);
03095 
03096    /* Presense of ADSI CPE on outgoing channel follows ours */
03097    tmp->chan->adsicpe = qe->chan->adsicpe;
03098 
03099    /* Inherit context and extension */
03100    macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
03101    ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext);
03102    macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
03103    if (!ast_strlen_zero(macroexten))
03104       ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
03105    else
03106       ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
03107    if (ast_cdr_isset_unanswered()) {
03108       /* they want to see the unanswered dial attempts! */
03109       /* set up the CDR fields on all the CDRs to give sensical information */
03110       ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name);
03111       strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid);
03112       strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel);
03113       strcpy(tmp->chan->cdr->src, qe->chan->cdr->src);
03114       strcpy(tmp->chan->cdr->dst, qe->chan->exten);
03115       strcpy(tmp->chan->cdr->dcontext, qe->chan->context);
03116       strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp);
03117       strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata);
03118       tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags;
03119       strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode);
03120       strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
03121    }
03122 
03123    ast_channel_unlock(tmp->chan);
03124    ast_channel_unlock(qe->chan);
03125 
03126    /* Place the call, but don't wait on the answer */
03127    if ((res = ast_call(tmp->chan, location, 0))) {
03128       /* Again, keep going even if there's an error */
03129       ast_debug(1, "ast call on peer returned %d\n", res);
03130       ast_verb(3, "Couldn't call %s\n", tmp->interface);
03131       do_hang(tmp);
03132       (*busies)++;
03133       update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
03134       return 0;
03135    } else if (qe->parent->eventwhencalled) {
03136       char vars[2048];
03137 
03138       ast_channel_lock_both(tmp->chan, qe->chan);
03139 
03140       manager_event(EVENT_FLAG_AGENT, "AgentCalled",
03141          "Queue: %s\r\n"
03142          "AgentCalled: %s\r\n"
03143          "AgentName: %s\r\n"
03144          "ChannelCalling: %s\r\n"
03145          "DestinationChannel: %s\r\n"
03146          "CallerIDNum: %s\r\n"
03147          "CallerIDName: %s\r\n"
03148          "ConnectedLineNum: %s\r\n"
03149          "ConnectedLineName: %s\r\n"
03150          "Context: %s\r\n"
03151          "Extension: %s\r\n"
03152          "Priority: %d\r\n"
03153          "Uniqueid: %s\r\n"
03154          "%s",
03155          qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
03156          S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
03157          S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
03158          S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),
03159          S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
03160          qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
03161          qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03162 
03163       ast_channel_unlock(tmp->chan);
03164       ast_channel_unlock(qe->chan);
03165 
03166       ast_verb(3, "Called %s\n", tmp->interface);
03167    }
03168 
03169    update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
03170    return 1;
03171 }

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

Return values:
1 if a member was called successfully
0 otherwise

Definition at line 3199 of file app_queue.c.

References ast_debug, callattempt::chan, queue_ent::expire, find_best(), callattempt::interface, callattempt::metric, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_entry(), callattempt::stillgoing, and call_queue::strategy.

Referenced by wait_for_answer().

03200 {
03201    int ret = 0;
03202 
03203    while (ret == 0) {
03204       struct callattempt *best = find_best(outgoing);
03205       if (!best) {
03206          ast_debug(1, "Nobody left to try ringing in queue\n");
03207          break;
03208       }
03209       if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
03210          struct callattempt *cur;
03211          /* Ring everyone who shares this best metric (for ringall) */
03212          for (cur = outgoing; cur; cur = cur->q_next) {
03213             if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
03214                ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
03215                ret |= ring_entry(qe, cur, busies);
03216             }
03217          }
03218       } else {
03219          /* Ring just the best channel */
03220          ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
03221          ret = ring_entry(qe, best, busies);
03222       }
03223       
03224       /* If we have timed out, break out */
03225       if (qe->expire && (time(NULL) >= qe->expire)) {
03226          ast_debug(1, "Queue timed out while ringing members.\n");
03227          ret = 0;
03228          break;
03229       }
03230    }
03231 
03232    return ret;
03233 }

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 3357 of file app_queue.c.

References ast_indicate(), ast_moh_start(), ast_queue_log(), ast_verb, call_queue::autopause, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, manager_event, queue_ent::moh, ast_channel::name, call_queue::name, queue_ent::parent, QUEUE_AUTOPAUSE_OFF, QUEUE_AUTOPAUSE_ON, QUEUE_EVENT_VARIABLES, queue_ent::ring_when_ringing, set_member_paused(), ast_channel::uniqueid, and vars2manager().

03358 {
03359    ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
03360 
03361    /* Stop ringing, and resume MOH if specified */
03362    if (qe->ring_when_ringing) {
03363       ast_indicate(qe->chan, -1);
03364       ast_moh_start(qe->chan, qe->moh, NULL);
03365    }
03366 
03367    if (qe->parent->eventwhencalled) {
03368       char vars[2048];
03369 
03370       manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
03371                   "Queue: %s\r\n"
03372                   "Uniqueid: %s\r\n"
03373                   "Channel: %s\r\n"
03374                   "Member: %s\r\n"
03375                   "MemberName: %s\r\n"
03376                   "Ringtime: %d\r\n"
03377                   "%s",
03378                   qe->parent->name,
03379                   qe->chan->uniqueid,
03380                   qe->chan->name,
03381                   interface,
03382                   membername,
03383                   rnatime,
03384                   qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03385    }
03386    ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
03387    if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) {
03388       if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
03389          if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
03390             ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
03391                interface, qe->parent->name);
03392          } else {
03393             ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
03394          }
03395       } else {
03396          /* If queue autopause is mode all, just don't send any queue to stop.
03397          * the function will stop in all queues */
03398          if (!set_member_paused("", interface, "Auto-Pause", 1)) {
03399             ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
03400                   interface, qe->parent->name);
03401          } else {
03402                ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
03403          }
03404       }
03405    }
03406    return;
03407 }

static int rqm_exec ( struct ast_channel chan,
const char *  data 
) [static]

RemoveQueueMember application.

Definition at line 5594 of file app_queue.c.

References args, AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_NOTICE, LOG_WARNING, ast_channel::name, parse(), pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and ast_channel::uniqueid.

Referenced by load_module().

05595 {
05596    int res=-1;
05597    char *parse, *temppos = NULL;
05598    AST_DECLARE_APP_ARGS(args,
05599       AST_APP_ARG(queuename);
05600       AST_APP_ARG(interface);
05601       AST_APP_ARG(options);
05602    );
05603 
05604 
05605    if (ast_strlen_zero(data)) {
05606       ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n");
05607       return -1;
05608    }
05609 
05610    parse = ast_strdupa(data);
05611 
05612    AST_STANDARD_APP_ARGS(args, parse);
05613 
05614    if (ast_strlen_zero(args.interface)) {
05615       args.interface = ast_strdupa(chan->name);
05616       temppos = strrchr(args.interface, '-');
05617       if (temppos)
05618          *temppos = '\0';
05619    }
05620 
05621    ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
05622 
05623    switch (remove_from_queue(args.queuename, args.interface)) {
05624    case RES_OKAY:
05625       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
05626       ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
05627       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
05628       res = 0;
05629       break;
05630    case RES_EXISTS:
05631       ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
05632       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
05633       res = 0;
05634       break;
05635    case RES_NOSUCHQUEUE:
05636       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
05637       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
05638       res = 0;
05639       break;
05640    case RES_NOT_DYNAMIC:
05641       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
05642       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
05643       res = 0;
05644       break;
05645    }
05646 
05647    return res;
05648 }

static void rt_handle_member_record ( struct call_queue q,
char *  interface,
const char *  rt_uniqueid,
const char *  membername,
const char *  penalty_str,
const char *  paused_str,
const char *  state_interface 
) [static]

Find rt member record to update otherwise create one.

Search for member in queue, if found update penalty/paused state, if no member exists create one flag it as a RT member and add to queue member list.

Definition at line 2078 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_ref, ast_copy_string(), ast_log(), ast_queue_log(), ast_strlen_zero(), create_queue_member(), member::dead, member::interface, LOG_WARNING, call_queue::members, call_queue::name, member::paused, member::penalty, member::realtime, member::rt_uniqueid, S_OR, and member::state_interface.

Referenced by update_realtime_members().

02079 {
02080    struct member *m;
02081    struct ao2_iterator mem_iter;
02082    int penalty = 0;
02083    int paused  = 0;
02084    int found = 0;
02085 
02086    if (ast_strlen_zero(rt_uniqueid)) {
02087       ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
02088       return;
02089    }
02090 
02091    if (penalty_str) {
02092       penalty = atoi(penalty_str);
02093       if (penalty < 0)
02094          penalty = 0;
02095    }
02096 
02097    if (paused_str) {
02098       paused = atoi(paused_str);
02099       if (paused < 0)
02100          paused = 0;
02101    }
02102 
02103    /* Find member by realtime uniqueid and update */
02104    mem_iter = ao2_iterator_init(q->members, 0);
02105    while ((m = ao2_iterator_next(&mem_iter))) {
02106       if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
02107          m->dead = 0;   /* Do not delete this one. */
02108          ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
02109          if (paused_str)
02110             m->paused = paused;
02111          if (strcasecmp(state_interface, m->state_interface)) {
02112             ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
02113          }     
02114          m->penalty = penalty;
02115          found = 1;
02116          ao2_ref(m, -1);
02117          break;
02118       }
02119       ao2_ref(m, -1);
02120    }
02121    ao2_iterator_destroy(&mem_iter);
02122 
02123    /* Create a new member */
02124    if (!found) {
02125       if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
02126          m->dead = 0;
02127          m->realtime = 1;
02128          ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
02129          ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
02130          ao2_link(q->members, m);
02131          ao2_ref(m, -1);
02132          m = NULL;
02133       }
02134    }
02135 }

static int say_periodic_announcement ( struct queue_ent qe,
int  ringing 
) [static]

Playback announcement to queued members if period has elapsed.

Definition at line 3284 of file app_queue.c.

References AST_CONTROL_RINGING, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_random(), ast_str_buffer(), ast_str_strlen(), ast_verb, queue_ent::chan, queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::moh, call_queue::numperiodicannounce, queue_ent::parent, call_queue::periodicannouncefrequency, play_file(), call_queue::randomperiodicannounce, call_queue::relativeperiodicannounce, call_queue::sound_periodicannounce, and valid_exit().

Referenced by queue_exec().

03285 {
03286    int res = 0;
03287    time_t now;
03288 
03289    /* Get the current time */
03290    time(&now);
03291 
03292    /* Check to see if it is time to announce */
03293    if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
03294       return 0;
03295 
03296    /* Stop the music on hold so we can play our own file */
03297    if (ringing)
03298       ast_indicate(qe->chan,-1);
03299    else
03300       ast_moh_stop(qe->chan);
03301 
03302    ast_verb(3, "Playing periodic announcement\n");
03303    
03304    if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) {
03305       qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
03306    } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce || 
03307       ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) {
03308       qe->last_periodic_announce_sound = 0;
03309    }
03310    
03311    /* play the announcement */
03312    res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]));
03313 
03314    if (res > 0 && !valid_exit(qe, res))
03315       res = 0;
03316 
03317    /* Resume Music on Hold if the caller is going to stay in the queue */
03318    if (!res) {
03319       if (ringing)
03320          ast_indicate(qe->chan, AST_CONTROL_RINGING);
03321       else
03322          ast_moh_start(qe->chan, qe->moh, NULL);
03323    }
03324 
03325    /* update last_periodic_announce_time */
03326    if (qe->parent->relativeperiodicannounce)
03327       time(&qe->last_periodic_announce_time);
03328    else
03329       qe->last_periodic_announce_time = now;
03330 
03331    /* Update the current periodic announcement to the next announcement */
03332    if (!qe->parent->randomperiodicannounce) {
03333       qe->last_periodic_announce_sound++;
03334    }
03335    
03336    return res;
03337 }

static int say_position ( struct queue_ent qe,
int  ringing 
) [static]

Definition at line 2588 of file app_queue.c.

References call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ONCE, call_queue::announceposition, ANNOUNCEPOSITION_LIMIT, ANNOUNCEPOSITION_MORE_THAN, ANNOUNCEPOSITION_YES, call_queue::announcepositionlimit, AST_CONTROL_RINGING, AST_DIGIT_ANY, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_say_number(), ast_verb, queue_ent::chan, call_queue::holdtime, ast_channel::language, queue_ent::last_pos, queue_ent::last_pos_said, call_queue::minannouncefrequency, queue_ent::moh, ast_channel::name, call_queue::name, queue_ent::parent, play_file(), queue_ent::pos, call_queue::queue_quantity1, call_queue::queue_quantity2, call_queue::roundingseconds, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_minute, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, queue_ent::start, and valid_exit().

Referenced by queue_exec().

02589 {
02590    int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
02591    int say_thanks = 1;
02592    time_t now;
02593 
02594    /* Let minannouncefrequency seconds pass between the start of each position announcement */
02595    time(&now);
02596    if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
02597       return 0;
02598 
02599    /* If either our position has changed, or we are over the freq timer, say position */
02600    if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
02601       return 0;
02602 
02603    if (ringing) {
02604       ast_indicate(qe->chan,-1);
02605    } else {
02606       ast_moh_stop(qe->chan);
02607    }
02608 
02609    if (qe->parent->announceposition == ANNOUNCEPOSITION_YES ||
02610       qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN ||
02611       (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT &&
02612       qe->pos <= qe->parent->announcepositionlimit))
02613          announceposition = 1;
02614 
02615 
02616    if (announceposition == 1) {
02617       /* Say we're next, if we are */
02618       if (qe->pos == 1) {
02619          res = play_file(qe->chan, qe->parent->sound_next);
02620          if (res)
02621             goto playout;
02622          else
02623             goto posout;
02624       } else {
02625          if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
02626             /* More than Case*/
02627             res = play_file(qe->chan, qe->parent->queue_quantity1);
02628             if (res)
02629                goto playout;
02630             res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
02631             if (res)
02632                goto playout;
02633          } else {
02634             /* Normal Case */
02635             res = play_file(qe->chan, qe->parent->sound_thereare);
02636             if (res)
02637                goto playout;
02638             res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
02639             if (res)
02640                goto playout;
02641          }
02642          if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
02643             /* More than Case*/
02644             res = play_file(qe->chan, qe->parent->queue_quantity2);
02645             if (res)
02646                goto playout;
02647          } else {
02648             res = play_file(qe->chan, qe->parent->sound_calls);
02649             if (res)
02650                goto playout;
02651          }
02652       }
02653    }
02654    /* Round hold time to nearest minute */
02655    avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
02656 
02657    /* If they have specified a rounding then round the seconds as well */
02658    if (qe->parent->roundingseconds) {
02659       avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
02660       avgholdsecs *= qe->parent->roundingseconds;
02661    } else {
02662       avgholdsecs = 0;
02663    }
02664 
02665    ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
02666 
02667    /* If the hold time is >1 min, if it's enabled, and if it's not
02668       supposed to be only once and we have already said it, say it */
02669     if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
02670         ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
02671         !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
02672       res = play_file(qe->chan, qe->parent->sound_holdtime);
02673       if (res)
02674          goto playout;
02675 
02676       if (avgholdmins >= 1) {
02677          res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
02678          if (res)
02679             goto playout;
02680 
02681          if (avgholdmins == 1) {
02682             res = play_file(qe->chan, qe->parent->sound_minute);
02683             if (res)
02684                goto playout;
02685          } else {
02686             res = play_file(qe->chan, qe->parent->sound_minutes);
02687             if (res)
02688                goto playout;
02689          }
02690       }
02691       if (avgholdsecs >= 1) {
02692          res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
02693          if (res)
02694             goto playout;
02695 
02696          res = play_file(qe->chan, qe->parent->sound_seconds);
02697          if (res)
02698             goto playout;
02699       }
02700    } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
02701       say_thanks = 0;
02702    }
02703 
02704 posout:
02705    if (qe->parent->announceposition) {
02706       ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
02707          qe->chan->name, qe->parent->name, qe->pos);
02708    }
02709    if (say_thanks) {
02710       res = play_file(qe->chan, qe->parent->sound_thanks);
02711    }
02712 playout:
02713 
02714    if ((res > 0 && !valid_exit(qe, res)))
02715       res = 0;
02716 
02717    /* Set our last_pos indicators */
02718    qe->last_pos = now;
02719    qe->last_pos_said = qe->pos;
02720 
02721    /* Don't restart music on hold if we're about to exit the caller from the queue */
02722    if (!res) {
02723       if (ringing) {
02724          ast_indicate(qe->chan, AST_CONTROL_RINGING);
02725       } else {
02726          ast_moh_start(qe->chan, qe->moh, NULL);
02727       }
02728    }
02729    return res;
02730 }

static void send_agent_complete ( const struct queue_ent qe,
const char *  queuename,
const struct ast_channel peer,
const struct member member,
time_t  callstart,
char *  vars,
size_t  vars_len,
enum agent_complete_reason  rsn 
) [static]

Send out AMI message with member call completion status information.

Definition at line 4115 of file app_queue.c.

References AGENT, CALLER, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, member::interface, manager_event, member::membername, ast_channel::name, queue_ent::parent, QUEUE_EVENT_VARIABLES, queue_ent::start, ast_channel::uniqueid, and vars2manager().

04118 {
04119    const char *reason = NULL; /* silence dumb compilers */
04120 
04121    if (!qe->parent->eventwhencalled)
04122       return;
04123 
04124    switch (rsn) {
04125    case CALLER:
04126       reason = "caller";
04127       break;
04128    case AGENT:
04129       reason = "agent";
04130       break;
04131    case TRANSFER:
04132       reason = "transfer";
04133       break;
04134    }
04135 
04136    manager_event(EVENT_FLAG_AGENT, "AgentComplete",
04137       "Queue: %s\r\n"
04138       "Uniqueid: %s\r\n"
04139       "Channel: %s\r\n"
04140       "Member: %s\r\n"
04141       "MemberName: %s\r\n"
04142       "HoldTime: %ld\r\n"
04143       "TalkTime: %ld\r\n"
04144       "Reason: %s\r\n"
04145       "%s",
04146       queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
04147       (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
04148       qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
04149 }

static int set_member_paused ( const char *  queuename,
const char *  interface,
const char *  reason,
int  paused 
) [static]

Definition at line 5270 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_debug, ast_log(), ast_queue_log(), ast_strlen_zero(), dump_queue_members(), EVENT_FLAG_AGENT, member::interface, interface_exists(), LOG_WARNING, manager_event, member::membername, call_queue::name, member::paused, queue_t_unref, queues, member::realtime, RESULT_FAILURE, RESULT_SUCCESS, S_OR, and update_realtime_member_field().

Referenced by handle_queue_pause_member(), manager_pause_queue_member(), pqm_exec(), rna(), and upqm_exec().

05271 {
05272    int found = 0;
05273    struct call_queue *q;
05274    struct member *mem;
05275    struct ao2_iterator queue_iter;
05276    int failed;
05277 
05278    /* Special event for when all queues are paused - individual events still generated */
05279    /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
05280    if (ast_strlen_zero(queuename))
05281       ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
05282 
05283    queue_iter = ao2_iterator_init(queues, 0);
05284    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
05285       ao2_lock(q);
05286       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
05287          if ((mem = interface_exists(q, interface))) {
05288             if (mem->paused == paused) {
05289                ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
05290             }
05291 
05292             failed = 0;
05293             if (mem->realtime) {
05294                failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
05295             }
05296          
05297             if (failed) {
05298                ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface);
05299                ao2_ref(mem, -1);
05300                ao2_unlock(q);
05301                queue_t_unref(q, "Done with iterator");
05302                continue;
05303             }  
05304             found++;
05305             mem->paused = paused;
05306 
05307             if (queue_persistent_members)
05308                dump_queue_members(q);
05309 
05310             ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
05311             
05312             if (!ast_strlen_zero(reason)) {
05313                manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
05314                   "Queue: %s\r\n"
05315                   "Location: %s\r\n"
05316                   "MemberName: %s\r\n"
05317                   "Paused: %d\r\n"
05318                   "Reason: %s\r\n",
05319                      q->name, mem->interface, mem->membername, paused, reason);
05320             } else {
05321                manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
05322                   "Queue: %s\r\n"
05323                   "Location: %s\r\n"
05324                   "MemberName: %s\r\n"
05325                   "Paused: %d\r\n",
05326                      q->name, mem->interface, mem->membername, paused);
05327             }
05328             ao2_ref(mem, -1);
05329          }
05330       }
05331       
05332       if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) {
05333          ao2_unlock(q);
05334          queue_t_unref(q, "Done with iterator");
05335          break;
05336       }
05337       
05338       ao2_unlock(q);
05339       queue_t_unref(q, "Done with iterator");
05340    }
05341    ao2_iterator_destroy(&queue_iter);
05342 
05343    return found ? RESULT_SUCCESS : RESULT_FAILURE;
05344 }

static int set_member_penalty ( const char *  queuename,
const char *  interface,
int  penalty 
) [static]

Definition at line 5347 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, ast_log(), ast_queue_log(), ast_strlen_zero(), EVENT_FLAG_AGENT, member::interface, interface_exists(), LOG_ERROR, manager_event, call_queue::name, member::penalty, queue_t_unref, queues, RESULT_FAILURE, and RESULT_SUCCESS.

Referenced by handle_queue_set_member_penalty(), manager_queue_member_penalty(), and queue_function_memberpenalty_write().

05348 {
05349    int foundinterface = 0, foundqueue = 0;
05350    struct call_queue *q;
05351    struct member *mem;
05352    struct ao2_iterator queue_iter;
05353 
05354    if (penalty < 0) {
05355       ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty);
05356       return RESULT_FAILURE;
05357    }
05358 
05359    queue_iter = ao2_iterator_init(queues, 0);
05360    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
05361       ao2_lock(q);
05362       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
05363          foundqueue++;
05364          if ((mem = interface_exists(q, interface))) {
05365             foundinterface++;
05366             mem->penalty = penalty;
05367             
05368             ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
05369             manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
05370                "Queue: %s\r\n"
05371                "Location: %s\r\n"
05372                "Penalty: %d\r\n",
05373                q->name, mem->interface, penalty);
05374             ao2_ref(mem, -1);
05375          }
05376       }
05377       ao2_unlock(q);
05378       queue_t_unref(q, "Done with iterator");
05379    }
05380    ao2_iterator_destroy(&queue_iter);
05381 
05382    if (foundinterface) {
05383       return RESULT_SUCCESS;
05384    } else if (!foundqueue) {
05385       ast_log (LOG_ERROR, "Invalid queuename\n"); 
05386    } else {
05387       ast_log (LOG_ERROR, "Invalid interface\n");
05388    }  
05389 
05390    return RESULT_FAILURE;
05391 }

static void set_queue_result ( struct ast_channel chan,
enum queue_result  res 
) [static]

sets the QUEUESTATUS channel variable

Definition at line 1193 of file app_queue.c.

References ARRAY_LEN, pbx_builtin_setvar_helper(), queue_results, and text.

Referenced by queue_exec().

01194 {
01195    int i;
01196 
01197    for (i = 0; i < ARRAY_LEN(queue_results); i++) {
01198       if (queue_results[i].id == res) {
01199          pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
01200          return;
01201       }
01202    }
01203 }

static void set_queue_variables ( struct call_queue q,
struct ast_channel chan 
) [static]

Set variables of queue.

Definition at line 1288 of file app_queue.c.

References ao2_lock, ao2_unlock, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, call_queue::count, call_queue::holdtime, int2strat(), call_queue::maxlen, call_queue::name, pbx_builtin_setvar_multiple(), call_queue::servicelevel, call_queue::setqueuevar, call_queue::strategy, and call_queue::talktime.

Referenced by end_bridge_callback(), and record_abandoned().

01289 {
01290    char interfacevar[256]="";
01291    float sl = 0;
01292 
01293    ao2_lock(q);
01294 
01295    if (q->setqueuevar) {
01296       sl = 0;
01297       if (q->callscompleted > 0) 
01298          sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
01299 
01300       snprintf(interfacevar, sizeof(interfacevar),
01301          "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
01302          q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned,  q->servicelevel, sl);
01303 
01304       ao2_unlock(q);
01305    
01306       pbx_builtin_setvar_multiple(chan, interfacevar); 
01307    } else {
01308       ao2_unlock(q);
01309    }
01310 }

static struct ast_datastore* setup_transfer_datastore ( struct queue_ent qe,
struct member member,
time_t  starttime,
int  callcompletedinsl 
) [static]

create a datastore for storing relevant info to log attended transfers in the queue_log

Definition at line 4219 of file app_queue.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_log(), queue_ent::chan, ast_datastore::data, LOG_WARNING, queue_transfer_ds::member, queue_transfer_ds::qe, and queue_transfer_info.

04220 {
04221    struct ast_datastore *ds;
04222    struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
04223 
04224    if (!qtds) {
04225       ast_log(LOG_WARNING, "Memory allocation error!\n");
04226       return NULL;
04227    }
04228 
04229    ast_channel_lock(qe->chan);
04230    if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) {
04231       ast_channel_unlock(qe->chan);
04232       ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
04233       return NULL;
04234    }
04235 
04236    qtds->qe = qe;
04237    /* This member is refcounted in try_calling, so no need to add it here, too */
04238    qtds->member = member;
04239    qtds->starttime = starttime;
04240    qtds->callcompletedinsl = callcompletedinsl;
04241    ds->data = qtds;
04242    ast_channel_datastore_add(qe->chan, ds);
04243    ast_channel_unlock(qe->chan);
04244    return ds;
04245 }

static int store_next_lin ( struct queue_ent qe,
struct callattempt outgoing 
) [static]

Search for best metric and add to Linear queue.

Definition at line 3260 of file app_queue.c.

References ast_debug, find_best(), callattempt::interface, queue_ent::linpos, queue_ent::linwrapped, and callattempt::metric.

03261 {
03262    struct callattempt *best = find_best(outgoing);
03263 
03264    if (best) {
03265       /* Ring just the best channel */
03266       ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
03267       qe->linpos = best->metric % 1000;
03268    } else {
03269       /* Just increment rrpos */
03270       if (qe->linwrapped) {
03271          /* No more channels, start over */
03272          qe->linpos = 0;
03273       } else {
03274          /* Prioritize next entry */
03275          qe->linpos++;
03276       }
03277    }
03278    qe->linwrapped = 0;
03279 
03280    return 0;
03281 }

static int store_next_rr ( struct queue_ent qe,
struct callattempt outgoing 
) [static]

Search for best metric and add to Round Robbin queue.

Definition at line 3236 of file app_queue.c.

References ast_debug, find_best(), callattempt::interface, callattempt::metric, queue_ent::parent, call_queue::rrpos, and call_queue::wrapped.

03237 {
03238    struct callattempt *best = find_best(outgoing);
03239 
03240    if (best) {
03241       /* Ring just the best channel */
03242       ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
03243       qe->parent->rrpos = best->metric % 1000;
03244    } else {
03245       /* Just increment rrpos */
03246       if (qe->parent->wrapped) {
03247          /* No more channels, start over */
03248          qe->parent->rrpos = 0;
03249       } else {
03250          /* Prioritize next entry */
03251          qe->parent->rrpos++;
03252       }
03253    }
03254    qe->parent->wrapped = 0;
03255 
03256    return 0;
03257 }

static int strat2int ( const char *  strategy  )  [static]

Definition at line 1217 of file app_queue.c.

References ARRAY_LEN, strategies, and strategy::strategy.

Referenced by find_queue_by_name_rt(), queue_set_param(), and reload_single_queue().

01218 {
01219    int x;
01220 
01221    for (x = 0; x < ARRAY_LEN(strategies); x++) {
01222       if (!strcasecmp(strategy, strategies[x].name))
01223          return strategies[x].strategy;
01224    }
01225 
01226    return -1;
01227 }

static int try_calling ( struct queue_ent qe,
const char *  options,
char *  announceoverride,
const char *  url,
int *  tries,
int *  noption,
const char *  agi,
const char *  macro,
const char *  gosub,
int  ringing 
) [static]

A large function which calls members, updates statistics, and bridges the caller and a member.

Here is the process of this function 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue() 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also during each iteration, we call calc_metric to determine which members should be rung when. 3. Call ring_one to place a call to the appropriate member(s) 4. Call wait_for_answer to wait for an answer. If no one answers, return. 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered. 6. Start the monitor or mixmonitor if the option is set 7. Remove the caller from the queue to allow other callers to advance 8. Bridge the call. 9. Do any post processing after the call has disconnected.

Parameters:
[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
[in] options the options passed as the third parameter to the Queue() application
[in] announceoverride filename to play to user when waiting
[in] url the url passed as the fourth parameter to the Queue() application
[in,out] tries the number of times we have tried calling queue members
[out] noption set if the call to Queue() has the 'n' option set.
[in] agi the agi passed as the fifth parameter to the Queue() application
[in] macro the macro passed as the sixth parameter to the Queue() application
[in] gosub the gosub passed as the seventh parameter to the Queue() application
[in] ringing 1 if the 'r' option is set, otherwise 0

Definition at line 4299 of file app_queue.c.

References ao2_container_count(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_FEATURE_AUTOMIXMON, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAG_ANSWERED_ELSEWHERE, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_set_flag, ast_test_flag, queue_ent::cancel_answered_elsewhere, queue_ent::chan, dialed_interface_info, queue_ent::expire, call_queue::members, queue_ent::parent, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, and call_queue::strategy.

Referenced by queue_exec().

04300 {
04301    struct member *cur;
04302    struct callattempt *outgoing = NULL; /* the list of calls we are building */
04303    int to, orig;
04304    char oldexten[AST_MAX_EXTENSION]="";
04305    char oldcontext[AST_MAX_CONTEXT]="";
04306    char queuename[256]="";
04307    char interfacevar[256]="";
04308    struct ast_channel *peer;
04309    struct ast_channel *which;
04310    struct callattempt *lpeer;
04311    struct member *member;
04312    struct ast_app *application;
04313    int res = 0, bridge = 0;
04314    int numbusies = 0;
04315    int x=0;
04316    char *announce = NULL;
04317    char digit = 0;
04318    time_t callstart;
04319    time_t now = time(NULL);
04320    struct ast_bridge_config bridge_config;
04321    char nondataquality = 1;
04322    char *agiexec = NULL;
04323    char *macroexec = NULL;
04324    char *gosubexec = NULL;
04325    const char *monitorfilename;
04326    const char *monitor_exec;
04327    const char *monitor_options;
04328    char tmpid[256], tmpid2[256];
04329    char meid[1024], meid2[1024];
04330    char mixmonargs[1512];
04331    struct ast_app *mixmonapp = NULL;
04332    char *p;
04333    char vars[2048];
04334    int forwardsallowed = 1;
04335    int update_connectedline = 1;
04336    int callcompletedinsl;
04337    struct ao2_iterator memi;
04338    struct ast_datastore *datastore, *transfer_ds;
04339    struct queue_end_bridge *queue_end_bridge = NULL;
04340 
04341    ast_channel_lock(qe->chan);
04342    datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
04343    ast_channel_unlock(qe->chan);
04344 
04345    memset(&bridge_config, 0, sizeof(bridge_config));
04346    tmpid[0] = 0;
04347    meid[0] = 0;
04348    time(&now);
04349 
04350    /* If we've already exceeded our timeout, then just stop
04351     * This should be extremely rare. queue_exec will take care
04352     * of removing the caller and reporting the timeout as the reason.
04353     */
04354    if (qe->expire && now >= qe->expire) {
04355       res = 0;
04356       goto out;
04357    }
04358       
04359    for (; options && *options; options++)
04360       switch (*options) {
04361       case 't':
04362          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
04363          break;
04364       case 'T':
04365          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
04366          break;
04367       case 'w':
04368          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
04369          break;
04370       case 'W':
04371          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
04372          break;
04373       case 'c':
04374          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN);
04375          break;
04376       case 'd':
04377          nondataquality = 0;
04378          break;
04379       case 'h':
04380          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
04381          break;
04382       case 'H':
04383          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
04384          break;
04385       case 'k':
04386          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
04387          break;
04388       case 'K':
04389          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
04390          break;
04391       case 'n':
04392          if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED)
04393             (*tries)++;
04394          else
04395             *tries = ao2_container_count(qe->parent->members);
04396          *noption = 1;
04397          break;
04398       case 'i':
04399          forwardsallowed = 0;
04400          break;
04401       case 'I':
04402          update_connectedline = 0;
04403          break;
04404       case 'x':
04405          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
04406          break;
04407       case 'X':
04408          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
04409          break;
04410       case 'C':
04411          qe->cancel_answered_elsewhere = 1;
04412          break;
04413       }
04414 
04415    /* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited. 
04416       (this is mainly to support chan_local)
04417    */
04418    if (ast_test_flag(qe->chan, AST_FLAG_ANSWERED_ELSEWHERE)) {
04419       qe->cancel_answered_elsewhere = 1;
04420    }
04421 
04422    ao2_lock(qe->parent);
04423    ast_debug(1, "%s is trying to call a queue member.\n",
04424                      qe->chan->name);
04425    ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
04426    if (!ast_strlen_zero(qe->announce))
04427       announce = qe->announce;
04428    if (!ast_strlen_zero(announceoverride))
04429       announce = announceoverride;
04430 
04431    memi = ao2_iterator_init(qe->parent->members, 0);
04432    while ((cur = ao2_iterator_next(&memi))) {
04433       struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
04434       struct ast_dialed_interface *di;
04435       AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
04436       if (!tmp) {
04437          ao2_ref(cur, -1);
04438          ao2_iterator_destroy(&memi);
04439          ao2_unlock(qe->parent);
04440          goto out;
04441       }
04442       if (!datastore) {
04443          if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
04444             callattempt_free(tmp);
04445             ao2_ref(cur, -1);
04446             ao2_iterator_destroy(&memi);
04447             ao2_unlock(qe->parent);
04448             goto out;
04449          }
04450          datastore->inheritance = DATASTORE_INHERIT_FOREVER;
04451          if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
04452             callattempt_free(tmp);
04453             ao2_ref(cur, -1);
04454             ao2_iterator_destroy(&memi);
04455             ao2_unlock(&qe->parent);
04456             goto out;
04457          }
04458          datastore->data = dialed_interfaces;
04459          AST_LIST_HEAD_INIT(dialed_interfaces);
04460 
04461          ast_channel_lock(qe->chan);
04462          ast_channel_datastore_add(qe->chan, datastore);
04463          ast_channel_unlock(qe->chan);
04464       } else
04465          dialed_interfaces = datastore->data;
04466 
04467       AST_LIST_LOCK(dialed_interfaces);
04468       AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
04469          if (!strcasecmp(cur->interface, di->interface)) {
04470             ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n", 
04471                di->interface);
04472             break;
04473          }
04474       }
04475       AST_LIST_UNLOCK(dialed_interfaces);
04476 
04477       if (di) {
04478          callattempt_free(tmp);
04479          ao2_ref(cur, -1);
04480          continue;
04481       }
04482 
04483       /* It is always ok to dial a Local interface.  We only keep track of
04484        * which "real" interfaces have been dialed.  The Local channel will
04485        * inherit this list so that if it ends up dialing a real interface,
04486        * it won't call one that has already been called. */
04487       if (strncasecmp(cur->interface, "Local/", 6)) {
04488          if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
04489             callattempt_free(tmp);
04490             ao2_ref(cur, -1);
04491             ao2_iterator_destroy(&memi);
04492             ao2_unlock(qe->parent);
04493             goto out;
04494          }
04495          strcpy(di->interface, cur->interface);
04496 
04497          AST_LIST_LOCK(dialed_interfaces);
04498          AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
04499          AST_LIST_UNLOCK(dialed_interfaces);
04500       }
04501 
04502       ast_channel_lock(qe->chan);
04503       /*
04504        * Seed the callattempt's connected line information with previously
04505        * acquired connected line info from the queued channel.  The
04506        * previously acquired connected line info could have been set
04507        * through the CONNECTED_LINE dialplan function.
04508        */
04509       ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected);
04510       ast_channel_unlock(qe->chan);
04511 
04512       tmp->stillgoing = -1;
04513       tmp->member = cur;/* Place the reference for cur into callattempt. */
04514       tmp->lastcall = cur->lastcall;
04515       tmp->lastqueue = cur->lastqueue;
04516       ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
04517       /* Special case: If we ring everyone, go ahead and ring them, otherwise
04518          just calculate their metric for the appropriate strategy */
04519       if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
04520          /* Put them in the list of outgoing thingies...  We're ready now.
04521             XXX If we're forcibly removed, these outgoing calls won't get
04522             hung up XXX */
04523          tmp->q_next = outgoing;
04524          outgoing = tmp;      
04525          /* If this line is up, don't try anybody else */
04526          if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
04527             break;
04528       } else {
04529          callattempt_free(tmp);
04530       }
04531    }
04532    ao2_iterator_destroy(&memi);
04533 
04534    if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) {
04535       /* Application arguments have higher timeout priority (behaviour for <=1.6) */
04536       if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
04537          to = (qe->expire - now) * 1000;
04538       else
04539          to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
04540    } else {
04541       /* Config timeout is higher priority thatn application timeout */
04542       if (qe->expire && qe->expire<=now) {
04543          to = 0;
04544       } else if (qe->parent->timeout) {
04545          to = qe->parent->timeout * 1000;
04546       } else {
04547          to = -1;
04548       }
04549    }
04550    orig = to;
04551    ++qe->pending;
04552    ao2_unlock(qe->parent);
04553    ring_one(qe, outgoing, &numbusies);
04554    lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline);
04555    /* The ast_channel_datastore_remove() function could fail here if the
04556     * datastore was moved to another channel during a masquerade. If this is
04557     * the case, don't free the datastore here because later, when the channel
04558     * to which the datastore was moved hangs up, it will attempt to free this
04559     * datastore again, causing a crash
04560     */
04561    ast_channel_lock(qe->chan);
04562    if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
04563       ast_datastore_free(datastore);
04564    }
04565    ast_channel_unlock(qe->chan);
04566    ao2_lock(qe->parent);
04567    if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) {
04568       store_next_rr(qe, outgoing);
04569 
04570    }
04571    if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
04572       store_next_lin(qe, outgoing);
04573    }
04574    ao2_unlock(qe->parent);
04575    peer = lpeer ? lpeer->chan : NULL;
04576    if (!peer) {
04577       qe->pending = 0;
04578       if (to) {
04579          /* Must gotten hung up */
04580          res = -1;
04581       } else {
04582          /* User exited by pressing a digit */
04583          res = digit;
04584       }
04585       if (res == -1)
04586          ast_debug(1, "%s: Nobody answered.\n", qe->chan->name);
04587       if (ast_cdr_isset_unanswered()) {
04588          /* channel contains the name of one of the outgoing channels
04589             in its CDR; zero out this CDR to avoid a dual-posting */
04590          struct callattempt *o;
04591          for (o = outgoing; o; o = o->q_next) {
04592             if (!o->chan) {
04593                continue;
04594             }
04595             if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) {
04596                ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED);
04597                break;
04598             }
04599          }
04600       }
04601    } else { /* peer is valid */
04602       /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
04603          we will always return with -1 so that it is hung up properly after the
04604          conversation.  */
04605       if (!strcmp(qe->chan->tech->type, "DAHDI"))
04606          ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
04607       if (!strcmp(peer->tech->type, "DAHDI"))
04608          ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
04609       /* Update parameters for the queue */
04610       time(&now);
04611       recalc_holdtime(qe, (now - qe->start));
04612       ao2_lock(qe->parent);
04613       callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
04614       ao2_unlock(qe->parent);
04615       member = lpeer->member;
04616       /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
04617       ao2_ref(member, 1);
04618       hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere);
04619       outgoing = NULL;
04620       if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
04621          int res2;
04622 
04623          res2 = ast_autoservice_start(qe->chan);
04624          if (!res2) {
04625             if (qe->parent->memberdelay) {
04626                ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
04627                res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
04628             }
04629             if (!res2 && announce) {
04630                play_file(peer, announce);
04631             }
04632             if (!res2 && qe->parent->reportholdtime) {
04633                if (!play_file(peer, qe->parent->sound_reporthold)) {
04634                   int holdtime, holdtimesecs;
04635 
04636                   time(&now);
04637                   holdtime = abs((now - qe->start) / 60);
04638                   holdtimesecs = abs((now - qe->start) % 60);
04639                   if (holdtime > 0) {
04640                      ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
04641                      play_file(peer, qe->parent->sound_minutes);
04642                   }
04643                   if (holdtimesecs > 1) {
04644                      ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL);
04645                      play_file(peer, qe->parent->sound_seconds);
04646                   }
04647                }
04648             }
04649          }
04650          res2 |= ast_autoservice_stop(qe->chan);
04651          if (ast_check_hangup(peer)) {
04652             /* Agent must have hung up */
04653             ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
04654             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
04655             if (qe->parent->eventwhencalled)
04656                manager_event(EVENT_FLAG_AGENT, "AgentDump",
04657                      "Queue: %s\r\n"
04658                      "Uniqueid: %s\r\n"
04659                      "Channel: %s\r\n"
04660                      "Member: %s\r\n"
04661                      "MemberName: %s\r\n"
04662                      "%s",
04663                      queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
04664                      qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
04665             ast_hangup(peer);
04666             ao2_ref(member, -1);
04667             goto out;
04668          } else if (res2) {
04669             /* Caller must have hung up just before being connected*/
04670             ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
04671             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
04672             record_abandoned(qe);
04673             ast_hangup(peer);
04674             ao2_ref(member, -1);
04675             return -1;
04676          }
04677       }
04678       /* Stop music on hold */
04679       if (ringing)
04680          ast_indicate(qe->chan,-1);
04681       else
04682          ast_moh_stop(qe->chan);
04683       /* If appropriate, log that we have a destination channel */
04684       if (qe->chan->cdr)
04685          ast_cdr_setdestchan(qe->chan->cdr, peer->name);
04686       /* Make sure channels are compatible */
04687       res = ast_channel_make_compatible(qe->chan, peer);
04688       if (res < 0) {
04689          ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
04690          ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
04691          record_abandoned(qe);
04692          ast_cdr_failed(qe->chan->cdr);
04693          ast_hangup(peer);
04694          ao2_ref(member, -1);
04695          return -1;
04696       }
04697 
04698       /* Play announcement to the caller telling it's his turn if defined */
04699       if (!ast_strlen_zero(qe->parent->sound_callerannounce)) {
04700          if (play_file(qe->chan, qe->parent->sound_callerannounce))
04701             ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
04702       }
04703 
04704       ao2_lock(qe->parent);
04705       /* if setinterfacevar is defined, make member variables available to the channel */
04706       /* use  pbx_builtin_setvar to set a load of variables with one call */
04707       if (qe->parent->setinterfacevar) {
04708          snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
04709             member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime);
04710          pbx_builtin_setvar_multiple(qe->chan, interfacevar);
04711          pbx_builtin_setvar_multiple(peer, interfacevar);
04712       }
04713       
04714       /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
04715       /* use  pbx_builtin_setvar to set a load of variables with one call */
04716       if (qe->parent->setqueueentryvar) {
04717          snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
04718             (long) time(NULL) - qe->start, qe->opos);
04719          pbx_builtin_setvar_multiple(qe->chan, interfacevar);
04720          pbx_builtin_setvar_multiple(peer, interfacevar);
04721       }
04722    
04723       ao2_unlock(qe->parent);
04724 
04725       /* try to set queue variables if configured to do so*/
04726       set_queue_variables(qe->parent, qe->chan);
04727       set_queue_variables(qe->parent, peer);
04728       
04729       ast_channel_lock(qe->chan);
04730       if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
04731             monitorfilename = ast_strdupa(monitorfilename);
04732       }
04733       ast_channel_unlock(qe->chan);
04734       /* Begin Monitoring */
04735       if (qe->parent->monfmt && *qe->parent->monfmt) {
04736          if (!qe->parent->montype) {
04737             const char *monexec, *monargs;
04738             ast_debug(1, "Starting Monitor as requested.\n");
04739             ast_channel_lock(qe->chan);
04740             if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || (monargs = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))) {
04741                which = qe->chan;
04742                monexec = monexec ? ast_strdupa(monexec) : NULL;
04743             }
04744             else
04745                which = peer;
04746             ast_channel_unlock(qe->chan);
04747             if (monitorfilename) {
04748                ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
04749             } else if (qe->chan->cdr) {
04750                ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT);
04751             } else {
04752                /* Last ditch effort -- no CDR, make up something */
04753                snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
04754                ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
04755             }
04756             if (!ast_strlen_zero(monexec)) {
04757                ast_monitor_setjoinfiles(which, 1);
04758             }
04759          } else {
04760             mixmonapp = pbx_findapp("MixMonitor");
04761             
04762             if (mixmonapp) {
04763                ast_debug(1, "Starting MixMonitor as requested.\n");
04764                if (!monitorfilename) {
04765                   if (qe->chan->cdr)
04766                      ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid));
04767                   else
04768                      snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
04769                } else {
04770                   const char *m = monitorfilename;
04771                   for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
04772                      switch (*m) {
04773                      case '^':
04774                         if (*(m + 1) == '{')
04775                            *p = '$';
04776                         break;
04777                      case ',':
04778                         *p++ = '\\';
04779                         /* Fall through */
04780                      default:
04781                         *p = *m;
04782                      }
04783                      if (*m == '\0')
04784                         break;
04785                   }
04786                   if (p == tmpid2 + sizeof(tmpid2))
04787                      tmpid2[sizeof(tmpid2) - 1] = '\0';
04788 
04789                   pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
04790                }
04791 
04792                ast_channel_lock(qe->chan);
04793                if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
04794                      monitor_exec = ast_strdupa(monitor_exec);
04795                }
04796                if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
04797                      monitor_options = ast_strdupa(monitor_options);
04798                } else {
04799                   monitor_options = "";
04800                }
04801                ast_channel_unlock(qe->chan);
04802 
04803                if (monitor_exec) {
04804                   const char *m = monitor_exec;
04805                   for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) {
04806                      switch (*m) {
04807                      case '^':
04808                         if (*(m + 1) == '{')
04809                            *p = '$';
04810                         break;
04811                      case ',':
04812                         *p++ = '\\';
04813                         /* Fall through */
04814                      default:
04815                         *p = *m;
04816                      }
04817                      if (*m == '\0')
04818                         break;
04819                   }
04820                   if (p == meid2 + sizeof(meid2))
04821                      meid2[sizeof(meid2) - 1] = '\0';
04822 
04823                   pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
04824                }
04825    
04826                snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt);
04827 
04828                if (!ast_strlen_zero(monitor_exec))
04829                   snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec);
04830                else
04831                   snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options);
04832                
04833                ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
04834                /* We purposely lock the CDR so that pbx_exec does not update the application data */
04835                if (qe->chan->cdr)
04836                   ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
04837                pbx_exec(qe->chan, mixmonapp, mixmonargs);
04838                if (qe->chan->cdr)
04839                   ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
04840 
04841             } else {
04842                ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
04843             }
04844          }
04845       }
04846       /* Drop out of the queue at this point, to prepare for next caller */
04847       leave_queue(qe);        
04848       if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
04849          ast_debug(1, "app_queue: sendurl=%s.\n", url);
04850          ast_channel_sendurl(peer, url);
04851       }
04852       
04853       /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
04854       /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
04855       if (!ast_strlen_zero(macro)) {
04856             macroexec = ast_strdupa(macro);
04857       } else {
04858          if (qe->parent->membermacro)
04859             macroexec = ast_strdupa(qe->parent->membermacro);
04860       }
04861 
04862       if (!ast_strlen_zero(macroexec)) {
04863          ast_debug(1, "app_queue: macro=%s.\n", macroexec);
04864          
04865          res = ast_autoservice_start(qe->chan);
04866          if (res) {
04867             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
04868             res = -1;
04869          }
04870          
04871          application = pbx_findapp("Macro");
04872 
04873          if (application) {
04874             res = pbx_exec(peer, application, macroexec);
04875             ast_debug(1, "Macro exited with status %d\n", res);
04876             res = 0;
04877          } else {
04878             ast_log(LOG_ERROR, "Could not find application Macro\n");
04879             res = -1;
04880          }
04881 
04882          if (ast_autoservice_stop(qe->chan) < 0) {
04883             ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
04884             res = -1;
04885          }
04886       }
04887 
04888       /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
04889       /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
04890       if (!ast_strlen_zero(gosub)) {
04891             gosubexec = ast_strdupa(gosub);
04892       } else {
04893          if (qe->parent->membergosub)
04894             gosubexec = ast_strdupa(qe->parent->membergosub);
04895       }
04896 
04897       if (!ast_strlen_zero(gosubexec)) {
04898          ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
04899          
04900          res = ast_autoservice_start(qe->chan);
04901          if (res) {
04902             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
04903             res = -1;
04904          }
04905          
04906          application = pbx_findapp("Gosub");
04907          
04908          if (application) {
04909             char *gosub_args, *gosub_argstart;
04910 
04911             /* Set where we came from */
04912             ast_copy_string(peer->context, "app_queue_gosub_virtual_context", sizeof(peer->context));
04913             ast_copy_string(peer->exten, "s", sizeof(peer->exten));
04914             peer->priority = 0;
04915 
04916             gosub_argstart = strchr(gosubexec, ',');
04917             if (gosub_argstart) {
04918                const char *what_is_s = "s";
04919                *gosub_argstart = 0;
04920                if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) &&
04921                    ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) {
04922                   what_is_s = "~~s~~";
04923                }
04924                if (asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
04925                   ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
04926                   gosub_args = NULL;
04927                }
04928                *gosub_argstart = ',';
04929             } else {
04930                const char *what_is_s = "s";
04931                if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) &&
04932                    ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) {
04933                   what_is_s = "~~s~~";
04934                }
04935                if (asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
04936                   ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
04937                   gosub_args = NULL;
04938                }
04939             }
04940             if (gosub_args) {
04941                res = pbx_exec(peer, application, gosub_args);
04942                if (!res) {
04943                   struct ast_pbx_args args;
04944                   memset(&args, 0, sizeof(args));
04945                   args.no_hangup_chan = 1;
04946                   ast_pbx_run_args(peer, &args);
04947                }
04948                ast_free(gosub_args);
04949                ast_debug(1, "Gosub exited with status %d\n", res);
04950             } else {
04951                ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
04952             }
04953          } else {
04954             ast_log(LOG_ERROR, "Could not find application Gosub\n");
04955             res = -1;
04956          }
04957       
04958          if (ast_autoservice_stop(qe->chan) < 0) {
04959             ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
04960             res = -1;
04961          }
04962       }
04963 
04964       if (!ast_strlen_zero(agi)) {
04965          ast_debug(1, "app_queue: agi=%s.\n", agi);
04966          application = pbx_findapp("agi");
04967          if (application) {
04968             agiexec = ast_strdupa(agi);
04969             pbx_exec(qe->chan, application, agiexec);
04970          } else
04971             ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
04972       }
04973       qe->handled++;
04974       ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid,
04975                                        (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
04976 
04977       if (qe->chan->cdr) {
04978          struct ast_cdr *cdr;
04979          struct ast_cdr *newcdr;
04980 
04981          /* Only work with the last CDR in the stack*/
04982          cdr = qe->chan->cdr;
04983          while (cdr->next) {
04984             cdr = cdr->next;
04985          }
04986 
04987          /* If this CDR is not related to us add new one*/
04988          if ((strcasecmp(cdr->uniqueid, qe->chan->uniqueid)) &&
04989              (strcasecmp(cdr->linkedid, qe->chan->uniqueid)) &&
04990              (newcdr = ast_cdr_dup(cdr))) {
04991             ast_channel_lock(qe->chan);
04992             ast_cdr_init(newcdr, qe->chan);
04993             ast_cdr_reset(newcdr, 0);
04994             cdr = ast_cdr_append(cdr, newcdr);
04995             cdr = cdr->next;
04996             ast_channel_unlock(qe->chan);
04997          }
04998 
04999          if (update_cdr) {
05000             ast_copy_string(cdr->dstchannel, member->membername, sizeof(cdr->dstchannel));
05001          }
05002       }
05003 
05004       if (qe->parent->eventwhencalled)
05005          manager_event(EVENT_FLAG_AGENT, "AgentConnect",
05006                "Queue: %s\r\n"
05007                "Uniqueid: %s\r\n"
05008                "Channel: %s\r\n"
05009                "Member: %s\r\n"
05010                "MemberName: %s\r\n"
05011                "Holdtime: %ld\r\n"
05012                "BridgedChannel: %s\r\n"
05013                "Ringtime: %ld\r\n"
05014                "%s",
05015                queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
05016                (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
05017                qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
05018       ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
05019       ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
05020    
05021       if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
05022          queue_end_bridge->q = qe->parent;
05023          queue_end_bridge->chan = qe->chan;
05024          bridge_config.end_bridge_callback = end_bridge_callback;
05025          bridge_config.end_bridge_callback_data = queue_end_bridge;
05026          bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
05027          /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
05028           * to make sure to increase the refcount of this queue so it cannot be freed until we
05029           * are done with it. We remove this reference in end_bridge_callback.
05030           */
05031          queue_t_ref(qe->parent, "For bridge_config reference");
05032       }
05033 
05034       time(&callstart);
05035       transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
05036       bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
05037 
05038       /* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log
05039        * when the masquerade occurred. These other "ending" queue_log messages are unnecessary, except for
05040        * the AgentComplete manager event
05041        */
05042       ast_channel_lock(qe->chan);
05043       if (!attended_transfer_occurred(qe->chan)) {
05044          struct ast_datastore *tds;
05045 
05046          /* detect a blind transfer */
05047          if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) {
05048             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
05049                qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
05050                (long) (time(NULL) - callstart), qe->opos);
05051             send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
05052          } else if (ast_check_hangup(qe->chan)) {
05053             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
05054                (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
05055             send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
05056          } else {
05057             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
05058                (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
05059             send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
05060          }
05061          if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) {  
05062             ast_channel_datastore_remove(qe->chan, tds);
05063          }
05064          ast_channel_unlock(qe->chan);
05065          update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
05066       } else {
05067          ast_channel_unlock(qe->chan);
05068 
05069          /* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */
05070          send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
05071       }
05072 
05073       if (transfer_ds) {
05074          ast_datastore_free(transfer_ds);
05075       }
05076       ast_hangup(peer);
05077       res = bridge ? bridge : 1;
05078       ao2_ref(member, -1);
05079    }
05080 out:
05081    hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere);
05082 
05083    return res;
05084 }

static int unload_module ( void   )  [static]

Definition at line 8258 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_ref, ao2_t_iterator_next, ARRAY_LEN, ast_cli_unregister_multiple(), ast_context_destroy(), ast_context_find(), ast_context_remove_extension2(), ast_custom_function_unregister(), ast_data_unregister, ast_event_unsubscribe(), ast_extension_state_del(), ast_manager_unregister(), ast_taskprocessor_unreference(), ast_unload_realtime(), ast_unregister_application(), cli_queue, device_state_sub, devicestate_tps, extension_state_cb(), queue_t_unref, queueexists_function, queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queues_t_unlink, queuevar_function, and queuewaitingcount_function.

08259 {
08260    int res;
08261    struct ast_context *con;
08262    struct ao2_iterator q_iter;
08263    struct call_queue *q = NULL;
08264 
08265    ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue));
08266    res = ast_manager_unregister("QueueStatus");
08267    res |= ast_manager_unregister("Queues");
08268    res |= ast_manager_unregister("QueueRule");
08269    res |= ast_manager_unregister("QueueSummary");
08270    res |= ast_manager_unregister("QueueAdd");
08271    res |= ast_manager_unregister("QueueRemove");
08272    res |= ast_manager_unregister("QueuePause");
08273    res |= ast_manager_unregister("QueueLog");
08274    res |= ast_manager_unregister("QueuePenalty");
08275    res |= ast_unregister_application(app_aqm);
08276    res |= ast_unregister_application(app_rqm);
08277    res |= ast_unregister_application(app_pqm);
08278    res |= ast_unregister_application(app_upqm);
08279    res |= ast_unregister_application(app_ql);
08280    res |= ast_unregister_application(app);
08281    res |= ast_custom_function_unregister(&queueexists_function);
08282    res |= ast_custom_function_unregister(&queuevar_function);
08283    res |= ast_custom_function_unregister(&queuemembercount_function);
08284    res |= ast_custom_function_unregister(&queuemembercount_dep);
08285    res |= ast_custom_function_unregister(&queuememberlist_function);
08286    res |= ast_custom_function_unregister(&queuewaitingcount_function);
08287    res |= ast_custom_function_unregister(&queuememberpenalty_function);
08288 
08289    res |= ast_data_unregister(NULL);
08290 
08291    if (device_state_sub)
08292       ast_event_unsubscribe(device_state_sub);
08293 
08294    ast_extension_state_del(0, extension_state_cb);
08295 
08296    if ((con = ast_context_find("app_queue_gosub_virtual_context"))) {
08297       ast_context_remove_extension2(con, "s", 1, NULL, 0);
08298       ast_context_destroy(con, "app_queue"); /* leave no trace */
08299    }
08300 
08301    q_iter = ao2_iterator_init(queues, 0);
08302    while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) {
08303       queues_t_unlink(queues, q, "Remove queue from container due to unload");
08304       queue_t_unref(q, "Done with iterator");
08305    }
08306    ao2_iterator_destroy(&q_iter);
08307    ao2_ref(queues, -1);
08308    devicestate_tps = ast_taskprocessor_unreference(devicestate_tps);
08309    ast_unload_realtime("queue_members");
08310    return res;
08311 }

static void update_qe_rule ( struct queue_ent qe  )  [static]

update rules for queues

Calculate min/max penalties making sure if relative they stay within bounds. Update queues penalty and set dialplan vars, goto next list entry.

Definition at line 3883 of file app_queue.c.

References ast_debug, AST_LIST_NEXT, queue_ent::chan, queue_ent::max_penalty, penalty_rule::max_relative, penalty_rule::max_value, queue_ent::min_penalty, penalty_rule::min_relative, penalty_rule::min_value, ast_channel::name, pbx_builtin_setvar_helper(), queue_ent::pr, and penalty_rule::time.

Referenced by queue_exec().

03884 {
03885    int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value;
03886    int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value;
03887    char max_penalty_str[20], min_penalty_str[20]; 
03888    /* a relative change to the penalty could put it below 0 */
03889    if (max_penalty < 0)
03890       max_penalty = 0;
03891    if (min_penalty < 0)
03892       min_penalty = 0;
03893    if (min_penalty > max_penalty)
03894       min_penalty = max_penalty;
03895    snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
03896    snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
03897    pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
03898    pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
03899    qe->max_penalty = max_penalty;
03900    qe->min_penalty = min_penalty;
03901    ast_debug(3, "Setting max penalty to %d and min penalty to %d for caller %s since %d seconds have elapsed\n", qe->max_penalty, qe->min_penalty, qe->chan->name, qe->pr->time);
03902    qe->pr = AST_LIST_NEXT(qe->pr, list);
03903 }

static int update_queue ( struct call_queue q,
struct member member,
int  callcompletedinsl,
int  newtalktime 
) [static]

update the queue status

Return values:
Always 0

Definition at line 3991 of file app_queue.c.

References ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_lock, ao2_ref, ao2_t_iterator_next, ao2_unlock, member::calls, call_queue::callscompleted, call_queue::callscompletedinsl, member::lastcall, member::lastqueue, call_queue::members, OBJ_POINTER, queue_t_unref, queues, and call_queue::talktime.

Referenced by queue_transfer_fixup().

03992 {
03993    int oldtalktime;
03994 
03995    struct member *mem;
03996    struct call_queue *qtmp;
03997    struct ao2_iterator queue_iter;  
03998    
03999    if (shared_lastcall) {
04000       queue_iter = ao2_iterator_init(queues, 0);
04001       while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
04002          ao2_lock(qtmp);
04003          if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
04004             time(&mem->lastcall);
04005             mem->calls++;
04006             mem->lastqueue = q;
04007             ao2_ref(mem, -1);
04008          }
04009          ao2_unlock(qtmp);
04010          queue_t_unref(qtmp, "Done with iterator");
04011       }
04012       ao2_iterator_destroy(&queue_iter);
04013    } else {
04014       ao2_lock(q);
04015       time(&member->lastcall);
04016       member->calls++;
04017       member->lastqueue = q;
04018       ao2_unlock(q);
04019    }  
04020    ao2_lock(q);
04021    q->callscompleted++;
04022    if (callcompletedinsl)
04023       q->callscompletedinsl++;
04024    /* Calculate talktime using the same exponential average as holdtime code*/
04025    oldtalktime = q->talktime;
04026    q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
04027    ao2_unlock(q);
04028    return 0;
04029 }

static int update_realtime_member_field ( struct member mem,
const char *  queue_name,
const char *  field,
const char *  value 
) [static]

Definition at line 2378 of file app_queue.c.

References ast_strlen_zero(), ast_update_realtime(), member::rt_uniqueid, and SENTINEL.

Referenced by set_member_paused().

02379 {
02380    int ret = -1;
02381 
02382    if (ast_strlen_zero(mem->rt_uniqueid))
02383       return ret;
02384 
02385    if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0)
02386       ret = 0;
02387 
02388    return ret;
02389 }

static void update_realtime_members ( struct call_queue q  )  [static]

Definition at line 2392 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ast_category_browse(), ast_config_destroy(), ast_debug, ast_load_realtime_multientry(), ast_queue_log(), ast_variable_retrieve(), member::dead, member::interface, call_queue::members, call_queue::name, member::realtime, rt_handle_member_record(), S_OR, and SENTINEL.

Referenced by load_realtime_queue(), and queue_exec().

02393 {
02394    struct ast_config *member_config = NULL;
02395    struct member *m;
02396    char *interface = NULL;
02397    struct ao2_iterator mem_iter;
02398 
02399    if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
02400       /*This queue doesn't have realtime members*/
02401       ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
02402       return;
02403    }
02404 
02405    ao2_lock(q);
02406 
02407    /* Temporarily set realtime  members dead so we can detect deleted ones.*/
02408    mem_iter = ao2_iterator_init(q->members, 0);
02409    while ((m = ao2_iterator_next(&mem_iter))) {
02410       if (m->realtime)
02411          m->dead = 1;
02412       ao2_ref(m, -1);
02413    }
02414    ao2_iterator_destroy(&mem_iter);
02415 
02416    while ((interface = ast_category_browse(member_config, interface))) {
02417       rt_handle_member_record(q, interface,
02418          ast_variable_retrieve(member_config, interface, "uniqueid"),
02419          S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
02420          ast_variable_retrieve(member_config, interface, "penalty"),
02421          ast_variable_retrieve(member_config, interface, "paused"),
02422          S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
02423    }
02424 
02425    /* Delete all realtime members that have been deleted in DB. */
02426    mem_iter = ao2_iterator_init(q->members, 0);
02427    while ((m = ao2_iterator_next(&mem_iter))) {
02428       if (m->dead) {
02429          ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
02430          ao2_unlink(q->members, m);
02431       }
02432       ao2_ref(m, -1);
02433    }
02434    ao2_iterator_destroy(&mem_iter);
02435    ao2_unlock(q);
02436    ast_config_destroy(member_config);
02437 }

static int update_status ( struct call_queue q,
struct member m,
const int  status 
) [static]

set a member's status based on device state of that member's state_interface.

Lock interface list find sc, iterate through each queues queue_member list for member to update state inside queues

Definition at line 1424 of file app_queue.c.

References EVENT_FLAG_AGENT, and manager_event.

Referenced by extension_state_cb(), handle_statechange(), and ring_entry().

01425 {
01426    m->status = status;
01427 
01428    if (q->maskmemberstatus)
01429       return 0;
01430 
01431    manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
01432       "Queue: %s\r\n"
01433       "Location: %s\r\n"
01434       "MemberName: %s\r\n"
01435       "Membership: %s\r\n"
01436       "Penalty: %d\r\n"
01437       "CallsTaken: %d\r\n"
01438       "LastCall: %d\r\n"
01439       "Status: %d\r\n"
01440       "Paused: %d\r\n",
01441       q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
01442       m->penalty, m->calls, (int)m->lastcall, m->status, m->paused
01443    );
01444 
01445    return 0;
01446 }

static int upqm_exec ( struct ast_channel chan,
const char *  data 
) [static]

UnPauseQueueMember application.

Definition at line 5558 of file app_queue.c.

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, parse(), pbx_builtin_setvar_helper(), and set_member_paused().

Referenced by load_module().

05559 {
05560    char *parse;
05561    AST_DECLARE_APP_ARGS(args,
05562       AST_APP_ARG(queuename);
05563       AST_APP_ARG(interface);
05564       AST_APP_ARG(options);
05565       AST_APP_ARG(reason);
05566    );
05567 
05568    if (ast_strlen_zero(data)) {
05569       ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
05570       return -1;
05571    }
05572 
05573    parse = ast_strdupa(data);
05574 
05575    AST_STANDARD_APP_ARGS(args, parse);
05576 
05577    if (ast_strlen_zero(args.interface)) {
05578       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
05579       return -1;
05580    }
05581 
05582    if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
05583       ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
05584       pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
05585       return 0;
05586    }
05587 
05588    pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
05589 
05590    return 0;
05591 }

static int valid_exit ( struct queue_ent qe,
char  digit 
) [static]

Check for valid exit from queue via goto.

Return values:
0 if failure
1 if successful

Definition at line 2554 of file app_queue.c.

References ast_canmatch_extension(), ast_goto_if_exists(), ast_strlen_zero(), ast_channel::caller, queue_ent::chan, queue_ent::context, queue_ent::digits, ast_party_caller::id, ast_party_id::number, S_COR, ast_party_number::str, ast_party_number::valid, and queue_ent::valid_digits.

Referenced by say_periodic_announcement(), say_position(), and wait_a_bit().

02555 {
02556    int digitlen = strlen(qe->digits);
02557 
02558    /* Prevent possible buffer overflow */
02559    if (digitlen < sizeof(qe->digits) - 2) {
02560       qe->digits[digitlen] = digit;
02561       qe->digits[digitlen + 1] = '\0';
02562    } else {
02563       qe->digits[0] = '\0';
02564       return 0;
02565    }
02566 
02567    /* If there's no context to goto, short-circuit */
02568    if (ast_strlen_zero(qe->context))
02569       return 0;
02570 
02571    /* If the extension is bad, then reset the digits to blank */
02572    if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
02573       S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, NULL))) {
02574       qe->digits[0] = '\0';
02575       return 0;
02576    }
02577 
02578    /* We have an exact match */
02579    if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
02580       qe->valid_digits = 1;
02581       /* Return 1 on a successful goto */
02582       return 1;
02583    }
02584 
02585    return 0;
02586 }

static char* vars2manager ( struct ast_channel chan,
char *  vars,
size_t  len 
) [static]

convert "\n" to "\nVariable: " ready for manager to use

Definition at line 2942 of file app_queue.c.

References ast_copy_string(), ast_str_buffer(), ast_str_thread_get(), queue_ent::chan, and pbx_builtin_serialize_variables().

Referenced by ring_entry(), rna(), and send_agent_complete().

02943 {
02944    struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1);
02945    const char *tmp;
02946 
02947    if (pbx_builtin_serialize_variables(chan, &buf)) {
02948       int i, j;
02949 
02950       /* convert "\n" to "\nVariable: " */
02951       strcpy(vars, "Variable: ");
02952       tmp = ast_str_buffer(buf);
02953 
02954       for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
02955          vars[j] = tmp[i];
02956 
02957          if (tmp[i + 1] == '\0')
02958             break;
02959          if (tmp[i] == '\n') {
02960             vars[j++] = '\r';
02961             vars[j++] = '\n';
02962 
02963             ast_copy_string(&(vars[j]), "Variable: ", len - j);
02964             j += 9;
02965          }
02966       }
02967       if (j > len - 3)
02968          j = len - 3;
02969       vars[j++] = '\r';
02970       vars[j++] = '\n';
02971       vars[j] = '\0';
02972    } else {
02973       /* there are no channel variables; leave it blank */
02974       *vars = '\0';
02975    }
02976    return vars;
02977 }

static int wait_a_bit ( struct queue_ent qe  )  [static]

Definition at line 5086 of file app_queue.c.

References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, call_queue::retry, and valid_exit().

Referenced by queue_exec().

05087 {
05088    /* Don't need to hold the lock while we setup the outgoing calls */
05089    int retrywait = qe->parent->retry * 1000;
05090 
05091    int res = ast_waitfordigit(qe->chan, retrywait);
05092    if (res > 0 && !valid_exit(qe, res))
05093       res = 0;
05094 
05095    return res;
05096 }

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 
) [static]

Wait for a member to answer the call.

Parameters:
[in] qe the queue_ent corresponding to the caller in the queue
[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
[in] to the amount of time (in milliseconds) to wait for a response
[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
[in] prebusies number of busy members calculated prior to calling wait_for_answer
[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
[in] update_connectedline Allow connected line and redirecting updates to pass through.
Todo:
eventually all call forward logic should be intergerated into and replaced by ast_call_forward()

Definition at line 3424 of file app_queue.c.

References ast_channel_lock, ast_channel_unlock, AST_MAX_WATCHERS, ast_party_connected_line_init(), ast_poll_channel_add(), ast_strdupa, callattempt::call_next, callattempt::chan, queue_ent::chan, f, ast_channel::name, call_queue::name, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), starttime, status, callattempt::stillgoing, and call_queue::strategy.

03425 {
03426    const char *queue = qe->parent->name;
03427    struct callattempt *o, *start = NULL, *prev = NULL;
03428    int res;
03429    int status;
03430    int numbusies = prebusies;
03431    int numnochan = 0;
03432    int stillgoing = 0;
03433    int orig = *to;
03434    struct ast_frame *f;
03435    struct callattempt *peer = NULL;
03436    struct ast_channel *winner;
03437    struct ast_channel *in = qe->chan;
03438    char on[80] = "";
03439    char membername[80] = "";
03440    long starttime = 0;
03441    long endtime = 0;
03442 #ifdef HAVE_EPOLL
03443    struct callattempt *epollo;
03444 #endif
03445    struct ast_party_connected_line connected_caller;
03446    char *inchan_name;
03447 
03448    ast_party_connected_line_init(&connected_caller);
03449 
03450    ast_channel_lock(qe->chan);
03451    inchan_name = ast_strdupa(qe->chan->name);
03452    ast_channel_unlock(qe->chan);
03453 
03454    starttime = (long) time(NULL);
03455 #ifdef HAVE_EPOLL
03456    for (epollo = outgoing; epollo; epollo = epollo->q_next) {
03457       if (epollo->chan)
03458          ast_poll_channel_add(in, epollo->chan);
03459    }
03460 #endif
03461    
03462    while (*to && !peer) {
03463       int numlines, retry, pos = 1;
03464       struct ast_channel *watchers[AST_MAX_WATCHERS];
03465       watchers[0] = in;
03466       start = NULL;
03467 
03468       for (retry = 0; retry < 2; retry++) {
03469          numlines = 0;
03470          for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
03471             if (o->stillgoing) { /* Keep track of important channels */
03472                stillgoing = 1;
03473                if (o->chan) {
03474                   if (pos < AST_MAX_WATCHERS) {
03475                      watchers[pos++] = o->chan;
03476                   }
03477                   if (!start)
03478                      start = o;
03479                   else
03480                      prev->call_next = o;
03481                   prev = o;
03482                }
03483             }
03484             numlines++;
03485          }
03486          if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
03487             (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
03488             break;
03489          /* On "ringall" strategy we only move to the next penalty level
03490             when *all* ringing phones are done in the current penalty level */
03491          ring_one(qe, outgoing, &numbusies);
03492          /* and retry... */
03493       }
03494       if (pos == 1 /* not found */) {
03495          if (numlines == (numbusies + numnochan)) {
03496             ast_debug(1, "Everyone is busy at this time\n");
03497          } else {
03498             ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
03499          }
03500          *to = 0;
03501          return NULL;
03502       }
03503 
03504       /* Poll for events from both the incoming channel as well as any outgoing channels */
03505       winner = ast_waitfor_n(watchers, pos, to);
03506 
03507       /* Service all of the outgoing channels */
03508       for (o = start; o; o = o->call_next) {
03509          /* We go with a static buffer here instead of using ast_strdupa. Using
03510           * ast_strdupa in a loop like this one can cause a stack overflow
03511           */
03512          char ochan_name[AST_CHANNEL_NAME];
03513          if (o->chan) {
03514             ast_channel_lock(o->chan);
03515             ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
03516             ast_channel_unlock(o->chan);
03517          }
03518          if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
03519             if (!peer) {
03520                ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
03521                if (update_connectedline) {
03522                   if (o->pending_connected_update) {
03523                      if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
03524                         ast_channel_update_connected_line(in, &o->connected, NULL);
03525                      }
03526                   } else if (!o->dial_callerid_absent) {
03527                      ast_channel_lock(o->chan);
03528                      ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
03529                      ast_channel_unlock(o->chan);
03530                      connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
03531                      ast_channel_update_connected_line(in, &connected_caller, NULL);
03532                      ast_party_connected_line_free(&connected_caller);
03533                   }
03534                }
03535                if (o->aoc_s_rate_list) {
03536                   size_t encoded_size;
03537                   struct ast_aoc_encoded *encoded;
03538                   if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
03539                      ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
03540                      ast_aoc_destroy_encoded(encoded);
03541                   }
03542                }
03543                peer = o;
03544             }
03545          } else if (o->chan && (o->chan == winner)) {
03546 
03547             ast_copy_string(on, o->member->interface, sizeof(on));
03548             ast_copy_string(membername, o->member->membername, sizeof(membername));
03549 
03550             if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
03551                ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward);
03552                numnochan++;
03553                do_hang(o);
03554                winner = NULL;
03555                continue;
03556             } else if (!ast_strlen_zero(o->chan->call_forward)) {
03557                struct ast_channel *original = o->chan;
03558                char tmpchan[256];
03559                char *stuff;
03560                char *tech;
03561 
03562                ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
03563                if ((stuff = strchr(tmpchan, '/'))) {
03564                   *stuff++ = '\0';
03565                   tech = tmpchan;
03566                } else {
03567                   snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
03568                   stuff = tmpchan;
03569                   tech = "Local";
03570                }
03571 
03572                ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL);
03573 
03574                /* Before processing channel, go ahead and check for forwarding */
03575                ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
03576                /* Setup parameters */
03577                o->chan = ast_request(tech, in->nativeformats, in, stuff, &status);
03578                if (!o->chan) {
03579                   ast_log(LOG_NOTICE,
03580                      "Forwarding failed to create channel to dial '%s/%s'\n",
03581                      tech, stuff);
03582                   o->stillgoing = 0;
03583                   numnochan++;
03584                } else {
03585                   struct ast_party_redirecting redirecting;
03586 
03587                   ast_channel_lock_both(o->chan, in);
03588                   ast_channel_inherit_variables(in, o->chan);
03589                   ast_channel_datastore_inherit(in, o->chan);
03590 
03591                   ast_string_field_set(o->chan, accountcode, in->accountcode);
03592 
03593                   ast_channel_set_redirecting(o->chan, &original->redirecting, NULL);
03594                   if (!o->chan->redirecting.from.number.valid
03595                      || ast_strlen_zero(o->chan->redirecting.from.number.str)) {
03596                      /*
03597                       * The call was not previously redirected so it is
03598                       * now redirected from this number.
03599                       */
03600                      ast_party_number_free(&o->chan->redirecting.from.number);
03601                      ast_party_number_init(&o->chan->redirecting.from.number);
03602                      o->chan->redirecting.from.number.valid = 1;
03603                      o->chan->redirecting.from.number.str =
03604                         ast_strdup(S_OR(in->macroexten, in->exten));
03605                   }
03606 
03607                   o->chan->dialed.transit_network_select = in->dialed.transit_network_select;
03608 
03609                   ast_party_caller_copy(&o->chan->caller, &in->caller);
03610                   ast_party_connected_line_copy(&o->chan->connected, &original->connected);
03611 
03612                   /*
03613                    * We must unlock o->chan before calling
03614                    * ast_channel_redirecting_macro, because we put o->chan into
03615                    * autoservice there.  That is pretty much a guaranteed
03616                    * deadlock.  This is why the handling of o->chan's lock may
03617                    * seem a bit unusual here.
03618                    */
03619                   ast_party_redirecting_init(&redirecting);
03620                   ast_party_redirecting_copy(&redirecting, &o->chan->redirecting);
03621                   ast_channel_unlock(o->chan);
03622                   res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0);
03623                   if (res) {
03624                      ast_channel_update_redirecting(in, &redirecting, NULL);
03625                   }
03626                   ast_party_redirecting_free(&redirecting);
03627                   ast_channel_unlock(in);
03628 
03629                   update_connectedline = 1;
03630 
03631                   if (ast_call(o->chan, stuff, 0)) {
03632                      ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
03633                         tech, stuff);
03634                      do_hang(o);
03635                      numnochan++;
03636                   }
03637                }
03638                /* Hangup the original channel now, in case we needed it */
03639                ast_hangup(winner);
03640                continue;
03641             }
03642             f = ast_read(winner);
03643             if (f) {
03644                if (f->frametype == AST_FRAME_CONTROL) {
03645                   switch (f->subclass.integer) {
03646                   case AST_CONTROL_ANSWER:
03647                      /* This is our guy if someone answered. */
03648                      if (!peer) {
03649                         ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
03650                         if (update_connectedline) {
03651                            if (o->pending_connected_update) {
03652                               if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
03653                                  ast_channel_update_connected_line(in, &o->connected, NULL);
03654                               }
03655                            } else if (!o->dial_callerid_absent) {
03656                               ast_channel_lock(o->chan);
03657                               ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
03658                               ast_channel_unlock(o->chan);
03659                               connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
03660                               ast_channel_update_connected_line(in, &connected_caller, NULL);
03661                               ast_party_connected_line_free(&connected_caller);
03662                            }
03663                         }
03664                         if (o->aoc_s_rate_list) {
03665                            size_t encoded_size;
03666                            struct ast_aoc_encoded *encoded;
03667                            if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
03668                               ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
03669                               ast_aoc_destroy_encoded(encoded);
03670                            }
03671                         }
03672                         peer = o;
03673                      }
03674                      break;
03675                   case AST_CONTROL_BUSY:
03676                      ast_verb(3, "%s is busy\n", ochan_name);
03677                      if (in->cdr)
03678                         ast_cdr_busy(in->cdr);
03679                      do_hang(o);
03680                      endtime = (long) time(NULL);
03681                      endtime -= starttime;
03682                      rna(endtime * 1000, qe, on, membername, 0);
03683                      if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03684                         if (qe->parent->timeoutrestart)
03685                            *to = orig;
03686                         /* Have enough time for a queue member to answer? */
03687                         if (*to > 500) {
03688                            ring_one(qe, outgoing, &numbusies);
03689                            starttime = (long) time(NULL);
03690                         }
03691                      }
03692                      numbusies++;
03693                      break;
03694                   case AST_CONTROL_CONGESTION:
03695                      ast_verb(3, "%s is circuit-busy\n", ochan_name);
03696                      if (in->cdr)
03697                         ast_cdr_busy(in->cdr);
03698                      endtime = (long) time(NULL);
03699                      endtime -= starttime;
03700                      rna(endtime * 1000, qe, on, membername, 0);
03701                      do_hang(o);
03702                      if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03703                         if (qe->parent->timeoutrestart)
03704                            *to = orig;
03705                         if (*to > 500) {
03706                            ring_one(qe, outgoing, &numbusies);
03707                            starttime = (long) time(NULL);
03708                         }
03709                      }
03710                      numbusies++;
03711                      break;
03712                   case AST_CONTROL_RINGING:
03713                      ast_verb(3, "%s is ringing\n", ochan_name);
03714 
03715                      /* Start ring indication when the channel is ringing, if specified */
03716                      if (qe->ring_when_ringing) {
03717                         ast_moh_stop(qe->chan);
03718                         ast_indicate(qe->chan, AST_CONTROL_RINGING);
03719                      }
03720                      break;
03721                   case AST_CONTROL_OFFHOOK:
03722                      /* Ignore going off hook */
03723                      break;
03724                   case AST_CONTROL_CONNECTED_LINE:
03725                      if (!update_connectedline) {
03726                         ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
03727                      } else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
03728                         struct ast_party_connected_line connected;
03729                         ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
03730                         ast_party_connected_line_set_init(&connected, &o->connected);
03731                         ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
03732                         ast_party_connected_line_set(&o->connected, &connected, NULL);
03733                         ast_party_connected_line_free(&connected);
03734                         o->pending_connected_update = 1;
03735                      } else {
03736                         if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
03737                            ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
03738                         }
03739                      }
03740                      break;
03741                   case AST_CONTROL_AOC:
03742                      {
03743                         struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
03744                         if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
03745                            ast_aoc_destroy_decoded(o->aoc_s_rate_list);
03746                            o->aoc_s_rate_list = decoded;
03747                         } else {
03748                            ast_aoc_destroy_decoded(decoded);
03749                         }
03750                      }
03751                      break;
03752                   case AST_CONTROL_REDIRECTING:
03753                      if (!update_connectedline) {
03754                         ast_verb(3, "Redirecting update to %s prevented\n", inchan_name);
03755                      } else if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03756                         ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name);
03757                         if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
03758                            ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
03759                         }
03760                      }
03761                      break;
03762                   default:
03763                      ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
03764                      break;
03765                   }
03766                }
03767                ast_frfree(f);
03768             } else { /* ast_read() returned NULL */
03769                endtime = (long) time(NULL) - starttime;
03770                rna(endtime * 1000, qe, on, membername, 1);
03771                do_hang(o);
03772                if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03773                   if (qe->parent->timeoutrestart)
03774                      *to = orig;
03775                   if (*to > 500) {
03776                      ring_one(qe, outgoing, &numbusies);
03777                      starttime = (long) time(NULL);
03778                   }
03779                }
03780             }
03781          }
03782       }
03783 
03784       /* If we received an event from the caller, deal with it. */
03785       if (winner == in) {
03786          f = ast_read(in);
03787          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
03788             /* Got hung up */
03789             *to = -1;
03790             if (f) {
03791                if (f->data.uint32) {
03792                   in->hangupcause = f->data.uint32;
03793                }
03794                ast_frfree(f);
03795             }
03796             return NULL;
03797          }
03798          if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
03799             ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
03800             *to = 0;
03801             ast_frfree(f);
03802             return NULL;
03803          }
03804          if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
03805             ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
03806             *to = 0;
03807             *digit = f->subclass.integer;
03808             ast_frfree(f);
03809             return NULL;
03810          }
03811          ast_frfree(f);
03812       }
03813       if (!*to) {
03814          for (o = start; o; o = o->call_next)
03815             rna(orig, qe, o->interface, o->member->membername, 1);
03816       }
03817    }
03818 
03819 #ifdef HAVE_EPOLL
03820    for (epollo = outgoing; epollo; epollo = epollo->q_next) {
03821       if (epollo->chan)
03822          ast_poll_channel_del(in, epollo->chan);
03823    }
03824 #endif
03825 
03826    return peer;
03827 }

static int wait_our_turn ( struct queue_ent qe,
int  ringing,
enum queue_result reason 
) [static]

The waiting areas for callers who are not actively calling members.

This function is one large loop. This function will return if a caller either exits the queue or it becomes that caller's turn to attempt calling queue members. Inside the loop, we service the caller with periodic announcements, holdtime announcements, etc. as configured in queues.conf

Return values:
0 if the caller's turn has arrived
-1 if the caller should exit the queue.

Definition at line 3915 of file app_queue.c.

References ast_queue_log(), queue_ent::chan, get_member_status(), is_our_turn(), leave_queue(), call_queue::leavewhenempty, queue_ent::max_penalty, queue_ent::min_penalty, call_queue::name, queue_ent::opos, queue_ent::parent, queue_ent::pos, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, queue_ent::start, status, and ast_channel::uniqueid.

Referenced by queue_exec().

03916 {
03917    int res = 0;
03918 
03919    /* This is the holding pen for callers 2 through maxlen */
03920    for (;;) {
03921 
03922       if (is_our_turn(qe))
03923          break;
03924 
03925       /* If we have timed out, break out */
03926       if (qe->expire && (time(NULL) >= qe->expire)) {
03927          *reason = QUEUE_TIMEOUT;
03928          break;
03929       }
03930 
03931       if (qe->parent->leavewhenempty) {
03932          int status = 0;
03933 
03934          if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty))) {
03935             *reason = QUEUE_LEAVEEMPTY;
03936             ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
03937             leave_queue(qe);
03938             break;
03939          }
03940       }
03941 
03942       /* Make a position announcement, if enabled */
03943       if (qe->parent->announcefrequency &&
03944          (res = say_position(qe,ringing)))
03945          break;
03946 
03947       /* If we have timed out, break out */
03948       if (qe->expire && (time(NULL) >= qe->expire)) {
03949          *reason = QUEUE_TIMEOUT;
03950          break;
03951       }
03952 
03953       /* Make a periodic announcement, if enabled */
03954       if (qe->parent->periodicannouncefrequency &&
03955          (res = say_periodic_announcement(qe,ringing)))
03956          break;
03957       
03958       /* see if we need to move to the next penalty level for this queue */
03959       while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
03960          update_qe_rule(qe);
03961       }
03962 
03963       /* If we have timed out, break out */
03964       if (qe->expire && (time(NULL) >= qe->expire)) {
03965          *reason = QUEUE_TIMEOUT;
03966          break;
03967       }
03968       
03969       /* Wait a second before checking again */
03970       if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
03971          if (res > 0 && !valid_exit(qe, res))
03972             res = 0;
03973          else
03974             break;
03975       }
03976       
03977       /* If we have timed out, break out */
03978       if (qe->expire && (time(NULL) >= qe->expire)) {
03979          *reason = QUEUE_TIMEOUT;
03980          break;
03981       }
03982    }
03983 
03984    return res;
03985 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_CONSUMER, .nonoptreq = "res_monitor", } [static]

Definition at line 8393 of file app_queue.c.

char* app = "Queue" [static]

Definition at line 901 of file app_queue.c.

char* app_aqm = "AddQueueMember" [static]

Definition at line 903 of file app_queue.c.

char* app_pqm = "PauseQueueMember" [static]

Definition at line 907 of file app_queue.c.

char* app_ql = "QueueLog" [static]

Definition at line 911 of file app_queue.c.

char* app_rqm = "RemoveQueueMember" [static]

Definition at line 905 of file app_queue.c.

char* app_upqm = "UnpauseQueueMember" [static]

Definition at line 909 of file app_queue.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 8393 of file app_queue.c.

int autofill_default = 1 [static]

queues.conf [general] option

Definition at line 925 of file app_queue.c.

struct autopause autopausesmodes[] [static]

Referenced by autopause2int().

struct ast_cli_entry cli_queue[] [static]

Definition at line 7977 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_event_sub* device_state_sub [static]

Subscription to device state change events.

Definition at line 934 of file app_queue.c.

Referenced by aji_init_event_distribution(), load_module(), load_pbx(), and unload_module().

struct ast_taskprocessor* devicestate_tps [static]

Definition at line 885 of file app_queue.c.

Referenced by device_state_cb(), load_module(), and unload_module().

enum queue_result id

Definition at line 951 of file app_queue.c.

Referenced by _sip_show_peers(), _skinny_show_devices(), _skinny_show_lines(), amixer_max(), ast_cc_extension_monitor_add_dialstring(), ast_party_id_presentation(), frame_trace_helper(), idemodulator(), misdn_queue_connected_line_update(), misdn_update_caller_id(), party_id_build_data(), party_id_read(), party_id_write(), pidf_validate_tuple(), and setamixer().

int montype_default = 0 [static]

queues.conf [general] option

Definition at line 928 of file app_queue.c.

const char* const pm_family = "Queue/PersistentMembers" [static]

Persistent Members astdb family.

Definition at line 914 of file app_queue.c.

const char qpm_cmd_usage[] [static]

Initial value:

 
"Usage: queue pause member <channel> in <queue> reason <reason>\n"

Definition at line 7968 of file app_queue.c.

const char qsmp_cmd_usage[] [static]

Initial value:

"Usage: queue set member penalty <channel> from <queue> <penalty>\n"

Definition at line 7974 of file app_queue.c.

struct ast_data_entry queue_data_providers[] [static]

Initial value:

 {
   AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider),
}

Definition at line 8254 of file app_queue.c.

Referenced by load_module().

int queue_persistent_members = 0 [static]

queues.conf [general] option

Definition at line 919 of file app_queue.c.

struct { ... } queue_results[] [static]

Referenced by set_queue_result().

struct ast_datastore_info queue_transfer_info [static]

Initial value:

 {
   .type = "queue_transfer",
   .chan_fixup = queue_transfer_fixup,
   .destroy = queue_transfer_destroy,
}
a datastore used to help correctly log attended transfers of queue callers

Definition at line 4166 of file app_queue.c.

Referenced by attended_transfer_occurred(), queue_transfer_fixup(), and setup_transfer_datastore().

struct ast_custom_function queueexists_function [static]

Initial value:

 {
   .name = "QUEUE_EXISTS",
   .read = queue_function_exists,
}

Definition at line 6417 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuemembercount_dep [static]

Initial value:

 {
   .name = "QUEUE_MEMBER_COUNT",
   .read = queue_function_qac_dep,
}

Definition at line 6432 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuemembercount_function [static]

Initial value:

 {
   .name = "QUEUE_MEMBER",
   .read = queue_function_qac,
}

Definition at line 6427 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuememberlist_function [static]

Initial value:

 {
   .name = "QUEUE_MEMBER_LIST",
   .read = queue_function_queuememberlist,
}

Definition at line 6442 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuememberpenalty_function [static]

Initial value:

 {
   .name = "QUEUE_MEMBER_PENALTY",
   .read = queue_function_memberpenalty_read,
   .write = queue_function_memberpenalty_write,
}

Definition at line 6447 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ao2_container* queues [static]

Definition at line 1186 of file app_queue.c.

Referenced by __queues_show(), clear_stats(), compare_weight(), complete_queue(), complete_queue_remove_member(), extension_state_cb(), find_queue_by_name_rt(), get_member_penalty(), handle_statechange(), leave_queue(), load_module(), load_realtime_queue(), manager_queues_status(), manager_queues_summary(), queue_function_queuememberlist(), queue_function_queuewaitingcount(), queue_function_var(), queues_data_provider_get(), reload_queue_members(), reload_queues(), reload_single_queue(), remove_from_queue(), set_member_paused(), set_member_penalty(), unload_module(), and update_queue().

struct ast_data_handler queues_data_provider [static]

Initial value:

Definition at line 8249 of file app_queue.c.

struct ast_custom_function queuevar_function [static]

Initial value:

 {
   .name = "QUEUE_VARIABLES",
   .read = queue_function_var,
}

Definition at line 6422 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuewaitingcount_function [static]

Initial value:

 {
   .name = "QUEUE_WAITING_COUNT",
   .read = queue_function_queuewaitingcount,
}

Definition at line 6437 of file app_queue.c.

Referenced by load_module(), and unload_module().

const char qum_cmd_usage[] [static]

Initial value:

"Usage: queue unpause member <channel> in <queue> reason <reason>\n"

Definition at line 7971 of file app_queue.c.

int shared_lastcall = 1 [static]

queues.conf [general] option

Definition at line 931 of file app_queue.c.

struct strategy strategies[] [static]

Referenced by int2strat(), and strat2int().

char* text

Definition at line 952 of file app_queue.c.

Referenced by festival_exec(), iconv_read(), method_match(), parse_sip_options(), process_sdp(), reqprep(), set_queue_result(), and sip_new().

int update_cdr = 0 [static]

queues.conf [general] option

Definition at line 937 of file app_queue.c.

Referenced by login_exec().

int use_weight = 0 [static]

queues.conf per-queue weight option

Definition at line 922 of file app_queue.c.


Generated on Mon Mar 19 11:30:33 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7