Wed Oct 28 13:31:32 2009

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/callerid.h"
#include "asterisk/cel.h"

Include dependency graph for app_queue.c:

Go to the source code of this file.

Data Structures

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

Defines

#define ANNOUNCEHOLDTIME_ALWAYS   1
#define ANNOUNCEHOLDTIME_ONCE   2
#define ANNOUNCEPOSITION_LIMIT   4
#define ANNOUNCEPOSITION_MORE_THAN   3
#define ANNOUNCEPOSITION_NO   2
#define ANNOUNCEPOSITION_YES   1
#define AST_MAX_WATCHERS   256
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY   15
#define DEFAULT_RETRY   5
#define DEFAULT_TIMEOUT   15
#define MAX_PERIODIC_ANNOUNCEMENTS   10
#define MAX_QUEUE_BUCKETS   53
#define PM_MAX_LEN   8192
#define QUEUE_EVENT_VARIABLES   3
#define RECHECK   1
#define RES_EXISTS   (-1)
#define RES_NOSUCHQUEUE   (-3)
#define RES_NOT_DYNAMIC   (-4)
#define RES_OKAY   0
#define RES_OUTOFMEMORY   (-2)

Enumerations

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

Functions

static char * __queues_show (struct mansession *s, int fd, int argc, const char *const *argv)
 Show queue(s) status and statistics.
static void __reg_module (void)
static void __unreg_module (void)
static int add_to_queue (const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
 Add member to queue.
static struct call_queuealloc_queue (const char *queuename)
static int aqm_exec (struct ast_channel *chan, const char *data)
 AddQueueMember application.
static int attended_transfer_occurred (struct ast_channel *chan)
 mechanism to tell if a queue caller was atxferred by a queue member.
static int calc_metric (struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
 Calculate the metric of each member in the outgoing callattempts.
static void clear_queue (struct call_queue *q)
static int clear_stats (const char *queuename)
 Facilitates resetting statistics for a queue.
static int compare_weight (struct call_queue *rq, struct member *member)
static char * complete_queue (const char *line, const char *word, int pos, int state)
static char * complete_queue_add_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_pause_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_remove_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_rule_show (const char *line, const char *word, int pos, int state)
static char * complete_queue_set_member_penalty (const char *line, const char *word, int pos, int state)
static char * complete_queue_show (const char *line, const char *word, int pos, int state)
static int compress_char (const char c)
static void copy_rules (struct queue_ent *qe, const char *rulename)
 Copy rule from global list into specified queue.
static struct 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 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 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_memberpenalty_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.
static int queue_function_memberpenalty_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.
static int queue_function_qac (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Get number either busy / free or total members of a specific queue.
static int queue_function_qac_dep (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Get the total number of members in a specific queue (Deprecated).
static int queue_function_queuememberlist (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue.
static int queue_function_queuewaitingcount (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue.
static int queue_function_var (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 create interface var with all queue details.
static int queue_hash_cb (const void *obj, const int flags)
static struct call_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 void recalc_holdtime (struct queue_ent *qe, int newholdtime)
static void record_abandoned (struct queue_ent *qe)
 Record that a caller gave up on waiting in queue.
static int reload (void)
static int reload_handler (int reload, struct ast_flags *mask, const char *queuename)
 The command center for all reload operations.
static void reload_queue_members (void)
 Reload dynamic queue members persisted into the astdb.
static int reload_queue_rules (int reload)
 Reload the rules defined in queuerules.conf.
static int reload_queues (int reload, struct ast_flags *mask, const char *queuename)
 reload the queues.conf file
static void reload_single_member (const char *memberdata, struct call_queue *q)
 reload information pertaining to a single member
static void reload_single_queue (struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
 Reload information pertaining to a particular queue.
static int remove_from_queue (const char *queuename, const char *interface)
 Remove member from queue.
static int ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies)
 Part 2 of ring_one.
static int ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies)
 Place a call to a queue member.
static void rna (int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause)
 RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.
static int rqm_exec (struct ast_channel *chan, const char *data)
 RemoveQueueMember application.
static void rt_handle_member_record (struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface)
 Find rt member record to update otherwise create one.
static int say_periodic_announcement (struct queue_ent *qe, int ringing)
 Playback announcement to queued members if peroid has elapsed.
static int say_position (struct queue_ent *qe, int ringing)
static void send_agent_complete (const struct queue_ent *qe, const char *queuename, const struct ast_channel *peer, const struct member *member, time_t callstart, char *vars, size_t vars_len, enum agent_complete_reason rsn)
 Send out AMI message with member call completion status information.
static int set_member_paused (const char *queuename, const char *interface, const char *reason, int paused)
static int set_member_penalty (const char *queuename, const char *interface, int penalty)
static void set_queue_result (struct ast_channel *chan, enum queue_result res)
 sets the QUEUESTATUS channel variable
static void set_queue_variables (struct call_queue *q, struct ast_channel *chan)
 Set variables of queue.
static struct ast_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_DEFAULT , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static char * app = "Queue"
static char * app_aqm = "AddQueueMember"
static char * app_pqm = "PauseQueueMember"
static char * app_ql = "QueueLog"
static char * app_rqm = "RemoveQueueMember"
static char * app_upqm = "UnpauseQueueMember"
static struct ast_module_infoast_module_info = &__mod_info
static int autofill_default = 0
 queues.conf [general] option
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 int queue_persistent_members = 0
 queues.conf [general] option
struct {
   enum queue_result   id
   char *   text
queue_results []
static struct ast_datastore_info queue_transfer_info
 a datastore used to help correctly log attended transfers of queue callers
static struct ast_custom_function queuemembercount_dep
static struct ast_custom_function queuemembercount_function
static struct ast_custom_function queuememberlist_function
static struct ast_custom_function queuememberpenalty_function
static struct ao2_containerqueues
static struct ast_custom_function queuevar_function
static struct ast_custom_function queuewaitingcount_function
static const char qum_cmd_usage []
static int shared_lastcall = 0
 queues.conf [general] option
static struct strategy strategies []
static int update_cdr = 0
 queues.conf [general] option
static int use_weight = 0
 queues.conf per-queue weight option


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

  • Per-queue holdtime calculation
  • Estimated holdtime announcement
  • Position announcement
  • Abandoned/completed call counters
  • Failout timer passed as optional app parameter
  • Optional monitoring of calls, started when call is answered
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 855 of file app_queue.c.

Referenced by queue_set_param().

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 856 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 871 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

#define ANNOUNCEPOSITION_MORE_THAN   3

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

Definition at line 870 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

#define ANNOUNCEPOSITION_NO   2

We don't announce position

Definition at line 869 of file app_queue.c.

Referenced by queue_set_param().

#define ANNOUNCEPOSITION_YES   1

We announce position

Definition at line 868 of file app_queue.c.

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

#define AST_MAX_WATCHERS   256

Definition at line 3009 of file app_queue.c.

#define DEFAULT_MIN_ANNOUNCE_FREQUENCY   15

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

Definition at line 691 of file app_queue.c.

Referenced by init_queue().

#define DEFAULT_RETRY   5

Definition at line 687 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

#define DEFAULT_TIMEOUT   15

Definition at line 688 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 690 of file app_queue.c.

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

#define MAX_QUEUE_BUCKETS   53

Definition at line 693 of file app_queue.c.

Referenced by load_module().

#define PM_MAX_LEN   8192

Definition at line 716 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

#define QUEUE_EVENT_VARIABLES   3

Definition at line 857 of file app_queue.c.

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

#define RECHECK   1

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

Definition at line 689 of file app_queue.c.

Referenced by wait_our_turn().

#define RES_EXISTS   (-1)

#define RES_NOSUCHQUEUE   (-3)

#define RES_NOT_DYNAMIC   (-4)

#define RES_OKAY   0

#define RES_OUTOFMEMORY   (-2)


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 

Definition at line 654 of file app_queue.c.

Enumerator:
CALLER 
AGENT 
TRANSFER 

Definition at line 3639 of file app_queue.c.

03639                            {
03640    CALLER,
03641    AGENT,
03642    TRANSFER
03643 };

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

00843                       {
00844    QUEUE_EMPTY_PENALTY = (1 << 0),
00845    QUEUE_EMPTY_PAUSED = (1 << 1),
00846    QUEUE_EMPTY_INUSE = (1 << 2),
00847    QUEUE_EMPTY_RINGING = (1 << 3),
00848    QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
00849    QUEUE_EMPTY_INVALID = (1 << 5),
00850    QUEUE_EMPTY_UNKNOWN = (1 << 6),
00851    QUEUE_EMPTY_WRAPUP = (1 << 7),
00852 };

Enumerator:
QUEUE_RELOAD_PARAMETERS 
QUEUE_RELOAD_MEMBER 
QUEUE_RELOAD_RULES 
QUEUE_RESET_STATS 

Definition at line 664 of file app_queue.c.

00664                        {
00665    QUEUE_RELOAD_PARAMETERS = (1 << 0),
00666    QUEUE_RELOAD_MEMBER = (1 << 1),
00667    QUEUE_RELOAD_RULES = (1 << 2),
00668    QUEUE_RESET_STATS = (1 << 3),
00669 };

Enumerator:
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 

Definition at line 739 of file app_queue.c.

00739                   {
00740    QUEUE_UNKNOWN = 0,
00741    QUEUE_TIMEOUT = 1,
00742    QUEUE_JOINEMPTY = 2,
00743    QUEUE_LEAVEEMPTY = 3,
00744    QUEUE_JOINUNAVAIL = 4,
00745    QUEUE_LEAVEUNAVAIL = 5,
00746    QUEUE_FULL = 6,
00747    QUEUE_CONTINUE = 7,
00748 };

Enumerator:
TIMEOUT_PRIORITY_APP 
TIMEOUT_PRIORITY_CONF 

Definition at line 764 of file app_queue.c.

00764                             {
00765    TIMEOUT_PRIORITY_APP,
00766    TIMEOUT_PRIORITY_CONF,
00767 };


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

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

Referenced by manager_queues_show(), and queue_show().

06364 {
06365    struct call_queue *q;
06366    struct ast_str *out = ast_str_alloca(240);
06367    int found = 0;
06368    time_t now = time(NULL);
06369    struct ao2_iterator queue_iter;
06370    struct ao2_iterator mem_iter;
06371 
06372    if (argc != 2 && argc != 3)
06373       return CLI_SHOWUSAGE;
06374 
06375    if (argc == 3) { /* specific queue */
06376       if ((q = load_realtime_queue(argv[2]))) {
06377          queue_unref(q);
06378       }
06379    } else if (ast_check_realtime("queues")) {
06380       /* This block is to find any queues which are defined in realtime but
06381        * which have not yet been added to the in-core container
06382        */
06383       struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
06384       char *queuename;
06385       if (cfg) {
06386          for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
06387             if ((q = load_realtime_queue(queuename))) {
06388                queue_unref(q);
06389             }
06390          }
06391          ast_config_destroy(cfg);
06392       }
06393    }
06394 
06395    queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
06396    ao2_lock(queues);
06397    while ((q = ao2_iterator_next(&queue_iter))) {
06398       float sl;
06399       struct call_queue *realtime_queue = NULL;
06400 
06401       ao2_lock(q);
06402       /* This check is to make sure we don't print information for realtime
06403        * queues which have been deleted from realtime but which have not yet
06404        * been deleted from the in-core container
06405        */
06406       if (q->realtime && !(realtime_queue = load_realtime_queue(q->name))) {
06407          ao2_unlock(q);
06408          queue_unref(q);
06409          continue;
06410       } else if (q->realtime) {
06411          queue_unref(realtime_queue);
06412       }
06413       if (argc == 3 && strcasecmp(q->name, argv[2])) {
06414          ao2_unlock(q);
06415          queue_unref(q);
06416          continue;
06417       }
06418       found = 1;
06419 
06420       ast_str_set(&out, 0, "%-12.12s has %d calls (max ", q->name, q->count);
06421       if (q->maxlen)
06422          ast_str_append(&out, 0, "%d", q->maxlen);
06423       else
06424          ast_str_append(&out, 0, "unlimited");
06425       sl = 0;
06426       if (q->callscompleted > 0)
06427          sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
06428       ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
06429          int2strat(q->strategy), q->holdtime, q->talktime, q->weight,
06430          q->callscompleted, q->callsabandoned,sl,q->servicelevel);
06431       do_print(s, fd, ast_str_buffer(out));
06432       if (!ao2_container_count(q->members))
06433          do_print(s, fd, "   No Members");
06434       else {
06435          struct member *mem;
06436 
06437          do_print(s, fd, "   Members: ");
06438          mem_iter = ao2_iterator_init(q->members, 0);
06439          while ((mem = ao2_iterator_next(&mem_iter))) {
06440             ast_str_set(&out, 0, "      %s", mem->membername);
06441             if (strcasecmp(mem->membername, mem->interface)) {
06442                ast_str_append(&out, 0, " (%s)", mem->interface);
06443             }
06444             if (mem->penalty)
06445                ast_str_append(&out, 0, " with penalty %d", mem->penalty);
06446             ast_str_append(&out, 0, "%s%s%s (%s)",
06447                mem->dynamic ? " (dynamic)" : "",
06448                mem->realtime ? " (realtime)" : "",
06449                mem->paused ? " (paused)" : "",
06450                ast_devstate2str(mem->status));
06451             if (mem->calls)
06452                ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
06453                   mem->calls, (long) (time(NULL) - mem->lastcall));
06454             else
06455                ast_str_append(&out, 0, " has taken no calls yet");
06456             do_print(s, fd, ast_str_buffer(out));
06457             ao2_ref(mem, -1);
06458          }
06459          ao2_iterator_destroy(&mem_iter);
06460       }
06461       if (!q->head)
06462          do_print(s, fd, "   No Callers");
06463       else {
06464          struct queue_ent *qe;
06465          int pos = 1;
06466 
06467          do_print(s, fd, "   Callers: ");
06468          for (qe = q->head; qe; qe = qe->next) {
06469             ast_str_set(&out, 0, "      %d. %s (wait: %ld:%2.2ld, prio: %d)",
06470                pos++, qe->chan->name, (long) (now - qe->start) / 60,
06471                (long) (now - qe->start) % 60, qe->prio);
06472             do_print(s, fd, ast_str_buffer(out));
06473          }
06474       }
06475       do_print(s, fd, ""); /* blank line between entries */
06476       ao2_unlock(q);
06477       queue_unref(q); /* Unref the iterator's reference */
06478    }
06479    ao2_iterator_destroy(&queue_iter);
06480    ao2_unlock(queues);
06481    if (!found) {
06482       if (argc == 3)
06483          ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
06484       else
06485          ast_str_set(&out, 0, "No queues.");
06486       do_print(s, fd, ast_str_buffer(out));
06487    }
06488    return CLI_SUCCESS;
06489 }

static void __reg_module ( void   )  [static]

Definition at line 7573 of file app_queue.c.

static void __unreg_module ( void   )  [static]

Definition at line 7573 of file app_queue.c.

static int add_to_queue ( const char *  queuename,
const char *  interface,
const char *  membername,
int  penalty,
int  paused,
int  dump,
const char *  state_interface 
) [static]

Add member to queue.

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

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

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

04734 {
04735    struct call_queue *q;
04736    struct member *new_member, *old_member;
04737    int res = RES_NOSUCHQUEUE;
04738 
04739    /*! \note Ensure the appropriate realtime queue is loaded.  Note that this
04740     * short-circuits if the queue is already in memory. */
04741    if (!(q = load_realtime_queue(queuename)))
04742       return res;
04743 
04744    ao2_lock(queues);
04745 
04746    ao2_lock(q);
04747    if ((old_member = interface_exists(q, interface)) == NULL) {
04748       if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
04749          new_member->dynamic = 1;
04750          ao2_link(q->members, new_member);
04751          q->membercount++;
04752          manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
04753             "Queue: %s\r\n"
04754             "Location: %s\r\n"
04755             "MemberName: %s\r\n"
04756             "Membership: %s\r\n"
04757             "Penalty: %d\r\n"
04758             "CallsTaken: %d\r\n"
04759             "LastCall: %d\r\n"
04760             "Status: %d\r\n"
04761             "Paused: %d\r\n",
04762             q->name, new_member->interface, new_member->membername,
04763             "dynamic",
04764             new_member->penalty, new_member->calls, (int) new_member->lastcall,
04765             new_member->status, new_member->paused);
04766          
04767          ao2_ref(new_member, -1);
04768          new_member = NULL;
04769 
04770          if (dump)
04771             dump_queue_members(q);
04772          
04773          res = RES_OKAY;
04774       } else {
04775          res = RES_OUTOFMEMORY;
04776       }
04777    } else {
04778       ao2_ref(old_member, -1);
04779       res = RES_EXISTS;
04780    }
04781    ao2_unlock(q);
04782    ao2_unlock(queues);
04783 
04784    return res;
04785 }

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

Definition at line 1812 of file app_queue.c.

References ao2_alloc, ao2_ref, ast_string_field_init, ast_string_field_set, and destroy_queue().

Referenced by find_queue_by_name_rt(), and reload_single_queue().

01813 {
01814    struct call_queue *q;
01815 
01816    if ((q = ao2_alloc(sizeof(*q), destroy_queue))) {
01817       if (ast_string_field_init(q, 64)) {
01818          ao2_ref(q, -1);
01819          return NULL;
01820       }
01821       ast_string_field_set(q, name, queuename);
01822    }
01823    return q;
01824 }

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

AddQueueMember application.

Definition at line 5170 of file app_queue.c.

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

Referenced by load_module().

05171 {
05172    int res=-1;
05173    char *parse, *temppos = NULL;
05174    AST_DECLARE_APP_ARGS(args,
05175       AST_APP_ARG(queuename);
05176       AST_APP_ARG(interface);
05177       AST_APP_ARG(penalty);
05178       AST_APP_ARG(options);
05179       AST_APP_ARG(membername);
05180       AST_APP_ARG(state_interface);
05181    );
05182    int penalty = 0;
05183 
05184    if (ast_strlen_zero(data)) {
05185       ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n");
05186       return -1;
05187    }
05188 
05189    parse = ast_strdupa(data);
05190 
05191    AST_STANDARD_APP_ARGS(args, parse);
05192 
05193    if (ast_strlen_zero(args.interface)) {
05194       args.interface = ast_strdupa(chan->name);
05195       temppos = strrchr(args.interface, '-');
05196       if (temppos)
05197          *temppos = '\0';
05198    }
05199 
05200    if (!ast_strlen_zero(args.penalty)) {
05201       if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
05202          ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
05203          penalty = 0;
05204       }
05205    }
05206 
05207    switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
05208    case RES_OKAY:
05209       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
05210       ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
05211       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
05212       res = 0;
05213       break;
05214    case RES_EXISTS:
05215       ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
05216       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
05217       res = 0;
05218       break;
05219    case RES_NOSUCHQUEUE:
05220       ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
05221       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
05222       res = 0;
05223       break;
05224    case RES_OUTOFMEMORY:
05225       ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
05226       break;
05227    }
05228 
05229    return res;
05230 }

static int attended_transfer_occurred ( struct ast_channel chan  )  [static]

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

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

Note:
Only call this with chan locked

Definition at line 3743 of file app_queue.c.

References ast_channel_datastore_find(), and queue_transfer_info.

Referenced by try_calling().

03744 {
03745    return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
03746 }

static int calc_metric ( struct call_queue q,
struct member mem,
int  pos,
struct queue_ent qe,
struct callattempt tmp 
) [static]

Calculate the metric of each member in the outgoing callattempts.

A numeric metric is given to each member depending on the ring strategy used by the queue. Members with lower metrics will be called before members with higher metrics

Return values:
-1 if penalties are exceeded
0 otherwise

Definition at line 3582 of file app_queue.c.

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

Referenced by try_calling().

03583 {
03584    if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || (qe->min_penalty && (mem->penalty < qe->min_penalty)))
03585       return -1;
03586 
03587    switch (q->strategy) {
03588    case QUEUE_STRATEGY_RINGALL:
03589       /* Everyone equal, except for penalty */
03590       tmp->metric = mem->penalty * 1000000;
03591       break;
03592    case QUEUE_STRATEGY_LINEAR:
03593       if (pos < qe->linpos) {
03594          tmp->metric = 1000 + pos;
03595       } else {
03596          if (pos > qe->linpos)
03597             /* Indicate there is another priority */
03598             qe->linwrapped = 1;
03599          tmp->metric = pos;
03600       }
03601       tmp->metric += mem->penalty * 1000000;
03602       break;
03603    case QUEUE_STRATEGY_RRMEMORY:
03604       if (pos < q->rrpos) {
03605          tmp->metric = 1000 + pos;
03606       } else {
03607          if (pos > q->rrpos)
03608             /* Indicate there is another priority */
03609             q->wrapped = 1;
03610          tmp->metric = pos;
03611       }
03612       tmp->metric += mem->penalty * 1000000;
03613       break;
03614    case QUEUE_STRATEGY_RANDOM:
03615       tmp->metric = ast_random() % 1000;
03616       tmp->metric += mem->penalty * 1000000;
03617       break;
03618    case QUEUE_STRATEGY_WRANDOM:
03619       tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
03620       break;
03621    case QUEUE_STRATEGY_FEWESTCALLS:
03622       tmp->metric = mem->calls;
03623       tmp->metric += mem->penalty * 1000000;
03624       break;
03625    case QUEUE_STRATEGY_LEASTRECENT:
03626       if (!mem->lastcall)
03627          tmp->metric = 0;
03628       else
03629          tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
03630       tmp->metric += mem->penalty * 1000000;
03631       break;
03632    default:
03633       ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
03634       break;
03635    }
03636    return 0;
03637 }

static void clear_queue ( struct call_queue q  )  [static]

Definition at line 1388 of file app_queue.c.

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

Referenced by clear_stats(), and find_queue_by_name_rt().

01389 {
01390    q->holdtime = 0;
01391    q->callscompleted = 0;
01392    q->callsabandoned = 0;
01393    q->callscompletedinsl = 0;
01394    q->wrapuptime = 0;
01395    q->talktime = 0;
01396 
01397    if (q->members) {
01398       struct member *mem;
01399       struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
01400       while ((mem = ao2_iterator_next(&mem_iter))) {
01401          mem->calls = 0;
01402          ao2_ref(mem, -1);
01403       }
01404       ao2_iterator_destroy(&mem_iter);
01405    }
01406 }

static int clear_stats ( const char *  queuename  )  [static]

Facilitates resetting statistics for a queue.

This function actually does not reset any statistics, but rather finds a call_queue struct which corresponds to the passed-in queue name and passes that structure to the clear_queue function. If no queuename is passed in, then all queues will have their statistics reset.

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

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

Referenced by reload_handler().

06306 {
06307    struct call_queue *q;
06308    struct ao2_iterator queue_iter = ao2_iterator_init(queues, 0);
06309    while ((q = ao2_iterator_next(&queue_iter))) {
06310       ao2_lock(q);
06311       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
06312          clear_queue(q);
06313       ao2_unlock(q);
06314    }
06315    ao2_iterator_destroy(&queue_iter);
06316    return 0;
06317 }

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

Definition at line 2526 of file app_queue.c.

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

Referenced by ring_entry().

02527 {
02528    struct call_queue *q;
02529    struct member *mem;
02530    int found = 0;
02531    struct ao2_iterator queue_iter;
02532    
02533    /* q's lock and rq's lock already set by try_calling()
02534     * to solve deadlock */
02535    queue_iter = ao2_iterator_init(queues, 0);
02536    while ((q = ao2_iterator_next(&queue_iter))) {
02537       if (q == rq) { /* don't check myself, could deadlock */
02538          queue_unref(q);
02539          continue;
02540       }
02541       ao2_lock(q);
02542       if (q->count && q->members) {
02543          if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
02544             ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
02545             if (q->weight > rq->weight && q->count >= num_available_members(q)) {
02546                ast_debug(1, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count);
02547                found = 1;
02548             }
02549             ao2_ref(mem, -1);
02550          }
02551       }
02552       ao2_unlock(q);
02553       queue_unref(q);
02554       if (found) {
02555          break;
02556       }
02557    }
02558    ao2_iterator_destroy(&queue_iter);
02559    return found;
02560 }

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

Definition at line 6491 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_strdup, call_queue::name, queue_unref(), and queues.

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

06492 {
06493    struct call_queue *q;
06494    char *ret = NULL;
06495    int which = 0;
06496    int wordlen = strlen(word);
06497    struct ao2_iterator queue_iter;
06498 
06499    queue_iter = ao2_iterator_init(queues, 0);
06500    while ((q = ao2_iterator_next(&queue_iter))) {
06501       if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
06502          ret = ast_strdup(q->name);
06503          queue_unref(q);
06504          break;
06505       }
06506       queue_unref(q);
06507    }
06508    ao2_iterator_destroy(&queue_iter);
06509 
06510    return ret;
06511 }

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

Definition at line 6923 of file app_queue.c.

References ast_malloc, ast_strdup, complete_queue(), and num.

Referenced by handle_queue_add_member().

06924 {
06925    /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
06926    switch (pos) {
06927    case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
06928       return NULL;
06929    case 4: /* only one possible match, "to" */
06930       return state == 0 ? ast_strdup("to") : NULL;
06931    case 5: /* <queue> */
06932       return complete_queue(line, word, pos, state);
06933    case 6: /* only one possible match, "penalty" */
06934       return state == 0 ? ast_strdup("penalty") : NULL;
06935    case 7:
06936       if (state < 100) {      /* 0-99 */
06937          char *num;
06938          if ((num = ast_malloc(3))) {
06939             sprintf(num, "%d", state);
06940          }
06941          return num;
06942       } else {
06943          return NULL;
06944       }
06945    case 8: /* only one possible match, "as" */
06946       return state == 0 ? ast_strdup("as") : NULL;
06947    case 9: /* Don't attempt to complete name of member (infinite possibilities) */
06948       return NULL;
06949    default:
06950       return NULL;
06951    }
06952 }

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

Definition at line 7144 of file app_queue.c.

References ast_strdup, and complete_queue().

Referenced by handle_queue_pause_member().

07145 {
07146    /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
07147    switch (pos) {
07148    case 3:  /* Don't attempt to complete name of interface (infinite possibilities) */
07149       return NULL;
07150    case 4:  /* only one possible match, "queue" */
07151       return state == 0 ? ast_strdup("queue") : NULL;
07152    case 5:  /* <queue> */
07153       return complete_queue(line, word, pos, state);
07154    case 6: /* "reason" */
07155       return state == 0 ? ast_strdup("reason") : NULL;
07156    case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
07157       return NULL;
07158    default:
07159       return NULL;
07160    }
07161 }

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

Definition at line 7053 of file app_queue.c.

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

Referenced by handle_queue_remove_member().

07054 {
07055    int which = 0;
07056    struct call_queue *q;
07057    struct member *m;
07058    struct ao2_iterator queue_iter;
07059    struct ao2_iterator mem_iter;
07060    int wordlen = strlen(word);
07061 
07062    /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
07063    if (pos > 5 || pos < 3)
07064       return NULL;
07065    if (pos == 4)   /* only one possible match, 'from' */
07066       return (state == 0 ? ast_strdup("from") : NULL);
07067 
07068    if (pos == 5)   /* No need to duplicate code */
07069       return complete_queue(line, word, pos, state);
07070 
07071    /* here is the case for 3, <member> */
07072    queue_iter = ao2_iterator_init(queues, 0);
07073    while ((q = ao2_iterator_next(&queue_iter))) {
07074       ao2_lock(q);
07075       mem_iter = ao2_iterator_init(q->members, 0);
07076       while ((m = ao2_iterator_next(&mem_iter))) {
07077          if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
07078             char *tmp;
07079             ao2_unlock(q);
07080             tmp = ast_strdup(m->interface);
07081             ao2_ref(m, -1);
07082             queue_unref(q);
07083             ao2_iterator_destroy(&mem_iter);
07084             ao2_iterator_destroy(&queue_iter);
07085             return tmp;
07086          }
07087          ao2_ref(m, -1);
07088       }
07089       ao2_iterator_destroy(&mem_iter);
07090       ao2_unlock(q);
07091       queue_unref(q);
07092    }
07093    ao2_iterator_destroy(&queue_iter);
07094 
07095    return NULL;
07096 }

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

Definition at line 7277 of file app_queue.c.

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

Referenced by handle_queue_rule_show().

07278 {
07279    int which = 0;
07280    struct rule_list *rl_iter;
07281    int wordlen = strlen(word);
07282    char *ret = NULL;
07283    if (pos != 3) /* Wha? */ {
07284       return NULL;
07285    }
07286 
07287    AST_LIST_LOCK(&rule_lists);
07288    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
07289       if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
07290          ret = ast_strdup(rl_iter->name);
07291          break;
07292       }
07293    }
07294    AST_LIST_UNLOCK(&rule_lists);
07295 
07296    return ret;
07297 }

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

Definition at line 7214 of file app_queue.c.

References ast_strdup, and complete_queue().

Referenced by handle_queue_set_member_penalty().

07215 {
07216    /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
07217    switch (pos) {
07218    case 4:
07219       if (state == 0) {
07220          return ast_strdup("on");
07221       } else {
07222          return NULL;
07223       }
07224    case 6:
07225       if (state == 0) {
07226          return ast_strdup("in");
07227       } else {
07228          return NULL;
07229       }
07230    case 7:
07231       return complete_queue(line, word, pos, state);
07232    default:
07233       return NULL;
07234    }
07235 }

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

Definition at line 6513 of file app_queue.c.

References complete_queue().

Referenced by queue_show().

06514 {
06515    if (pos == 2)
06516       return complete_queue(line, word, pos, state);
06517    return NULL;
06518 }

static int compress_char ( const char  c  )  [static]

Definition at line 1287 of file app_queue.c.

Referenced by member_hash_fn().

01288 {
01289    if (c < 32)
01290       return 0;
01291    else if (c > 96)
01292       return c - 64;
01293    else
01294       return c - 32;
01295 }

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

Copy rule from global list into specified queue.

Definition at line 5267 of file app_queue.c.

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

Referenced by queue_exec().

05268 {
05269    struct penalty_rule *pr_iter;
05270    struct rule_list *rl_iter;
05271    const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
05272    AST_LIST_LOCK(&rule_lists);
05273    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
05274       if (!strcasecmp(rl_iter->name, tmp))
05275          break;
05276    }
05277    if (rl_iter) {
05278       AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
05279          struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
05280          if (!new_pr) {
05281             ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
05282             AST_LIST_UNLOCK(&rule_lists);
05283             break;
05284          }
05285          new_pr->time = pr_iter->time;
05286          new_pr->max_value = pr_iter->max_value;
05287          new_pr->min_value = pr_iter->min_value;
05288          new_pr->max_relative = pr_iter->max_relative;
05289          new_pr->min_relative = pr_iter->min_relative;
05290          AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
05291       }
05292    }
05293    AST_LIST_UNLOCK(&rule_lists);
05294 }

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

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

Definition at line 1262 of file app_queue.c.

References ao2_alloc, ast_copy_string(), ast_log(), ast_strlen_zero(), member::interface, LOG_WARNING, member::membername, member::paused, member::penalty, member::state_interface, and member::status.

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

01263 {
01264    struct member *cur;
01265    
01266    if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
01267       cur->penalty = penalty;
01268       cur->paused = paused;
01269       ast_copy_string(cur->interface, interface, sizeof(cur->interface));
01270       if (!ast_strlen_zero(state_interface))
01271          ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
01272       else
01273          ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
01274       if (!ast_strlen_zero(membername))
01275          ast_copy_string(cur->membername, membername, sizeof(cur->membername));
01276       else
01277          ast_copy_string(cur->membername, interface, sizeof(cur->membername));
01278       if (!strchr(cur->interface, '/'))
01279          ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
01280       cur->status = ast_device_state(cur->state_interface);
01281    }
01282 
01283    return cur;
01284 }

static void destroy_queue ( void *  obj  )  [static]

Free queue's member list then its string fields.

Definition at line 1798 of file app_queue.c.

References ao2_ref, ast_string_field_free_memory, free, free_members(), MAX_PERIODIC_ANNOUNCEMENTS, call_queue::members, and call_queue::sound_periodicannounce.

Referenced by alloc_queue().

01799 {
01800    struct call_queue *q = obj;
01801    int i;
01802 
01803    free_members(q, 1);
01804    ast_string_field_free_memory(q);
01805    for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
01806       if (q->sound_periodicannounce[i])
01807          free(q->sound_periodicannounce[i]);
01808    }
01809    ao2_ref(q->members, -1);
01810 }

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

Definition at line 1235 of file app_queue.c.

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

Referenced by load_module(), and load_pbx().

01236 {
01237    enum ast_device_state state;
01238    const char *device;
01239    struct statechange *sc;
01240    size_t datapsize;
01241 
01242    state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
01243    device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
01244 
01245    if (ast_strlen_zero(device)) {
01246       ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
01247       return;
01248    }
01249    datapsize = sizeof(*sc) + strlen(device) + 1;
01250    if (!(sc = ast_calloc(1, datapsize))) {
01251       ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
01252       return;
01253    }
01254    sc->state = state;
01255    strcpy(sc->dev, device);
01256    if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
01257       ast_free(sc);
01258    }
01259 }

static void do_hang ( struct callattempt o  )  [static]

common hangup actions

Definition at line 2563 of file app_queue.c.

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

Referenced by ring_entry(), and wait_for_answer().

02564 {
02565    o->stillgoing = 0;
02566    ast_hangup(o->chan);
02567    o->chan = NULL;
02568 }

static void do_print ( struct mansession s,
int  fd,
const char *  str 
) [static]

direct ouput to manager or cli with proper terminator

Definition at line 6349 of file app_queue.c.

References ast_cli(), and astman_append().

Referenced by __queues_show().

06350 {
06351    if (s)
06352       astman_append(s, "%s\r\n", str);
06353    else
06354       ast_cli(fd, "%s\n", str);
06355 }

static void dump_queue_members ( struct call_queue pm_queue  )  [static]

Dump all members in a specific queue to the database.

<pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]

Definition at line 4634 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_db_del(), ast_db_put(), ast_log(), member::dynamic, member::interface, LOG_WARNING, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, PM_MAX_LEN, member::state_interface, and value.

Referenced by add_to_queue(), remove_from_queue(), and set_member_paused().

04635 {
04636    struct member *cur_member;
04637    char value[PM_MAX_LEN];
04638    int value_len = 0;
04639    int res;
04640    struct ao2_iterator mem_iter;
04641 
04642    memset(value, 0, sizeof(value));
04643 
04644    if (!pm_queue)
04645       return;
04646 
04647    mem_iter = ao2_iterator_init(pm_queue->members, 0);
04648    while ((cur_member = ao2_iterator_next(&mem_iter))) {
04649       if (!cur_member->dynamic) {
04650          ao2_ref(cur_member, -1);
04651          continue;
04652       }
04653 
04654       res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s",
04655          value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface);
04656 
04657       ao2_ref(cur_member, -1);
04658 
04659       if (res != strlen(value + value_len)) {
04660          ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
04661          break;
04662       }
04663       value_len += res;
04664    }
04665    ao2_iterator_destroy(&mem_iter);
04666    
04667    if (value_len && !cur_member) {
04668       if (ast_db_put(pm_family, pm_queue->name, value))
04669          ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
04670    } else
04671       /* Delete the entry if the queue is empty or there is an error */
04672       ast_db_del(pm_family, pm_queue->name);
04673 }

static void end_bridge_callback ( void *  data  )  [static]

Definition at line 3790 of file app_queue.c.

References ao2_lock(), ao2_ref, ao2_unlock(), queue_end_bridge::chan, queue_ent::chan, queue_end_bridge::q, queue_unref(), and set_queue_variables().

03791 {
03792    struct queue_end_bridge *qeb = data;
03793    struct call_queue *q = qeb->q;
03794    struct ast_channel *chan = qeb->chan;
03795 
03796    if (ao2_ref(qeb, -1) == 1) {
03797       ao2_lock(q);
03798       set_queue_variables(q, chan);
03799       ao2_unlock(q);
03800       /* This unrefs the reference we made in try_calling when we allocated qeb */
03801       queue_unref(q);
03802    }
03803 }

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

Definition at line 3783 of file app_queue.c.

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

03784 {
03785    struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
03786    ao2_ref(qeb, +1);
03787    qeb->chan = originator;
03788 }

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

find the entry with the best metric, or NULL

Definition at line 2796 of file app_queue.c.

References callattempt::metric, and callattempt::q_next.

Referenced by ast_cli_command_full(), ring_one(), store_next_lin(), and store_next_rr().

02797 {
02798    struct callattempt *best = NULL, *cur;
02799 
02800    for (cur = outgoing; cur; cur = cur->q_next) {
02801       if (cur->stillgoing &&              /* Not already done */
02802          !cur->chan &&              /* Isn't already going */
02803          (!best || cur->metric < best->metric)) {     /* We haven't found one yet, or it's better */
02804          best = cur;
02805       }
02806    }
02807 
02808    return best;
02809 }

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

Reload a single queue via realtime.

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

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

References alloc_queue(), ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_lock(), ao2_ref, ao2_unlink, ao2_unlock(), ast_category_browse(), ast_copy_string(), ast_debug, ast_log(), ast_queue_log(), ast_strlen_zero(), ast_variable_retrieve(), clear_queue(), member::dead, call_queue::dead, init_queue(), member::interface, LOG_WARNING, call_queue::membercount, call_queue::members, ast_variable::name, call_queue::name, ast_variable::next, OBJ_POINTER, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_unref(), queues, member::realtime, call_queue::realtime, rt_handle_member_record(), S_OR, strat2int(), call_queue::strategy, and ast_variable::value.

Referenced by load_realtime_queue().

01837 {
01838    struct ast_variable *v;
01839    struct call_queue *q, tmpq = {
01840       .name = queuename,   
01841    };
01842    struct member *m;
01843    struct ao2_iterator mem_iter;
01844    char *interface = NULL;
01845    const char *tmp_name;
01846    char *tmp;
01847    char tmpbuf[64];  /* Must be longer than the longest queue param name. */
01848 
01849    /* Static queues override realtime. */
01850    if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
01851       ao2_lock(q);
01852       if (!q->realtime) {
01853          if (q->dead) {
01854             ao2_unlock(q);
01855             queue_unref(q);
01856             return NULL;
01857          } else {
01858             ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
01859             ao2_unlock(q);
01860             return q;
01861          }
01862       }
01863       queue_unref(q);
01864    } else if (!member_config)
01865       /* Not found in the list, and it's not realtime ... */
01866       return NULL;
01867 
01868    /* Check if queue is defined in realtime. */
01869    if (!queue_vars) {
01870       /* Delete queue from in-core list if it has been deleted in realtime. */
01871       if (q) {
01872          /*! \note Hmm, can't seem to distinguish a DB failure from a not
01873             found condition... So we might delete an in-core queue
01874             in case of DB failure. */
01875          ast_debug(1, "Queue %s not found in realtime.\n", queuename);
01876 
01877          q->dead = 1;
01878          /* Delete if unused (else will be deleted when last caller leaves). */
01879          ao2_unlink(queues, q);
01880          ao2_unlock(q);
01881          queue_unref(q);
01882       }
01883       return NULL;
01884    }
01885 
01886    /* Create a new queue if an in-core entry does not exist yet. */
01887    if (!q) {
01888       struct ast_variable *tmpvar = NULL;
01889       if (!(q = alloc_queue(queuename)))
01890          return NULL;
01891       ao2_lock(q);
01892       clear_queue(q);
01893       q->realtime = 1;
01894       q->membercount = 0;
01895       /*Before we initialize the queue, we need to set the strategy, so that linear strategy
01896        * will allocate the members properly
01897        */
01898       for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
01899          if (!strcasecmp(tmpvar->name, "strategy")) {
01900             q->strategy = strat2int(tmpvar->value);
01901             if (q->strategy < 0) {
01902                ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
01903                tmpvar->value, q->name);
01904                q->strategy = QUEUE_STRATEGY_RINGALL;
01905             }
01906             break;
01907          }
01908       }
01909       /* We traversed all variables and didn't find a strategy */
01910       if (!tmpvar)
01911          q->strategy = QUEUE_STRATEGY_RINGALL;
01912       ao2_link(queues, q);
01913    }
01914    init_queue(q);    /* Ensure defaults for all parameters not set explicitly. */
01915 
01916    memset(tmpbuf, 0, sizeof(tmpbuf));
01917    for (v = queue_vars; v; v = v->next) {
01918       /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
01919       if ((tmp = strchr(v->name, '_'))) {
01920          ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
01921          tmp_name = tmpbuf;
01922          tmp = tmpbuf;
01923          while ((tmp = strchr(tmp, '_')))
01924             *tmp++ = '-';
01925       } else
01926          tmp_name = v->name;
01927 
01928       if (!ast_strlen_zero(v->value)) {
01929          /* Don't want to try to set the option if the value is empty */
01930          queue_set_param(q, tmp_name, v->value, -1, 0);
01931       }
01932    }
01933 
01934    /* Temporarily set realtime members dead so we can detect deleted ones. 
01935     * Also set the membercount correctly for realtime*/
01936    mem_iter = ao2_iterator_init(q->members, 0);
01937    while ((m = ao2_iterator_next(&mem_iter))) {
01938       q->membercount++;
01939       if (m->realtime)
01940          m->dead = 1;
01941       ao2_ref(m, -1);
01942    }
01943    ao2_iterator_destroy(&mem_iter);
01944 
01945    while ((interface = ast_category_browse(member_config, interface))) {
01946       rt_handle_member_record(q, interface,
01947          ast_variable_retrieve(member_config, interface, "uniqueid"),
01948          S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
01949          ast_variable_retrieve(member_config, interface, "penalty"),
01950          ast_variable_retrieve(member_config, interface, "paused"),
01951          S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
01952    }
01953 
01954    /* Delete all realtime members that have been deleted in DB. */
01955    mem_iter = ao2_iterator_init(q->members, 0);
01956    while ((m = ao2_iterator_next(&mem_iter))) {
01957       if (m->dead) {
01958          ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
01959          ao2_unlink(q->members, m);
01960          q->membercount--;
01961       }
01962       ao2_ref(m, -1);
01963    }
01964    ao2_iterator_destroy(&mem_iter);
01965 
01966    ao2_unlock(q);
01967 
01968    return q;
01969 }

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

Iterate through queue's member list and delete them.

Definition at line 1781 of file app_queue.c.

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

Referenced by destroy_queue().

01782 {
01783    /* Free non-dynamic members */
01784    struct member *cur;
01785    struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
01786 
01787    while ((cur = ao2_iterator_next(&mem_iter))) {
01788       if (all || !cur->dynamic) {
01789          ao2_unlink(q->members, cur);
01790          q->membercount--;
01791       }
01792       ao2_ref(cur, -1);
01793    }
01794    ao2_iterator_destroy(&mem_iter);
01795 }

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

Definition at line 4912 of file app_queue.c.

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

Referenced by queue_function_memberpenalty_read().

04913 {
04914    int foundqueue = 0, penalty;
04915    struct call_queue *q, tmpq = {
04916       .name = queuename,   
04917    };
04918    struct member *mem;
04919    
04920    if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
04921       foundqueue = 1;
04922       ao2_lock(q);
04923       if ((mem = interface_exists(q, interface))) {
04924          penalty = mem->penalty;
04925          ao2_ref(mem, -1);
04926          ao2_unlock(q);
04927          queue_unref(q);
04928          return penalty;
04929       }
04930       ao2_unlock(q);
04931       queue_unref(q);
04932    }
04933 
04934    /* some useful debuging */
04935    if (foundqueue) 
04936       ast_log (LOG_ERROR, "Invalid queuename\n");
04937    else 
04938       ast_log (LOG_ERROR, "Invalid interface\n");
04939 
04940    return RESULT_FAILURE;
04941 }

static int get_member_status ( struct call_queue q,
int  max_penalty,
int  min_penalty,
enum empty_conditions  conditions 
) [static]

Check if members are available.

This function checks to see if members are available to be called. If any member is available, the function immediately returns 0. If no members are available, then -1 is returned.

Definition at line 1096 of file app_queue.c.

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

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

01097 {
01098    struct member *member;
01099    struct ao2_iterator mem_iter;
01100 
01101    ao2_lock(q);
01102    mem_iter = ao2_iterator_init(q->members, 0);
01103    for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
01104       if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
01105          if (conditions & QUEUE_EMPTY_PENALTY) {
01106             ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
01107             continue;
01108          }
01109       }
01110 
01111       switch (member->status) {
01112       case AST_DEVICE_INVALID:
01113          if (conditions & QUEUE_EMPTY_INVALID) {
01114             ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
01115             break;
01116          }
01117       case AST_DEVICE_UNAVAILABLE:
01118          if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
01119             ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
01120             break;
01121          }
01122       case AST_DEVICE_INUSE:
01123          if (conditions & QUEUE_EMPTY_INUSE) {
01124             ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
01125             break;
01126          }
01127       case AST_DEVICE_UNKNOWN:
01128          if (conditions & QUEUE_EMPTY_UNKNOWN) {
01129             ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
01130             break;
01131          }
01132       default:
01133          if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
01134             ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
01135             break;
01136          } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
01137             ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
01138             break;
01139          } else {
01140             ao2_unlock(q);
01141             ao2_ref(member, -1);
01142             ao2_iterator_destroy(&mem_iter);
01143             ast_debug(4, "%s is available.\n", member->membername);
01144             return 0;
01145          }
01146          break;
01147       }
01148    }
01149    ao2_iterator_destroy(&mem_iter);
01150 
01151    ao2_unlock(q);
01152    return -1;
01153 }

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

Definition at line 6979 of file app_queue.c.

References add_to_queue(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_add_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, ast_cli_entry::usage, and ast_cli_args::word.

06980 {
06981    const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
06982    int penalty;
06983 
06984    switch ( cmd ) {
06985    case CLI_INIT:
06986       e->command = "queue add member";
06987       e->usage =
06988          "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"
06989          "       Add a channel to a queue with optionally:  a penalty, membername and a state_interface\n";
06990       return NULL;
06991    case CLI_GENERATE:
06992       return complete_queue_add_member(a->line, a->word, a->pos, a->n);
06993    }
06994 
06995    if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
06996       return CLI_SHOWUSAGE;
06997    } else if (strcmp(a->argv[4], "to")) {
06998       return CLI_SHOWUSAGE;
06999    } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
07000       return CLI_SHOWUSAGE;
07001    } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
07002       return CLI_SHOWUSAGE;
07003    } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
07004       return CLI_SHOWUSAGE;
07005    }
07006 
07007    queuename = a->argv[5];
07008    interface = a->argv[3];
07009    if (a->argc >= 8) {
07010       if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
07011          if (penalty < 0) {
07012             ast_cli(a->fd, "Penalty must be >= 0\n");
07013             penalty = 0;
07014          }
07015       } else {
07016          ast_cli(a->fd, "Penalty must be an integer >= 0\n");
07017          penalty = 0;
07018       }
07019    } else {
07020       penalty = 0;
07021    }
07022 
07023    if (a->argc >= 10) {
07024       membername = a->argv[9];
07025    }
07026 
07027    if (a->argc >= 12) {
07028       state_interface = a->argv[11];
07029    }
07030 
07031    switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
07032    case RES_OKAY:
07033       ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
07034       ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
07035       return CLI_SUCCESS;
07036    case RES_EXISTS:
07037       ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
07038       return CLI_FAILURE;
07039    case RES_NOSUCHQUEUE:
07040       ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
07041       return CLI_FAILURE;
07042    case RES_OUTOFMEMORY:
07043       ast_cli(a->fd, "Out of memory\n");
07044       return CLI_FAILURE;
07045    case RES_NOT_DYNAMIC:
07046       ast_cli(a->fd, "Member not dynamic\n");
07047       return CLI_FAILURE;
07048    default:
07049       return CLI_FAILURE;
07050    }
07051 }

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

Definition at line 7163 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_pause_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RESULT_SUCCESS, set_member_paused(), ast_cli_entry::usage, and word.

07164 {
07165    const char *queuename, *interface, *reason;
07166    int paused;
07167 
07168    switch (cmd) {
07169    case CLI_INIT:
07170       e->command = "queue {pause|unpause} member";
07171       e->usage = 
07172          "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
07173          "  Pause or unpause a queue member. Not specifying a particular queue\n"
07174          "  will pause or unpause a member across all queues to which the member\n"
07175          "  belongs.\n";
07176       return NULL;
07177    case CLI_GENERATE:
07178       return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
07179    }
07180 
07181    if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
07182       return CLI_SHOWUSAGE;
07183    } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
07184       return CLI_SHOWUSAGE;
07185    } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
07186       return CLI_SHOWUSAGE;
07187    }
07188 
07189 
07190    interface = a->argv[3];
07191    queuename = a->argc >= 6 ? a->argv[5] : NULL;
07192    reason = a->argc == 8 ? a->argv[7] : NULL;
07193    paused = !strcasecmp(a->argv[1], "pause");
07194 
07195    if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
07196       ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
07197       if (!ast_strlen_zero(queuename))
07198          ast_cli(a->fd, " in queue '%s'", queuename);
07199       if (!ast_strlen_zero(reason))
07200          ast_cli(a->fd, " for reason '%s'", reason);
07201       ast_cli(a->fd, "\n");
07202       return CLI_SUCCESS;
07203    } else {
07204       ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
07205       if (!ast_strlen_zero(queuename))
07206          ast_cli(a->fd, " in queue '%s'", queuename);
07207       if (!ast_strlen_zero(reason))
07208          ast_cli(a->fd, " for reason '%s'", reason);
07209       ast_cli(a->fd, "\n");
07210       return CLI_FAILURE;
07211    }
07212 }

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

Definition at line 7372 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, AST_FLAGS_ALL, ast_set_flag, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue(), ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, reload_handler(), ast_cli_entry::usage, and ast_cli_args::word.

07373 {
07374    struct ast_flags mask = {0,};
07375    int i;
07376 
07377    switch (cmd) {
07378       case CLI_INIT:
07379          e->command = "queue reload {parameters|members|rules|all}";
07380          e->usage =
07381             "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
07382             "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
07383             "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
07384             "specified in order to know what information to reload. Below is an explanation\n"
07385             "of each of these qualifiers.\n"
07386             "\n"
07387             "\t'members' - reload queue members from queues.conf\n"
07388             "\t'parameters' - reload all queue options except for queue members\n"
07389             "\t'rules' - reload the queuerules.conf file\n"
07390             "\t'all' - reload queue rules, parameters, and members\n"
07391             "\n"
07392             "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
07393             "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
07394             "one queue is specified when using this command, reloading queue rules may cause\n"
07395             "other queues to be affected\n";
07396          return NULL;
07397       case CLI_GENERATE:
07398          if (a->pos >= 3) {
07399             return complete_queue(a->line, a->word, a->pos, a->n);
07400          } else {
07401             return NULL;
07402          }
07403    }
07404 
07405    if (a->argc < 3)
07406       return CLI_SHOWUSAGE;
07407 
07408    if (!strcasecmp(a->argv[2], "rules")) {
07409       ast_set_flag(&mask, QUEUE_RELOAD_RULES);
07410    } else if (!strcasecmp(a->argv[2], "members")) {
07411       ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
07412    } else if (!strcasecmp(a->argv[2], "parameters")) {
07413       ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
07414    } else if (!strcasecmp(a->argv[2], "all")) {
07415       ast_set_flag(&mask, AST_FLAGS_ALL);
07416    }
07417 
07418    if (a->argc == 3) {
07419       reload_handler(1, &mask, NULL);
07420       return CLI_SUCCESS;
07421    }
07422 
07423    for (i = 3; i < a->argc; ++i) {
07424       reload_handler(1, &mask, a->argv[i]);
07425    }
07426 
07427    return CLI_SUCCESS;
07428 }

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

Definition at line 7098 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_queue_log(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_remove_member(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, RES_OUTOFMEMORY, ast_cli_entry::usage, and ast_cli_args::word.

07099 {
07100    const char *queuename, *interface;
07101 
07102    switch (cmd) {
07103    case CLI_INIT:
07104       e->command = "queue remove member";
07105       e->usage = 
07106          "Usage: queue remove member <channel> from <queue>\n"
07107          "       Remove a specific channel from a queue.\n";
07108       return NULL;
07109    case CLI_GENERATE:
07110       return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
07111    }
07112 
07113    if (a->argc != 6) {
07114       return CLI_SHOWUSAGE;
07115    } else if (strcmp(a->argv[4], "from")) {
07116       return CLI_SHOWUSAGE;
07117    }
07118 
07119    queuename = a->argv[5];
07120    interface = a->argv[3];
07121 
07122    switch (remove_from_queue(queuename, interface)) {
07123    case RES_OKAY:
07124       ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
07125       ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
07126       return CLI_SUCCESS;
07127    case RES_EXISTS:
07128       ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
07129       return CLI_FAILURE;
07130    case RES_NOSUCHQUEUE:
07131       ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
07132       return CLI_FAILURE;
07133    case RES_OUTOFMEMORY:
07134       ast_cli(a->fd, "Out of memory\n");
07135       return CLI_FAILURE;
07136    case RES_NOT_DYNAMIC:
07137       ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
07138       return CLI_FAILURE;
07139    default:
07140       return CLI_FAILURE;
07141    }
07142 }

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

Definition at line 7333 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue(), ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, QUEUE_RESET_STATS, reload_handler(), ast_cli_entry::usage, and ast_cli_args::word.

07334 {
07335    struct ast_flags mask = {QUEUE_RESET_STATS,};
07336    int i;
07337 
07338    switch (cmd) {
07339       case CLI_INIT:
07340          e->command = "queue reset stats";
07341          e->usage =
07342             "Usage: queue reset stats [<queuenames>]\n"
07343             "\n"
07344             "Issuing this command will reset statistics for\n"
07345             "<queuenames>, or for all queues if no queue is\n"
07346             "specified.\n";
07347          return NULL;
07348       case CLI_GENERATE:
07349          if (a->pos >= 3) {
07350             return complete_queue(a->line, a->word, a->pos, a->n);
07351          } else {
07352             return NULL;
07353          }
07354    }
07355 
07356    if (a->argc < 3) {
07357       return CLI_SHOWUSAGE;
07358    }
07359 
07360    if (a->argc == 3) {
07361       reload_handler(1, &mask, NULL);
07362       return CLI_SUCCESS;
07363    }
07364 
07365    for (i = 3; i < a->argc; ++i) {
07366       reload_handler(1, &mask, a->argv[i]);
07367    }
07368 
07369    return CLI_SUCCESS;
07370 }

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

Definition at line 7299 of file app_queue.c.

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

07300 {
07301    const char *rule;
07302    struct rule_list *rl_iter;
07303    struct penalty_rule *pr_iter;
07304    switch (cmd) {
07305    case CLI_INIT:
07306       e->command = "queue show rules";
07307       e->usage =
07308       "Usage: queue show rules [rulename]\n"
07309       "  Show the list of rules associated with rulename. If no\n"
07310       "  rulename is specified, list all rules defined in queuerules.conf\n";
07311       return NULL;
07312    case CLI_GENERATE:
07313       return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
07314    }
07315 
07316    if (a->argc != 3 && a->argc != 4)
07317       return CLI_SHOWUSAGE;
07318 
07319    rule = a->argc == 4 ? a->argv[3] : "";
07320    AST_LIST_LOCK(&rule_lists);
07321    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
07322       if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
07323          ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
07324          AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
07325             ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d and adjust QUEUE_MIN_PENALTY %s %d\n", pr_iter->time, pr_iter->max_relative ? "by" : "to", pr_iter->max_value, pr_iter->min_relative ? "by" : "to", pr_iter->min_value);
07326          }
07327       }
07328    }
07329    AST_LIST_UNLOCK(&rule_lists);
07330    return CLI_SUCCESS; 
07331 }

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

Definition at line 7237 of file app_queue.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_queue_set_member_penalty(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, RESULT_FAILURE, RESULT_SUCCESS, set_member_penalty(), ast_cli_entry::usage, and ast_cli_args::word.

07238 {
07239    const char *queuename = NULL, *interface;
07240    int penalty = 0;
07241 
07242    switch (cmd) {
07243    case CLI_INIT:
07244       e->command = "queue set penalty";
07245       e->usage = 
07246       "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
07247       "  Set a member's penalty in the queue specified. If no queue is specified\n"
07248       "  then that interface's penalty is set in all queues to which that interface is a member\n";
07249       return NULL;
07250    case CLI_GENERATE:
07251       return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n);
07252    }
07253 
07254    if (a->argc != 6 && a->argc != 8) {
07255       return CLI_SHOWUSAGE;
07256    } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
07257       return CLI_SHOWUSAGE;
07258    }
07259 
07260    if (a->argc == 8)
07261       queuename = a->argv[7];
07262    interface = a->argv[5];
07263    penalty = atoi(a->argv[3]);
07264 
07265    switch (set_member_penalty(queuename, interface, penalty)) {
07266    case RESULT_SUCCESS:
07267       ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
07268       return CLI_SUCCESS;
07269    case RESULT_FAILURE:
07270       ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
07271       return CLI_FAILURE;
07272    default:
07273       return CLI_FAILURE;
07274    }
07275 }

static int handle_statechange ( void *  datap  )  [static]

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

Definition at line 1191 of file app_queue.c.

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

Referenced by device_state_cb().

01192 {
01193    struct statechange *sc = datap;
01194    struct ao2_iterator miter, qiter;
01195    struct member *m;
01196    struct call_queue *q;
01197    char interface[80], *slash_pos;
01198    int found = 0;
01199 
01200    qiter = ao2_iterator_init(queues, 0);
01201    while ((q = ao2_iterator_next(&qiter))) {
01202       ao2_lock(q);
01203 
01204       miter = ao2_iterator_init(q->members, 0);
01205       for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
01206          ast_copy_string(interface, m->state_interface, sizeof(interface));
01207 
01208          if ((slash_pos = strchr(interface, '/')))
01209             if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/')))
01210                *slash_pos = '\0';
01211 
01212          if (!strcasecmp(interface, sc->dev)) {
01213             found = 1;
01214             update_status(q, m, sc->state);
01215             ao2_ref(m, -1);
01216             break;
01217          }
01218       }
01219       ao2_iterator_destroy(&miter);
01220 
01221       ao2_unlock(q);
01222       ao2_ref(q, -1);
01223    }
01224    ao2_iterator_destroy(&qiter);
01225 
01226    if (found)
01227       ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
01228    else
01229       ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", sc->dev, sc->state, ast_devstate2str(sc->state));
01230 
01231    ast_free(sc);
01232    return 0;
01233 }

static void hangupcalls ( struct callattempt outgoing,
struct ast_channel exception,
int  cancel_answered_elsewhere 
) [static]

Hang up a list of outgoing calls.

Definition at line 2455 of file app_queue.c.

References ao2_ref, AST_FLAG_ANSWERED_ELSEWHERE, ast_free, ast_hangup(), ast_set_flag, callattempt::chan, callattempt::member, and callattempt::q_next.

Referenced by try_calling().

02456 {
02457    struct callattempt *oo;
02458 
02459    while (outgoing) {
02460       /* If someone else answered the call we should indicate this in the CANCEL */
02461       /* Hangup any existing lines we have open */
02462       if (outgoing->chan && (outgoing->chan != exception || cancel_answered_elsewhere)) {
02463          if (exception || cancel_answered_elsewhere)
02464             ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
02465          ast_hangup(outgoing->chan);
02466       }
02467       oo = outgoing;
02468       outgoing = outgoing->q_next;
02469       if (oo->member)
02470          ao2_ref(oo->member, -1);
02471       ast_free(oo);
02472    }
02473 }

static void init_queue ( struct call_queue q  )  [static]

Initialize Queue default values.

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

Definition at line 1319 of file app_queue.c.

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

Referenced by find_queue_by_name_rt(), and reload_single_queue().

01320 {
01321    int i;
01322    struct penalty_rule *pr_iter;
01323 
01324    q->dead = 0;
01325    q->retry = DEFAULT_RETRY;
01326    q->timeout = DEFAULT_TIMEOUT;
01327    q->maxlen = 0;
01328    q->announcefrequency = 0;
01329    q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
01330    q->announceholdtime = 1;
01331    q->announcepositionlimit = 10; /* Default 10 positions */
01332    q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
01333    q->roundingseconds = 0; /* Default - don't announce seconds */
01334    q->servicelevel = 0;
01335    q->ringinuse = 1;
01336    q->setinterfacevar = 0;
01337    q->setqueuevar = 0;
01338    q->setqueueentryvar = 0;
01339    q->autofill = autofill_default;
01340    q->montype = montype_default;
01341    q->monfmt[0] = '\0';
01342    q->reportholdtime = 0;
01343    q->wrapuptime = 0;
01344    q->joinempty = 0;
01345    q->leavewhenempty = 0;
01346    q->memberdelay = 0;
01347    q->maskmemberstatus = 0;
01348    q->eventwhencalled = 0;
01349    q->weight = 0;
01350    q->timeoutrestart = 0;
01351    q->periodicannouncefrequency = 0;
01352    q->randomperiodicannounce = 0;
01353    q->numperiodicannounce = 0;
01354    q->timeoutpriority = TIMEOUT_PRIORITY_APP;
01355    if (!q->members) {
01356       if (q->strategy == QUEUE_STRATEGY_LINEAR)
01357          /* linear strategy depends on order, so we have to place all members in a single bucket */
01358          q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
01359       else
01360          q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
01361    }
01362    q->found = 1;
01363 
01364    ast_string_field_set(q, sound_next, "queue-youarenext");
01365    ast_string_field_set(q, sound_thereare, "queue-thereare");
01366    ast_string_field_set(q, sound_calls, "queue-callswaiting");
01367    ast_string_field_set(q, queue_quantity1, "queue-quantity1");
01368    ast_string_field_set(q, queue_quantity2, "queue-quantity2");
01369    ast_string_field_set(q, sound_holdtime, "queue-holdtime");
01370    ast_string_field_set(q, sound_minutes, "queue-minutes");
01371    ast_string_field_set(q, sound_minute, "queue-minute");
01372    ast_string_field_set(q, sound_seconds, "queue-seconds");
01373    ast_string_field_set(q, sound_thanks, "queue-thankyou");
01374    ast_string_field_set(q, sound_reporthold, "queue-reporthold");
01375 
01376    if ((q->sound_periodicannounce[0] = ast_str_create(32)))
01377       ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
01378 
01379    for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
01380       if (q->sound_periodicannounce[i])
01381          ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
01382    }
01383 
01384    while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list)))
01385       ast_free(pr_iter);
01386 }

static void insert_entry ( struct call_queue q,
struct queue_ent prev,
struct queue_ent new,
int *  pos 
) [inline, static]

Insert the 'new' entry after the 'prev' entry of queue 'q'.

Definition at line 1071 of file app_queue.c.

References call_queue::head, queue_ent::next, and queue_ent::parent.

Referenced by join_queue().

01072 {
01073    struct queue_ent *cur;
01074 
01075    if (!q || !new)
01076       return;
01077    if (prev) {
01078       cur = prev->next;
01079       prev->next = new;
01080    } else {
01081       cur = q->head;
01082       q->head = new;
01083    }
01084    new->next = cur;
01085    new->parent = q;
01086    new->pos = ++(*pos);
01087    new->opos = *pos;
01088 }

static int insert_penaltychange ( const char *  list_name,
const char *  content,
const int  linenum 
) [static]

Change queue penalty by adding rule.

Check rule for errors with time or fomatting, see if rule is relative to rest of queue, iterate list of rules to find correct insertion point, insert and return.

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

Definition at line 1417 of file app_queue.c.

References ast_calloc, ast_free, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_strdupa, ast_strlen_zero(), LOG_WARNING, penalty_rule::max_relative, penalty_rule::max_value, penalty_rule::min_relative, penalty_rule::min_value, rule_list::name, rule_list::rules, and penalty_rule::time.

Referenced by reload_queue_rules().

01418 {
01419    char *timestr, *maxstr, *minstr, *contentdup;
01420    struct penalty_rule *rule = NULL, *rule_iter;
01421    struct rule_list *rl_iter;
01422    int penaltychangetime, inserted = 0;
01423 
01424    if (!(rule = ast_calloc(1, sizeof(*rule)))) {
01425       return -1;
01426    }
01427 
01428    contentdup = ast_strdupa(content);
01429    
01430    if (!(maxstr = strchr(contentdup, ','))) {
01431       ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
01432       ast_free(rule);
01433       return -1;
01434    }
01435 
01436    *maxstr++ = '\0';
01437    timestr = contentdup;
01438 
01439    if ((penaltychangetime = atoi(timestr)) < 0) {
01440       ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
01441       ast_free(rule);
01442       return -1;
01443    }
01444 
01445    rule->time = penaltychangetime;
01446 
01447    if ((minstr = strchr(maxstr,',')))
01448       *minstr++ = '\0';
01449    
01450    /* The last check will evaluate true if either no penalty change is indicated for a given rule
01451     * OR if a min penalty change is indicated but no max penalty change is */
01452    if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
01453       rule->max_relative = 1;
01454    }
01455 
01456    rule->max_value = atoi(maxstr);
01457 
01458    if (!ast_strlen_zero(minstr)) {
01459       if (*minstr == '+' || *minstr == '-')
01460          rule->min_relative = 1;
01461       rule->min_value = atoi(minstr);
01462    } else /*there was no minimum specified, so assume this means no change*/
01463       rule->min_relative = 1;
01464 
01465    /*We have the rule made, now we need to insert it where it belongs*/
01466    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
01467       if (strcasecmp(rl_iter->name, list_name))
01468          continue;
01469 
01470       AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
01471          if (rule->time < rule_iter->time) {
01472             AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
01473             inserted = 1;
01474             break;
01475          }
01476       }
01477       AST_LIST_TRAVERSE_SAFE_END;
01478    
01479       if (!inserted) {
01480          AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
01481       }
01482    }
01483 
01484    return 0;
01485 }

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

Definition at line 1002 of file app_queue.c.

References ARRAY_LEN, strategy::name, and strategies.

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

01003 {
01004    int x;
01005 
01006    for (x = 0; x < ARRAY_LEN(strategies); x++) {
01007       if (strategy == strategies[x].strategy)
01008          return strategies[x].name;
01009    }
01010 
01011    return "<unknown>";
01012 }

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

Definition at line 4608 of file app_queue.c.

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

Referenced by add_to_queue(), get_member_penalty(), set_member_paused(), and set_member_penalty().

04609 {
04610    struct member *mem;
04611    struct ao2_iterator mem_iter;
04612 
04613    if (!q)
04614       return NULL;
04615 
04616    mem_iter = ao2_iterator_init(q->members, 0);
04617    while ((mem = ao2_iterator_next(&mem_iter))) {
04618       if (!strcasecmp(interface, mem->interface)) {
04619          ao2_iterator_destroy(&mem_iter);
04620          return mem;
04621       }
04622       ao2_ref(mem, -1);
04623    }
04624    ao2_iterator_destroy(&mem_iter);
04625 
04626    return NULL;
04627 }

static int is_our_turn ( struct queue_ent qe  )  [static]

Check if we should start attempting to call queue members.

A simple process, really. Count the number of members who are available to take our call and then see if we are in a position in the queue at which a member could accept our call.

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

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

Referenced by queue_exec(), and wait_our_turn().

03386 {
03387    struct queue_ent *ch;
03388    int res;
03389    int avl;
03390    int idx = 0;
03391    /* This needs a lock. How many members are available to be served? */
03392    ao2_lock(qe->parent);
03393 
03394    avl = num_available_members(qe->parent);
03395 
03396    ch = qe->parent->head;
03397 
03398    ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
03399 
03400    while ((idx < avl) && (ch) && (ch != qe)) {
03401       if (!ch->pending)
03402          idx++;
03403       ch = ch->next;       
03404    }
03405 
03406    ao2_unlock(qe->parent);
03407 
03408    /* If the queue entry is within avl [the number of available members] calls from the top ... */
03409    if (ch && idx < avl) {
03410       ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
03411       res = 1;
03412    } else {
03413       ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
03414       res = 0;
03415    }
03416 
03417    return res;
03418 }

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

Definition at line 2097 of file app_queue.c.

References call_queue::announce, queue_ent::announce, ao2_lock(), ao2_unlock(), ast_copy_string(), ast_debug, ast_log(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, call_queue::context, queue_ent::context, call_queue::count, EVENT_FLAG_CALL, get_member_status(), call_queue::head, insert_entry(), call_queue::joinempty, load_realtime_queue(), LOG_NOTICE, manager_event, queue_ent::max_penalty, call_queue::maxlen, queue_ent::min_penalty, call_queue::moh, queue_ent::moh, call_queue::name, ast_channel::name, queue_ent::next, queue_ent::pos, queue_ent::prio, QUEUE_FULL, QUEUE_JOINEMPTY, QUEUE_UNKNOWN, queues, S_OR, status, and ast_channel::uniqueid.

Referenced by queue_exec().

02098 {
02099    struct call_queue *q;
02100    struct queue_ent *cur, *prev = NULL;
02101    int res = -1;
02102    int pos = 0;
02103    int inserted = 0;
02104 
02105    if (!(q = load_realtime_queue(queuename)))
02106       return res;
02107 
02108    ao2_lock(queues);
02109    ao2_lock(q);
02110 
02111    /* This is our one */
02112    if (q->joinempty) {
02113       int status = 0;
02114       if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) {
02115          *reason = QUEUE_JOINEMPTY;
02116          ao2_unlock(q);
02117          ao2_unlock(queues);
02118          return res;
02119       }
02120    }
02121    if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen))
02122       *reason = QUEUE_FULL;
02123    else if (*reason == QUEUE_UNKNOWN) {
02124       /* There's space for us, put us at the right position inside
02125        * the queue.
02126        * Take into account the priority of the calling user */
02127       inserted = 0;
02128       prev = NULL;
02129       cur = q->head;
02130       while (cur) {
02131          /* We have higher priority than the current user, enter
02132           * before him, after all the other users with priority
02133           * higher or equal to our priority. */
02134          if ((!inserted) && (qe->prio > cur->prio)) {
02135             insert_entry(q, prev, qe, &pos);
02136             inserted = 1;
02137          }
02138          /* <= is necessary for the position comparison because it may not be possible to enter
02139           * at our desired position since higher-priority callers may have taken the position we want
02140           */
02141          if (!inserted && (qe->prio <= cur->prio) && position && (position <= pos + 1)) {
02142             insert_entry(q, prev, qe, &pos);
02143             /*pos is incremented inside insert_entry, so don't need to add 1 here*/
02144             if (position < pos) {
02145                ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
02146             }
02147             inserted = 1;
02148          }
02149          cur->pos = ++pos;
02150          prev = cur;
02151          cur = cur->next;
02152       }
02153       /* No luck, join at the end of the queue */
02154       if (!inserted)
02155          insert_entry(q, prev, qe, &pos);
02156       ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
02157       ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
02158       ast_copy_string(qe->context, q->context, sizeof(qe->context));
02159       q->count++;
02160       res = 0;
02161       manager_event(EVENT_FLAG_CALL, "Join",
02162          "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
02163          qe->chan->name,
02164          S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
02165          S_OR(qe->chan->cid.cid_name, "unknown"),
02166          q->name, qe->pos, q->count, qe->chan->uniqueid );
02167       ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
02168    }
02169    ao2_unlock(q);
02170    ao2_unlock(queues);
02171 
02172    return res;
02173 }

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

Definition at line 6084 of file app_queue.c.

References CMP_MATCH, member::delme, member::dynamic, call_queue::membercount, member::state_interface, and member::status.

Referenced by reload_single_queue().

06085 {
06086    struct member *member = obj;
06087    struct call_queue *q = arg;
06088 
06089    if (!member->delme) {
06090       if (member->dynamic) {
06091          /* dynamic members were not counted toward the member count
06092           * when reloading members from queues.conf, so we do that here
06093           */
06094          q->membercount++;
06095       }
06096       member->status = ast_device_state(member->state_interface);
06097       return 0;
06098    } else {
06099       q->membercount--;
06100       return CMP_MATCH;
06101    }
06102 }

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

Definition at line 6222 of file app_queue.c.

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

Referenced by reload_queues().

06223 {
06224    struct call_queue *q = obj;
06225    char *queuename = arg;
06226    if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
06227       return CMP_MATCH;
06228    } else {
06229       return 0;
06230    }
06231 }

static void leave_queue ( struct queue_ent qe  )  [static]

Caller leaving queue.

Search the queue to find the leaving client, if found remove from queue create manager event, move others up the queue.

Definition at line 2395 of file app_queue.c.

References ao2_lock(), ao2_unlink, ao2_unlock(), ast_debug, ast_free, AST_LIST_REMOVE_HEAD, ast_load_realtime(), ast_variables_destroy(), queue_ent::chan, call_queue::count, call_queue::dead, EVENT_FLAG_CALL, call_queue::head, manager_event, call_queue::name, ast_channel::name, queue_ent::next, queue_ent::parent, pbx_builtin_setvar_helper(), queue_ent::pos, queue_ent::qe_rules, queue_ref(), queue_unref(), queues, call_queue::realtime, SENTINEL, ast_channel::uniqueid, and var.

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

02396 {
02397    struct call_queue *q;
02398    struct queue_ent *current, *prev = NULL;
02399    struct penalty_rule *pr_iter;
02400    int pos = 0;
02401 
02402    if (!(q = qe->parent))
02403       return;
02404    queue_ref(q);
02405    ao2_lock(q);
02406 
02407    prev = NULL;
02408    for (current = q->head; current; current = current->next) {
02409       if (current == qe) {
02410          char posstr[20];
02411          q->count--;
02412 
02413          /* Take us out of the queue */
02414          manager_event(EVENT_FLAG_CALL, "Leave",
02415             "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
02416             qe->chan->name, q->name,  q->count, qe->pos, qe->chan->uniqueid);
02417          ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
02418          /* Take us out of the queue */
02419          if (prev)
02420             prev->next = current->next;
02421          else
02422             q->head = current->next;
02423          /* Free penalty rules */
02424          while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
02425             ast_free(pr_iter);
02426          snprintf(posstr, sizeof(posstr), "%d", qe->pos);
02427          pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
02428       } else {
02429          /* Renumber the people after us in the queue based on a new count */
02430          current->pos = ++pos;
02431          prev = current;
02432       }
02433    }
02434    ao2_unlock(q);
02435 
02436    /*If the queue is a realtime queue, check to see if it's still defined in real time*/
02437    if (q->realtime) {
02438       struct ast_variable *var;
02439       if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
02440          q->dead = 1;
02441       } else {
02442          ast_variables_destroy(var);
02443       }
02444    }
02445 
02446    if (q->dead) { 
02447       /* It's dead and nobody is in it, so kill it */
02448       ao2_unlink(queues, q);
02449    }
02450    /* unref the explicit ref earlier in the function */
02451    queue_unref(q);
02452 }

static int load_module ( void   )  [static]

Definition at line 7500 of file app_queue.c.

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

07501 {
07502    int res;
07503    struct ast_context *con;
07504    struct ast_flags mask = {AST_FLAGS_ALL, };
07505 
07506    queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
07507 
07508    use_weight = 0;
07509 
07510    if (reload_handler(0, &mask, NULL))
07511       return AST_MODULE_LOAD_DECLINE;
07512 
07513    con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
07514    if (!con)
07515       ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n");
07516    else
07517       ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue");
07518 
07519    if (queue_persistent_members)
07520       reload_queue_members();
07521 
07522    ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue));
07523    res = ast_register_application_xml(app, queue_exec);
07524    res |= ast_register_application_xml(app_aqm, aqm_exec);
07525    res |= ast_register_application_xml(app_rqm, rqm_exec);
07526    res |= ast_register_application_xml(app_pqm, pqm_exec);
07527    res |= ast_register_application_xml(app_upqm, upqm_exec);
07528    res |= ast_register_application_xml(app_ql, ql_exec);
07529    res |= ast_manager_register_xml("Queues", 0, manager_queues_show);
07530    res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
07531    res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
07532    res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member);
07533    res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member);
07534    res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member);
07535    res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom);
07536    res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty);
07537    res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
07538    res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
07539    res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
07540    res |= ast_custom_function_register(&queuevar_function);
07541    res |= ast_custom_function_register(&queuemembercount_function);
07542    res |= ast_custom_function_register(&queuemembercount_dep);
07543    res |= ast_custom_function_register(&queuememberlist_function);
07544    res |= ast_custom_function_register(&queuewaitingcount_function);
07545    res |= ast_custom_function_register(&queuememberpenalty_function);
07546 
07547    if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) {
07548       ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
07549    }
07550 
07551    /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
07552    if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) {
07553       res = -1;
07554    }
07555 
07556    ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
07557 
07558    return res ? AST_MODULE_LOAD_DECLINE : 0;
07559 }

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

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

References ao2_find, ao2_lock(), ao2_unlock(), ast_atomic_fetchadd_int(), ast_config_destroy(), ast_load_realtime(), ast_load_realtime_multientry(), ast_log(), ast_variables_destroy(), find_queue_by_name_rt(), LOG_ERROR, call_queue::name, OBJ_POINTER, queues, call_queue::realtime, SENTINEL, update_realtime_members(), and call_queue::weight.

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

01972 {
01973    struct ast_variable *queue_vars;
01974    struct ast_config *member_config = NULL;
01975    struct call_queue *q = NULL, tmpq = {
01976       .name = queuename,   
01977    };
01978    int prev_weight = 0;
01979 
01980    /* Find the queue in the in-core list first. */
01981    q = ao2_find(queues, &tmpq, OBJ_POINTER);
01982 
01983    if (!q || q->realtime) {
01984       /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
01985          queue operations while waiting for the DB.
01986 
01987          This will be two separate database transactions, so we might
01988          see queue parameters as they were before another process
01989          changed the queue and member list as it was after the change.
01990          Thus we might see an empty member list when a queue is
01991          deleted. In practise, this is unlikely to cause a problem. */
01992 
01993       queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
01994       if (queue_vars) {
01995          member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
01996          if (!member_config) {
01997             ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
01998             ast_variables_destroy(queue_vars);
01999             return NULL;
02000          }
02001       }
02002       if (q) {
02003          prev_weight = q->weight ? 1 : 0;
02004       }
02005 
02006       ao2_lock(queues);
02007 
02008       q = find_queue_by_name_rt(queuename, queue_vars, member_config);
02009       if (member_config) {
02010          ast_config_destroy(member_config);
02011       }
02012       if (queue_vars) {
02013          ast_variables_destroy(queue_vars);
02014       }
02015       /* update the use_weight value if the queue's has gained or lost a weight */ 
02016       if (q) {
02017          if (!q->weight && prev_weight) {
02018             ast_atomic_fetchadd_int(&use_weight, -1);
02019          }
02020          if (q->weight && !prev_weight) {
02021             ast_atomic_fetchadd_int(&use_weight, +1);
02022          }
02023       }
02024       /* Other cases will end up with the proper value for use_weight */
02025       ao2_unlock(queues);
02026 
02027    } else {
02028       update_realtime_members(q);
02029    }
02030    return q;
02031 }

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

Definition at line 6746 of file app_queue.c.

References add_to_queue(), ast_queue_log(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.

Referenced by load_module().

06747 {
06748    const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
06749    int paused, penalty = 0;
06750 
06751    queuename = astman_get_header(m, "Queue");
06752    interface = astman_get_header(m, "Interface");
06753    penalty_s = astman_get_header(m, "Penalty");
06754    paused_s = astman_get_header(m, "Paused");
06755    membername = astman_get_header(m, "MemberName");
06756    state_interface = astman_get_header(m, "StateInterface");
06757 
06758    if (ast_strlen_zero(queuename)) {
06759       astman_send_error(s, m, "'Queue' not specified.");
06760       return 0;
06761    }
06762 
06763    if (ast_strlen_zero(interface)) {
06764       astman_send_error(s, m, "'Interface' not specified.");
06765       return 0;
06766    }
06767 
06768    if (ast_strlen_zero(penalty_s))
06769       penalty = 0;
06770    else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0)
06771       penalty = 0;
06772 
06773    if (ast_strlen_zero(paused_s))
06774       paused = 0;
06775    else
06776       paused = abs(ast_true(paused_s));
06777 
06778    switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
06779    case RES_OKAY:
06780       ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
06781       astman_send_ack(s, m, "Added interface to queue");
06782       break;
06783    case RES_EXISTS:
06784       astman_send_error(s, m, "Unable to add interface: Already there");
06785       break;
06786    case RES_NOSUCHQUEUE:
06787       astman_send_error(s, m, "Unable to add interface to queue: No such queue");
06788       break;
06789    case RES_OUTOFMEMORY:
06790       astman_send_error(s, m, "Out of memory");
06791       break;
06792    }
06793 
06794    return 0;
06795 }

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

Definition at line 6831 of file app_queue.c.

References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), and set_member_paused().

Referenced by load_module().

06832 {
06833    const char *queuename, *interface, *paused_s, *reason;
06834    int paused;
06835 
06836    interface = astman_get_header(m, "Interface");
06837    paused_s = astman_get_header(m, "Paused");
06838    queuename = astman_get_header(m, "Queue");      /* Optional - if not supplied, pause the given Interface in all queues */
06839    reason = astman_get_header(m, "Reason");        /* Optional - Only used for logging purposes */
06840 
06841    if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
06842       astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
06843       return 0;
06844    }
06845 
06846    paused = abs(ast_true(paused_s));
06847 
06848    if (set_member_paused(queuename, interface, reason, paused))
06849       astman_send_error(s, m, "Interface not found");
06850    else
06851       astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
06852    return 0;
06853 }

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

Definition at line 6855 of file app_queue.c.

References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and S_OR.

Referenced by load_module().

06856 {
06857    const char *queuename, *event, *message, *interface, *uniqueid;
06858 
06859    queuename = astman_get_header(m, "Queue");
06860    uniqueid = astman_get_header(m, "UniqueId");
06861    interface = astman_get_header(m, "Interface");
06862    event = astman_get_header(m, "Event");
06863    message = astman_get_header(m, "Message");
06864 
06865    if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
06866       astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
06867       return 0;
06868    }
06869 
06870    ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
06871    astman_send_ack(s, m, "Event added successfully");
06872 
06873    return 0;
06874 }

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

Definition at line 6954 of file app_queue.c.

References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and set_member_penalty().

Referenced by load_module().

06955 {
06956    const char *queuename, *interface, *penalty_s;
06957    int penalty;
06958 
06959    interface = astman_get_header(m, "Interface");
06960    penalty_s = astman_get_header(m, "Penalty");
06961    /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
06962    queuename = astman_get_header(m, "Queue");
06963 
06964    if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
06965       astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
06966       return 0;
06967    }
06968  
06969    penalty = atoi(penalty_s);
06970 
06971    if (set_member_penalty((char *)queuename, (char *)interface, penalty))
06972       astman_send_error(s, m, "Invalid interface, queuename or penalty");
06973    else
06974       astman_send_ack(s, m, "Interface penalty set successfully");
06975 
06976    return 0;
06977 }

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

Definition at line 6876 of file app_queue.c.

References AST_FLAGS_ALL, ast_set_flag, astman_get_header(), astman_send_ack(), astman_send_error(), QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, reload_handler(), and S_OR.

Referenced by load_module().

06877 {
06878    struct ast_flags mask = {0,};
06879    const char *queuename = NULL;
06880    int header_found = 0;
06881 
06882    queuename = astman_get_header(m, "Queue");
06883    if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
06884       ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
06885       header_found = 1;
06886    }
06887    if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
06888       ast_set_flag(&mask, QUEUE_RELOAD_RULES);
06889       header_found = 1;
06890    }
06891    if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
06892       ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
06893       header_found = 1;
06894    }
06895 
06896    if (!header_found) {
06897       ast_set_flag(&mask, AST_FLAGS_ALL);
06898    }
06899 
06900    if (!reload_handler(1, &mask, queuename)) {
06901       astman_send_ack(s, m, "Queue reloaded successfully");
06902    } else {
06903       astman_send_error(s, m, "Error encountered while reloading queue");
06904    }
06905    return 0;
06906 }

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

Definition at line 6908 of file app_queue.c.

References astman_get_header(), astman_send_ack(), astman_send_error(), QUEUE_RESET_STATS, and reload_handler().

Referenced by load_module().

06909 {
06910    const char *queuename = NULL;
06911    struct ast_flags mask = {QUEUE_RESET_STATS,};
06912    
06913    queuename = astman_get_header(m, "Queue");
06914 
06915    if (!reload_handler(1, &mask, queuename)) {
06916       astman_send_ack(s, m, "Queue stats reset successfully");
06917    } else {
06918       astman_send_error(s, m, "Error encountered while resetting queue stats");
06919    }
06920    return 0;
06921 }

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

Definition at line 6549 of file app_queue.c.

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

Referenced by load_module().

06550 {
06551    const char *rule = astman_get_header(m, "Rule");
06552    struct rule_list *rl_iter;
06553    struct penalty_rule *pr_iter;
06554 
06555    AST_LIST_LOCK(&rule_lists);
06556    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
06557       if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
06558          astman_append(s, "RuleList: %s\r\n", rl_iter->name);
06559          AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
06560             astman_append(s, "Rule: %d,%s%d,%s%d\r\n", pr_iter->time, pr_iter->max_relative && pr_iter->max_value >= 0 ? "+" : "", pr_iter->max_value, pr_iter->min_relative && pr_iter->min_value >= 0 ? "+" : "", pr_iter->min_value );
06561          }
06562          if (!ast_strlen_zero(rule))
06563             break;
06564       }
06565    }
06566    AST_LIST_UNLOCK(&rule_lists);
06567 
06568    astman_append(s, "\r\n\r\n");
06569 
06570    return RESULT_SUCCESS;
06571 }

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

Definition at line 6539 of file app_queue.c.

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

Referenced by load_module().

06540 {
06541    static const char * const a[] = { "queue", "show" };
06542 
06543    __queues_show(s, -1, 2, a);
06544    astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
06545 
06546    return RESULT_SUCCESS;
06547 }

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

Queue status info via AMI.

Definition at line 6649 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock(), ao2_ref, ao2_unlock(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, call_queue::count, member::dynamic, call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, call_queue::maxlen, member::membername, call_queue::members, ast_channel::name, call_queue::name, queue_ent::next, member::paused, member::penalty, queue_ent::pos, queue_unref(), queues, RESULT_SUCCESS, S_OR, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, call_queue::talktime, ast_channel::uniqueid, and call_queue::weight.

Referenced by load_module().

06650 {
06651    time_t now;
06652    int pos;
06653    const char *id = astman_get_header(m,"ActionID");
06654    const char *queuefilter = astman_get_header(m,"Queue");
06655    const char *memberfilter = astman_get_header(m,"Member");
06656    char idText[256] = "";
06657    struct call_queue *q;
06658    struct queue_ent *qe;
06659    float sl = 0;
06660    struct member *mem;
06661    struct ao2_iterator queue_iter;
06662    struct ao2_iterator mem_iter;
06663 
06664    astman_send_ack(s, m, "Queue status will follow");
06665    time(&now);
06666    if (!ast_strlen_zero(id))
06667       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
06668 
06669    queue_iter = ao2_iterator_init(queues, 0);
06670    while ((q = ao2_iterator_next(&queue_iter))) {
06671       ao2_lock(q);
06672 
06673       /* List queue properties */
06674       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
06675          sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
06676          astman_append(s, "Event: QueueParams\r\n"
06677             "Queue: %s\r\n"
06678             "Max: %d\r\n"
06679             "Strategy: %s\r\n"
06680             "Calls: %d\r\n"
06681             "Holdtime: %d\r\n"
06682             "TalkTime: %d\r\n"
06683             "Completed: %d\r\n"
06684             "Abandoned: %d\r\n"
06685             "ServiceLevel: %d\r\n"
06686             "ServicelevelPerf: %2.1f\r\n"
06687             "Weight: %d\r\n"
06688             "%s"
06689             "\r\n",
06690             q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
06691             q->callsabandoned, q->servicelevel, sl, q->weight, idText);
06692          /* List Queue Members */
06693          mem_iter = ao2_iterator_init(q->members, 0);
06694          while ((mem = ao2_iterator_next(&mem_iter))) {
06695             if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
06696                astman_append(s, "Event: QueueMember\r\n"
06697                   "Queue: %s\r\n"
06698                   "Name: %s\r\n"
06699                   "Location: %s\r\n"
06700                   "Membership: %s\r\n"
06701                   "Penalty: %d\r\n"
06702                   "CallsTaken: %d\r\n"
06703                   "LastCall: %d\r\n"
06704                   "Status: %d\r\n"
06705                   "Paused: %d\r\n"
06706                   "%s"
06707                   "\r\n",
06708                   q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
06709                   mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
06710             }
06711             ao2_ref(mem, -1);
06712          }
06713          ao2_iterator_destroy(&mem_iter);
06714          /* List Queue Entries */
06715          pos = 1;
06716          for (qe = q->head; qe; qe = qe->next) {
06717             astman_append(s, "Event: QueueEntry\r\n"
06718                "Queue: %s\r\n"
06719                "Position: %d\r\n"
06720                "Channel: %s\r\n"
06721                "Uniqueid: %s\r\n"
06722                "CallerIDNum: %s\r\n"
06723                "CallerIDName: %s\r\n"
06724                "Wait: %ld\r\n"
06725                "%s"
06726                "\r\n",
06727                q->name, pos++, qe->chan->name, qe->chan->uniqueid,
06728                S_OR(qe->chan->cid.cid_num, "unknown"),
06729                S_OR(qe->chan->cid.cid_name, "unknown"),
06730                (long) (now - qe->start), idText);
06731          }
06732       }
06733       ao2_unlock(q);
06734       queue_unref(q);
06735    }
06736    ao2_iterator_destroy(&queue_iter);
06737 
06738    astman_append(s,
06739       "Event: QueueStatusComplete\r\n"
06740       "%s"
06741       "\r\n",idText);
06742 
06743    return RESULT_SUCCESS;
06744 }

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

Summary of queue info via the AMI.

Definition at line 6574 of file app_queue.c.

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

Referenced by load_module().

06575 {
06576    time_t now;
06577    int qmemcount = 0;
06578    int qmemavail = 0;
06579    int qchancount = 0;
06580    int qlongestholdtime = 0;
06581    const char *id = astman_get_header(m, "ActionID");
06582    const char *queuefilter = astman_get_header(m, "Queue");
06583    char idText[256] = "";
06584    struct call_queue *q;
06585    struct queue_ent *qe;
06586    struct member *mem;
06587    struct ao2_iterator queue_iter;
06588    struct ao2_iterator mem_iter;
06589 
06590    astman_send_ack(s, m, "Queue summary will follow");
06591    time(&now);
06592    if (!ast_strlen_zero(id))
06593       snprintf(idText, 256, "ActionID: %s\r\n", id);
06594    queue_iter = ao2_iterator_init(queues, 0);
06595    while ((q = ao2_iterator_next(&queue_iter))) {
06596       ao2_lock(q);
06597 
06598       /* List queue properties */
06599       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
06600          /* Reset the necessary local variables if no queuefilter is set*/
06601          qmemcount = 0;
06602          qmemavail = 0;
06603          qchancount = 0;
06604          qlongestholdtime = 0;
06605 
06606          /* List Queue Members */
06607          mem_iter = ao2_iterator_init(q->members, 0);
06608          while ((mem = ao2_iterator_next(&mem_iter))) {
06609             if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
06610                ++qmemcount;
06611                if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) {
06612                   ++qmemavail;
06613                }
06614             }
06615             ao2_ref(mem, -1);
06616          }
06617          ao2_iterator_destroy(&mem_iter);
06618          for (qe = q->head; qe; qe = qe->next) {
06619             if ((now - qe->start) > qlongestholdtime) {
06620                qlongestholdtime = now - qe->start;
06621             }
06622             ++qchancount;
06623          }
06624          astman_append(s, "Event: QueueSummary\r\n"
06625             "Queue: %s\r\n"
06626             "LoggedIn: %d\r\n"
06627             "Available: %d\r\n"
06628             "Callers: %d\r\n" 
06629             "HoldTime: %d\r\n"
06630             "TalkTime: %d\r\n"
06631             "LongestHoldTime: %d\r\n"
06632             "%s"
06633             "\r\n",
06634             q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
06635       }
06636       ao2_unlock(q);
06637       queue_unref(q);
06638    }
06639    ao2_iterator_destroy(&queue_iter);
06640    astman_append(s,
06641       "Event: QueueSummaryComplete\r\n"
06642       "%s"
06643       "\r\n", idText);
06644 
06645    return RESULT_SUCCESS;
06646 }

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

Definition at line 6797 of file app_queue.c.

References ast_queue_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and RES_OUTOFMEMORY.

Referenced by load_module().

06798 {
06799    const char *queuename, *interface;
06800 
06801    queuename = astman_get_header(m, "Queue");
06802    interface = astman_get_header(m, "Interface");
06803 
06804    if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
06805       astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
06806       return 0;
06807    }
06808 
06809    switch (remove_from_queue(queuename, interface)) {
06810    case RES_OKAY:
06811       ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
06812       astman_send_ack(s, m, "Removed interface from queue");
06813       break;
06814    case RES_EXISTS:
06815       astman_send_error(s, m, "Unable to remove interface: Not there");
06816       break;
06817    case RES_NOSUCHQUEUE:
06818       astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
06819       break;
06820    case RES_OUTOFMEMORY:
06821       astman_send_error(s, m, "Out of memory");
06822       break;
06823    case RES_NOT_DYNAMIC:
06824       astman_send_error(s, m, "Member not dynamic");
06825       break;
06826    }
06827 
06828    return 0;
06829 }

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

Definition at line 6211 of file app_queue.c.

References ast_strlen_zero(), call_queue::dead, call_queue::found, call_queue::name, and call_queue::realtime.

Referenced by reload_queues().

06212 {
06213    struct call_queue *q = obj;
06214    char *queuename = arg;
06215    if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
06216       q->dead = 1;
06217       q->found = 0;
06218    }
06219    return 0;
06220 }

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

Definition at line 6075 of file app_queue.c.

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

Referenced by reload_single_queue().

06076 {
06077    struct member *member = obj;
06078    if (!member->dynamic) {
06079       member->delme = 1;
06080    }
06081    return 0;
06082 }

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

Definition at line 1309 of file app_queue.c.

References CMP_MATCH, CMP_STOP, and member::interface.

Referenced by init_queue().

01310 {
01311    struct member *mem1 = obj1, *mem2 = obj2;
01312    return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
01313 }

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

Definition at line 1297 of file app_queue.c.

References compress_char(), and member::interface.

Referenced by init_queue().

01298 {
01299    const struct member *mem = obj;
01300    const char *chname = strchr(mem->interface, '/');
01301    int ret = 0, i;
01302    if (!chname)
01303       chname = mem->interface;
01304    for (i = 0; i < 5 && chname[i]; i++)
01305       ret += compress_char(chname[i]) << (i * 6);
01306    return ret;
01307 }

static int num_available_members ( struct call_queue q  )  [static]

Get the number of members available to accept a call.

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, call_queue::autofill, call_queue::members, member::paused, QUEUE_STRATEGY_RINGALL, call_queue::ringinuse, member::status, and call_queue::strategy.

Referenced by compare_weight(), and is_our_turn().

02484 {
02485    struct member *mem;
02486    int avl = 0;
02487    struct ao2_iterator mem_iter;
02488 
02489    mem_iter = ao2_iterator_init(q->members, 0);
02490    while ((mem = ao2_iterator_next(&mem_iter))) {
02491       switch (mem->status) {
02492       case AST_DEVICE_INUSE:
02493          if (!q->ringinuse)
02494             break;
02495          /* else fall through */
02496       case AST_DEVICE_NOT_INUSE:
02497       case AST_DEVICE_UNKNOWN:
02498          if (!mem->paused) {
02499             avl++;
02500          }
02501          break;
02502       }
02503       ao2_ref(mem, -1);
02504 
02505       /* If autofill is not enabled or if the queue's strategy is ringall, then
02506        * we really don't care about the number of available members so much as we
02507        * do that there is at least one available.
02508        *
02509        * In fact, we purposely will return from this function stating that only
02510        * one member is available if either of those conditions hold. That way,
02511        * functions which determine what action to take based on the number of available
02512        * members will operate properly. The reasoning is that even if multiple
02513        * members are available, only the head caller can actually be serviced.
02514        */
02515       if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
02516          break;
02517       }
02518    }
02519    ao2_iterator_destroy(&mem_iter);
02520 
02521    return avl;
02522 }

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

Definition at line 1487 of file app_queue.c.

References ast_false(), ast_log(), ast_strdupa, ast_true(), LOG_WARNING, QUEUE_EMPTY_INUSE, QUEUE_EMPTY_INVALID, QUEUE_EMPTY_PAUSED, QUEUE_EMPTY_PENALTY, QUEUE_EMPTY_RINGING, QUEUE_EMPTY_UNAVAILABLE, QUEUE_EMPTY_UNKNOWN, QUEUE_EMPTY_WRAPUP, and strsep().

Referenced by queue_set_param().

01488 {
01489    char *value_copy = ast_strdupa(value);
01490    char *option = NULL;
01491    while ((option = strsep(&value_copy, ","))) {
01492       if (!strcasecmp(option, "paused")) {
01493          *empty |= QUEUE_EMPTY_PAUSED;
01494       } else if (!strcasecmp(option, "penalty")) {
01495          *empty |= QUEUE_EMPTY_PENALTY;
01496       } else if (!strcasecmp(option, "inuse")) {
01497          *empty |= QUEUE_EMPTY_INUSE;
01498       } else if (!strcasecmp(option, "ringing")) {
01499          *empty |= QUEUE_EMPTY_RINGING;
01500       } else if (!strcasecmp(option, "invalid")) {
01501          *empty |= QUEUE_EMPTY_INVALID;
01502       } else if (!strcasecmp(option, "wrapup")) {
01503          *empty |= QUEUE_EMPTY_WRAPUP;
01504       } else if (!strcasecmp(option, "unavailable")) {
01505          *empty |= QUEUE_EMPTY_UNAVAILABLE;
01506       } else if (!strcasecmp(option, "unknown")) {
01507          *empty |= QUEUE_EMPTY_UNKNOWN;
01508       } else if (!strcasecmp(option, "loose")) {
01509          *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID);
01510       } else if (!strcasecmp(option, "strict")) {
01511          *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE);
01512       } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
01513          *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED);
01514       } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
01515          *empty = 0;
01516       } else {
01517          ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
01518       }
01519    }
01520 }

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

Definition at line 2175 of file app_queue.c.

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

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

02176 {
02177    int res;
02178 
02179    if (ast_strlen_zero(filename)) {
02180       return 0;
02181    }
02182 
02183    ast_stopstream(chan);
02184 
02185    res = ast_streamfile(chan, filename, chan->language);
02186    if (!res)
02187       res = ast_waitstream(chan, AST_DIGIT_ANY);
02188 
02189    ast_stopstream(chan);
02190 
02191    return res;
02192 }

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

PauseQueueMember application.

Definition at line 5041 of file app_queue.c.

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

Referenced by load_module().

05042 {
05043    char *parse;
05044    AST_DECLARE_APP_ARGS(args,
05045       AST_APP_ARG(queuename);
05046       AST_APP_ARG(interface);
05047       AST_APP_ARG(options);
05048       AST_APP_ARG(reason);
05049    );
05050 
05051    if (ast_strlen_zero(data)) {
05052       ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
05053       return -1;
05054    }
05055 
05056    parse = ast_strdupa(data);
05057 
05058    AST_STANDARD_APP_ARGS(args, parse);
05059 
05060    if (ast_strlen_zero(args.interface)) {
05061       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
05062       return -1;
05063    }
05064 
05065    if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
05066       ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
05067       pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
05068       return 0;
05069    }
05070 
05071    pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
05072 
05073    return 0;
05074 }

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

QueueLog application.

Definition at line 5233 of file app_queue.c.

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

Referenced by load_module().

05234 {
05235    char *parse;
05236 
05237    AST_DECLARE_APP_ARGS(args,
05238       AST_APP_ARG(queuename);
05239       AST_APP_ARG(uniqueid);
05240       AST_APP_ARG(membername);
05241       AST_APP_ARG(event);
05242       AST_APP_ARG(params);
05243    );
05244 
05245    if (ast_strlen_zero(data)) {
05246       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
05247       return -1;
05248    }
05249 
05250    parse = ast_strdupa(data);
05251 
05252    AST_STANDARD_APP_ARGS(args, parse);
05253 
05254    if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
05255        || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
05256       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
05257       return -1;
05258    }
05259 
05260    ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 
05261       "%s", args.params ? args.params : "");
05262 
05263    return 0;
05264 }

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

Definition at line 1033 of file app_queue.c.

References CMP_MATCH, CMP_STOP, and call_queue::name.

Referenced by load_module().

01034 {
01035    struct call_queue *q = obj, *q2 = arg;
01036    return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
01037 }

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

The starting point for all queue calls.

The process involved here is to 1. Parse the options specified in the call to Queue() 2. Join the queue 3. Wait in a loop until it is our turn to try calling a queue member 4. Attempt to call a queue member 5. If 4. did not result in a bridged call, then check for between call options such as periodic announcements etc. 6. Try 4 again unless some condition (such as an expiration time) causes us to exit the queue.

Definition at line 5308 of file app_queue.c.

References call_queue::announcefrequency, AST_APP_ARG, ast_cdr_noanswer(), ast_channel_lock, ast_channel_unlock, AST_CONTROL_RINGING, ast_debug, AST_DECLARE_APP_ARGS, ast_indicate(), AST_LIST_FIRST, ast_log(), ast_moh_start(), ast_moh_stop(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::cdr, queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, copy_rules(), queue_ent::digits, queue_ent::expire, get_member_status(), queue_ent::handled, is_our_turn(), join_queue(), queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::last_pos, queue_ent::last_pos_said, leave_queue(), call_queue::leavewhenempty, LOG_WARNING, queue_ent::max_penalty, call_queue::membercount, queue_ent::min_penalty, queue_ent::moh, call_queue::name, ast_channel::name, queue_ent::opos, queue_ent::parent, parse(), pbx_builtin_getvar_helper(), call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::pr, queue_ent::prio, queue_ent::qe_rules, QUEUE_CONTINUE, QUEUE_LEAVEEMPTY, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), S_OR, say_periodic_announcement(), say_position(), set_queue_result(), set_queue_variables(), queue_ent::start, status, stop, penalty_rule::time, try_calling(), ast_channel::uniqueid, update_qe_rule(), update_realtime_members(), url, queue_ent::valid_digits, wait_a_bit(), and wait_our_turn().

Referenced by load_module().

05309 {
05310    int res=-1;
05311    int ringing=0;
05312    const char *user_priority;
05313    const char *max_penalty_str;
05314    const char *min_penalty_str;
05315    int prio;
05316    int qcontinue = 0;
05317    int max_penalty, min_penalty;
05318    enum queue_result reason = QUEUE_UNKNOWN;
05319    /* whether to exit Queue application after the timeout hits */
05320    int tries = 0;
05321    int noption = 0;
05322    char *parse;
05323    int makeannouncement = 0;
05324    int position = 0;
05325    AST_DECLARE_APP_ARGS(args,
05326       AST_APP_ARG(queuename);
05327       AST_APP_ARG(options);
05328       AST_APP_ARG(url);
05329       AST_APP_ARG(announceoverride);
05330       AST_APP_ARG(queuetimeoutstr);
05331       AST_APP_ARG(agi);
05332       AST_APP_ARG(macro);
05333       AST_APP_ARG(gosub);
05334       AST_APP_ARG(rule);
05335       AST_APP_ARG(position);
05336    );
05337    /* Our queue entry */
05338    struct queue_ent qe;
05339    
05340    if (ast_strlen_zero(data)) {
05341       ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
05342       return -1;
05343    }
05344    
05345    parse = ast_strdupa(data);
05346    AST_STANDARD_APP_ARGS(args, parse);
05347 
05348    /* Setup our queue entry */
05349    memset(&qe, 0, sizeof(qe));
05350    qe.start = time(NULL);
05351 
05352    /* set the expire time based on the supplied timeout; */
05353    if (!ast_strlen_zero(args.queuetimeoutstr))
05354       qe.expire = qe.start + atoi(args.queuetimeoutstr);
05355    else
05356       qe.expire = 0;
05357 
05358    /* Get the priority from the variable ${QUEUE_PRIO} */
05359    ast_channel_lock(chan);
05360    user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
05361    if (user_priority) {
05362       if (sscanf(user_priority, "%30d", &prio) == 1) {
05363          ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio);
05364       } else {
05365          ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
05366             user_priority, chan->name);
05367          prio = 0;
05368       }
05369    } else {
05370       ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
05371       prio = 0;
05372    }
05373 
05374    /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
05375 
05376    if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
05377       if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
05378          ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty);
05379       } else {
05380          ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
05381             max_penalty_str, chan->name);
05382          max_penalty = 0;
05383       }
05384    } else {
05385       max_penalty = 0;
05386    }
05387 
05388    if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
05389       if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
05390          ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty);
05391       } else {
05392          ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
05393             min_penalty_str, chan->name);
05394          min_penalty = 0;
05395       }
05396    } else {
05397       min_penalty = 0;
05398    }
05399    ast_channel_unlock(chan);
05400 
05401    if (args.options && (strchr(args.options, 'r')))
05402       ringing = 1;
05403 
05404    if (args.options && (strchr(args.options, 'c')))
05405       qcontinue = 1;
05406 
05407    if (args.position) {
05408       position = atoi(args.position);
05409       if (position < 0) {
05410          ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
05411          position = 0;
05412       }
05413    }
05414 
05415    ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
05416       args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
05417 
05418    qe.chan = chan;
05419    qe.prio = prio;
05420    qe.max_penalty = max_penalty;
05421    qe.min_penalty = min_penalty;
05422    qe.last_pos_said = 0;
05423    qe.last_pos = 0;
05424    qe.last_periodic_announce_time = time(NULL);
05425    qe.last_periodic_announce_sound = 0;
05426    qe.valid_digits = 0;
05427    if (join_queue(args.queuename, &qe, &reason, position)) {
05428       ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
05429       set_queue_result(chan, reason);
05430       return 0;
05431    }
05432    ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d", S_OR(args.url, ""),
05433       S_OR(chan->cid.cid_num, ""), qe.opos);
05434    copy_rules(&qe, args.rule);
05435    qe.pr = AST_LIST_FIRST(&qe.qe_rules);
05436 check_turns:
05437    if (ringing) {
05438       ast_indicate(chan, AST_CONTROL_RINGING);
05439    } else {
05440       ast_moh_start(chan, qe.moh, NULL);
05441    }
05442 
05443    /* This is the wait loop for callers 2 through maxlen */
05444    res = wait_our_turn(&qe, ringing, &reason);
05445    if (res) {
05446       goto stop;
05447    }
05448 
05449    makeannouncement = 0;
05450 
05451    for (;;) {
05452       /* This is the wait loop for the head caller*/
05453       /* To exit, they may get their call answered; */
05454       /* they may dial a digit from the queue context; */
05455       /* or, they may timeout. */
05456 
05457       /* Leave if we have exceeded our queuetimeout */
05458       if (qe.expire && (time(NULL) >= qe.expire)) {
05459          record_abandoned(&qe);
05460          ast_cdr_noanswer(qe.chan->cdr);
05461          reason = QUEUE_TIMEOUT;
05462          res = 0;
05463          ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 
05464             qe.pos, qe.opos, (long) time(NULL) - qe.start);
05465          break;
05466       }
05467 
05468       if (makeannouncement) {
05469          /* Make a position announcement, if enabled */
05470          if (qe.parent->announcefrequency)
05471             if ((res = say_position(&qe,ringing)))
05472                goto stop;
05473       }
05474       makeannouncement = 1;
05475 
05476       /* Make a periodic announcement, if enabled */
05477       if (qe.parent->periodicannouncefrequency)
05478          if ((res = say_periodic_announcement(&qe,ringing)))
05479             goto stop;
05480    
05481       /* Leave if we have exceeded our queuetimeout */
05482       if (qe.expire && (time(NULL) >= qe.expire)) {
05483          record_abandoned(&qe);
05484          ast_cdr_noanswer(qe.chan->cdr);
05485          reason = QUEUE_TIMEOUT;
05486          res = 0;
05487          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
05488          break;
05489       }
05490 
05491       /* see if we need to move to the next penalty level for this queue */
05492       while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
05493          update_qe_rule(&qe);
05494       }
05495 
05496       /* Try calling all queue members for 'timeout' seconds */
05497       res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
05498       if (res) {
05499          goto stop;
05500       }
05501 
05502       if (qe.parent->leavewhenempty) {
05503          int status = 0;
05504          if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty))) {
05505             record_abandoned(&qe);
05506             ast_cdr_noanswer(qe.chan->cdr);
05507             reason = QUEUE_LEAVEEMPTY;
05508             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
05509             res = 0;
05510             break;
05511          }
05512       }
05513 
05514       /* exit after 'timeout' cycle if 'n' option enabled */
05515       if (noption && tries >= qe.parent->membercount) {
05516          ast_verb(3, "Exiting on time-out cycle\n");
05517          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
05518          record_abandoned(&qe);
05519          ast_cdr_noanswer(qe.chan->cdr);
05520          reason = QUEUE_TIMEOUT;
05521          res = 0;
05522          break;
05523       }
05524 
05525       
05526       /* Leave if we have exceeded our queuetimeout */
05527       if (qe.expire && (time(NULL) >= qe.expire)) {
05528          record_abandoned(&qe);
05529          ast_cdr_noanswer(qe.chan->cdr);
05530          reason = QUEUE_TIMEOUT;
05531          res = 0;
05532          ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start);
05533          break;
05534       }
05535 
05536       /* If using dynamic realtime members, we should regenerate the member list for this queue */
05537       update_realtime_members(qe.parent);
05538       /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
05539       res = wait_a_bit(&qe);
05540       if (res)
05541          goto stop;
05542 
05543       /* Since this is a priority queue and
05544        * it is not sure that we are still at the head
05545        * of the queue, go and check for our turn again.
05546        */
05547       if (!is_our_turn(&qe)) {
05548          ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name);
05549          goto check_turns;
05550       }
05551    }
05552 
05553 stop:
05554    if (res) {
05555       if (res < 0) {
05556          if (!qe.handled) {
05557             record_abandoned(&qe);
05558             ast_cdr_noanswer(qe.chan->cdr);
05559             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
05560                "%d|%d|%ld", qe.pos, qe.opos,
05561                (long) time(NULL) - qe.start);
05562             res = -1;
05563          } else if (qcontinue) {
05564             reason = QUEUE_CONTINUE;
05565             res = 0;
05566          }
05567       } else if (qe.valid_digits) {
05568          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
05569             "%s|%d", qe.digits, qe.pos);
05570       }
05571    }
05572 
05573    /* Don't allow return code > 0 */
05574    if (res >= 0) {
05575       res = 0; 
05576       if (ringing) {
05577          ast_indicate(chan, -1);
05578       } else {
05579          ast_moh_stop(chan);
05580       }        
05581       ast_stopstream(chan);
05582    }
05583 
05584    set_queue_variables(qe.parent, qe.chan);
05585 
05586    leave_queue(&qe);
05587    if (reason != QUEUE_UNKNOWN)
05588       set_queue_result(chan, reason);
05589 
05590    return res;
05591 }

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

Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.

Definition at line 5827 of file app_queue.c.

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

05828 {
05829    int penalty;
05830    AST_DECLARE_APP_ARGS(args,
05831       AST_APP_ARG(queuename);
05832       AST_APP_ARG(interface);
05833    );
05834    /* Make sure the returned value on error is NULL. */
05835    buf[0] = '\0';
05836 
05837    if (ast_strlen_zero(data)) {
05838       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
05839       return -1;
05840    }
05841 
05842    AST_STANDARD_APP_ARGS(args, data);
05843 
05844    if (args.argc < 2) {
05845       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
05846       return -1;
05847    }
05848 
05849    penalty = get_member_penalty (args.queuename, args.interface);
05850    
05851    if (penalty >= 0) /* remember that buf is already '\0' */
05852       snprintf (buf, len, "%d", penalty);
05853 
05854    return 0;
05855 }

static int queue_function_memberpenalty_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
) [static]

Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.

Definition at line 5858 of file app_queue.c.

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

05859 {
05860    int penalty;
05861    AST_DECLARE_APP_ARGS(args,
05862       AST_APP_ARG(queuename);
05863       AST_APP_ARG(interface);
05864    );
05865 
05866    if (ast_strlen_zero(data)) {
05867       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
05868       return -1;
05869    }
05870 
05871    AST_STANDARD_APP_ARGS(args, data);
05872 
05873    if (args.argc < 2) {
05874       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
05875       return -1;
05876    }
05877 
05878    penalty = atoi(value);
05879 
05880    if (ast_strlen_zero(args.interface)) {
05881       ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
05882       return -1;
05883    }
05884 
05885    /* if queuename = NULL then penalty will be set for interface in all the queues. */
05886    if (set_member_penalty(args.queuename, args.interface, penalty)) {
05887       ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
05888       return -1;
05889    }
05890 
05891    return 0;
05892 }

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

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

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

Definition at line 5646 of file app_queue.c.

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

05647 {
05648    int count = 0;
05649    struct member *m;
05650    struct ao2_iterator mem_iter;
05651    struct call_queue *q;
05652    char *option;
05653 
05654    if (ast_strlen_zero(data)) {
05655       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
05656       return -1;
05657    }
05658 
05659    if ((option = strchr(data, ',')))
05660       *option++ = '\0';
05661    else
05662       option = "logged";
05663    if ((q = load_realtime_queue(data))) {
05664       ao2_lock(q);
05665       if (!strcasecmp(option, "logged")) {
05666          mem_iter = ao2_iterator_init(q->members, 0);
05667          while ((m = ao2_iterator_next(&mem_iter))) {
05668             /* Count the agents who are logged in and presently answering calls */
05669             if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
05670                count++;
05671             }
05672             ao2_ref(m, -1);
05673          }
05674          ao2_iterator_destroy(&mem_iter);
05675       } else if (!strcasecmp(option, "free")) {
05676          mem_iter = ao2_iterator_init(q->members, 0);
05677          while ((m = ao2_iterator_next(&mem_iter))) {
05678             /* Count the agents who are logged in and presently answering calls */
05679             if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
05680                count++;
05681             }
05682             ao2_ref(m, -1);
05683          }
05684          ao2_iterator_destroy(&mem_iter);
05685       } else /* must be "count" */
05686          count = q->membercount;
05687       ao2_unlock(q);
05688       queue_unref(q);
05689    } else
05690       ast_log(LOG_WARNING, "queue %s was not found\n", data);
05691 
05692    snprintf(buf, len, "%d", count);
05693 
05694    return 0;
05695 }

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

Get the total number of members in a specific queue (Deprecated).

Return values:
number of members
-1 on error

Definition at line 5702 of file app_queue.c.

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

05703 {
05704    int count = 0;
05705    struct member *m;
05706    struct call_queue *q;
05707    struct ao2_iterator mem_iter;
05708    static int depflag = 1;
05709 
05710    if (depflag) {
05711       depflag = 0;
05712       ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
05713    }
05714 
05715    if (ast_strlen_zero(data)) {
05716       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
05717       return -1;
05718    }
05719    
05720    if ((q = load_realtime_queue(data))) {
05721       ao2_lock(q);
05722       mem_iter = ao2_iterator_init(q->members, 0);
05723       while ((m = ao2_iterator_next(&mem_iter))) {
05724          /* Count the agents who are logged in and presently answering calls */
05725          if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
05726             count++;
05727          }
05728          ao2_ref(m, -1);
05729       }
05730       ao2_iterator_destroy(&mem_iter);
05731       ao2_unlock(q);
05732       queue_unref(q);
05733    } else
05734       ast_log(LOG_WARNING, "queue %s was not found\n", data);
05735 
05736    snprintf(buf, len, "%d", count);
05737 
05738    return 0;
05739 }

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

Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue.

Definition at line 5778 of file app_queue.c.

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

05779 {
05780    struct call_queue *q, tmpq = {
05781       .name = data,  
05782    };
05783    struct member *m;
05784 
05785    /* Ensure an otherwise empty list doesn't return garbage */
05786    buf[0] = '\0';
05787 
05788    if (ast_strlen_zero(data)) {
05789       ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
05790       return -1;
05791    }
05792 
05793    if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
05794       int buflen = 0, count = 0;
05795       struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
05796 
05797       ao2_lock(q);
05798       while ((m = ao2_iterator_next(&mem_iter))) {
05799          /* strcat() is always faster than printf() */
05800          if (count++) {
05801             strncat(buf + buflen, ",", len - buflen - 1);
05802             buflen++;
05803          }
05804          strncat(buf + buflen, m->interface, len - buflen - 1);
05805          buflen += strlen(m->interface);
05806          /* Safeguard against overflow (negative length) */
05807          if (buflen >= len - 2) {
05808             ao2_ref(m, -1);
05809             ast_log(LOG_WARNING, "Truncating list\n");
05810             break;
05811          }
05812          ao2_ref(m, -1);
05813       }
05814       ao2_iterator_destroy(&mem_iter);
05815       ao2_unlock(q);
05816       queue_unref(q);
05817    } else
05818       ast_log(LOG_WARNING, "queue %s was not found\n", data);
05819 
05820    /* We should already be terminated, but let's make sure. */
05821    buf[len - 1] = '\0';
05822 
05823    return 0;
05824 }

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

Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue.

Definition at line 5742 of file app_queue.c.

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

05743 {
05744    int count = 0;
05745    struct call_queue *q, tmpq = {
05746       .name = data,  
05747    };
05748    struct ast_variable *var = NULL;
05749 
05750    buf[0] = '\0';
05751    
05752    if (ast_strlen_zero(data)) {
05753       ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
05754       return -1;
05755    }
05756 
05757    if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
05758       ao2_lock(q);
05759       count = q->count;
05760       ao2_unlock(q);
05761       queue_unref(q);
05762    } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
05763       /* if the queue is realtime but was not found in memory, this
05764        * means that the queue had been deleted from memory since it was 
05765        * "dead." This means it has a 0 waiting count
05766        */
05767       count = 0;
05768       ast_variables_destroy(var);
05769    } else
05770       ast_log(LOG_WARNING, "queue %s was not found\n", data);
05771 
05772    snprintf(buf, len, "%d", count);
05773 
05774    return 0;
05775 }

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

create interface var with all queue details.

Return values:
0 on success
-1 on error

Definition at line 5598 of file app_queue.c.

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

05599 {
05600    int res = -1;
05601    struct call_queue *q, tmpq = {
05602       .name = data,  
05603    };
05604 
05605    char interfacevar[256] = "";
05606    float sl = 0;
05607 
05608    if (ast_strlen_zero(data)) {
05609       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
05610       return -1;
05611    }
05612 
05613    if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
05614       ao2_lock(q);
05615       if (q->setqueuevar) {
05616          sl = 0;
05617          res = 0;
05618 
05619          if (q->callscompleted > 0) {
05620             sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
05621          }
05622 
05623          snprintf(interfacevar, sizeof(interfacevar),
05624             "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
05625             q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned,  q->servicelevel, sl);
05626 
05627          pbx_builtin_setvar_multiple(chan, interfacevar);
05628       }
05629 
05630       ao2_unlock(q);
05631       queue_unref(q);
05632    } else {
05633       ast_log(LOG_WARNING, "queue %s was not found\n", data);
05634    }
05635 
05636    snprintf(buf, len, "%d", res);
05637 
05638    return 0;
05639 }

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

Definition at line 1026 of file app_queue.c.

References ast_str_case_hash(), and call_queue::name.

Referenced by load_module().

01027 {
01028    const struct call_queue *q = obj;
01029 
01030    return ast_str_case_hash(q->name);
01031 }

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

Definition at line 1039 of file app_queue.c.

References ao2_ref.

Referenced by leave_queue(), and try_calling().

01040 {
01041    ao2_ref(q, 1);
01042    return q;
01043 }

static void queue_set_global_params ( struct ast_config cfg  )  [static]

Set the global queue parameters as defined in the "general" section of queues.conf

Definition at line 5979 of file app_queue.c.

References ast_true(), and ast_variable_retrieve().

Referenced by reload_queues().

05980 {
05981    const char *general_val = NULL;
05982    queue_persistent_members = 0;
05983    if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
05984       queue_persistent_members = ast_true(general_val);
05985    autofill_default = 0;
05986    if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
05987       autofill_default = ast_true(general_val);
05988    montype_default = 0;
05989    if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
05990       if (!strcasecmp(general_val, "mixmonitor"))
05991          montype_default = 1;
05992    }
05993    update_cdr = 0;
05994    if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
05995       update_cdr = ast_true(general_val);
05996    shared_lastcall = 0;
05997    if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
05998       shared_lastcall = ast_true(general_val);
05999 }

static void queue_set_param ( struct call_queue q,
const char *  param,
const char *  val,
int  linenum,
int  failunknown 
) [static]

Configure a queue parameter.

The failunknown flag is set for config files (and static realtime) to show errors for unknown parameters. It is cleared for dynamic realtime to allow extra fields in the tables.

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

Definition at line 1530 of file app_queue.c.

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

Referenced by find_queue_by_name_rt(), and reload_single_queue().

01531 {
01532    if (!strcasecmp(param, "musicclass") || 
01533       !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
01534       ast_string_field_set(q, moh, val);
01535    } else if (!strcasecmp(param, "announce")) {
01536       ast_string_field_set(q, announce, val);
01537    } else if (!strcasecmp(param, "context")) {
01538       ast_string_field_set(q, context, val);
01539    } else if (!strcasecmp(param, "timeout")) {
01540       q->timeout = atoi(val);
01541       if (q->timeout < 0)
01542          q->timeout = DEFAULT_TIMEOUT;
01543    } else if (!strcasecmp(param, "ringinuse")) {
01544       q->ringinuse = ast_true(val);
01545    } else if (!strcasecmp(param, "setinterfacevar")) {
01546       q->setinterfacevar = ast_true(val);
01547    } else if (!strcasecmp(param, "setqueuevar")) {
01548       q->setqueuevar = ast_true(val);
01549    } else if (!strcasecmp(param, "setqueueentryvar")) {
01550       q->setqueueentryvar = ast_true(val);
01551    } else if (!strcasecmp(param, "monitor-format")) {
01552       ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
01553    } else if (!strcasecmp(param, "membermacro")) {
01554       ast_string_field_set(q, membermacro, val);
01555    } else if (!strcasecmp(param, "membergosub")) {
01556       ast_string_field_set(q, membergosub, val);
01557    } else if (!strcasecmp(param, "queue-youarenext")) {
01558       ast_string_field_set(q, sound_next, val);
01559    } else if (!strcasecmp(param, "queue-thereare")) {
01560       ast_string_field_set(q, sound_thereare, val);
01561    } else if (!strcasecmp(param, "queue-callswaiting")) {
01562       ast_string_field_set(q, sound_calls, val);
01563    } else if (!strcasecmp(param, "queue-quantity1")) {
01564       ast_string_field_set(q, queue_quantity1, val);
01565    } else if (!strcasecmp(param, "queue-quantity2")) {
01566       ast_string_field_set(q, queue_quantity2, val);
01567    } else if (!strcasecmp(param, "queue-holdtime")) {
01568       ast_string_field_set(q, sound_holdtime, val);
01569    } else if (!strcasecmp(param, "queue-minutes")) {
01570       ast_string_field_set(q, sound_minutes, val);
01571    } else if (!strcasecmp(param, "queue-minute")) {
01572       ast_string_field_set(q, sound_minute, val);
01573    } else if (!strcasecmp(param, "queue-seconds")) {
01574       ast_string_field_set(q, sound_seconds, val);
01575    } else if (!strcasecmp(param, "queue-thankyou")) {
01576       ast_string_field_set(q, sound_thanks, val);
01577    } else if (!strcasecmp(param, "queue-callerannounce")) {
01578       ast_string_field_set(q, sound_callerannounce, val);
01579    } else if (!strcasecmp(param, "queue-reporthold")) {
01580       ast_string_field_set(q, sound_reporthold, val);
01581    } else if (!strcasecmp(param, "announce-frequency")) {
01582       q->announcefrequency = atoi(val);
01583    } else if (!strcasecmp(param, "min-announce-frequency")) {
01584       q->minannouncefrequency = atoi(val);
01585       ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
01586    } else if (!strcasecmp(param, "announce-round-seconds")) {
01587       q->roundingseconds = atoi(val);
01588       /* Rounding to any other values just doesn't make sense... */
01589       if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
01590          || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
01591          if (linenum >= 0) {
01592             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01593                "using 0 instead for queue '%s' at line %d of queues.conf\n",
01594                val, param, q->name, linenum);
01595          } else {
01596             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01597                "using 0 instead for queue '%s'\n", val, param, q->name);
01598          }
01599          q->roundingseconds=0;
01600       }
01601    } else if (!strcasecmp(param, "announce-holdtime")) {
01602       if (!strcasecmp(val, "once"))
01603          q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
01604       else if (ast_true(val))
01605          q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
01606       else
01607          q->announceholdtime = 0;
01608    } else if (!strcasecmp(param, "announce-position")) {
01609       if (!strcasecmp(val, "limit"))
01610          q->announceposition = ANNOUNCEPOSITION_LIMIT;
01611       else if (!strcasecmp(val, "more"))
01612          q->announceposition = ANNOUNCEPOSITION_MORE_THAN;
01613       else if (ast_true(val))
01614          q->announceposition = ANNOUNCEPOSITION_YES;
01615       else
01616          q->announceposition = ANNOUNCEPOSITION_NO;
01617    } else if (!strcasecmp(param, "announce-position-limit")) {
01618       q->announcepositionlimit = atoi(val);
01619    } else if (!strcasecmp(param, "periodic-announce")) {
01620       if (strchr(val, ',')) {
01621          char *s, *buf = ast_strdupa(val);
01622          unsigned int i = 0;
01623 
01624          while ((s = strsep(&buf, ",|"))) {
01625             if (!q->sound_periodicannounce[i])
01626                q->sound_periodicannounce[i] = ast_str_create(16);
01627             ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
01628             i++;
01629             if (i == MAX_PERIODIC_ANNOUNCEMENTS)
01630                break;
01631          }
01632          q->numperiodicannounce = i;
01633       } else {
01634          ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
01635          q->numperiodicannounce = 1;
01636       }
01637    } else if (!strcasecmp(param, "periodic-announce-frequency")) {
01638       q->periodicannouncefrequency = atoi(val);
01639    } else if (!strcasecmp(param, "random-periodic-announce")) {
01640       q->randomperiodicannounce = ast_true(val);
01641    } else if (!strcasecmp(param, "retry")) {
01642       q->retry = atoi(val);
01643       if (q->retry <= 0)
01644          q->retry = DEFAULT_RETRY;
01645    } else if (!strcasecmp(param, "wrapuptime")) {
01646       q->wrapuptime = atoi(val);
01647    } else if (!strcasecmp(param, "autofill")) {
01648       q->autofill = ast_true(val);
01649    } else if (!strcasecmp(param, "monitor-type")) {
01650       if (!strcasecmp(val, "mixmonitor"))
01651          q->montype = 1;
01652    } else if (!strcasecmp(param, "autopause")) {
01653       q->autopause = ast_true(val);
01654    } else if (!strcasecmp(param, "maxlen")) {
01655       q->maxlen = atoi(val);
01656       if (q->maxlen < 0)
01657          q->maxlen = 0;
01658    } else if (!strcasecmp(param, "servicelevel")) {
01659       q->servicelevel= atoi(val);
01660    } else if (!strcasecmp(param, "strategy")) {
01661       int strategy;
01662 
01663       /* We are a static queue and already have set this, no need to do it again */
01664       if (failunknown) {
01665          return;
01666       }
01667       strategy = strat2int(val);
01668       if (strategy < 0) {
01669          ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
01670             val, q->name);
01671          q->strategy = QUEUE_STRATEGY_RINGALL;
01672       }
01673       if (strategy == q->strategy) {
01674          return;
01675       }
01676       if (strategy == QUEUE_STRATEGY_LINEAR) {
01677          ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
01678          return;
01679       }
01680       q->strategy = strategy;
01681    } else if (!strcasecmp(param, "joinempty")) {
01682       parse_empty_options(val, &q->joinempty, 1);
01683    } else if (!strcasecmp(param, "leavewhenempty")) {
01684       parse_empty_options(val, &q->leavewhenempty, 0);
01685    } else if (!strcasecmp(param, "eventmemberstatus")) {
01686       q->maskmemberstatus = !ast_true(val);
01687    } else if (!strcasecmp(param, "eventwhencalled")) {
01688       if (!strcasecmp(val, "vars")) {
01689          q->eventwhencalled = QUEUE_EVENT_VARIABLES;
01690       } else {
01691          q->eventwhencalled = ast_true(val) ? 1 : 0;
01692       }
01693    } else if (!strcasecmp(param, "reportholdtime")) {
01694       q->reportholdtime = ast_true(val);
01695    } else if (!strcasecmp(param, "memberdelay")) {
01696       q->memberdelay = atoi(val);
01697    } else if (!strcasecmp(param, "weight")) {
01698       q->weight = atoi(val);
01699    } else if (!strcasecmp(param, "timeoutrestart")) {
01700       q->timeoutrestart = ast_true(val);
01701    } else if (!strcasecmp(param, "defaultrule")) {
01702       ast_string_field_set(q, defaultrule, val);
01703    } else if (!strcasecmp(param, "timeoutpriority")) {
01704       if (!strcasecmp(val, "conf")) {
01705          q->timeoutpriority = TIMEOUT_PRIORITY_CONF;
01706       } else {
01707          q->timeoutpriority = TIMEOUT_PRIORITY_APP;
01708       }
01709    } else if (failunknown) {
01710       if (linenum >= 0) {
01711          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
01712             q->name, param, linenum);
01713       } else {
01714          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
01715       }
01716    }
01717 }

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

Definition at line 6520 of file app_queue.c.

References __queues_show(), ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, ast_cli_entry::command, complete_queue_show(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

06521 {
06522    switch ( cmd ) {
06523    case CLI_INIT:
06524       e->command = "queue show";
06525       e->usage =
06526          "Usage: queue show\n"
06527          "       Provides summary information on a specified queue.\n";
06528       return NULL;
06529    case CLI_GENERATE:
06530       return complete_queue_show(a->line, a->word, a->pos, a->n); 
06531    }
06532 
06533    return __queues_show(NULL, a->fd, a->argc, a->argv);
06534 }

static void queue_transfer_destroy ( void *  data  )  [static]

Definition at line 3689 of file app_queue.c.

References ast_free.

03690 {
03691    struct queue_transfer_ds *qtds = data;
03692    ast_free(qtds);
03693 }

static void queue_transfer_fixup ( void *  data,
struct ast_channel old_chan,
struct ast_channel new_chan 
) [static]

Log an attended transfer when a queue caller channel is masqueraded.

When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when the actual transfer occurs. This happens during the masquerade after datastores are moved from old_chan to new_chan. This is why new_chan is referenced for exten, context, and datastore information.

At the end of this, we want to remove the datastore so that this fixup function is not called on any future masquerades of the caller during the current call.

Definition at line 3712 of file app_queue.c.

References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_log(), ast_queue_log(), queue_transfer_ds::callcompletedinsl, queue_ent::chan, ast_channel::context, ast_channel::exten, LOG_WARNING, queue_transfer_ds::member, member::membername, call_queue::name, queue_ent::opos, queue_ent::parent, queue_transfer_ds::qe, queue_transfer_info, queue_ent::start, queue_transfer_ds::starttime, ast_channel::uniqueid, and update_queue().

03713 {
03714    struct queue_transfer_ds *qtds = data;
03715    struct queue_ent *qe = qtds->qe;
03716    struct member *member = qtds->member;
03717    time_t callstart = qtds->starttime;
03718    int callcompletedinsl = qtds->callcompletedinsl;
03719    struct ast_datastore *datastore;
03720 
03721    ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
03722             new_chan->exten, new_chan->context, (long) (callstart - qe->start),
03723             (long) (time(NULL) - callstart), qe->opos);
03724 
03725    update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
03726    
03727    /* No need to lock the channels because they are already locked in ast_do_masquerade */
03728    if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
03729       ast_channel_datastore_remove(old_chan, datastore);
03730    } else {
03731       ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
03732    }
03733 }

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

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

Definition at line 2376 of file app_queue.c.

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

Referenced by try_calling().

02377 {
02378    int oldvalue;
02379 
02380    /* Calculate holdtime using an exponential average */
02381    /* Thanks to SRT for this contribution */
02382    /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
02383 
02384    ao2_lock(qe->parent);
02385    oldvalue = qe->parent->holdtime;
02386    qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
02387    ao2_unlock(qe->parent);
02388 }

static void record_abandoned ( struct queue_ent qe  )  [static]

Record that a caller gave up on waiting in queue.

Definition at line 2959 of file app_queue.c.

References ao2_lock(), ao2_unlock(), call_queue::callsabandoned, queue_ent::chan, EVENT_FLAG_AGENT, manager_event, call_queue::name, queue_ent::opos, queue_ent::parent, queue_ent::pos, set_queue_variables(), queue_ent::start, and ast_channel::uniqueid.

Referenced by queue_exec(), and try_calling().

02960 {
02961    ao2_lock(qe->parent);
02962    set_queue_variables(qe->parent, qe->chan);
02963    manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
02964       "Queue: %s\r\n"
02965       "Uniqueid: %s\r\n"
02966       "Position: %d\r\n"
02967       "OriginalPosition: %d\r\n"
02968       "HoldTime: %d\r\n",
02969       qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
02970 
02971    qe->parent->callsabandoned++;
02972    ao2_unlock(qe->parent);
02973 }

static int reload ( void   )  [static]

Definition at line 7561 of file app_queue.c.

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

07562 {
07563    struct ast_flags mask = {AST_FLAGS_ALL,};
07564    ast_unload_realtime("queue_members");
07565    reload_handler(1, &mask, NULL);
07566    return 0;
07567 }

static int reload_handler ( int  reload,
struct ast_flags mask,
const char *  queuename 
) [static]

The command center for all reload operations.

Whenever any piece of queue information is to be reloaded, this function is called. It interprets the flags set in the mask parameter and acts based on how they are set.

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

References ast_test_flag, clear_stats(), QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, QUEUE_RELOAD_RULES, QUEUE_RESET_STATS, reload_queue_rules(), and reload_queues().

Referenced by handle_queue_reload(), handle_queue_reset(), load_module(), manager_queue_reload(), manager_queue_reset(), and reload().

06333 {
06334    int res = 0;
06335 
06336    if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
06337       res |= reload_queue_rules(reload);
06338    }
06339    if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
06340       res |= clear_stats(queuename);
06341    }
06342    if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) {
06343       res |= reload_queues(reload, mask, queuename);
06344    }
06345    return res;
06346 }

static void reload_queue_members ( void   )  [static]

Reload dynamic queue members persisted into the astdb.

Definition at line 4944 of file app_queue.c.

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

Referenced by load_module().

04945 {
04946    char *cur_ptr;
04947    const char *queue_name;
04948    char *member;
04949    char *interface;
04950    char *membername = NULL;
04951    char *state_interface;
04952    char *penalty_tok;
04953    int penalty = 0;
04954    char *paused_tok;
04955    int paused = 0;
04956    struct ast_db_entry *db_tree;
04957    struct ast_db_entry *entry;
04958    struct call_queue *cur_queue;
04959    char queue_data[PM_MAX_LEN];
04960 
04961    ao2_lock(queues);
04962 
04963    /* Each key in 'pm_family' is the name of a queue */
04964    db_tree = ast_db_gettree(pm_family, NULL);
04965    for (entry = db_tree; entry; entry = entry->next) {
04966 
04967       queue_name = entry->key + strlen(pm_family) + 2;
04968 
04969       {
04970          struct call_queue tmpq = {
04971             .name = queue_name,
04972          };
04973          cur_queue = ao2_find(queues, &tmpq, OBJ_POINTER);
04974       }  
04975 
04976       if (!cur_queue)
04977          cur_queue = load_realtime_queue(queue_name);
04978 
04979       if (!cur_queue) {
04980          /* If the queue no longer exists, remove it from the
04981           * database */
04982          ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
04983          ast_db_del(pm_family, queue_name);
04984          continue;
04985       } 
04986 
04987       if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) {
04988          queue_unref(cur_queue);
04989          continue;
04990       }
04991 
04992       cur_ptr = queue_data;
04993       while ((member = strsep(&cur_ptr, ",|"))) {
04994          if (ast_strlen_zero(member))
04995             continue;
04996 
04997          interface = strsep(&member, ";");
04998          penalty_tok = strsep(&member, ";");
04999          paused_tok = strsep(&member, ";");
05000          membername = strsep(&member, ";");
05001          state_interface = strsep(&member, ";");
05002 
05003          if (!penalty_tok) {
05004             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
05005             break;
05006          }
05007          penalty = strtol(penalty_tok, NULL, 10);
05008          if (errno == ERANGE) {
05009             ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
05010             break;
05011          }
05012          
05013          if (!paused_tok) {
05014             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
05015             break;
05016          }
05017          paused = strtol(paused_tok, NULL, 10);
05018          if ((errno == ERANGE) || paused < 0 || paused > 1) {
05019             ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
05020             break;
05021          }
05022 
05023          ast_debug(1, "Reload Members: Queue: %s  Member: %s  Name: %s  Penalty: %d  Paused: %d\n", queue_name, interface, membername, penalty, paused);
05024          
05025          if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
05026             ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
05027             break;
05028          }
05029       }
05030       queue_unref(cur_queue);
05031    }
05032 
05033    ao2_unlock(queues);
05034    if (db_tree) {
05035       ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
05036       ast_db_freetree(db_tree);
05037    }
05038 }

static int reload_queue_rules ( int  reload  )  [static]

Reload the rules defined in queuerules.conf.

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

References ast_calloc, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, insert_penaltychange(), ast_variable::lineno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_variable::name, rule_list::name, ast_variable::next, rule_list::rules, and ast_variable::value.

Referenced by reload_handler().

05932 {
05933    struct ast_config *cfg;
05934    struct rule_list *rl_iter, *new_rl;
05935    struct penalty_rule *pr_iter;
05936    char *rulecat = NULL;
05937    struct ast_variable *rulevar = NULL;
05938    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
05939    
05940    if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
05941       ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
05942       return AST_MODULE_LOAD_SUCCESS;
05943    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
05944       ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
05945       return AST_MODULE_LOAD_SUCCESS;
05946    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
05947       ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format.  Aborting.\n");
05948       return AST_MODULE_LOAD_SUCCESS;
05949    }
05950 
05951    AST_LIST_LOCK(&rule_lists);
05952    while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
05953       while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
05954          ast_free(pr_iter);
05955       ast_free(rl_iter);
05956    }
05957    while ((rulecat = ast_category_browse(cfg, rulecat))) {
05958       if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
05959          AST_LIST_UNLOCK(&rule_lists);
05960          return AST_MODULE_LOAD_FAILURE;
05961       } else {
05962          ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
05963          AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
05964          for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
05965             if(!strcasecmp(rulevar->name, "penaltychange"))
05966                insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
05967             else
05968                ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
05969       }
05970    }
05971    AST_LIST_UNLOCK(&rule_lists);
05972 
05973    ast_config_destroy(cfg);
05974 
05975    return AST_MODULE_LOAD_SUCCESS;
05976 }

static int reload_queues ( int  reload,
struct ast_flags mask,
const char *  queuename 
) [static]

reload the queues.conf file

This function reloads the information in the general section of the queues.conf file and potentially more, depending on the value of mask.

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

References ao2_callback, ao2_lock(), ao2_unlock(), ast_category_browse(), ast_config_destroy(), ast_config_load, ast_log(), ast_strlen_zero(), ast_test_flag, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, kill_dead_queues(), LOG_ERROR, LOG_NOTICE, mark_dead_and_unfound(), OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, QUEUE_RELOAD_PARAMETERS, queue_set_global_params(), queues, and reload_single_queue().

Referenced by reload_handler().

06246 {
06247    struct ast_config *cfg;
06248    char *cat;
06249    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06250    const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
06251 
06252    if (!(cfg = ast_config_load("queues.conf", config_flags))) {
06253       ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
06254       return -1;
06255    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06256       return 0;
06257    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06258       ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format.  Aborting.\n");
06259       return -1;
06260    }
06261 
06262    /* We've made it here, so it looks like we're doing operations on all queues. */
06263    ao2_lock(queues);
06264    
06265    /* Mark all queues as dead for the moment if we're reloading queues.
06266     * For clarity, we could just be reloading members, in which case we don't want to mess
06267     * with the other queue parameters at all*/
06268    if (queue_reload) {
06269       ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename);
06270    }
06271 
06272    /* Chug through config file */
06273    cat = NULL;
06274    while ((cat = ast_category_browse(cfg, cat)) ) {
06275       if (!strcasecmp(cat, "general") && queue_reload) {
06276          queue_set_global_params(cfg);
06277          continue;
06278       }
06279       if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
06280          reload_single_queue(cfg, mask, cat);
06281    }
06282 
06283    ast_config_destroy(cfg);
06284    /* Unref all the dead queues if we were reloading queues */
06285    if (queue_reload) {
06286       ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename);
06287    }
06288    ao2_unlock(queues);
06289    return 0;
06290 }

static void reload_single_member ( const char *  memberdata,
struct call_queue q 
) [static]

reload information pertaining to a single member

This function is called when a member = line is encountered in queues.conf.

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

Definition at line 6009 of file app_queue.c.

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

Referenced by reload_single_queue().

06010 {
06011    char *membername, *interface, *state_interface, *tmp;
06012    char *parse;
06013    struct member *cur, *newm;
06014    struct member tmpmem;
06015    int penalty;
06016    AST_DECLARE_APP_ARGS(args,
06017       AST_APP_ARG(interface);
06018       AST_APP_ARG(penalty);
06019       AST_APP_ARG(membername);
06020       AST_APP_ARG(state_interface);
06021    );
06022 
06023    if (ast_strlen_zero(memberdata)) {
06024       ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
06025       return;
06026    }
06027 
06028    /* Add a new member */
06029    parse = ast_strdupa(memberdata);
06030             
06031    AST_STANDARD_APP_ARGS(args, parse);
06032 
06033    interface = args.interface;
06034    if (!ast_strlen_zero(args.penalty)) {
06035       tmp = args.penalty;
06036       ast_strip(tmp);
06037       penalty = atoi(tmp);
06038       if (penalty < 0) {
06039          penalty = 0;
06040       }
06041    } else {
06042       penalty = 0;
06043    }
06044 
06045    if (!ast_strlen_zero(args.membername)) {
06046       membername = args.membername;
06047       ast_strip(membername);
06048    } else {
06049       membername = interface;
06050    }
06051 
06052    if (!ast_strlen_zero(args.state_interface)) {
06053       state_interface = args.state_interface;
06054       ast_strip(state_interface);
06055    } else {
06056       state_interface = interface;
06057    }
06058 
06059    /* Find the old position in the list */
06060    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
06061    cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
06062    if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) {
06063       ao2_link(q->members, newm);
06064       ao2_ref(newm, -1);
06065    }
06066    newm = NULL;
06067 
06068    if (cur) {
06069       ao2_ref(cur, -1);
06070    } else {
06071       q->membercount++;
06072    }
06073 }

static void reload_single_queue ( struct ast_config cfg,
struct ast_flags mask,
const char *  queuename 
) [static]

Reload information pertaining to a particular queue.

Once we have isolated a queue within reload_queues, we call this. This will either reload information for the queue or if we're just reloading member information, we'll just reload that without touching other settings within the queue

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

References alloc_queue(), ao2_callback, ao2_find, ao2_link, ao2_lock(), ao2_unlock(), ast_atomic_fetchadd_int(), ast_log(), ast_test_flag, ast_variable_browse(), ast_variable_retrieve(), call_queue::found, init_queue(), kill_dead_members(), ast_variable::lineno, LOG_WARNING, mark_member_dead(), call_queue::membercount, call_queue::members, ast_variable::name, call_queue::name, ast_variable::next, OBJ_MULTIPLE, OBJ_NODATA, OBJ_POINTER, OBJ_UNLINK, QUEUE_RELOAD_MEMBER, QUEUE_RELOAD_PARAMETERS, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_unref(), queues, reload_single_member(), strat2int(), call_queue::strategy, ast_variable::value, var, and call_queue::weight.

Referenced by reload_queues().

06116 {
06117    int new;
06118    struct call_queue *q = NULL;
06119    /*We're defining a queue*/
06120    struct call_queue tmpq = {
06121       .name = queuename,
06122    };
06123    const char *tmpvar;
06124    const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
06125    const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
06126    int prev_weight = 0;
06127    struct ast_variable *var;
06128    if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
06129       if (queue_reload) {
06130          /* Make one then */
06131          if (!(q = alloc_queue(queuename))) {
06132             return;
06133          }
06134       } else {
06135          /* Since we're not reloading queues, this means that we found a queue
06136           * in the configuration file which we don't know about yet. Just return.
06137           */
06138          return;
06139       }
06140       new = 1;
06141    } else {
06142       new = 0;
06143    }
06144    
06145    if (!new) {
06146       ao2_lock(q);
06147       prev_weight = q->weight ? 1 : 0;
06148    }
06149    /* Check if we already found a queue with this name in the config file */
06150    if (q->found) {
06151       ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
06152       if (!new) {
06153          /* It should be impossible to *not* hit this case*/
06154          ao2_unlock(q);
06155       }
06156       queue_unref(q);
06157       return;
06158    }
06159    /* Due to the fact that the "linear" strategy will have a different allocation
06160     * scheme for queue members, we must devise the queue's strategy before other initializations.
06161     * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
06162     * container used will have only a single bucket instead of the typical number.
06163     */
06164    if (queue_reload) {
06165       if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
06166          q->strategy = strat2int(tmpvar);
06167          if (q->strategy < 0) {
06168             ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
06169             tmpvar, q->name);
06170             q->strategy = QUEUE_STRATEGY_RINGALL;
06171          }
06172       } else {
06173          q->strategy = QUEUE_STRATEGY_RINGALL;
06174       }
06175       init_queue(q);
06176    }
06177    if (member_reload) {
06178       q->membercount = 0;
06179       ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL);
06180    }
06181    for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
06182       if (member_reload && !strcasecmp(var->name, "member")) {
06183          reload_single_member(var->value, q);
06184       } else if (queue_reload) {
06185          queue_set_param(q, var->name, var->value, var->lineno, 1);
06186       }
06187    }
06188    /* At this point, we've determined if the queue has a weight, so update use_weight
06189     * as appropriate
06190     */
06191    if (!q->weight && prev_weight) {
06192       ast_atomic_fetchadd_int(&use_weight, -1);
06193    }
06194    else if (q->weight && !prev_weight) {
06195       ast_atomic_fetchadd_int(&use_weight, +1);
06196    }
06197 
06198    /* Free remaining members marked as delme */
06199    if (member_reload) {
06200       ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q);
06201    }
06202 
06203    if (new) {
06204       ao2_link(queues, q);
06205    } else {
06206       ao2_unlock(q);
06207    }
06208    queue_unref(q);
06209 }

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

Remove member from queue.

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

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

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

04682 {
04683    struct call_queue *q, tmpq = {
04684       .name = queuename,   
04685    };
04686    struct member *mem, tmpmem;
04687    int res = RES_NOSUCHQUEUE;
04688 
04689    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
04690    if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
04691       ao2_lock(queues);
04692       ao2_lock(q);
04693       if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
04694          /* XXX future changes should beware of this assumption!! */
04695          if (!mem->dynamic) {
04696             ao2_ref(mem, -1);
04697             ao2_unlock(q);
04698             queue_unref(q);
04699             ao2_unlock(queues);
04700             return RES_NOT_DYNAMIC;
04701          }
04702          q->membercount--;
04703          manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
04704             "Queue: %s\r\n"
04705             "Location: %s\r\n"
04706             "MemberName: %s\r\n",
04707             q->name, mem->interface, mem->membername);
04708          ao2_unlink(q->members, mem);
04709          ao2_ref(mem, -1);
04710 
04711          if (queue_persistent_members)
04712             dump_queue_members(q);
04713          
04714          res = RES_OKAY;
04715       } else {
04716          res = RES_EXISTS;
04717       }
04718       ao2_unlock(q);
04719       ao2_unlock(queues);
04720       queue_unref(q);
04721    }
04722 
04723    return res;
04724 }

static int ring_entry ( struct queue_ent qe,
struct callattempt tmp,
int *  busies 
) [static]

Part 2 of ring_one.

Does error checking before attempting to request a channel and call a member. This function is only called from ring_one(). Failure can occur if:

  • Agent on call
  • Agent is paused
  • Wrapup time not expired
  • Priority by another queue

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

Definition at line 2622 of file app_queue.c.

References ast_cdr::accountcode, ast_channel::adsicpe, ast_cdr::amaflags, ast_party_connected_line::ani, ao2_lock(), ao2_unlock(), ast_channel::appl, ast_call(), ast_cdr_busy(), ast_cdr_isset_unanswered(), ast_cdr_setdestchan(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_connected_line_copy_from_caller(), ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, AST_FLAG_ANSWERED_ELSEWHERE, ast_free, ast_party_redirecting_copy(), ast_request(), ast_set_callerid(), ast_set_flag, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_verb, queue_ent::cancel_answered_elsewhere, ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_cdr::channel, CHANNEL_DEADLOCK_AVOIDANCE, ast_channel::cid, ast_callerid::cid_dnid, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_cdr::clid, compare_weight(), ast_channel::connected, ast_channel::context, ast_channel::data, ast_cdr::dcontext, dialcontext, do_hang(), ast_cdr::dst, EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, ast_party_connected_line::id, callattempt::interface, ast_cdr::lastapp, callattempt::lastcall, ast_cdr::lastdata, callattempt::lastqueue, queue_ent::linpos, ast_channel::macroexten, manager_event, callattempt::member, member::membername, ast_channel::name, ast_party_id::name, call_queue::name, ast_channel::nativeformats, ast_party_id::number, ast_party_id::number_presentation, queue_ent::parent, member::paused, pbx_builtin_getvar_helper(), ast_channel::priority, QUEUE_EVENT_VARIABLES, ast_channel::redirecting, call_queue::ringinuse, call_queue::rrpos, S_OR, ast_cdr::src, member::state_interface, member::status, status, callattempt::stillgoing, ast_channel::uniqueid, callattempt::update_connectedline, update_status(), ast_cdr::userfield, vars2manager(), ast_channel::whentohangup, and call_queue::wrapuptime.

Referenced by ring_one().

02623 {
02624    int res;
02625    int status;
02626    char tech[256];
02627    char *location;
02628    const char *macrocontext, *macroexten;
02629 
02630    /* on entry here, we know that tmp->chan == NULL */
02631    if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
02632       (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
02633       ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 
02634             (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
02635       if (qe->chan->cdr)
02636          ast_cdr_busy(qe->chan->cdr);
02637       tmp->stillgoing = 0;
02638       (*busies)++;
02639       return 0;
02640    }
02641 
02642    if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
02643       ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
02644       if (qe->chan->cdr)
02645          ast_cdr_busy(qe->chan->cdr);
02646       tmp->stillgoing = 0;
02647       return 0;
02648    }
02649 
02650    if (tmp->member->paused) {
02651       ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
02652       if (qe->chan->cdr)
02653          ast_cdr_busy(qe->chan->cdr);
02654       tmp->stillgoing = 0;
02655       return 0;
02656    }
02657    if (use_weight && compare_weight(qe->parent,tmp->member)) {
02658       ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
02659       if (qe->chan->cdr)
02660          ast_cdr_busy(qe->chan->cdr);
02661       tmp->stillgoing = 0;
02662       (*busies)++;
02663       return 0;
02664    }
02665 
02666    ast_copy_string(tech, tmp->interface, sizeof(tech));
02667    if ((location = strchr(tech, '/')))
02668       *location++ = '\0';
02669    else
02670       location = "";
02671 
02672    /* Request the peer */
02673    tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
02674    if (!tmp->chan) {       /* If we can't, just go on to the next call */
02675       if (qe->chan->cdr)
02676          ast_cdr_busy(qe->chan->cdr);
02677       tmp->stillgoing = 0; 
02678 
02679       ao2_lock(qe->parent);
02680       update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
02681       qe->parent->rrpos++;
02682       qe->linpos++;
02683       ao2_unlock(qe->parent);
02684 
02685       (*busies)++;
02686       return 0;
02687    }
02688 
02689    ast_channel_lock(tmp->chan);
02690    while (ast_channel_trylock(qe->chan)) {
02691       CHANNEL_DEADLOCK_AVOIDANCE(tmp->chan);
02692    }
02693 
02694    if (qe->cancel_answered_elsewhere) {
02695       ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE);
02696    }
02697    tmp->chan->appl = "AppQueue";
02698    tmp->chan->data = "(Outgoing Line)";
02699    memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
02700 
02701    /* If the new channel has no callerid, try to guess what it should be */
02702    if (ast_strlen_zero(tmp->chan->cid.cid_num)) {
02703       if (!ast_strlen_zero(qe->chan->connected.id.number)) {
02704          ast_set_callerid(tmp->chan, qe->chan->connected.id.number, qe->chan->connected.id.name, qe->chan->connected.ani);
02705          tmp->chan->cid.cid_pres = qe->chan->connected.id.number_presentation;
02706       } else if (!ast_strlen_zero(qe->chan->cid.cid_dnid)) {
02707          ast_set_callerid(tmp->chan, qe->chan->cid.cid_dnid, NULL, NULL);
02708       } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
02709          ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL); 
02710       }
02711       tmp->update_connectedline = 0;
02712    }
02713 
02714    if (tmp->chan->cid.cid_rdnis)
02715       ast_free(tmp->chan->cid.cid_rdnis);
02716    tmp->chan->cid.cid_rdnis = ast_strdup(qe->chan->cid.cid_rdnis);
02717    ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
02718 
02719    tmp->chan->cid.cid_tns = qe->chan->cid.cid_tns;
02720 
02721    ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->cid);
02722 
02723    /* Inherit specially named variables from parent channel */
02724    ast_channel_inherit_variables(qe->chan, tmp->chan);
02725    ast_channel_datastore_inherit(qe->chan, tmp->chan);
02726 
02727    /* Presense of ADSI CPE on outgoing channel follows ours */
02728    tmp->chan->adsicpe = qe->chan->adsicpe;
02729 
02730    /* Inherit context and extension */
02731    macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
02732    ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext);
02733    macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
02734    if (!ast_strlen_zero(macroexten))
02735       ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
02736    else
02737       ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
02738    if (ast_cdr_isset_unanswered()) {
02739       /* they want to see the unanswered dial attempts! */
02740       /* set up the CDR fields on all the CDRs to give sensical information */
02741       ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name);
02742       strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid);
02743       strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel);
02744       strcpy(tmp->chan->cdr->src, qe->chan->cdr->src);
02745       strcpy(tmp->chan->cdr->dst, qe->chan->exten);
02746       strcpy(tmp->chan->cdr->dcontext, qe->chan->context);
02747       strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp);
02748       strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata);
02749       tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags;
02750       strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode);
02751       strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
02752    }
02753 
02754    /* Place the call, but don't wait on the answer */
02755    if ((res = ast_call(tmp->chan, location, 0))) {
02756       /* Again, keep going even if there's an error */
02757       ast_debug(1, "ast call on peer returned %d\n", res);
02758       ast_verb(3, "Couldn't call %s\n", tmp->interface);
02759       ast_channel_unlock(tmp->chan);
02760       ast_channel_unlock(qe->chan);
02761       do_hang(tmp);
02762       (*busies)++;
02763       update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
02764       return 0;
02765    } else if (qe->parent->eventwhencalled) {
02766       char vars[2048];
02767 
02768       manager_event(EVENT_FLAG_AGENT, "AgentCalled",
02769                "Queue: %s\r\n"
02770                "AgentCalled: %s\r\n"
02771                "AgentName: %s\r\n"
02772                "ChannelCalling: %s\r\n"
02773                "DestinationChannel: %s\r\n"
02774                "CallerIDNum: %s\r\n"
02775                "CallerIDName: %s\r\n"
02776                "Context: %s\r\n"
02777                "Extension: %s\r\n"
02778                "Priority: %d\r\n"
02779                "Uniqueid: %s\r\n"
02780                "%s",
02781                qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
02782                tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
02783                tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
02784                qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
02785                qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
02786       ast_verb(3, "Called %s\n", tmp->interface);
02787    }
02788    ast_channel_unlock(tmp->chan);
02789    ast_channel_unlock(qe->chan);
02790 
02791    update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
02792    return 1;
02793 }

static int ring_one ( struct queue_ent qe,
struct callattempt outgoing,
int *  busies 
) [static]

Place a call to a queue member.

Once metrics have been calculated for each member, this function is used to place a call to the appropriate member (or members). The low-level channel-handling and error detection is handled in ring_entry

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

Definition at line 2821 of file app_queue.c.

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

Referenced by try_calling(), and wait_for_answer().

02822 {
02823    int ret = 0;
02824 
02825    while (ret == 0) {
02826       struct callattempt *best = find_best(outgoing);
02827       if (!best) {
02828          ast_debug(1, "Nobody left to try ringing in queue\n");
02829          break;
02830       }
02831       if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
02832          struct callattempt *cur;
02833          /* Ring everyone who shares this best metric (for ringall) */
02834          for (cur = outgoing; cur; cur = cur->q_next) {
02835             if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
02836                ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
02837                ret |= ring_entry(qe, cur, busies);
02838             }
02839          }
02840       } else {
02841          /* Ring just the best channel */
02842          ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
02843          ret = ring_entry(qe, best, busies);
02844       }
02845       
02846       /* If we have timed out, break out */
02847       if (qe->expire && (time(NULL) >= qe->expire)) {
02848          ast_debug(1, "Queue timed out while ringing members.\n");
02849          ret = 0;
02850          break;
02851       }
02852    }
02853 
02854    return ret;
02855 }

static void rna ( int  rnatime,
struct queue_ent qe,
char *  interface,
char *  membername,
int  pause 
) [static]

RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.

Definition at line 2976 of file app_queue.c.

References ast_queue_log(), ast_verb, call_queue::autopause, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::eventwhencalled, manager_event, ast_channel::name, call_queue::name, queue_ent::parent, QUEUE_EVENT_VARIABLES, set_member_paused(), ast_channel::uniqueid, and vars2manager().

Referenced by wait_for_answer().

02977 {
02978    ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
02979    if (qe->parent->eventwhencalled) {
02980       char vars[2048];
02981 
02982       manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
02983                   "Queue: %s\r\n"
02984                   "Uniqueid: %s\r\n"
02985                   "Channel: %s\r\n"
02986                   "Member: %s\r\n"
02987                   "MemberName: %s\r\n"
02988                   "Ringtime: %d\r\n"
02989                   "%s",
02990                   qe->parent->name,
02991                   qe->chan->uniqueid,
02992                   qe->chan->name,
02993                   interface,
02994                   membername,
02995                   rnatime,
02996                   qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
02997    }
02998    ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
02999    if (qe->parent->autopause && pause) {
03000       if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
03001          ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
03002       } else {
03003          ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
03004       }
03005    }
03006    return;
03007 }

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

RemoveQueueMember application.

Definition at line 5113 of file app_queue.c.

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

Referenced by load_module().

05114 {
05115    int res=-1;
05116    char *parse, *temppos = NULL;
05117    AST_DECLARE_APP_ARGS(args,
05118       AST_APP_ARG(queuename);
05119       AST_APP_ARG(interface);
05120       AST_APP_ARG(options);
05121    );
05122 
05123 
05124    if (ast_strlen_zero(data)) {
05125       ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n");
05126       return -1;
05127    }
05128 
05129    parse = ast_strdupa(data);
05130 
05131    AST_STANDARD_APP_ARGS(args, parse);
05132 
05133    if (ast_strlen_zero(args.interface)) {
05134       args.interface = ast_strdupa(chan->name);
05135       temppos = strrchr(args.interface, '-');
05136       if (temppos)
05137          *temppos = '\0';
05138    }
05139 
05140    ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
05141 
05142    switch (remove_from_queue(args.queuename, args.interface)) {
05143    case RES_OKAY:
05144       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
05145       ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
05146       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
05147       res = 0;
05148       break;
05149    case RES_EXISTS:
05150       ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
05151       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
05152       res = 0;
05153       break;
05154    case RES_NOSUCHQUEUE:
05155       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
05156       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
05157       res = 0;
05158       break;
05159    case RES_NOT_DYNAMIC:
05160       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
05161       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
05162       res = 0;
05163       break;
05164    }
05165 
05166    return res;
05167 }

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

Find rt member record to update otherwise create one.

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

Definition at line 1725 of file app_queue.c.

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

Referenced by find_queue_by_name_rt(), and update_realtime_members().

01726 {
01727    struct member *m;
01728    struct ao2_iterator mem_iter;
01729    int penalty = 0;
01730    int paused  = 0;
01731    int found = 0;
01732 
01733    if (penalty_str) {
01734       penalty = atoi(penalty_str);
01735       if (penalty < 0)
01736          penalty = 0;
01737    }
01738 
01739    if (paused_str) {
01740       paused = atoi(paused_str);
01741       if (paused < 0)
01742          paused = 0;
01743    }
01744 
01745    /* Find member by realtime uniqueid and update */
01746    mem_iter = ao2_iterator_init(q->members, 0);
01747    while ((m = ao2_iterator_next(&mem_iter))) {
01748       if (!strcasecmp(m->rt_