Wed Oct 28 11:45:46 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 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  interfaces
struct  member
struct  member_interface
struct  penalty_rule
struct  queue_end_bridge
struct  queue_ent
struct  queue_transfer_ds
struct  rule_list
struct  rule_lists
struct  statechange
struct  strategy

Defines

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

Enumerations

enum  {
  QUEUE_STRATEGY_RINGALL = 0, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_RANDOM,
  QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_LINEAR, QUEUE_STRATEGY_WRANDOM
}
enum  agent_complete_reason { CALLER, AGENT, TRANSFER }
enum  queue_member_status { QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, QUEUE_NORMAL }
enum  queue_result {
  QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, QUEUE_JOINEMPTY = 2, QUEUE_LEAVEEMPTY = 3,
  QUEUE_JOINUNAVAIL = 4, QUEUE_LEAVEUNAVAIL = 5, QUEUE_FULL = 6, QUEUE_CONTINUE = 7
}

Functions

static char * __queues_show (struct mansession *s, int fd, int argc, char **argv)
 Show queue(s) status and statistics.
static void __reg_module (void)
static void __unreg_module (void)
static int add_to_interfaces (const char *interface)
static int add_to_queue (const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
 Add member to queue.
static struct call_queuealloc_queue (const char *queuename)
static int aqm_exec (struct ast_channel *chan, void *data)
 AddQueueMember application.
static int attended_transfer_occurred (struct ast_channel *chan)
 mechanism to tell if a queue caller was atxferred by a queue member.
static int calc_metric (struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
 Calculate the metric of each member in the outgoing callattempts.
static void clear_and_free_interfaces (void)
static void clear_queue (struct call_queue *q)
static int compare_weight (struct call_queue *rq, struct member *member)
static char * complete_queue (const char *line, const char *word, int pos, int state)
static char * complete_queue_add_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_pause_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_remove_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_rule_show (const char *line, const char *word, int pos, int state)
static char * complete_queue_set_member_penalty (const char *line, const char *word, int pos, int state)
static char * complete_queue_show (const char *line, const char *word, int pos, int state)
static int compress_char (const char c)
static void copy_rules (struct queue_ent *qe, const char *rulename)
 Copy rule from global list into specified queue.
static struct 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 * device_state_thread (void *data)
 Consumer of the statechange queue.
static void do_hang (struct callattempt *o)
 common hangup actions
static void do_print (struct mansession *s, int fd, const char *str)
 direct ouput to manager or cli with proper terminator
static void dump_queue_members (struct call_queue *pm_queue)
 Dump all members in a specific queue to the database.
static void end_bridge_callback (void *data)
static void end_bridge_callback_data_fixup (struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
static struct 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 enum queue_member_status get_member_status (struct call_queue *q, int max_penalty, int min_penalty)
 Check if members are available.
static char * handle_queue_add_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_pause_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_remove_member (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_rule_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_rule_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_queue_set_member_penalty (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void * handle_statechange (struct statechange *sc)
 set a member's status based on device state of that member's interface
static void hangupcalls (struct callattempt *outgoing, struct ast_channel *exception)
 Hang up a list of outgoing calls.
static void init_queue (struct call_queue *q)
 Initialize Queue default values.
static void insert_entry (struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
 Insert the 'new' entry after the 'prev' entry of queue 'q'.
static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
 Change queue penalty by adding rule.
static char * int2strat (int strategy)
static struct memberinterface_exists (struct call_queue *q, const char *interface)
static int interface_exists_global (const char *interface, int lock_queue_container)
static int is_our_turn (struct queue_ent *qe)
 Check if we should start attempting to call queue members.
static int join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason, const char *overriding_rule)
static void leave_queue (struct queue_ent *qe)
 Caller leaving queue.
static int load_module (void)
static struct call_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_rule_show (struct mansession *s, const struct message *m)
static int manager_queues_show (struct mansession *s, const struct message *m)
static int manager_queues_status (struct mansession *s, const struct message *m)
 Queue status info via AMI.
static int manager_queues_summary (struct mansession *s, const struct message *m)
 Summary of queue info via the AMI.
static int manager_remove_queue_member (struct mansession *s, const struct message *m)
static int member_cmp_fn (void *obj1, void *obj2, int flags)
static int member_hash_fn (const void *obj, const int flags)
static int num_available_members (struct call_queue *q)
 Get the number of members available to accept a call.
static int play_file (struct ast_channel *chan, const char *filename)
static int pqm_exec (struct ast_channel *chan, void *data)
 PauseQueueMember application.
static int ql_exec (struct ast_channel *chan, void *data)
 QueueLog application.
static int queue_cmp_cb (void *obj, void *arg, int flags)
static int queue_exec (struct ast_channel *chan, void *data)
 The starting point for all queue calls.
static int queue_function_memberpenalty_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.
static int queue_function_memberpenalty_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.
static int queue_function_qac (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Get number either busy / free or total members of a specific queue.
static int queue_function_qac_dep (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Get the total number of members in a specific queue (Deprecated).
static int queue_function_queuememberlist (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue.
static int queue_function_queuewaitingcount (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue.
static int queue_function_var (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 create interface var with all queue details.
static int queue_hash_cb (const void *obj, const int flags)
static struct call_queuequeue_ref (struct call_queue *q)
static void queue_set_param (struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
 Configure a queue parameter.
static char * queue_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void queue_transfer_destroy (void *data)
static void queue_transfer_fixup (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
 Log an attended transfer when a queue caller channel is masqueraded.
static struct call_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 void reload_queue_members (void)
 Reload dynamic queue members persisted into the astdb.
static int reload_queue_rules (int reload)
static int reload_queues (int reload)
static int remove_from_interfaces (const char *interface, int lock_queue_container)
static int remove_from_queue (const char *queuename, const char *interface)
 Remove member from queue.
static int ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies)
 Part 2 of ring_one.
static int ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies)
 Place a call to a queue member.
static void rna (int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause)
 RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.
static int rqm_exec (struct ast_channel *chan, void *data)
 RemoveQueueMember application.
static void rt_handle_member_record (struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface)
 Find rt member record to update otherwise create one.
static int say_periodic_announcement (struct queue_ent *qe, int ringing)
 Playback announcement to queued members if peroid has elapsed.
static int say_position (struct queue_ent *qe, int ringing)
static void send_agent_complete (const struct queue_ent *qe, const char *queuename, const struct ast_channel *peer, const struct member *member, time_t callstart, char *vars, size_t vars_len, enum agent_complete_reason rsn)
 Send out AMI message with member call completion status information.
static int set_member_paused (const char *queuename, const char *interface, const char *reason, int paused)
static int set_member_penalty (char *queuename, char *interface, int penalty)
static void set_queue_result (struct ast_channel *chan, enum queue_result res)
 sets the QUEUESTATUS channel variable
static void set_queue_variables (struct call_queue *q, struct ast_channel *chan)
 Set variables of queue.
static struct ast_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 statechange_queue (const char *dev, enum ast_device_state state)
 Producer of the statechange queue.
static int store_next_lin (struct queue_ent *qe, struct callattempt *outgoing)
 Search for best metric and add to Linear queue.
static int store_next_rr (struct queue_ent *qe, struct callattempt *outgoing)
 Search for best metric and add to Round Robbin queue.
static int strat2int (const char *strategy)
static int try_calling (struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
 A large function which calls members, updates statistics, and bridges the caller and a member.
static int unload_module (void)
static void update_qe_rule (struct queue_ent *qe)
 update rules for queues
static int update_queue (struct call_queue *q, struct member *member, int callcompletedinsl)
 update the queue status
static int update_realtime_member_field (struct member *mem, const char *queue_name, const char *field, const char *value)
static void update_realtime_members (struct call_queue *q)
static int update_status (const char *interface, const int status)
 set a member's status based on device state of that member's state_interface.
static int upqm_exec (struct ast_channel *chan, void *data)
 UnPauseQueueMember application.
static int valid_exit (struct queue_ent *qe, char digit)
 Check for valid exit from queue via goto.
static char * vars2manager (struct ast_channel *chan, char *vars, size_t len)
 convert "\n" to "\nVariable: " ready for manager to use
static int wait_a_bit (struct queue_ent *qe)
static struct callattemptwait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
 Wait for a member to answer the call.
static int wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason)
 The waiting areas for callers who are not actively calling members.

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static char * app = "Queue"
static char * app_aqm = "AddQueueMember"
static char * app_aqm_descrip
static char * app_aqm_synopsis = "Dynamically adds queue members"
static char * app_pqm = "PauseQueueMember"
static char * app_pqm_descrip
static char * app_pqm_synopsis = "Pauses a queue member"
static char * app_ql = "QueueLog"
static char * app_ql_descrip
static char * app_ql_synopsis = "Writes to the queue_log"
static char * app_rqm = "RemoveQueueMember"
static char * app_rqm_descrip
static char * app_rqm_synopsis = "Dynamically removes queue members"
static char * app_upqm = "UnpauseQueueMember"
static char * app_upqm_descrip
static char * app_upqm_synopsis = "Unpauses a queue member"
static const struct
ast_module_info
ast_module_info = &__mod_info
static int autofill_default = 0
 queues.conf [general] option
static struct ast_cli_entry cli_queue []
static char * descrip
struct {
   ast_cond_t   cond
   ast_mutex_t   lock
   struct {
      struct statechange *   first
      struct statechange *   last
   }   state_change_q
   unsigned int   stop:1
   pthread_t   thread
device_state
 Data used by the device state thread.
static struct ast_event_subdevice_state_sub
 Subscription to device state change events.
static int montype_default = 0
 queues.conf [general] option
static const char * pm_family = "Queue/PersistentMembers"
 Persistent Members astdb family.
static const char qpm_cmd_usage []
static const char qsmp_cmd_usage []
static int queue_keep_stats = 0
 queues.conf [general] option
static int queue_persistent_members = 0
 queues.conf [general] option
struct {
   enum queue_result   id
   char *   text
queue_results []
static struct ast_datastore_info queue_transfer_info
 a datastore used to help correctly log attended transfers of queue callers
static struct ast_custom_function queuemembercount_dep
static struct ast_custom_function queuemembercount_function
static struct ast_custom_function queuememberlist_function
static struct ast_custom_function queuememberpenalty_function
static struct ao2_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 char * synopsis = "Queue a call for a call queue"
static int update_cdr = 0
 queues.conf [general] option
static int use_weight = 0
 queues.conf per-queue weight option


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

Referenced by queue_set_param().

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 411 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

#define AST_MAX_WATCHERS   256

Definition at line 2550 of file app_queue.c.

#define DEFAULT_MIN_ANNOUNCE_FREQUENCY   15

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

Definition at line 140 of file app_queue.c.

Referenced by init_queue().

#define DEFAULT_RETRY   5

Definition at line 136 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

#define DEFAULT_TIMEOUT   15

Definition at line 137 of file app_queue.c.

Referenced by queue_set_param().

#define MAX_PERIODIC_ANNOUNCEMENTS   10

The maximum periodic announcements we can have

Definition at line 139 of file app_queue.c.

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

#define MAX_QUEUE_BUCKETS   53

Definition at line 142 of file app_queue.c.

Referenced by load_module().

#define PM_MAX_LEN   8192

Definition at line 278 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

#define QUEUE_EMPTY_LOOSE   3

Definition at line 409 of file app_queue.c.

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

#define QUEUE_EMPTY_NORMAL   1

Definition at line 407 of file app_queue.c.

Referenced by queue_set_param().

#define QUEUE_EMPTY_STRICT   2

Definition at line 408 of file app_queue.c.

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

#define QUEUE_EVENT_VARIABLES   3

Definition at line 412 of file app_queue.c.

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

#define RECHECK   1

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

Definition at line 138 of file app_queue.c.

Referenced by wait_our_turn().

#define RES_EXISTS   (-1)

#define RES_NOSUCHQUEUE   (-3)

#define RES_NOT_DYNAMIC   (-4)

Member is not dynamic

Definition at line 148 of file app_queue.c.

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

#define RES_OKAY   0

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

Enumerator:
CALLER 
AGENT 
TRANSFER 

Definition at line 3115 of file app_queue.c.

03115                            {
03116    CALLER,
03117    AGENT,
03118    TRANSFER
03119 };

Enumerator:
QUEUE_NO_MEMBERS 
QUEUE_NO_REACHABLE_MEMBERS 
QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS 
QUEUE_NORMAL 

Definition at line 634 of file app_queue.c.

Enumerator:
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 
QUEUE_CONTINUE 

Definition at line 304 of file app_queue.c.

00304                   {
00305    QUEUE_UNKNOWN = 0,
00306    QUEUE_TIMEOUT = 1,
00307    QUEUE_JOINEMPTY = 2,
00308    QUEUE_LEAVEEMPTY = 3,
00309    QUEUE_JOINUNAVAIL = 4,
00310    QUEUE_LEAVEUNAVAIL = 5,
00311    QUEUE_FULL = 6,
00312    QUEUE_CONTINUE = 7,
00313 };


Function Documentation

static char* __queues_show ( struct mansession s,
int  fd,
int  argc,
char **  argv 
) [static]

Show queue(s) status and statistics.

List the queues strategy, calls processed, members logged in, other queue statistics such as avg hold time.

Definition at line 5696 of file app_queue.c.

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

Referenced by manager_queues_show(), and queue_show().

05697 {
05698    struct call_queue *q;
05699    struct ast_str *out = ast_str_alloca(240);
05700    int found = 0;
05701    time_t now = time(NULL);
05702    struct ao2_iterator queue_iter;
05703    struct ao2_iterator mem_iter;
05704 
05705    if (argc != 2 && argc != 3)
05706       return CLI_SHOWUSAGE;
05707 
05708    if (argc == 3) { /* specific queue */
05709       if ((q = load_realtime_queue(argv[2]))) {
05710          queue_unref(q);
05711       }
05712    } else if (ast_check_realtime("queues")) {
05713       /* This block is to find any queues which are defined in realtime but
05714        * which have not yet been added to the in-core container
05715        */
05716       struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", (char *) NULL);
05717       char *queuename;
05718       if (cfg) {
05719          for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
05720             if ((q = load_realtime_queue(queuename))) {
05721                queue_unref(q);
05722             }
05723          }
05724          ast_config_destroy(cfg);
05725       }
05726    }
05727 
05728    queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
05729    ao2_lock(queues);
05730    while ((q = ao2_iterator_next(&queue_iter))) {
05731       float sl;
05732       struct call_queue *realtime_queue = NULL;
05733 
05734       ao2_lock(q);
05735       /* This check is to make sure we don't print information for realtime
05736        * queues which have been deleted from realtime but which have not yet
05737        * been deleted from the in-core container
05738        */
05739       if (q->realtime && !(realtime_queue = load_realtime_queue(q->name))) {
05740          ao2_unlock(q);
05741          queue_unref(q);
05742          continue;
05743       } else if (q->realtime) {
05744          queue_unref(realtime_queue);
05745       }
05746       if (argc == 3 && strcasecmp(q->name, argv[2])) {
05747          ao2_unlock(q);
05748          queue_unref(q);
05749          continue;
05750       }
05751       found = 1;
05752 
05753       ast_str_set(&out, 0, "%-12.12s has %d calls (max ", q->name, q->count);
05754       if (q->maxlen)
05755          ast_str_append(&out, 0, "%d", q->maxlen);
05756       else
05757          ast_str_append(&out, 0, "unlimited");
05758       sl = 0;
05759       if (q->callscompleted > 0)
05760          sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
05761       ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
05762          int2strat(q->strategy), q->holdtime, q->weight,
05763          q->callscompleted, q->callsabandoned,sl,q->servicelevel);
05764       do_print(s, fd, out->str);
05765       if (!ao2_container_count(q->members))
05766          do_print(s, fd, "   No Members");
05767       else {
05768          struct member *mem;
05769 
05770          do_print(s, fd, "   Members: ");
05771          mem_iter = ao2_iterator_init(q->members, 0);
05772          while ((mem = ao2_iterator_next(&mem_iter))) {
05773             ast_str_set(&out, 0, "      %s", mem->membername);
05774             if (strcasecmp(mem->membername, mem->interface)) {
05775                ast_str_append(&out, 0, " (%s)", mem->interface);
05776             }
05777             if (mem->penalty)
05778                ast_str_append(&out, 0, " with penalty %d", mem->penalty);
05779             ast_str_append(&out, 0, "%s%s%s (%s)",
05780                mem->dynamic ? " (dynamic)" : "",
05781                mem->realtime ? " (realtime)" : "",
05782                mem->paused ? " (paused)" : "",
05783                devstate2str(mem->status));
05784             if (mem->calls)
05785                ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
05786                   mem->calls, (long) (time(NULL) - mem->lastcall));
05787             else
05788                ast_str_append(&out, 0, " has taken no calls yet");
05789             do_print(s, fd, out->str);
05790             ao2_ref(mem, -1);
05791          }
05792          ao2_iterator_destroy(&mem_iter);
05793       }
05794       if (!q->head)
05795          do_print(s, fd, "   No Callers");
05796       else {
05797          struct queue_ent *qe;
05798          int pos = 1;
05799 
05800          do_print(s, fd, "   Callers: ");
05801          for (qe = q->head; qe; qe = qe->next) {
05802             ast_str_set(&out, 0, "      %d. %s (wait: %ld:%2.2ld, prio: %d)",
05803                pos++, qe->chan->name, (long) (now - qe->start) / 60,
05804                (long) (now - qe->start) % 60, qe->prio);
05805             do_print(s, fd, out->str);
05806          }
05807       }
05808       do_print(s, fd, ""); /* blank line between entries */
05809       ao2_unlock(q);
05810       queue_unref(q); /* Unref the iterator's reference */
05811    }
05812    ao2_iterator_destroy(&queue_iter);
05813    ao2_unlock(queues);
05814    if (!found) {
05815       if (argc == 3)
05816          ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
05817       else
05818          ast_str_set(&out, 0, "No queues.");
05819       do_print(s, fd, out->str);
05820    }
05821    return CLI_SUCCESS;
05822 }

static void __reg_module ( void   )  [static]

Definition at line 6767 of file app_queue.c.

static void __unreg_module ( void   )  [static]

Definition at line 6767 of file app_queue.c.

static int add_to_interfaces ( const char *  interface  )  [static]

Definition at line 995 of file app_queue.c.

References ast_calloc, ast_copy_string(), ast_debug, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and member_interface::interface.

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

00996 {
00997    struct member_interface *curint;
00998 
00999    AST_LIST_LOCK(&interfaces);
01000    AST_LIST_TRAVERSE(&interfaces, curint, list) {
01001       if (!strcasecmp(curint->interface, interface))
01002          break;
01003    }
01004 
01005    if (curint) {
01006       AST_LIST_UNLOCK(&interfaces);
01007       return 0;
01008    }
01009 
01010    ast_debug(1, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
01011    
01012    if ((curint = ast_calloc(1, sizeof(*curint)))) {
01013       ast_copy_string(curint->interface, interface, sizeof(curint->interface));
01014       AST_LIST_INSERT_HEAD(&interfaces, curint, list);
01015    }
01016    AST_LIST_UNLOCK(&interfaces);
01017 
01018    return 0;
01019 }

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

Add member to queue.

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

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

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

04171 {
04172    struct call_queue *q;
04173    struct member *new_member, *old_member;
04174    int res = RES_NOSUCHQUEUE;
04175 
04176    /*! \note Ensure the appropriate realtime queue is loaded.  Note that this
04177     * short-circuits if the queue is already in memory. */
04178    if (!(q = load_realtime_queue(queuename)))
04179       return res;
04180 
04181    ao2_lock(queues);
04182 
04183    ao2_lock(q);
04184    if ((old_member = interface_exists(q, interface)) == NULL) {
04185       if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
04186          add_to_interfaces(new_member->state_interface);
04187          new_member->dynamic = 1;
04188          ao2_link(q->members, new_member);
04189          q->membercount++;
04190          manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
04191             "Queue: %s\r\n"
04192             "Location: %s\r\n"
04193             "MemberName: %s\r\n"
04194             "Membership: %s\r\n"
04195             "Penalty: %d\r\n"
04196             "CallsTaken: %d\r\n"
04197             "LastCall: %d\r\n"
04198             "Status: %d\r\n"
04199             "Paused: %d\r\n",
04200             q->name, new_member->interface, new_member->membername,
04201             "dynamic",
04202             new_member->penalty, new_member->calls, (int) new_member->lastcall,
04203             new_member->status, new_member->paused);
04204          
04205          ao2_ref(new_member, -1);
04206          new_member = NULL;
04207 
04208          if (dump)
04209             dump_queue_members(q);
04210          
04211          res = RES_OKAY;
04212       } else {
04213          res = RES_OUTOFMEMORY;
04214       }
04215    } else {
04216       ao2_ref(old_member, -1);
04217       res = RES_EXISTS;
04218    }
04219    ao2_unlock(q);
04220    ao2_unlock(queues);
04221 
04222    return res;
04223 }

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

Definition at line 1439 of file app_queue.c.

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

Referenced by find_queue_by_name_rt(), and reload_queues().

01440 {
01441    struct call_queue *q;
01442 
01443    if ((q = ao2_alloc(sizeof(*q), destroy_queue))) {
01444       if (ast_string_field_init(q, 64)) {
01445          ao2_ref(q, -1);
01446          return NULL;
01447       }
01448       ast_string_field_set(q, name, queuename);
01449    }
01450    return q;
01451 }

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

AddQueueMember application.

Definition at line 4600 of file app_queue.c.

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

Referenced by load_module().

04601 {
04602    int res=-1;
04603    char *parse, *temppos = NULL;
04604    AST_DECLARE_APP_ARGS(args,
04605       AST_APP_ARG(queuename);
04606       AST_APP_ARG(interface);
04607       AST_APP_ARG(penalty);
04608       AST_APP_ARG(options);
04609       AST_APP_ARG(membername);
04610       AST_APP_ARG(state_interface);
04611    );
04612    int penalty = 0;
04613 
04614    if (ast_strlen_zero(data)) {
04615       ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n");
04616       return -1;
04617    }
04618 
04619    parse = ast_strdupa(data);
04620 
04621    AST_STANDARD_APP_ARGS(args, parse);
04622 
04623    if (ast_strlen_zero(args.interface)) {
04624       args.interface = ast_strdupa(chan->name);
04625       temppos = strrchr(args.interface, '-');
04626       if (temppos)
04627          *temppos = '\0';
04628    }
04629 
04630    if (!ast_strlen_zero(args.penalty)) {
04631       if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
04632          ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
04633          penalty = 0;
04634       }
04635    }
04636 
04637    switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
04638    case RES_OKAY:
04639       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
04640       ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
04641       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
04642       res = 0;
04643       break;
04644    case RES_EXISTS:
04645       ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
04646       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
04647       res = 0;
04648       break;
04649    case RES_NOSUCHQUEUE:
04650       ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
04651       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
04652       res = 0;
04653       break;
04654    case RES_OUTOFMEMORY:
04655       ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
04656       break;
04657    }
04658 
04659    return res;
04660 }

static int attended_transfer_occurred ( struct ast_channel chan  )  [static]

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

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

Note:
Only call this with chan locked

Definition at line 3219 of file app_queue.c.

References ast_channel_datastore_find(), and queue_transfer_info.

Referenced by try_calling().

03220 {
03221    return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
03222 }

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

Calculate the metric of each member in the outgoing callattempts.

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

Return values:
-1 if penalties are exceeded
0 otherwise

Definition at line 3058 of file app_queue.c.

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

Referenced by try_calling().

03059 {
03060    if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || (qe->min_penalty && (mem->penalty < qe->min_penalty)))
03061       return -1;
03062 
03063    switch (q->strategy) {
03064    case QUEUE_STRATEGY_RINGALL:
03065       /* Everyone equal, except for penalty */
03066       tmp->metric = mem->penalty * 1000000;
03067       break;
03068    case QUEUE_STRATEGY_LINEAR:
03069       if (pos < qe->linpos) {
03070          tmp->metric = 1000 + pos;
03071       } else {
03072          if (pos > qe->linpos)
03073             /* Indicate there is another priority */
03074             qe->linwrapped = 1;
03075          tmp->metric = pos;
03076       }
03077       tmp->metric += mem->penalty * 1000000;
03078       break;
03079    case QUEUE_STRATEGY_RRMEMORY:
03080       if (pos < q->rrpos) {
03081          tmp->metric = 1000 + pos;
03082       } else {
03083          if (pos > q->rrpos)
03084             /* Indicate there is another priority */
03085             q->wrapped = 1;
03086          tmp->metric = pos;
03087       }
03088       tmp->metric += mem->penalty * 1000000;
03089       break;
03090    case QUEUE_STRATEGY_RANDOM:
03091       tmp->metric = ast_random() % 1000;
03092       tmp->metric += mem->penalty * 1000000;
03093       break;
03094    case QUEUE_STRATEGY_WRANDOM:
03095       tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
03096       break;
03097    case QUEUE_STRATEGY_FEWESTCALLS:
03098       tmp->metric = mem->calls;
03099       tmp->metric += mem->penalty * 1000000;
03100       break;
03101    case QUEUE_STRATEGY_LEASTRECENT:
03102       if (!mem->lastcall)
03103          tmp->metric = 0;
03104       else
03105          tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
03106       tmp->metric += mem->penalty * 1000000;
03107       break;
03108    default:
03109       ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
03110       break;
03111    }
03112    return 0;
03113 }

static void clear_and_free_interfaces ( void   )  [static]

Definition at line 1071 of file app_queue.c.

References ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, and AST_LIST_UNLOCK.

Referenced by unload_module().

01072 {
01073    struct member_interface *curint;
01074 
01075    AST_LIST_LOCK(&interfaces);
01076    while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
01077       ast_free(curint);
01078    AST_LIST_UNLOCK(&interfaces);
01079 }

static void clear_queue ( struct call_queue q  )  [static]

Definition at line 986 of file app_queue.c.

References call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, call_queue::holdtime, and call_queue::wrapuptime.

Referenced by find_queue_by_name_rt(), and reload_queues().

00987 {
00988    q->holdtime = 0;
00989    q->callscompleted = 0;
00990    q->callsabandoned = 0;
00991    q->callscompletedinsl = 0;
00992    q->wrapuptime = 0;
00993 }

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

Definition at line 2113 of file app_queue.c.

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

Referenced by ring_entry().

02114 {
02115    struct call_queue *q;
02116    struct member *mem;
02117    int found = 0;
02118    struct ao2_iterator queue_iter;
02119    
02120    /* q's lock and rq's lock already set by try_calling()
02121     * to solve deadlock */
02122    queue_iter = ao2_iterator_init(queues, 0);
02123    while ((q = ao2_iterator_next(&queue_iter))) {
02124       if (q == rq) { /* don't check myself, could deadlock */
02125          queue_unref(q);
02126          continue;
02127       }
02128       ao2_lock(q);
02129       if (q->count && q->members) {
02130          if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
02131             ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
02132             if (q->weight > rq->weight && q->count >= num_available_members(q)) {
02133                ast_debug(1, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count);
02134                found = 1;
02135             }
02136             ao2_ref(mem, -1);
02137          }
02138       }
02139       ao2_unlock(q);
02140       queue_unref(q);
02141       if (found) {
02142          break;
02143       }
02144    }
02145    ao2_iterator_destroy(&queue_iter);
02146    return found;
02147 }

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

Definition at line 5824 of file app_queue.c.

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

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

05825 {
05826    struct call_queue *q;
05827    char *ret = NULL;
05828    int which = 0;
05829    int wordlen = strlen(word);
05830    struct ao2_iterator queue_iter;
05831 
05832    queue_iter = ao2_iterator_init(queues, 0);
05833    while ((q = ao2_iterator_next(&queue_iter))) {
05834       if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
05835          ret = ast_strdup(q->name);
05836          queue_unref(q);
05837          break;
05838       }
05839       queue_unref(q);
05840    }
05841    ao2_iterator_destroy(&queue_iter);
05842 
05843    return ret;
05844 }

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

Definition at line 6206 of file app_queue.c.

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

Referenced by handle_queue_add_member().

06207 {
06208    /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
06209    switch (pos) {
06210    case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
06211       return NULL;
06212    case 4: /* only one possible match, "to" */
06213       return state == 0 ? ast_strdup("to") : NULL;
06214    case 5: /* <queue> */
06215       return complete_queue(line, word, pos, state);
06216    case 6: /* only one possible match, "penalty" */
06217       return state == 0 ? ast_strdup("penalty") : NULL;
06218    case 7:
06219       if (state < 100) {      /* 0-99 */
06220          char *num;
06221          if ((num = ast_malloc(3))) {
06222             sprintf(num, "%d", state);
06223          }
06224          return num;
06225       } else {
06226          return NULL;
06227       }
06228    case 8: /* only one possible match, "as" */
06229       return state == 0 ? ast_strdup("as") : NULL;
06230    case 9: /* Don't attempt to complete name of member (infinite possibilities) */
06231       return NULL;
06232    default:
06233       return NULL;
06234    }
06235 }

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

Definition at line 6421 of file app_queue.c.

References ast_strdup, and complete_queue().

Referenced by handle_queue_pause_member().

06422 {
06423    /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
06424    switch (pos) {
06425    case 3:  /* Don't attempt to complete name of interface (infinite possibilities) */
06426       return NULL;
06427    case 4:  /* only one possible match, "queue" */
06428       return state == 0 ? ast_strdup("queue") : NULL;
06429    case 5:  /* <queue> */
06430       return complete_queue(line, word, pos, state);
06431    case 6: /* "reason" */
06432       return state == 0 ? ast_strdup("reason") : NULL;
06433    case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
06434       return NULL;
06435    default:
06436       return NULL;
06437    }
06438 }

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

Definition at line 6335 of file app_queue.c.

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

Referenced by handle_queue_remove_member().

06336 {
06337    int which = 0;
06338    struct call_queue *q;
06339    struct member *m;
06340    struct ao2_iterator queue_iter;
06341    struct ao2_iterator mem_iter;
06342    int wordlen = strlen(word);
06343 
06344    /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
06345    if (pos > 5 || pos < 3)
06346       return NULL;
06347    if (pos == 4)   /* only one possible match, 'from' */
06348       return (state == 0 ? ast_strdup("from") : NULL);
06349 
06350    if (pos == 5)   /* No need to duplicate code */
06351       return complete_queue(line, word, pos, state);
06352 
06353    /* here is the case for 3, <member> */
06354    queue_iter = ao2_iterator_init(queues, 0);
06355    while ((q = ao2_iterator_next(&queue_iter))) {
06356       ao2_lock(q);
06357       mem_iter = ao2_iterator_init(q->members, 0);
06358       while ((m = ao2_iterator_next(&mem_iter))) {
06359          if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
06360             char *tmp;
06361             ao2_unlock(q);
06362             tmp = ast_strdup(m->interface);
06363             ao2_ref(m, -1);
06364             queue_unref(q);
06365             ao2_iterator_destroy(&mem_iter);
06366             ao2_iterator_destroy(&queue_iter);
06367             return tmp;
06368          }
06369          ao2_ref(m, -1);
06370       }
06371       ao2_iterator_destroy(&mem_iter);
06372       ao2_unlock(q);
06373       queue_unref(q);
06374    }
06375    ao2_iterator_destroy(&queue_iter);
06376 
06377    return NULL;
06378 }

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

Definition at line 6554 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strdup, LOG_DEBUG, and rule_list::name.

Referenced by handle_queue_rule_show().

06555 {
06556    int which = 0;
06557    struct rule_list *rl_iter;
06558    int wordlen = strlen(word);
06559    char *ret = NULL;
06560    if (pos != 3) /* Wha? */ {
06561       ast_log(LOG_DEBUG, "Hitting this???, pos is %d\n", pos);
06562       return NULL;
06563    }
06564 
06565    AST_LIST_LOCK(&rule_lists);
06566    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
06567       if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
06568          ret = ast_strdup(rl_iter->name);
06569          break;
06570       }
06571    }
06572    AST_LIST_UNLOCK(&rule_lists);
06573 
06574    return ret;
06575 }

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

Definition at line 6491 of file app_queue.c.

References ast_strdup, and complete_queue().

Referenced by handle_queue_set_member_penalty().

06492 {
06493    /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
06494    switch (pos) {
06495    case 4:
06496       if (state == 0) {
06497          return ast_strdup("on");
06498       } else {
06499          return NULL;
06500       }
06501    case 6:
06502       if (state == 0) {
06503          return ast_strdup("in");
06504       } else {
06505          return NULL;
06506       }
06507    case 7:
06508       return complete_queue(line, word, pos, state);
06509    default:
06510       return NULL;
06511    }
06512 }

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

Definition at line 5846 of file app_queue.c.

References complete_queue().

Referenced by queue_show().

05847 {
05848    if (pos == 2)
05849       return complete_queue(line, word, pos, state);
05850    return NULL;
05851 }

static int compress_char ( const char  c  )  [static]

Definition at line 890 of file app_queue.c.

00891 {
00892    if (c < 32)
00893       return 0;
00894    else if (c > 96)
00895       return c - 64;
00896    else
00897       return c - 32;
00898 }

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

Copy rule from global list into specified queue.

Definition at line 4697 of file app_queue.c.

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

Referenced by join_queue().

04698 {
04699    struct penalty_rule *pr_iter;
04700    struct rule_list *rl_iter;
04701    const char *tmp = rulename;
04702    if (ast_strlen_zero(tmp)) {
04703       return;
04704    }
04705    AST_LIST_LOCK(&rule_lists);
04706    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
04707       if (!strcasecmp(rl_iter->name, tmp))
04708          break;
04709    }
04710    if (rl_iter) {
04711       AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
04712          struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
04713          if (!new_pr) {
04714             ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
04715             AST_LIST_UNLOCK(&rule_lists);
04716             break;
04717          }
04718          new_pr->time = pr_iter->time;
04719          new_pr->max_value = pr_iter->max_value;
04720          new_pr->min_value = pr_iter->min_value;
04721          new_pr->max_relative = pr_iter->max_relative;
04722          new_pr->min_relative = pr_iter->min_relative;
04723          AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
04724       }
04725    }
04726    AST_LIST_UNLOCK(&rule_lists);
04727 }

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

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

Definition at line 865 of file app_queue.c.

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

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

00866 {
00867    struct member *cur;
00868    
00869    if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
00870       cur->penalty = penalty;
00871       cur->paused = paused;
00872       ast_copy_string(cur->interface, interface, sizeof(cur->interface));
00873       if (!ast_strlen_zero(state_interface))
00874          ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
00875       else
00876          ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
00877       if (!ast_strlen_zero(membername))
00878          ast_copy_string(cur->membername, membername, sizeof(cur->membername));
00879       else
00880          ast_copy_string(cur->membername, interface, sizeof(cur->membername));
00881       if (!strchr(cur->interface, '/'))
00882          ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
00883       cur->status = ast_device_state(cur->state_interface);
00884    }
00885 
00886    return cur;
00887 }

static void destroy_queue ( void *  obj  )  [static]

Free queue's member list then its string fields.

Definition at line 1425 of file app_queue.c.

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

Referenced by alloc_queue().

01426 {
01427    struct call_queue *q = obj;
01428    int i;
01429 
01430    free_members(q, 1);
01431    ast_string_field_free_memory(q);
01432    for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
01433       if (q->sound_periodicannounce[i])
01434          free(q->sound_periodicannounce[i]);
01435    }
01436    ao2_ref(q->members, -1);
01437 }

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

Definition at line 848 of file app_queue.c.

References ast_event_get_ie_str(), ast_event_get_ie_uint(), AST_EVENT_IE_DEVICE, AST_EVENT_IE_STATE, ast_log(), ast_strlen_zero(), LOG_ERROR, and statechange_queue().

00849 {
00850    enum ast_device_state state;
00851    const char *device;
00852 
00853    state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00854    device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
00855 
00856    if (ast_strlen_zero(device)) {
00857       ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
00858       return;
00859    }
00860 
00861    statechange_queue(device, state);
00862 }

static void* device_state_thread ( void *  data  )  [static]

Consumer of the statechange queue.

Definition at line 795 of file app_queue.c.

References ast_cond_wait(), ast_free, AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), device_state, statechange::entry, and handle_statechange().

00796 {
00797    struct statechange *sc = NULL;
00798 
00799    while (!device_state.stop) {
00800       ast_mutex_lock(&device_state.lock);
00801       if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
00802          ast_cond_wait(&device_state.cond, &device_state.lock);
00803          sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry);
00804       }
00805       ast_mutex_unlock(&device_state.lock);
00806 
00807       /* Check to see if we were woken up to see the request to stop */
00808       if (device_state.stop)
00809          break;
00810 
00811       if (!sc)
00812          continue;
00813 
00814       handle_statechange(sc);
00815 
00816       ast_free(sc);
00817       sc = NULL;
00818    }
00819 
00820    if (sc)
00821       ast_free(sc);
00822 
00823    while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry)))
00824       ast_free(sc);
00825 
00826    return NULL;
00827 }

static void do_hang ( struct callattempt o  )  [static]

common hangup actions

Definition at line 2150 of file app_queue.c.

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

Referenced by ring_entry(), and wait_for_answer().

02151 {
02152    o->stillgoing = 0;
02153    ast_hangup(o->chan);
02154    o->chan = NULL;
02155 }

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

direct ouput to manager or cli with proper terminator

Definition at line 5682 of file app_queue.c.

References ast_cli(), and astman_append().

Referenced by __queues_show().

05683 {
05684    if (s)
05685       astman_append(s, "%s\r\n", str);
05686    else
05687       ast_cli(fd, "%s\n", str);
05688 }

static void dump_queue_members ( struct call_queue pm_queue  )  [static]

Dump all members in a specific queue to the database.

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

Definition at line 4070 of file app_queue.c.

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

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

04071 {
04072    struct member *cur_member;
04073    char value[PM_MAX_LEN];
04074    int value_len = 0;
04075    int res;
04076    struct ao2_iterator mem_iter;
04077 
04078    memset(value, 0, sizeof(value));
04079 
04080    if (!pm_queue)
04081       return;
04082 
04083    mem_iter = ao2_iterator_init(pm_queue->members, 0);
04084    while ((cur_member = ao2_iterator_next(&mem_iter))) {
04085       if (!cur_member->dynamic) {
04086          ao2_ref(cur_member, -1);
04087          continue;
04088       }
04089 
04090       res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s",
04091          value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface);
04092 
04093       ao2_ref(cur_member, -1);
04094 
04095       if (res != strlen(value + value_len)) {
04096          ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
04097          break;
04098       }
04099       value_len += res;
04100    }
04101    ao2_iterator_destroy(&mem_iter);
04102    
04103    if (value_len && !cur_member) {
04104       if (ast_db_put(pm_family, pm_queue->name, value))
04105          ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
04106    } else
04107       /* Delete the entry if the queue is empty or there is an error */
04108       ast_db_del(pm_family, pm_queue->name);
04109 }

static void end_bridge_callback ( void *  data  )  [static]

Definition at line 3266 of file app_queue.c.

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

03267 {
03268    struct queue_end_bridge *qeb = data;
03269    struct call_queue *q = qeb->q;
03270    struct ast_channel *chan = qeb->chan;
03271 
03272    if (ao2_ref(qeb, -1) == 1) {
03273       ao2_lock(q);
03274       set_queue_variables(q, chan);
03275       ao2_unlock(q);
03276       /* This unrefs the reference we made in try_calling when we allocated qeb */
03277       queue_unref(q);
03278    }
03279 }

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

Definition at line 3259 of file app_queue.c.

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

03260 {
03261    struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
03262    ao2_ref(qeb, +1);
03263    qeb->chan = originator;
03264 }

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

find the entry with the best metric, or NULL

Definition at line 2365 of file app_queue.c.

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

02366 {
02367    struct callattempt *best = NULL, *cur;
02368 
02369    for (cur = outgoing; cur; cur = cur->q_next) {
02370       if (cur->stillgoing &&              /* Not already done */
02371          !cur->chan &&              /* Isn't already going */
02372          (!best || cur->metric < best->metric)) {     /* We haven't found one yet, or it's better */
02373          best = cur;
02374       }
02375    }
02376 
02377    return best;
02378 }

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

Reload a single queue via realtime.

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

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

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

Referenced by load_realtime_queue().

01464 {
01465    struct ast_variable *v;
01466    struct call_queue *q, tmpq = {
01467       .name = queuename,   
01468    };
01469    struct member *m;
01470    struct ao2_iterator mem_iter;
01471    char *interface = NULL;
01472    const char *tmp_name;
01473    char *tmp;
01474    char tmpbuf[64];  /* Must be longer than the longest queue param name. */
01475 
01476    /* Static queues override realtime. */
01477    if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
01478       ao2_lock(q);
01479       if (!q->realtime) {
01480          if (q->dead) {
01481             ao2_unlock(q);
01482             queue_unref(q);
01483             return NULL;
01484          } else {
01485             ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
01486             ao2_unlock(q);
01487             return q;
01488          }
01489       }
01490       queue_unref(q);
01491    } else if (!member_config)
01492       /* Not found in the list, and it's not realtime ... */
01493       return NULL;
01494 
01495    /* Check if queue is defined in realtime. */
01496    if (!queue_vars) {
01497       /* Delete queue from in-core list if it has been deleted in realtime. */
01498       if (q) {
01499          /*! \note Hmm, can't seem to distinguish a DB failure from a not
01500             found condition... So we might delete an in-core queue
01501             in case of DB failure. */
01502          ast_debug(1, "Queue %s not found in realtime.\n", queuename);
01503 
01504          q->dead = 1;
01505          /* Delete if unused (else will be deleted when last caller leaves). */
01506          ao2_unlink(queues, q);
01507          ao2_unlock(q);
01508          queue_unref(q);
01509       }
01510       return NULL;
01511    }
01512 
01513    /* Create a new queue if an in-core entry does not exist yet. */
01514    if (!q) {
01515       struct ast_variable *tmpvar = NULL;
01516       if (!(q = alloc_queue(queuename)))
01517          return NULL;
01518       ao2_lock(q);
01519       clear_queue(q);
01520       q->realtime = 1;
01521       /*Before we initialize the queue, we need to set the strategy, so that linear strategy
01522        * will allocate the members properly
01523        */
01524       for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
01525          if (!strcasecmp(tmpvar->name, "strategy")) {
01526             q->strategy = strat2int(tmpvar->value);
01527             if (q->strategy < 0) {
01528                ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
01529                tmpvar->value, q->name);
01530                q->strategy = QUEUE_STRATEGY_RINGALL;
01531             }
01532             break;
01533          }
01534       }
01535       /* We traversed all variables and didn't find a strategy */
01536       if (!tmpvar)
01537          q->strategy = QUEUE_STRATEGY_RINGALL;
01538       ao2_link(queues, q);
01539    }
01540    init_queue(q);    /* Ensure defaults for all parameters not set explicitly. */
01541 
01542    memset(tmpbuf, 0, sizeof(tmpbuf));
01543    for (v = queue_vars; v; v = v->next) {
01544       /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
01545       if ((tmp = strchr(v->name, '_'))) {
01546          ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
01547          tmp_name = tmpbuf;
01548          tmp = tmpbuf;
01549          while ((tmp = strchr(tmp, '_')))
01550             *tmp++ = '-';
01551       } else
01552          tmp_name = v->name;
01553 
01554       if (!ast_strlen_zero(v->value)) {
01555          /* Don't want to try to set the option if the value is empty */
01556          queue_set_param(q, tmp_name, v->value, -1, 0);
01557       }
01558    }
01559 
01560    /* Temporarily set realtime members dead so we can detect deleted ones. 
01561     * Also set the membercount correctly for realtime*/
01562    mem_iter = ao2_iterator_init(q->members, 0);
01563    while ((m = ao2_iterator_next(&mem_iter))) {
01564       q->membercount++;
01565       if (m->realtime)
01566          m->dead = 1;
01567       ao2_ref(m, -1);
01568    }
01569    ao2_iterator_destroy(&mem_iter);
01570 
01571    while ((interface = ast_category_browse(member_config, interface))) {
01572       rt_handle_member_record(q, interface,
01573          S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
01574          ast_variable_retrieve(member_config, interface, "penalty"),
01575          ast_variable_retrieve(member_config, interface, "paused"),
01576          S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
01577    }
01578 
01579    /* Delete all realtime members that have been deleted in DB. */
01580    mem_iter = ao2_iterator_init(q->members, 0);
01581    while ((m = ao2_iterator_next(&mem_iter))) {
01582       if (m->dead) {
01583          ao2_unlink(q->members, m);
01584          remove_from_interfaces(m->state_interface, 0);
01585          q->membercount--;
01586       }
01587       ao2_ref(m, -1);
01588    }
01589    ao2_iterator_destroy(&mem_iter);
01590 
01591    ao2_unlock(q);
01592 
01593    return q;
01594 }

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

Iterate through queue's member list and delete them.

Definition at line 1407 of file app_queue.c.

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

Referenced by destroy_queue().

01408 {
01409    /* Free non-dynamic members */
01410    struct member *cur;
01411    struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
01412 
01413    while ((cur = ao2_iterator_next(&mem_iter))) {
01414       if (all || !cur->dynamic) {
01415          ao2_unlink(q->members, cur);
01416          remove_from_interfaces(cur->state_interface, 1);
01417          q->membercount--;
01418       }
01419       ao2_ref(cur, -1);
01420    }
01421    ao2_iterator_destroy(&mem_iter);
01422 }

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

Definition at line 4344 of file app_queue.c.

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

Referenced by queue_function_memberpenalty_read().

04345 {
04346    int foundqueue = 0, penalty;
04347    struct call_queue *q, tmpq = {
04348       .name = queuename,   
04349    };
04350    struct member *mem;
04351    
04352    if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
04353       foundqueue = 1;
04354       ao2_lock(q);
04355       if ((mem = interface_exists(q, interface))) {
04356          penalty = mem->penalty;
04357          ao2_ref(mem, -1);
04358          ao2_unlock(q);
04359          queue_unref(q);
04360          return penalty;
04361       }
04362       ao2_unlock(q);
04363       queue_unref(q);
04364    }
04365 
04366    /* some useful debuging */
04367    if (foundqueue) 
04368       ast_log (LOG_ERROR, "Invalid queuename\n");
04369    else 
04370       ast_log (LOG_ERROR, "Invalid interface\n");
04371 
04372    return RESULT_FAILURE;
04373 }

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

Check if members are available.

This function checks to see if members are available to be called. If any member is available, the function immediately returns QUEUE_NORMAL. If no members are available, the appropriate reason why is returned

Definition at line 647 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, call_queue::members, member::paused, member::penalty, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, QUEUE_NORMAL, and member::status.

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

00648 {
00649    struct member *member;
00650    struct ao2_iterator mem_iter;
00651    enum queue_member_status result = QUEUE_NO_MEMBERS;
00652 
00653    ao2_lock(q);
00654    mem_iter = ao2_iterator_init(q->members, 0);
00655    for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
00656       if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty)))
00657          continue;
00658 
00659       switch (member->status) {
00660       case AST_DEVICE_INVALID:
00661          /* nothing to do */
00662          break;
00663       case AST_DEVICE_UNAVAILABLE:
00664          if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS) 
00665             result = QUEUE_NO_REACHABLE_MEMBERS;
00666          break;
00667       default:
00668          if (member->paused) {
00669             result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS;
00670          } else {
00671             ao2_unlock(q);
00672             ao2_ref(member, -1);
00673             ao2_iterator_destroy(&mem_iter);
00674             return QUEUE_NORMAL;
00675          }
00676          break;
00677       }
00678    }
00679    ao2_iterator_destroy(&mem_iter);
00680 
00681    ao2_unlock(q);
00682    return result;
00683 }

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

Definition at line 6262 of file app_queue.c.

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

06263 {
06264    char *queuename, *interface, *membername = NULL, *state_interface = NULL;
06265    int penalty;
06266 
06267    switch ( cmd ) {
06268    case CLI_INIT:
06269       e->command = "queue add member";
06270       e->usage =
06271          "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"; 
06272       return NULL;
06273    case CLI_GENERATE:
06274       return complete_queue_add_member(a->line, a->word, a->pos, a->n);
06275    }
06276 
06277    if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
06278       return CLI_SHOWUSAGE;
06279    } else if (strcmp(a->argv[4], "to")) {
06280       return CLI_SHOWUSAGE;
06281    } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
06282       return CLI_SHOWUSAGE;
06283    } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
06284       return CLI_SHOWUSAGE;
06285    } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
06286       return CLI_SHOWUSAGE;
06287    }
06288 
06289    queuename = a->argv[5];
06290    interface = a->argv[3];
06291    if (a->argc >= 8) {
06292       if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
06293          if (penalty < 0) {
06294             ast_cli(a->fd, "Penalty must be >= 0\n");
06295             penalty = 0;
06296          }
06297       } else {
06298          ast_cli(a->fd, "Penalty must be an integer >= 0\n");
06299          penalty = 0;
06300       }
06301    } else {
06302       penalty = 0;
06303    }
06304 
06305    if (a->argc >= 10) {
06306       membername = a->argv[9];
06307    }
06308 
06309    if (a->argc >= 12) {
06310       state_interface = a->argv[11];
06311    }
06312 
06313    switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
06314    case RES_OKAY:
06315       ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
06316       ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
06317       return CLI_SUCCESS;
06318    case RES_EXISTS:
06319       ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
06320       return CLI_FAILURE;
06321    case RES_NOSUCHQUEUE:
06322       ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
06323       return CLI_FAILURE;
06324    case RES_OUTOFMEMORY:
06325       ast_cli(a->fd, "Out of memory\n");
06326       return CLI_FAILURE;
06327    case RES_NOT_DYNAMIC:
06328       ast_cli(a->fd, "Member not dynamic\n");
06329       return CLI_FAILURE;
06330    default:
06331       return CLI_FAILURE;
06332    }
06333 }

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

Definition at line 6440 of file app_queue.c.

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

06441 {
06442    char *queuename, *interface, *reason;
06443    int paused;
06444 
06445    switch (cmd) {
06446    case CLI_INIT:
06447       e->command = "queue {pause|unpause} member";
06448       e->usage = 
06449          "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
06450          "     Pause or unpause a queue member. Not specifying a particular queue\n"
06451          "     will pause or unpause a member across all queues to which the member\n"
06452          "     belongs.\n";
06453       return NULL;
06454    case CLI_GENERATE:
06455       return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
06456    }
06457 
06458    if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
06459       return CLI_SHOWUSAGE;
06460    } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
06461       return CLI_SHOWUSAGE;
06462    } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
06463       return CLI_SHOWUSAGE;
06464    }
06465 
06466 
06467    interface = a->argv[3];
06468    queuename = a->argc >= 6 ? a->argv[5] : NULL;
06469    reason = a->argc == 8 ? a->argv[7] : NULL;
06470    paused = !strcasecmp(a->argv[1], "pause");
06471 
06472    if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
06473       ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
06474       if (!ast_strlen_zero(queuename))
06475          ast_cli(a->fd, " in queue '%s'", queuename);
06476       if (!ast_strlen_zero(reason))
06477          ast_cli(a->fd, " for reason '%s'", reason);
06478       ast_cli(a->fd, "\n");
06479       return CLI_SUCCESS;
06480    } else {
06481       ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
06482       if (!ast_strlen_zero(queuename))
06483          ast_cli(a->fd, " in queue '%s'", queuename);
06484       if (!ast_strlen_zero(reason))
06485          ast_cli(a->fd, " for reason '%s'", reason);
06486       ast_cli(a->fd, "\n");
06487       return CLI_FAILURE;
06488    }
06489 }

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

Definition at line 6380 of file app_queue.c.

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

06381 {
06382    char *queuename, *interface;
06383 
06384    switch (cmd) {
06385    case CLI_INIT:
06386       e->command = "queue remove member";
06387       e->usage = "Usage: queue remove member <channel> from <queue>\n"; 
06388       return NULL;
06389    case CLI_GENERATE:
06390       return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
06391    }
06392 
06393    if (a->argc != 6) {
06394       return CLI_SHOWUSAGE;
06395    } else if (strcmp(a->argv[4], "from")) {
06396       return CLI_SHOWUSAGE;
06397    }
06398 
06399    queuename = a->argv[5];
06400    interface = a->argv[3];
06401 
06402    switch (remove_from_queue(queuename, interface)) {
06403    case RES_OKAY:
06404       ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
06405       ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
06406       return CLI_SUCCESS;
06407    case RES_EXISTS:
06408       ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
06409       return CLI_FAILURE;
06410    case RES_NOSUCHQUEUE:
06411       ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
06412       return CLI_FAILURE;
06413    case RES_OUTOFMEMORY:
06414       ast_cli(a->fd, "Out of memory\n");
06415       return CLI_FAILURE;
06416    default:
06417       return CLI_FAILURE;
06418    }
06419 }

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

Definition at line 6611 of file app_queue.c.

References CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, reload_queue_rules(), and ast_cli_entry::usage.

06612 {
06613    switch (cmd) {
06614       case CLI_INIT:
06615          e->command = "queue rules reload";
06616          e->usage = 
06617             "Usage: queue rules reload\n"
06618             "Reloads rules defined in queuerules.conf\n";
06619          return NULL;
06620       case CLI_GENERATE:
06621          return NULL;
06622    }
06623    reload_queue_rules(1);
06624    return CLI_SUCCESS;
06625 }

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

Definition at line 6577 of file app_queue.c.

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

06578 {
06579    char *rule;
06580    struct rule_list *rl_iter;
06581    struct penalty_rule *pr_iter;
06582    switch (cmd) {
06583    case CLI_INIT:
06584       e->command = "queue rules show";
06585       e->usage =
06586       "Usage: queue rules show [rulename]\n"
06587       "Show the list of rules associated with rulename. If no\n"
06588       "rulename is specified, list all rules defined in queuerules.conf\n";
06589       return NULL;
06590    case CLI_GENERATE:
06591       return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
06592    }
06593 
06594    if (a->argc != 3 && a->argc != 4)
06595       return CLI_SHOWUSAGE;
06596 
06597    rule = a->argc == 4 ? a->argv[3] : "";
06598    AST_LIST_LOCK(&rule_lists);
06599    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
06600       if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
06601          ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
06602          AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
06603             ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d and adjust QUEUE_MIN_PENALTY %s %d\n", pr_iter->time, pr_iter->max_relative ? "by" : "to", pr_iter->max_value, pr_iter->min_relative ? "by" : "to", pr_iter->min_value);
06604          }
06605       }
06606    }
06607    AST_LIST_UNLOCK(&rule_lists);
06608    return CLI_SUCCESS; 
06609 }

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

Definition at line 6514 of file app_queue.c.

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

06515 {
06516    char *queuename = NULL, *interface;
06517    int penalty = 0;
06518 
06519    switch (cmd) {
06520    case CLI_INIT:
06521       e->command = "queue set penalty";
06522       e->usage = 
06523       "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
06524       "Set a member's penalty in the queue specified. If no queue is specified\n"
06525       "then that interface's penalty is set in all queues to which that interface is a member\n";
06526       return NULL;
06527    case CLI_GENERATE:
06528       return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n);
06529    }
06530 
06531    if (a->argc != 6 && a->argc != 8) {
06532       return CLI_SHOWUSAGE;
06533    } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
06534       return CLI_SHOWUSAGE;
06535    }
06536 
06537    if (a->argc == 8)
06538       queuename = a->argv[7];
06539    interface = a->argv[5];
06540    penalty = atoi(a->argv[3]);
06541 
06542    switch (set_member_penalty(queuename, interface, penalty)) {
06543    case RESULT_SUCCESS:
06544       ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
06545       return CLI_SUCCESS;
06546    case RESULT_FAILURE:
06547       ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
06548       return CLI_FAILURE;
06549    default:
06550       return CLI_FAILURE;
06551    }
06552 }

static void* handle_statechange ( struct statechange sc  )  [static]

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

Definition at line 749 of file app_queue.c.

References ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, statechange::dev, devstate2str(), member_interface::interface, statechange::state, and update_status().

00750 {
00751    struct member_interface *curint;
00752    char interface[80];
00753 
00754    AST_LIST_LOCK(&interfaces);
00755    AST_LIST_TRAVERSE(&interfaces, curint, list) {
00756       char *slash_pos;
00757       ast_copy_string(interface, curint->interface, sizeof(interface));
00758       if ((slash_pos = strchr(interface, '/')))
00759          if ((slash_pos = strchr(slash_pos + 1, '/')))
00760             *slash_pos = '\0';
00761       if (!strcasecmp(interface, sc->dev))
00762          break;
00763    }
00764    AST_LIST_UNLOCK(&interfaces);
00765 
00766    if (!curint) {
00767       ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", sc->dev, sc->state, devstate2str(sc->state));
00768       return NULL;
00769    }
00770 
00771    ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, devstate2str(sc->state));
00772 
00773    update_status(sc->dev, sc->state);
00774 
00775    return NULL;
00776 }

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

Hang up a list of outgoing calls.

Definition at line 2046 of file app_queue.c.

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

Referenced by try_calling().

02047 {
02048    struct callattempt *oo;
02049 
02050    while (outgoing) {
02051       /* Hangup any existing lines we have open */
02052       if (outgoing->chan && (outgoing->chan != exception))
02053          ast_hangup(outgoing->chan);
02054       oo = outgoing;
02055       outgoing = outgoing->q_next;
02056       if (oo->member)
02057          ao2_ref(oo->member, -1);
02058       ast_free(oo);
02059    }
02060 }

static void init_queue ( struct call_queue q  )  [static]

Initialize Queue default values.

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

Definition at line 922 of file app_queue.c.

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

Referenced by find_queue_by_name_rt(), and reload_queues().

00923 {
00924    int i;
00925    struct penalty_rule *pr_iter;
00926 
00927    q->dead = 0;
00928    q->retry = DEFAULT_RETRY;
00929    q->timeout = -1;
00930    q->maxlen = 0;
00931    q->announcefrequency = 0;
00932    q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
00933    q->announceholdtime = 0;
00934    q->announceholdtime = 1;
00935    q->roundingseconds = 0; /* Default - don't announce seconds */
00936    q->servicelevel = 0;
00937    q->ringinuse = 1;
00938    q->setinterfacevar = 0;
00939    q->setqueuevar = 0;
00940    q->setqueueentryvar = 0;
00941    q->autofill = autofill_default;
00942    q->montype = montype_default;
00943    q->monfmt[0] = '\0';
00944    q->reportholdtime = 0;
00945    q->wrapuptime = 0;
00946    q->joinempty = 0;
00947    q->leavewhenempty = 0;
00948    q->memberdelay = 0;
00949    q->maskmemberstatus = 0;
00950    q->eventwhencalled = 0;
00951    q->weight = 0;
00952    q->timeoutrestart = 0;
00953    q->periodicannouncefrequency = 0;
00954    if (!q->members) {
00955       if (q->strategy == QUEUE_STRATEGY_LINEAR)
00956          /* linear strategy depends on order, so we have to place all members in a single bucket */
00957          q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
00958       else
00959          q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
00960    }
00961    q->membercount = 0;
00962    q->found = 1;
00963 
00964    ast_string_field_set(q, sound_next, "queue-youarenext");
00965    ast_string_field_set(q, sound_thereare, "queue-thereare");
00966    ast_string_field_set(q, sound_calls, "queue-callswaiting");
00967    ast_string_field_set(q, sound_holdtime, "queue-holdtime");
00968    ast_string_field_set(q, sound_minutes, "queue-minutes");
00969    ast_string_field_set(q, sound_minute, "queue-minute");
00970    ast_string_field_set(q, sound_seconds, "queue-seconds");
00971    ast_string_field_set(q, sound_thanks, "queue-thankyou");
00972    ast_string_field_set(q, sound_reporthold, "queue-reporthold");
00973 
00974    if ((q->sound_periodicannounce[0] = ast_str_create(32)))
00975       ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
00976 
00977    for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
00978       if (q->sound_periodicannounce[i])
00979          ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
00980    }
00981 
00982    while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list)))
00983       ast_free(pr_iter);
00984 }

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

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

Definition at line 615 of file app_queue.c.

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

Referenced by join_queue().

00616 {
00617    struct queue_ent *cur;
00618 
00619    if (!q || !new)
00620       return;
00621    if (prev) {
00622       cur = prev->next;
00623       prev->next = new;
00624    } else {
00625       cur = q->head;
00626       q->head = new;
00627    }
00628    new->next = cur;
00629    new->parent = q;
00630    new->pos = ++(*pos);
00631    new->opos = *pos;
00632 }

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

Change queue penalty by adding rule.

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

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

Definition at line 1090 of file app_queue.c.

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

Referenced by reload_queue_rules().

01091 {
01092    char *timestr, *maxstr, *minstr, *contentdup;
01093    struct penalty_rule *rule = NULL, *rule_iter;
01094    struct rule_list *rl_iter;
01095    int time, inserted = 0;
01096 
01097    if (!(rule = ast_calloc(1, sizeof(*rule)))) {
01098       ast_log(LOG_ERROR, "Cannot allocate memory for penaltychange rule at line %d!\n", linenum);
01099       return -1;
01100    }
01101 
01102    contentdup = ast_strdupa(content);
01103    
01104    if (!(maxstr = strchr(contentdup, ','))) {
01105       ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
01106       ast_free(rule);
01107       return -1;
01108    }
01109 
01110    *maxstr++ = '\0';
01111    timestr = contentdup;
01112 
01113    if ((time = atoi(timestr)) < 0) {
01114       ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
01115       ast_free(rule);
01116       return -1;
01117    }
01118 
01119    rule->time = time;
01120 
01121    if ((minstr = strchr(maxstr,',')))
01122       *minstr++ = '\0';
01123    
01124    /* The last check will evaluate true if either no penalty change is indicated for a given rule
01125     * OR if a min penalty change is indicated but no max penalty change is */
01126    if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
01127       rule->max_relative = 1;
01128    }
01129 
01130    rule->max_value = atoi(maxstr);
01131 
01132    if (!ast_strlen_zero(minstr)) {
01133       if (*minstr == '+' || *minstr == '-')
01134          rule->min_relative = 1;
01135       rule->min_value = atoi(minstr);
01136    } else /*there was no minimum specified, so assume this means no change*/
01137       rule->min_relative = 1;
01138 
01139    /*We have the rule made, now we need to insert it where it belongs*/
01140    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
01141       if (strcasecmp(rl_iter->name, list_name))
01142          continue;
01143 
01144       AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
01145          if (rule->time < rule_iter->time) {
01146             AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
01147             inserted = 1;
01148             break;
01149          }
01150       }
01151       AST_LIST_TRAVERSE_SAFE_END;
01152    
01153       if (!inserted) {
01154          AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
01155       }
01156    }
01157 
01158    return 0;
01159 }

static char* int2strat ( int  strategy  )  [static]

Definition at line 545 of file app_queue.c.

References strategy::name, and strategies.

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

00546 {
00547    int x;
00548 
00549    for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
00550       if (strategy == strategies[x].strategy)
00551          return strategies[x].name;
00552    }
00553 
00554    return "<unknown>";
00555 }

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

Definition at line 4044 of file app_queue.c.

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

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

04045 {
04046    struct member *mem;
04047    struct ao2_iterator mem_iter;
04048 
04049    if (!q)
04050       return NULL;
04051 
04052    mem_iter = ao2_iterator_init(q->members, 0);
04053    while ((mem = ao2_iterator_next(&mem_iter))) {
04054       if (!strcasecmp(interface, mem->interface)) {
04055          ao2_iterator_destroy(&mem_iter);
04056          return mem;
04057       }
04058       ao2_ref(mem, -1);
04059    }
04060    ao2_iterator_destroy(&mem_iter);
04061 
04062    return NULL;
04063 }

static int interface_exists_global ( const char *  interface,
int  lock_queue_container 
) [static]

Definition at line 1021 of file app_queue.c.

References ao2_iterator_destroy(), AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), ast_copy_string(), member::interface, call_queue::members, queue_unref(), queues, and member::state_interface.

Referenced by remove_from_interfaces().

01022 {
01023    struct call_queue *q;
01024    struct member *mem, tmpmem;
01025    struct ao2_iterator queue_iter, mem_iter;
01026    int ret = 0;
01027 
01028    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
01029    queue_iter = ao2_iterator_init(queues, lock_queue_container ? 0 : AO2_ITERATOR_DONTLOCK);
01030    while ((q = ao2_iterator_next(&queue_iter))) {
01031       ao2_lock(q);
01032       mem_iter = ao2_iterator_init(q->members, 0);
01033       while ((mem = ao2_iterator_next(&mem_iter))) { 
01034          if (!strcasecmp(mem->state_interface, interface)) {
01035             ao2_ref(mem, -1);
01036             ret = 1;
01037             break;
01038          }
01039       }
01040       ao2_unlock(q);
01041       queue_unref(q);
01042       ao2_iterator_destroy(&mem_iter);
01043    }
01044    ao2_iterator_destroy(&queue_iter);
01045 
01046    return ret;
01047 }

static int is_our_turn ( struct queue_ent qe  )  [static]

Check if we should start attempting to call queue members.

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

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

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

Referenced by queue_exec(), and wait_our_turn().

02834 {
02835    struct queue_ent *ch;
02836    int res;
02837    int avl;
02838    int idx = 0;
02839    /* This needs a lock. How many members are available to be served? */
02840    ao2_lock(qe->parent);
02841 
02842    avl = num_available_members(qe->parent);
02843 
02844    ch = qe->parent->head;
02845 
02846    ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
02847 
02848    while ((idx < avl) && (ch) && (ch != qe)) {
02849       if (!ch->pending)
02850          idx++;
02851       ch = ch->next;       
02852    }
02853 
02854    ao2_unlock(qe->parent);
02855 
02856    /* If the queue entry is within avl [the number of available members] calls from the top ... */
02857    if (ch && idx < avl) {
02858       ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
02859       res = 1;
02860    } else {
02861       ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
02862       res = 0;
02863    }
02864 
02865    return res;
02866 }

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

Definition at line 1715 of file app_queue.c.

References call_queue::announce, queue_ent::announce, ao2_lock(), ao2_unlock(), ast_copy_string(), ast_debug, AST_LIST_FIRST, queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, call_queue::context, queue_ent::context, copy_rules(), call_queue::count, call_queue::defaultrule, EVENT_FLAG_CALL, get_member_status(), call_queue::head, insert_entry(), call_queue::joinempty, load_realtime_queue(), manager_event, queue_ent::max_penalty, call_queue::maxlen, queue_ent::min_penalty, call_queue::moh, queue_ent::moh, call_queue::name, ast_channel::name, queue_ent::next, queue_ent::pos, queue_ent::pr, queue_ent::prio, queue_ent::qe_rules, QUEUE_EMPTY_LOOSE, QUEUE_EMPTY_STRICT, QUEUE_FULL, QUEUE_JOINEMPTY, QUEUE_JOINUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS, queues, S_OR, ast_channel::uniqueid, and update_qe_rule().

Referenced by queue_exec().

01716 {
01717    struct call_queue *q;
01718    struct queue_ent *cur, *prev = NULL;
01719    int res = -1;
01720    int pos = 0;
01721    int inserted = 0;
01722    enum queue_member_status stat;
01723    int exit = 0;
01724 
01725    if (!(q = load_realtime_queue(queuename)))
01726       return res;
01727 
01728    ao2_lock(queues);
01729    ao2_lock(q);
01730 
01731    copy_rules(qe, S_OR(overriding_rule, q->defaultrule));
01732    qe->pr = AST_LIST_FIRST(&qe->qe_rules);
01733 
01734    /* This is our one */
01735    while (!exit) {
01736       stat = get_member_status(q, qe->max_penalty, qe->min_penalty);
01737       if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
01738          *reason = QUEUE_JOINEMPTY;
01739       else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS))
01740          *reason = QUEUE_JOINUNAVAIL;
01741       else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS))
01742          *reason = QUEUE_JOINUNAVAIL;
01743       else if (q->maxlen && (q->count >= q->maxlen))
01744          *reason = QUEUE_FULL;
01745       else {
01746          /* There's space for us, put us at the right position inside
01747           * the queue.
01748           * Take into account the priority of the calling user */
01749          inserted = 0;
01750          prev = NULL;
01751          cur = q->head;
01752          while (cur) {
01753             /* We have higher priority than the current user, enter
01754              * before him, after all the other users with priority
01755              * higher or equal to our priority. */
01756             if ((!inserted) && (qe->prio > cur->prio)) {
01757                insert_entry(q, prev, qe, &pos);
01758                inserted = 1;
01759             }
01760             cur->pos = ++pos;
01761             prev = cur;
01762             cur = cur->next;
01763          }
01764          /* No luck, join at the end of the queue */
01765          if (!inserted)
01766             insert_entry(q, prev, qe, &pos);
01767          ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
01768          ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
01769          ast_copy_string(qe->context, q->context, sizeof(qe->context));
01770          q->count++;
01771          res = 0;
01772          manager_event(EVENT_FLAG_CALL, "Join",
01773             "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
01774             qe->chan->name,
01775             S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
01776             S_OR(qe->chan->cid.cid_name, "unknown"),
01777             q->name, qe->pos, q->count, qe->chan->uniqueid );
01778          ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
01779       }
01780       if (!exit && qe->pr && res) {
01781          /* We failed to join the queue, but perhaps we can join if we move
01782           * to the next defined penalty rule
01783           */
01784          update_qe_rule(qe);
01785       } else {
01786          exit = 1;
01787       }
01788    }
01789    ao2_unlock(q);
01790    ao2_unlock(queues);
01791 
01792    return res;
01793 }

static void leave_queue ( struct queue_ent qe  )  [static]

Caller leaving queue.

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

Definition at line 1989 of file app_queue.c.

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

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

01990 {
01991    struct call_queue *q;
01992    struct queue_ent *cur, *prev = NULL;
01993    struct penalty_rule *pr_iter;
01994    int pos = 0;
01995 
01996    if (!(q = qe->parent))
01997       return;
01998    queue_ref(q);
01999    ao2_lock(q);
02000 
02001    prev = NULL;
02002    for (cur = q->head; cur; cur = cur->next) {
02003       if (cur == qe) {
02004          q->count--;
02005 
02006          /* Take us out of the queue */
02007          manager_event(EVENT_FLAG_CALL, "Leave",
02008             "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
02009             qe->chan->name, q->name,  q->count, qe->chan->uniqueid);
02010          ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
02011          /* Take us out of the queue */
02012          if (prev)
02013             prev->next = cur->next;
02014          else
02015             q->head = cur->next;
02016          /* Free penalty rules */
02017          while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
02018             ast_free(pr_iter);
02019       } else {
02020          /* Renumber the people after us in the queue based on a new count */
02021          cur->pos = ++pos;
02022          prev = cur;
02023       }
02024    }
02025    ao2_unlock(q);
02026 
02027    /*If the queue is a realtime queue, check to see if it's still defined in real time*/
02028    if (q->realtime) {
02029       struct ast_variable *var;
02030       if (!(var = ast_load_realtime("queues", "name", q->name, NULL))) {
02031          q->dead = 1;
02032       } else {
02033          ast_variables_destroy(var);
02034       }
02035    }
02036 
02037    if (q->dead) { 
02038       /* It's dead and nobody is in it, so kill it */
02039       ao2_unlink(queues, q);
02040    }
02041    /* unref the explicit ref earlier in the function */
02042    queue_unref(q);
02043 }

static int load_module ( void   )  [static]

Definition at line 6706 of file app_queue.c.

References ao2_container_alloc(), aqm_exec(), ast_add_extension2(), ast_cli_register_multiple(), ast_cond_init(), ast_context_find_or_create(), ast_custom_function_register, AST_EVENT_DEVICE_STATE, AST_EVENT_IE_END, ast_event_subscribe(), ast_free_ptr, ast_log(), ast_manager_register, AST_MODULE_LOAD_DECLINE, ast_mutex_init(), ast_pthread_create, ast_register_application, ast_strdup, cli_queue, device_state, device_state_cb(), device_state_thread(), EVENT_FLAG_AGENT, LOG_ERROR, manager_add_queue_member(), manager_pause_queue_member(), manager_queue_log_custom(), manager_queue_member_penalty(), manager_queue_rule_show(), manager_queues_show(), manager_queues_status(), manager_queues_summary(), manager_remove_queue_member(), MAX_QUEUE_BUCKETS, pqm_exec(), ql_exec(), queue_cmp_cb(), queue_exec(), queue_hash_cb(), queuemembercount_dep, queuemembercount_function, queuememberlist_function, queuememberpenalty_function, queues, queuevar_function, queuewaitingcount_function, reload_queue_members(), reload_queues(), rqm_exec(), and upqm_exec().

06707 {
06708    int res;
06709    struct ast_context *con;
06710 
06711    queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
06712 
06713    if (!reload_queues(0))
06714       return AST_MODULE_LOAD_DECLINE;
06715 
06716    con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
06717    if (!con)
06718       ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n");
06719    else
06720       ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue");
06721 
06722    if (queue_persistent_members)
06723       reload_queue_members();
06724 
06725    ast_mutex_init(&device_state.lock);
06726    ast_cond_init(&device_state.cond, NULL);
06727    ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL);
06728 
06729    ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
06730    res = ast_register_application(app, queue_exec, synopsis, descrip);
06731    res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip);
06732    res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip);
06733    res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip);
06734    res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip);
06735    res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip);
06736    res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues");
06737    res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status");
06738    res |= ast_manager_register("QueueSummary", 0, manager_queues_summary, "Queue Summary");
06739    res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue.");
06740    res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
06741    res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
06742    res |= ast_manager_register("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom, "Adds custom entry in queue_log");
06743    res |= ast_manager_register("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty, "Set the penalty for a queue member"); 
06744    res |= ast_manager_register("QueueRule", 0, manager_queue_rule_show, "Queue Rules");
06745    res |= ast_custom_function_register(&queuevar_function);
06746    res |= ast_custom_function_register(&queuemembercount_function);
06747    res |= ast_custom_function_register(&queuemembercount_dep);
06748    res |= ast_custom_function_register(&queuememberlist_function);
06749    res |= ast_custom_function_register(&queuewaitingcount_function);
06750    res |= ast_custom_function_register(&queuememberpenalty_function);
06751    if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL, AST_EVENT_IE_END)))
06752       res = -1;
06753 
06754    return res ? AST_MODULE_LOAD_DECLINE : 0;
06755 }

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

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

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

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

01597 {
01598    struct ast_variable *queue_vars;
01599    struct ast_config *member_config = NULL;
01600    struct call_queue *q = NULL, tmpq = {
01601       .name = queuename,   
01602    };
01603 
01604    /* Find the queue in the in-core list first. */
01605    q = ao2_find(queues, &tmpq, OBJ_POINTER);
01606 
01607    if (!q || q->realtime) {
01608       /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
01609          queue operations while waiting for the DB.
01610 
01611          This will be two separate database transactions, so we might
01612          see queue parameters as they were before another process
01613          changed the queue and member list as it was after the change.
01614          Thus we might see an empty member list when a queue is
01615          deleted. In practise, this is unlikely to cause a problem. */
01616 
01617       queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
01618       if (queue_vars) {
01619          member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
01620          if (!member_config) {
01621             ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
01622             ast_variables_destroy(queue_vars);
01623             return NULL;
01624          }
01625       }
01626 
01627       ao2_lock(queues);
01628       q = find_queue_by_name_rt(queuename, queue_vars, member_config);
01629       if (member_config)
01630          ast_config_destroy(member_config);
01631       if (queue_vars)
01632          ast_variables_destroy(queue_vars);
01633       ao2_unlock(queues);
01634 
01635    } else {
01636       update_realtime_members(q);
01637    }
01638    return q;
01639 }

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

Definition at line 6076 of file app_queue.c.

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

Referenced by load_module().

06077 {
06078    const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
06079    int paused, penalty = 0;
06080 
06081    queuename = astman_get_header(m, "Queue");
06082    interface = astman_get_header(m, "Interface");
06083    penalty_s = astman_get_header(m, "Penalty");
06084    paused_s = astman_get_header(m, "Paused");
06085    membername = astman_get_header(m, "MemberName");
06086    state_interface = astman_get_header(m, "StateInterface");
06087 
06088    if (ast_strlen_zero(queuename)) {
06089       astman_send_error(s, m, "'Queue' not specified.");
06090       return 0;
06091    }
06092 
06093    if (ast_strlen_zero(interface)) {
06094       astman_send_error(s, m, "'Interface' not specified.");
06095       return 0;
06096    }
06097 
06098    if (ast_strlen_zero(penalty_s))
06099       penalty = 0;
06100    else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0)
06101       penalty = 0;
06102 
06103    if (ast_strlen_zero(paused_s))
06104       paused = 0;
06105    else
06106       paused = abs(ast_true(paused_s));
06107 
06108    switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
06109    case RES_OKAY:
06110       ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
06111       astman_send_ack(s, m, "Added interface to queue");
06112       break;
06113    case RES_EXISTS:
06114       astman_send_error(s, m, "Unable to add interface: Already there");
06115       break;
06116    case RES_NOSUCHQUEUE:
06117       astman_send_error(s, m, "Unable to add interface to queue: No such queue");
06118       break;
06119    case RES_OUTOFMEMORY:
06120       astman_send_error(s, m, "Out of memory");
06121       break;
06122    }
06123 
06124    return 0;
06125 }

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

Definition at line 6161 of file app_queue.c.

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

Referenced by load_module().

06162 {
06163    const char *queuename, *interface, *paused_s, *reason;
06164    int paused;
06165 
06166    interface = astman_get_header(m, "Interface");
06167    paused_s = astman_get_header(m, "Paused");
06168    queuename = astman_get_header(m, "Queue");      /* Optional - if not supplied, pause the given Interface in all queues */
06169    reason = astman_get_header(m, "Reason");        /* Optional - Only used for logging purposes */
06170 
06171    if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
06172       astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
06173       return 0;
06174    }
06175 
06176    paused = abs(ast_true(paused_s));
06177 
06178    if (set_member_paused(queuename, interface, reason, paused))
06179       astman_send_error(s, m, "Interface not found");
06180    else
06181       astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
06182    return 0;
06183 }

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

Definition at line 6185 of file app_queue.c.

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

Referenced by load_module().

06186 {
06187    const char *queuename, *event, *message, *interface, *uniqueid;
06188 
06189    queuename = astman_get_header(m, "Queue");
06190    uniqueid = astman_get_header(m, "UniqueId");
06191    interface = astman_get_header(m, "Interface");
06192    event = astman_get_header(m, "Event");
06193    message = astman_get_header(m, "Message");
06194 
06195    if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
06196       astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
06197       return 0;
06198    }
06199 
06200    ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
06201    astman_send_ack(s, m, "Event added successfully");
06202 
06203    return 0;
06204 }

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

Definition at line 6237 of file app_queue.c.

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

Referenced by load_module().

06238 {
06239    const char *queuename, *interface, *penalty_s;
06240    int penalty;
06241 
06242    interface = astman_get_header(m, "Interface");
06243    penalty_s = astman_get_header(m, "Penalty");
06244    /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
06245    queuename = astman_get_header(m, "Queue");
06246 
06247    if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
06248       astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
06249       return 0;
06250    }
06251  
06252    penalty = atoi(penalty_s);
06253 
06254    if (set_member_penalty((char *)queuename, (char *)interface, penalty))
06255       astman_send_error(s, m, "Invalid interface, queuename or penalty");
06256    else
06257       astman_send_ack(s, m, "Interface penalty set successfully");
06258 
06259    return 0;
06260 }

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

Definition at line 5882 of file app_queue.c.

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

Referenced by load_module().

05883 {
05884    const char *rule = astman_get_header(m, "Rule");
05885    struct rule_list *rl_iter;
05886    struct penalty_rule *pr_iter;
05887 
05888    AST_LIST_LOCK(&rule_lists);
05889    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
05890       if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
05891          astman_append(s, "RuleList: %s\r\n", rl_iter->name);
05892          AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
05893             astman_append(s, "Rule: %d,%s%d,%s%d\r\n", pr_iter->time, pr_iter->max_relative && pr_iter->max_value >= 0 ? "+" : "", pr_iter->max_value, pr_iter->min_relative && pr_iter->min_value >= 0 ? "+" : "", pr_iter->min_value );
05894          }
05895          if (!ast_strlen_zero(rule))
05896             break;
05897       }
05898    }
05899    AST_LIST_UNLOCK(&rule_lists);
05900 
05901    astman_append(s, "\r\n\r\n");
05902 
05903    return RESULT_SUCCESS;
05904 }

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

Definition at line 5872 of file app_queue.c.

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

Referenced by load_module().

05873 {
05874    char *a[] = { "queue", "show" };
05875 
05876    __queues_show(s, -1, 2, a);
05877    astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
05878 
05879    return RESULT_SUCCESS;
05880 }

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

Queue status info via AMI.

Definition at line 5981 of file app_queue.c.

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

Referenced by load_module().

05982 {
05983    time_t now;
05984    int pos;
05985    const char *id = astman_get_header(m,"ActionID");
05986    const char *queuefilter = astman_get_header(m,"Queue");
05987    const char *memberfilter = astman_get_header(m,"Member");
05988    char idText[256] = "";
05989    struct call_queue *q;
05990    struct queue_ent *qe;
05991    float sl = 0;
05992    struct member *mem;
05993    struct ao2_iterator queue_iter;
05994    struct ao2_iterator mem_iter;
05995 
05996    astman_send_ack(s, m, "Queue status will follow");
05997    time(&now);
05998    if (!ast_strlen_zero(id))
05999       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
06000 
06001    queue_iter = ao2_iterator_init(queues, 0);
06002    while ((q = ao2_iterator_next(&queue_iter))) {
06003       ao2_lock(q);
06004 
06005       /* List queue properties */
06006       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
06007          sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
06008          astman_append(s, "Event: QueueParams\r\n"
06009             "Queue: %s\r\n"
06010             "Max: %d\r\n"
06011             "Strategy: %s\r\n"
06012             "Calls: %d\r\n"
06013             "Holdtime: %d\r\n"
06014             "Completed: %d\r\n"
06015             "Abandoned: %d\r\n"
06016             "ServiceLevel: %d\r\n"
06017             "ServicelevelPerf: %2.1f\r\n"
06018             "Weight: %d\r\n"
06019             "%s"
06020             "\r\n",
06021             q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted,
06022             q->callsabandoned, q->servicelevel, sl, q->weight, idText);
06023          /* List Queue Members */
06024          mem_iter = ao2_iterator_init(q->members, 0);
06025          while ((mem = ao2_iterator_next(&mem_iter))) {
06026             if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
06027                astman_append(s, "Event: QueueMember\r\n"
06028                   "Queue: %s\r\n"
06029                   "Name: %s\r\n"
06030                   "Location: %s\r\n"
06031                   "Membership: %s\r\n"
06032                   "Penalty: %d\r\n"
06033                   "CallsTaken: %d\r\n"
06034                   "LastCall: %d\r\n"
06035                   "Status: %d\r\n"
06036                   "Paused: %d\r\n"
06037                   "%s"
06038                   "\r\n",
06039                   q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
06040                   mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
06041             }
06042             ao2_ref(mem, -1);
06043          }
06044          ao2_iterator_destroy(&mem_iter);
06045          /* List Queue Entries */
06046          pos = 1;
06047          for (qe = q->head; qe; qe = qe->next) {
06048             astman_append(s, "Event: QueueEntry\r\n"
06049                "Queue: %s\r\n"
06050                "Position: %d\r\n"
06051                "Channel: %s\r\n"
06052                "CallerIDNum: %s\r\n"
06053                "CallerIDName: %s\r\n"
06054                "Wait: %ld\r\n"
06055                "%s"
06056                "\r\n",
06057                q->name, pos++, qe->chan->name,
06058                S_OR(qe->chan->cid.cid_num, "unknown"),
06059                S_OR(qe->chan->cid.cid_name, "unknown"),
06060                (long) (now - qe->start), idText);
06061          }
06062       }
06063       ao2_unlock(q);
06064       queue_unref(q);
06065    }
06066    ao2_iterator_destroy(&queue_iter);
06067 
06068    astman_append(s,
06069       "Event: QueueStatusComplete\r\n"
06070       "%s"
06071       "\r\n",idText);
06072 
06073    return RESULT_SUCCESS;
06074 }

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

Summary of queue info via the AMI.

Definition at line 5907 of file app_queue.c.

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

Referenced by load_module().

05908 {
05909    time_t now;
05910    int qmemcount = 0;
05911    int qmemavail = 0;
05912    int qchancount = 0;
05913    int qlongestholdtime = 0;
05914    const char *id = astman_get_header(m, "ActionID");
05915    const char *queuefilter = astman_get_header(m, "Queue");
05916    char idText[256] = "";
05917    struct call_queue *q;
05918    struct queue_ent *qe;
05919    struct member *mem;
05920    struct ao2_iterator queue_iter;
05921    struct ao2_iterator mem_iter;
05922 
05923    astman_send_ack(s, m, "Queue summary will follow");
05924    time(&now);
05925    if (!ast_strlen_zero(id))
05926       snprintf(idText, 256, "ActionID: %s\r\n", id);
05927    queue_iter = ao2_iterator_init(queues, 0);
05928    while ((q = ao2_iterator_next(&queue_iter))) {
05929       ao2_lock(q);
05930 
05931       /* List queue properties */
05932       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
05933          /* Reset the necessary local variables if no queuefilter is set*/
05934          qmemcount = 0;
05935          qmemavail = 0;
05936          qchancount = 0;
05937          qlongestholdtime = 0;
05938 
05939          /* List Queue Members */
05940          mem_iter = ao2_iterator_init(q->members, 0);
05941          while ((mem = ao2_iterator_next(&mem_iter))) {
05942             if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
05943                ++qmemcount;
05944                if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) {
05945                   ++qmemavail;
05946                }
05947             }
05948             ao2_ref(mem, -1);
05949          }
05950          ao2_iterator_destroy(&mem_iter);
05951          for (qe = q->head; qe; qe = qe->next) {
05952             if ((now - qe->start) > qlongestholdtime) {
05953                qlongestholdtime = now - qe->start;
05954             }
05955             ++qchancount;
05956          }
05957          astman_append(s, "Event: QueueSummary\r\n"
05958             "Queue: %s\r\n"
05959             "LoggedIn: %d\r\n"
05960             "Available: %d\r\n"
05961             "Callers: %d\r\n" 
05962             "HoldTime: %d\r\n"
05963             "LongestHoldTime: %d\r\n"
05964             "%s"
05965             "\r\n",
05966             q->name, qmemcount, qmemavail, qchancount, q->holdtime, qlongestholdtime, idText);
05967       }
05968       ao2_unlock(q);
05969       queue_unref(q);
05970    }
05971    ao2_iterator_destroy(&queue_iter);
05972    astman_append(s,
05973       "Event: QueueSummaryComplete\r\n"
05974       "%s"
05975       "\r\n", idText);
05976 
05977    return RESULT_SUCCESS;
05978 }

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

Definition at line 6127 of file app_queue.c.

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

Referenced by load_module().

06128 {
06129    const char *queuename, *interface;
06130 
06131    queuename = astman_get_header(m, "Queue");
06132    interface = astman_get_header(m, "Interface");
06133 
06134    if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
06135       astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
06136       return 0;
06137    }
06138 
06139    switch (remove_from_queue(queuename, interface)) {
06140    case RES_OKAY:
06141       ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
06142       astman_send_ack(s, m, "Removed interface from queue");
06143       break;
06144    case RES_EXISTS:
06145       astman_send_error(s, m, "Unable to remove interface: Not there");
06146       break;
06147    case RES_NOSUCHQUEUE:
06148       astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
06149       break;
06150    case RES_OUTOFMEMORY:
06151       astman_send_error(s, m, "Out of memory");
06152       break;
06153    case RES_NOT_DYNAMIC:
06154       astman_send_error(s, m, "Member not dynamic");
06155       break;
06156    }
06157 
06158    return 0;
06159 }

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

Definition at line 912 of file app_queue.c.

References CMP_MATCH, and member::interface.

Referenced by init_queue().

00913 {
00914    struct member *mem1 = obj1, *mem2 = obj2;
00915    return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH;
00916 }

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

Definition at line 900 of file app_queue.c.

References compress_char(), and member::interface.

Referenced by init_queue().

00901 {
00902    const struct member *mem = obj;
00903    const char *chname = strchr(mem->interface, '/');
00904    int ret = 0, i;
00905    if (!chname)
00906       chname = mem->interface;
00907    for (i = 0; i < 5 && chname[i]; i++)
00908       ret += compress_char(chname[i]) << (i * 6);
00909    return ret;
00910 }

static int num_available_members ( struct call_queue q  )  [static]

Get the number of members available to accept a call.

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

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

Referenced by compare_weight(), and is_our_turn().

02071 {
02072    struct member *mem;
02073    int avl = 0;
02074    struct ao2_iterator mem_iter;
02075 
02076    mem_iter = ao2_iterator_init(q->members, 0);
02077    while ((mem = ao2_iterator_next(&mem_iter))) {
02078       switch (mem->status) {
02079       case AST_DEVICE_INUSE:
02080          if (!q->ringinuse)
02081             break;
02082          /* else fall through */
02083       case AST_DEVICE_NOT_INUSE:
02084       case AST_DEVICE_UNKNOWN:
02085          if (!mem->paused) {
02086             avl++;
02087          }
02088          break;
02089       }
02090       ao2_ref(mem, -1);
02091 
02092       /* If autofill is not enabled or if the queue's strategy is ringall, then
02093        * we really don't care about the number of available members so much as we
02094        * do that there is at least one available.
02095        *
02096        * In fact, we purposely will return from this function stating that only
02097        * one member is available if either of those conditions hold. That way,
02098        * functions which determine what action to take based on the number of available
02099        * members will operate properly. The reasoning is that even if multiple
02100        * members are available, only the head caller can actually be serviced.
02101        */
02102       if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
02103          break;
02104       }
02105    }
02106    ao2_iterator_destroy(&mem_iter);
02107 
02108    return avl;
02109 }

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

Definition at line 1795 of file app_queue.c.

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

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

01796 {
01797    int res;
01798 
01799    if (ast_strlen_zero(filename)) {
01800       return 0;
01801    }
01802 
01803    ast_stopstream(chan);
01804 
01805    res = ast_streamfile(chan, filename, chan->language);
01806    if (!res)
01807       res = ast_waitstream(chan, AST_DIGIT_ANY);
01808 
01809    ast_stopstream(chan);
01810 
01811    return res;
01812 }

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

PauseQueueMember application.

Definition at line 4473 of file app_queue.c.

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

Referenced by load_module().

04474 {
04475    char *parse;
04476    AST_DECLARE_APP_ARGS(args,
04477       AST_APP_ARG(queuename);
04478       AST_APP_ARG(interface);
04479       AST_APP_ARG(options);
04480       AST_APP_ARG(reason);
04481    );
04482 
04483    if (ast_strlen_zero(data)) {
04484       ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
04485       return -1;
04486    }
04487 
04488    parse = ast_strdupa(data);
04489 
04490    AST_STANDARD_APP_ARGS(args, parse);
04491 
04492    if (ast_strlen_zero(args.interface)) {
04493       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
04494       return -1;
04495    }
04496 
04497    if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
04498       ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
04499       pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
04500       return 0;
04501    }
04502 
04503    pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
04504 
04505    return 0;
04506 }

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

QueueLog application.

Definition at line 4663 of file app_queue.c.

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

Referenced by load_module().

04664 {
04665    char *parse;
04666 
04667    AST_DECLARE_APP_ARGS(args,
04668       AST_APP_ARG(queuename);
04669       AST_APP_ARG(uniqueid);
04670       AST_APP_ARG(membername);
04671       AST_APP_ARG(event);
04672       AST_APP_ARG(params);
04673    );
04674 
04675    if (ast_strlen_zero(data)) {
04676       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
04677       return -1;
04678    }
04679 
04680    parse = ast_strdupa(data);
04681 
04682    AST_STANDARD_APP_ARGS(args, parse);
04683 
04684    if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
04685        || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
04686       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
04687       return -1;
04688    }
04689 
04690    ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 
04691       "%s", args.params ? args.params : "");
04692 
04693    return 0;
04694 }

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

Definition at line 576 of file app_queue.c.

References CMP_MATCH, and call_queue::name.

Referenced by load_module().

00577 {
00578    struct call_queue *q = obj, *q2 = arg;
00579    return !strcasecmp(q->name, q2->name) ? CMP_MATCH : 0;
00580 }

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

The starting point for all queue calls.

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

Definition at line 4741 of file app_queue.c.

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

Referenced by load_module().

04742 {
04743    int res=-1;
04744    int ringing=0;
04745    const char *user_priority;
04746    const char *max_penalty_str;
04747    const char *min_penalty_str;
04748    int prio;
04749    int qcontinue = 0;
04750    int max_penalty, min_penalty;
04751    enum queue_result reason = QUEUE_UNKNOWN;
04752    /* whether to exit Queue application after the timeout hits */
04753    int tries = 0;
04754    int noption = 0;
04755    char *parse;
04756    int makeannouncement = 0;
04757    AST_DECLARE_APP_ARGS(args,
04758       AST_APP_ARG(queuename);
04759       AST_APP_ARG(options);
04760       AST_APP_ARG(url);
04761       AST_APP_ARG(announceoverride);
04762       AST_APP_ARG(queuetimeoutstr);
04763       AST_APP_ARG(agi);
04764       AST_APP_ARG(macro);
04765       AST_APP_ARG(gosub);
04766       AST_APP_ARG(rule);
04767    );
04768    /* Our queue entry */
04769    struct queue_ent qe;
04770    
04771    if (ast_strlen_zero(data)) {
04772       ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule]]]]]]]]\n");
04773       return -1;
04774    }
04775    
04776    parse = ast_strdupa(data);
04777    AST_STANDARD_APP_ARGS(args, parse);
04778 
04779    /* Setup our queue entry */
04780    memset(&qe, 0, sizeof(qe));
04781    qe.start = time(NULL);
04782 
04783    /* set the expire time based on the supplied timeout; */
04784    if (!ast_strlen_zero(args.queuetimeoutstr))
04785       qe.expire = qe.start + atoi(args.queuetimeoutstr);
04786    else
04787       qe.expire = 0;
04788 
04789    /* Get the priority from the variable ${QUEUE_PRIO} */
04790    user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
04791    if (user_priority) {
04792       if (sscanf(user_priority, "%30d", &prio) == 1) {
04793          ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio);
04794       } else {
04795          ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
04796             user_priority, chan->name);
04797          prio = 0;
04798       }
04799    } else {
04800       ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
04801       prio = 0;
04802    }
04803 
04804    /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
04805 
04806    if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
04807       if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
04808          ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty);
04809       } else {
04810          ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
04811             max_penalty_str, chan->name);
04812          max_penalty = 0;
04813       }
04814    } else {
04815       max_penalty = 0;
04816    }
04817 
04818    if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
04819       if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
04820          ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty);
04821       } else {
04822          ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
04823             min_penalty_str, chan->name);
04824          min_penalty = 0;
04825       }
04826    } else {
04827       min_penalty = 0;
04828    }
04829 
04830    if (args.options && (strchr(args.options, 'r')))
04831       ringing = 1;
04832 
04833    if (args.options && (strchr(args.options, 'c')))
04834       qcontinue = 1;
04835 
04836    ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
04837       args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
04838 
04839    qe.chan = chan;
04840    qe.prio = prio;
04841    qe.max_penalty = max_penalty;
04842    qe.min_penalty = min_penalty;
04843    qe.last_pos_said = 0;
04844    qe.last_pos = 0;
04845    qe.last_periodic_announce_time = time(NULL);
04846    qe.last_periodic_announce_sound = 0;
04847    qe.valid_digits = 0;
04848    if (join_queue(args.queuename, &qe, &reason, args.rule)) {
04849       ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
04850       set_queue_result(chan, reason);
04851       return 0;
04852    }
04853    ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
04854       S_OR(chan->cid.cid_num, ""));
04855 check_turns:
04856    if (ringing) {
04857       ast_indicate(chan, AST_CONTROL_RINGING);
04858    } else {
04859       ast_moh_start(chan, qe.moh, NULL);
04860    }
04861 
04862    /* This is the wait loop for callers 2 through maxlen */
04863    res = wait_our_turn(&qe, ringing, &reason);
04864    if (res) {
04865       goto stop;
04866    }
04867 
04868    makeannouncement = 0;
04869 
04870    for (;;) {
04871       /* This is the wait loop for the head caller*/
04872       /* To exit, they may get their call answered; */
04873       /* they may dial a digit from the queue context; */
04874       /* or, they may timeout. */
04875 
04876       enum queue_member_status stat = QUEUE_NORMAL;
04877       int exit = 0;
04878 
04879       /* Leave if we have exceeded our queuetimeout */
04880       if (qe.expire && (time(NULL) >= qe.expire)) {
04881          record_abandoned(&qe);
04882          ast_cdr_noanswer(qe.chan->cdr);
04883          reason = QUEUE_TIMEOUT;
04884          res = 0;
04885          ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 
04886             qe.pos, qe.opos, (long) time(NULL) - qe.start);
04887          break;
04888       }
04889 
04890       if (makeannouncement) {
04891          /* Make a position announcement, if enabled */
04892          if (qe.parent->announcefrequency)
04893             if ((res = say_position(&qe,ringing)))
04894                goto stop;
04895       }
04896       makeannouncement = 1;
04897 
04898       /* Make a periodic announcement, if enabled */
04899       if (qe.parent->periodicannouncefrequency)
04900          if ((res = say_periodic_announcement(&qe,ringing)))
04901             goto stop;
04902    
04903       /* Leave if we have exceeded our queuetimeout */
04904       if (qe.expire && (time(NULL) >= qe.expire)) {
04905          record_abandoned(&qe);
04906          ast_cdr_noanswer(qe.chan->cdr);
04907          reason = QUEUE_TIMEOUT;
04908          res = 0;
04909          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04910          break;
04911       }
04912 
04913       /* see if we need to move to the next penalty level for this queue */
04914       while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
04915          update_qe_rule(&qe);
04916       }
04917 
04918       /* Try calling all queue members for 'timeout' seconds */
04919       res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
04920       if (res) {
04921          goto stop;
04922       }
04923 
04924       /* exit after 'timeout' cycle if 'n' option enabled */
04925       if (noption && tries >= qe.parent->membercount) {
04926          ast_verb(3, "Exiting on time-out cycle\n");
04927          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04928          record_abandoned(&qe);
04929          ast_cdr_noanswer(qe.chan->cdr);
04930          reason = QUEUE_TIMEOUT;
04931          res = 0;
04932          break;
04933       }
04934 
04935       for (; !exit || qe.pr; update_qe_rule(&qe)) {
04936          stat = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty);
04937 
04938          if (!qe.pr || stat == QUEUE_NORMAL) {
04939             break;
04940          }
04941 
04942          if ((qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) ||
04943                ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) ||
04944                ((qe.parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS))) {
04945             continue;
04946          } else {
04947             exit = 1;
04948          }
04949       }
04950 
04951       /* leave the queue if no agents, if enabled */
04952       if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
04953          record_abandoned(&qe);
04954          reason = QUEUE_LEAVEEMPTY;
04955          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
04956          res = 0;
04957          break;
04958       }
04959 
04960       /* leave the queue if no reachable agents, if enabled */
04961       if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) {
04962          record_abandoned(&qe);
04963          reason = QUEUE_LEAVEUNAVAIL;
04964          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
04965          res = 0;
04966          break;
04967       }
04968       if ((qe.parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
04969          record_abandoned(&qe);
04970          reason = QUEUE_LEAVEUNAVAIL;
04971          res = 0;
04972          break;
04973       }
04974 
04975       /* Leave if we have exceeded our queuetimeout */
04976       if (qe.expire && (time(NULL) >= qe.expire)) {
04977          record_abandoned(&qe);
04978          ast_cdr_noanswer(qe.chan->cdr);
04979          reason = QUEUE_TIMEOUT;
04980          res = 0;
04981          ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start);
04982          break;
04983       }
04984 
04985       /* If using dynamic realtime members, we should regenerate the member list for this queue */
04986       update_realtime_members(qe.parent);
04987       /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
04988       res = wait_a_bit(&qe);
04989       if (res)
04990          goto stop;
04991 
04992       /* Since this is a priority queue and
04993        * it is not sure that we are still at the head
04994        * of the queue, go and check for our turn again.
04995        */
04996       if (!is_our_turn(&qe)) {
04997          ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name);
04998          goto check_turns;
04999       }
05000    }
05001 
05002 stop:
05003    if (res) {
05004       if (res < 0) {
05005          if (!qe.handled) {
05006             record_abandoned(&qe);
05007             ast_cdr_noanswer(qe.chan->cdr);
05008             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
05009                "%d|%d|%ld", qe.pos, qe.opos,
05010                (long) time(NULL) - qe.start);
05011             res = -1;
05012          } else if (qcontinue) {
05013             reason = QUEUE_CONTINUE;
05014             res = 0;
05015          }
05016       } else if (qe.valid_digits) {
05017          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
05018             "%s|%d", qe.digits, qe.pos);
05019       }
05020    }
05021 
05022    /* Don't allow return code > 0 */
05023    if (res >= 0) {
05024       res = 0; 
05025       if (ringing) {
05026          ast_indicate(chan, -1);
05027       } else {
05028          ast_moh_stop(chan);
05029       }        
05030       ast_stopstream(chan);
05031    }
05032 
05033    set_queue_variables(qe.parent, qe.chan);
05034 
05035    leave_queue(&qe);
05036    if (reason != QUEUE_UNKNOWN)
05037       set_queue_result(chan, reason);
05038 
05039    return res;
05040 }

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

Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.

Definition at line 5274 of file app_queue.c.

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

05275 {
05276    int penalty;
05277    AST_DECLARE_APP_ARGS(args,
05278       AST_APP_ARG(queuename);
05279       AST_APP_ARG(interface);
05280         );
05281    /* Make sure the returned value on error is NULL. */
05282    buf[0] = '\0';
05283 
05284    if (ast_strlen_zero(data)) {
05285       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
05286       return -1;
05287    }
05288 
05289    AST_STANDARD_APP_ARGS(args, data);
05290 
05291    if (args.argc < 2) {
05292       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
05293       return -1;
05294    }
05295 
05296    penalty = get_member_penalty (args.queuename, args.interface);
05297    
05298    if (penalty >= 0) /* remember that buf is already '\0' */
05299       snprintf (buf, len, "%d", penalty);
05300 
05301    return 0;
05302 }

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

Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.

Definition at line 5305 of file app_queue.c.

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

05306 {
05307    int penalty;
05308    AST_DECLARE_APP_ARGS(args,
05309       AST_APP_ARG(queuename);
05310       AST_APP_ARG(interface);
05311    );
05312 
05313    if (ast_strlen_zero(data)) {
05314       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
05315       return -1;
05316    }
05317 
05318    AST_STANDARD_APP_ARGS(args, data);
05319 
05320    if (args.argc < 2) {
05321       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
05322       return -1;
05323    }
05324 
05325    penalty = atoi(value);
05326 
05327    if (ast_strlen_zero(args.interface)) {
05328       ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
05329       return -1;
05330    }
05331 
05332    /* if queuename = NULL then penalty will be set for interface in all the queues. */
05333    if (set_member_penalty(args.queuename, args.interface, penalty)) {
05334       ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
05335       return -1;
05336    }
05337 
05338    return 0;
05339 }

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

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

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

Definition at line 5093 of file app_queue.c.

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

05094 {
05095    int count = 0;
05096    struct member *m;
05097    struct ao2_iterator mem_iter;
05098    struct call_queue *q;
05099    char *option;
05100 
05101    if (ast_strlen_zero(data)) {
05102       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
05103       return -1;
05104    }
05105 
05106    if ((option = strchr(data, ',')))
05107       *option++ = '\0';
05108    else
05109       option = "logged";
05110    if ((q = load_realtime_queue(data))) {
05111       ao2_lock(q);
05112       if (!strcasecmp(option, "logged")) {
05113          mem_iter = ao2_iterator_init(q->members, 0);
05114          while ((m = ao2_iterator_next(&mem_iter))) {
05115             /* Count the agents who are logged in and presently answering calls */
05116             if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
05117                count++;
05118             }
05119             ao2_ref(m, -1);
05120          }
05121          ao2_iterator_destroy(&mem_iter);
05122       } else if (!strcasecmp(option, "free")) {
05123          mem_iter = ao2_iterator_init(q->members, 0);
05124          while ((m = ao2_iterator_next(&mem_iter))) {
05125             /* Count the agents who are logged in and presently answering calls */
05126             if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
05127                count++;
05128             }
05129             ao2_ref(m, -1);
05130          }
05131          ao2_iterator_destroy(&mem_iter);
05132       } else /* must be "count" */
05133          count = q->membercount;
05134       ao2_unlock(q);
05135       queue_unref(q);
05136    } else
05137       ast_log(LOG_WARNING, "queue %s was not found\n", data);
05138 
05139    snprintf(buf, len, "%d", count);
05140 
05141    return 0;
05142 }

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

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

Return values:
number of members
-1 on error

Definition at line 5149 of file app_queue.c.

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

05150 {
05151    int count = 0;
05152    struct member *m;
05153    struct call_queue *q;
05154    struct ao2_iterator mem_iter;
05155    static int depflag = 1;
05156 
05157    if (depflag) {
05158       depflag = 0;
05159       ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
05160    }
05161 
05162    if (ast_strlen_zero(data)) {
05163       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
05164       return -1;
05165    }
05166    
05167    if ((q = load_realtime_queue(data))) {
05168       ao2_lock(q);
05169       mem_iter = ao2_iterator_init(q->members, 0);
05170       while ((m = ao2_iterator_next(&mem_iter))) {
05171          /* Count the agents who are logged in and presently answering calls */
05172          if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
05173             count++;
05174          }
05175          ao2_ref(m, -1);
05176       }
05177       ao2_iterator_destroy(&mem_iter);
05178       ao2_unlock(q);
05179       queue_unref(q);
05180    } else
05181       ast_log(LOG_WARNING, "queue %s was not found\n", data);
05182 
05183    snprintf(buf, len, "%d", count);
05184 
05185    return 0;
05186 }

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

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

Definition at line 5225 of file app_queue.c.

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

05226 {
05227    struct call_queue *q, tmpq = {
05228       .name = data,  
05229    };
05230    struct member *m;
05231 
05232    /* Ensure an otherwise empty list doesn't return garbage */
05233    buf[0] = '\0';
05234 
05235    if (ast_strlen_zero(data)) {
05236       ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
05237       return -1;
05238    }
05239 
05240    if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
05241       int buflen = 0, count = 0;
05242       struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
05243 
05244       ao2_lock(q);
05245       while ((m = ao2_iterator_next(&mem_iter))) {
05246          /* strcat() is always faster than printf() */
05247          if (count++) {
05248             strncat(buf + buflen, ",", len - buflen - 1);
05249             buflen++;
05250          }
05251          strncat(buf + buflen, m->interface, len - buflen - 1);
05252          buflen += strlen(m->interface);
05253          /* Safeguard against overflow (negative length) */
05254          if (buflen >= len - 2) {
05255             ao2_ref(m, -1);
05256             ast_log(LOG_WARNING, "Truncating list\n");
05257             break;
05258          }
05259          ao2_ref(m, -1);
05260       }
05261       ao2_iterator_destroy(&mem_iter);
05262       ao2_unlock(q);
05263       queue_unref(q);
05264    } else
05265       ast_log(LOG_WARNING, "queue %s was not found\n", data);
05266 
05267    /* We should already be terminated, but let's make sure. */
05268    buf[len - 1] = '\0';
05269 
05270    return 0;
05271 }

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

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

Definition at line 5189 of file app_queue.c.

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

05190 {
05191    int count = 0;
05192    struct call_queue *q, tmpq = {
05193       .name = data,  
05194    };
05195    struct ast_variable *var = NULL;
05196 
05197    buf[0] = '\0';
05198    
05199    if (ast_strlen_zero(data)) {
05200       ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
05201       return -1;
05202    }
05203 
05204    if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
05205       ao2_lock(q);
05206       count = q->count;
05207       ao2_unlock(q);
05208       queue_unref(q);
05209    } else if ((var = ast_load_realtime("queues", "name", data, NULL))) {
05210       /* if the queue is realtime but was not found in memory, this
05211        * means that the queue had been deleted from memory since it was 
05212        * "dead." This means it has a 0 waiting count
05213        */
05214       count = 0;
05215       ast_variables_destroy(var);
05216    } else
05217       ast_log(LOG_WARNING, "queue %s was not found\n", data);
05218 
05219    snprintf(buf, len, "%d", count);
05220 
05221    return 0;
05222 }

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

create interface var with all queue details.

Return values:
0 on success
-1 on error

Definition at line 5047 of file app_queue.c.

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

05048 {
05049    int res = -1;
05050    struct call_queue *q, tmpq = {
05051       .name = data,  
05052    };
05053 
05054    char interfacevar[256]="";
05055         float sl = 0;
05056 
05057    if (ast_strlen_zero(data)) {
05058       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
05059       return -1;
05060    }
05061 
05062    if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
05063       ao2_lock(q);
05064          if (q->setqueuevar) {
05065               sl = 0;
05066          res = 0;
05067 
05068               if (q->callscompleted > 0)
05069                       sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
05070 
05071               snprintf(interfacevar, sizeof(interfacevar),
05072                      "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
05073                       q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, q->callsabandoned,  q->servicelevel, sl);
05074 
05075               pbx_builtin_setvar_multiple(chan, interfacevar);
05076            }
05077 
05078       ao2_unlock(q);
05079       queue_unref(q);
05080    } else
05081       ast_log(LOG_WARNING, "queue %s was not found\n", data);
05082 
05083    snprintf(buf, len, "%d", res);
05084 
05085    return 0;
05086 }

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

Definition at line 569 of file app_queue.c.

References ast_str_case_hash(), and call_queue::name.

Referenced by load_module().

00570 {
00571    const struct call_queue *q = obj;
00572 
00573    return ast_str_case_hash(q->name);
00574 }

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

Definition at line 582 of file app_queue.c.

References ao2_ref().

Referenced by leave_queue(), and try_calling().

00583 {
00584    ao2_ref(q, 1);
00585    return q;
00586 }

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

Configure a queue parameter.

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

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

Definition at line 1169 of file app_queue.c.

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

Referenced by find_queue_by_name_rt(), and reload_queues().

01170 {
01171    if (!strcasecmp(param, "musicclass") || 
01172       !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
01173       ast_string_field_set(q, moh, val);
01174    } else if (!strcasecmp(param, "announce")) {
01175       ast_string_field_set(q, announce, val);
01176    } else if (!strcasecmp(param, "context")) {
01177       ast_string_field_set(q, context, val);
01178    } else if (!strcasecmp(param, "timeout")) {
01179       q->timeout = atoi(val);
01180       if (q->timeout < 0)
01181          q->timeout = DEFAULT_TIMEOUT;
01182    } else if (!strcasecmp(param, "ringinuse")) {
01183       q->ringinuse = ast_true(val);
01184    } else if (!strcasecmp(param, "setinterfacevar")) {
01185       q->setinterfacevar = ast_true(val);
01186    } else if (!strcasecmp(param, "setqueuevar")) {
01187       q->setqueuevar = ast_true(val);
01188    } else if (!strcasecmp(param, "setqueueentryvar")) {
01189       q->setqueueentryvar = ast_true(val);
01190    } else if (!strcasecmp(param, "monitor-format")) {
01191       ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
01192    } else if (!strcasecmp(param, "membermacro")) {
01193       ast_string_field_set(q, membermacro, val);
01194    } else if (!strcasecmp(param, "membergosub")) {
01195       ast_string_field_set(q, membergosub, val);
01196    } else if (!strcasecmp(param, "queue-youarenext")) {
01197       ast_string_field_set(q, sound_next, val);
01198    } else if (!strcasecmp(param, "queue-thereare")) {
01199       ast_string_field_set(q, sound_thereare, val);
01200    } else if (!strcasecmp(param, "queue-callswaiting")) {
01201       ast_string_field_set(q, sound_calls, val);
01202    } else if (!strcasecmp(param, "queue-holdtime")) {
01203       ast_string_field_set(q, sound_holdtime, val);
01204    } else if (!strcasecmp(param, "queue-minutes")) {
01205       ast_string_field_set(q, sound_minutes, val);
01206    } else if (!strcasecmp(param, "queue-minute")) {
01207       ast_string_field_set(q, sound_minute, val);
01208    } else if (!strcasecmp(param, "queue-seconds")) {
01209       ast_string_field_set(q, sound_seconds, val);
01210    } else if (!strcasecmp(param, "queue-thankyou")) {
01211       ast_string_field_set(q, sound_thanks, val);
01212    } else if (!strcasecmp(param, "queue-callerannounce")) {
01213       ast_string_field_set(q, sound_callerannounce, val);
01214    } else if (!strcasecmp(param, "queue-reporthold")) {
01215       ast_string_field_set(q, sound_reporthold, val);
01216    } else if (!strcasecmp(param, "announce-frequency")) {
01217       q->announcefrequency = atoi(val);
01218    } else if (!strcasecmp(param, "min-announce-frequency")) {
01219       q->minannouncefrequency = atoi(val);
01220       ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
01221    } else if (!strcasecmp(param, "announce-round-seconds")) {
01222       q->roundingseconds = atoi(val);
01223       /* Rounding to any other values just doesn't make sense... */
01224       if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
01225          || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
01226          if (linenum >= 0) {
01227             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01228                "using 0 instead for queue '%s' at line %d of queues.conf\n",
01229                val, param, q->name, linenum);
01230          } else {
01231             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01232                "using 0 instead for queue '%s'\n", val, param, q->name);
01233          }
01234          q->roundingseconds=0;
01235       }
01236    } else if (!strcasecmp(param, "announce-holdtime")) {
01237       if (!strcasecmp(val, "once"))
01238          q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
01239       else if (ast_true(val))
01240          q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
01241       else
01242          q->announceholdtime = 0;
01243    } else if (!strcasecmp(param, "announce-position")) {
01244       q->announceposition = ast_true(val);
01245    } else if (!strcasecmp(param, "periodic-announce")) {
01246       if (strchr(val, ',')) {
01247          char *s, *buf = ast_strdupa(val);
01248          unsigned int i = 0;
01249 
01250          while ((s = strsep(&buf, ",|"))) {
01251             if (!q->sound_periodicannounce[i])
01252                q->sound_periodicannounce[i] = ast_str_create(16);
01253             ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
01254             i++;
01255             if (i == MAX_PERIODIC_ANNOUNCEMENTS)
01256                break;
01257          }
01258       } else {
01259          ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
01260       }
01261    } else if (!strcasecmp(param, "periodic-announce-frequency")) {
01262       q->periodicannouncefrequency = atoi(val);
01263    } else if (!strcasecmp(param, "retry")) {
01264       q->retry = atoi(val);
01265       if (q->retry <= 0)
01266          q->retry = DEFAULT_RETRY;
01267    } else if (!strcasecmp(param, "wrapuptime")) {
01268       q->wrapuptime = atoi(val);
01269    } else if (!strcasecmp(param, "autofill")) {
01270       q->autofill = ast_true(val);
01271    } else if (!strcasecmp(param, "monitor-type")) {
01272       if (!strcasecmp(val, "mixmonitor"))
01273          q->montype = 1;
01274    } else if (!strcasecmp(param, "autopause")) {
01275       q->autopause = ast_true(val);
01276    } else if (!strcasecmp(param, "maxlen")) {
01277       q->maxlen = atoi(val);
01278       if (q->maxlen < 0)
01279          q->maxlen = 0;
01280    } else if (!strcasecmp(param, "servicelevel")) {
01281       q->servicelevel= atoi(val);
01282    } else if (!strcasecmp(param, "strategy")) {
01283       int strategy;
01284 
01285       /* We are a static queue and already have set this, no need to do it again */
01286       if (failunknown) {
01287          return;
01288       }
01289       strategy = strat2int(val);
01290       if (strategy < 0) {
01291          ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
01292             val, q->name);
01293          q->strategy = QUEUE_STRATEGY_RINGALL;
01294       }
01295       if (strategy == q->strategy) {
01296          return;
01297       }
01298       if (strategy == QUEUE_STRATEGY_LINEAR) {
01299          ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
01300          return;
01301       }
01302       q->strategy = strategy;
01303    } else if (!strcasecmp(param, "joinempty")) {
01304       if (!strcasecmp(val, "loose"))
01305          q->joinempty = QUEUE_EMPTY_LOOSE;
01306       else if (!strcasecmp(val, "strict"))
01307          q->joinempty = QUEUE_EMPTY_STRICT;
01308       else if (ast_true(val))
01309          q->joinempty = QUEUE_EMPTY_NORMAL;
01310       else
01311          q->joinempty = 0;
01312    } else if (!strcasecmp(param, "leavewhenempty")) {
01313       if (!strcasecmp(val, "loose"))
01314          q->leavewhenempty = QUEUE_EMPTY_LOOSE;
01315       else if (!strcasecmp(val, "strict"))
01316          q->leavewhenempty = QUEUE_EMPTY_STRICT;
01317       else if (ast_true(val))
01318          q->leavewhenempty = QUEUE_EMPTY_NORMAL;
01319       else
01320          q->leavewhenempty = 0;
01321    } else if (!strcasecmp(param, "eventmemberstatus")) {
01322       q->maskmemberstatus = !ast_true(val);
01323    } else if (!strcasecmp(param, "eventwhencalled")) {
01324       if (!strcasecmp(val, "vars")) {
01325          q->eventwhencalled = QUEUE_EVENT_VARIABLES;
01326       } else {
01327          q->eventwhencalled = ast_true(val) ? 1 : 0;
01328       }
01329    } else if (!strcasecmp(param, "reportholdtime")) {
01330       q->reportholdtime = ast_true(val);
01331    } else if (!strcasecmp(param, "memberdelay")) {
01332       q->memberdelay = atoi(val);
01333    } else if (!strcasecmp(param, "weight")) {
01334       q->weight = atoi(val);
01335       if (q->weight)
01336          use_weight++;
01337       /* With Realtime queues, if the last queue using weights is deleted in realtime,
01338          we will not see any effect on use_weight until next reload. */
01339    } else if (!strcasecmp(param, "timeoutrestart")) {
01340       q->timeoutrestart = ast_true(val);
01341    } else if (!strcasecmp(param, "defaultrule")) {
01342       ast_string_field_set(q, defaultrule, val);
01343    } else if (failunknown) {
01344       if (linenum >= 0) {
01345          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
01346             q->name, param, linenum);
01347       } else {
01348          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
01349       }
01350    }
01351 }

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

Definition at line 5853 of file app_queue.c.

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

05854 {
05855    switch ( cmd ) {
05856    case CLI_INIT:
05857       e->command = "queue show";
05858       e->usage =
05859          "Usage: queue show\n"
05860          "       Provides summary information on a specified queue.\n";
05861       return NULL;
05862    case CLI_GENERATE:
05863       return complete_queue_show(a->line, a->word, a->pos, a->n); 
05864    }
05865 
05866    return __queues_show(NULL, a->fd, a->argc, a->argv);
05867 }

static void queue_transfer_destroy ( void *  data  )  [static]

Definition at line 3165 of file app_queue.c.

References ast_free.

03166 {
03167    struct queue_transfer_ds *qtds = data;
03168    ast_free(qtds);
03169 }

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

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

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

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

Definition at line 3188 of file app_queue.c.

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

03189 {
03190    struct queue_transfer_ds *qtds = data;
03191    struct queue_ent *qe = qtds->qe;
03192    struct member *member = qtds->member;
03193    time_t callstart = qtds->starttime;
03194    int callcompletedinsl = qtds->callcompletedinsl;
03195    struct ast_datastore *datastore;
03196 
03197    ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
03198             new_chan->exten, new_chan->context, (long) (callstart - qe->start),
03199             (long) (time(NULL) - callstart));
03200 
03201    update_queue(qe->parent, member, callcompletedinsl);
03202    
03203    /* No need to lock the channels because they are already locked in ast_do_masquerade */
03204    if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
03205       ast_channel_datastore_remove(old_chan, datastore);
03206    } else {
03207       ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
03208    }
03209 }

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

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

Definition at line 1970 of file app_queue.c.

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

Referenced by try_calling().

01971 {
01972    int oldvalue;
01973 
01974    /* Calculate holdtime using an exponential average */
01975    /* Thanks to SRT for this contribution */
01976    /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
01977 
01978    ao2_lock(qe->parent);
01979    oldvalue = qe->parent->holdtime;
01980    qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
01981    ao2_unlock(qe->parent);
01982 }

static void record_abandoned ( struct queue_ent qe  )  [static]

Record that a caller gave up on waiting in queue.

Definition at line 2519 of file app_queue.c.

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

Referenced by queue_exec(), and try_calling().

02520 {
02521    ao2_lock(qe->parent);
02522    set_queue_variables(qe->parent, qe->chan);
02523    manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
02524       "Queue: %s\r\n"
02525       "Uniqueid: %s\r\n"
02526       "Position: %d\r\n"
02527       "OriginalPosition: %d\r\n"
02528       "HoldTime: %d\r\n",
02529       qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
02530 
02531    qe->parent->callsabandoned++;
02532    ao2_unlock(qe->parent);
02533 }

static int reload ( void   )  [static]

Definition at line 6757 of file app_queue.c.

References reload_queues().

06758 {
06759    reload_queues(1);
06760    return 0;
06761 }

static void reload_queue_members ( void   )  [static]

Reload dynamic queue members persisted into the astdb.

Definition at line 4376 of file app_queue.c.

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

Referenced by load_module().

04377 {
04378    char *cur_ptr;
04379    const char *queue_name;
04380    char *member;
04381    char *interface;
04382    char *membername = NULL;
04383    char *state_interface;
04384    char *penalty_tok;
04385    int penalty = 0;
04386    char *paused_tok;
04387    int paused = 0;
04388    struct ast_db_entry *db_tree;
04389    struct ast_db_entry *entry;
04390    struct call_queue *cur_queue;
04391    char queue_data[PM_MAX_LEN];
04392 
04393    ao2_lock(queues);
04394 
04395    /* Each key in 'pm_family' is the name of a queue */
04396    db_tree = ast_db_gettree(pm_family, NULL);
04397    for (entry = db_tree; entry; entry = entry->next) {
04398 
04399       queue_name = entry->key + strlen(pm_family) + 2;
04400 
04401       {
04402          struct call_queue tmpq = {
04403             .name = queue_name,
04404          };
04405          cur_queue = ao2_find(queues, &tmpq, OBJ_POINTER);
04406       }  
04407 
04408       if (!cur_queue)
04409          cur_queue = load_realtime_queue(queue_name);
04410 
04411       if (!cur_queue) {
04412          /* If the queue no longer exists, remove it from the
04413           * database */
04414          ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
04415          ast_db_del(pm_family, queue_name);
04416          continue;
04417       } 
04418 
04419       if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) {
04420          queue_unref(cur_queue);
04421          continue;
04422       }
04423 
04424       cur_ptr = queue_data;
04425       while ((member = strsep(&cur_ptr, ",|"))) {
04426          if (ast_strlen_zero(member))
04427             continue;
04428 
04429          interface = strsep(&member, ";");
04430          penalty_tok = strsep(&member, ";");
04431          paused_tok = strsep(&member, ";");
04432          membername = strsep(&member, ";");
04433          state_interface = strsep(&member, ";");
04434 
04435          if (!penalty_tok) {
04436             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
04437             break;
04438          }
04439          penalty = strtol(penalty_tok, NULL, 10);
04440          if (errno == ERANGE) {
04441             ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
04442             break;
04443          }
04444          
04445          if (!paused_tok) {
04446             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
04447             break;
04448          }
04449          paused = strtol(paused_tok, NULL, 10);
04450          if ((errno == ERANGE) || paused < 0 || paused > 1) {
04451             ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
04452             break;
04453          }
04454 
04455          ast_debug(1, "Reload Members: Queue: %s  Member: %s  Name: %s  Penalty: %d  Paused: %d\n", queue_name, interface, membername, penalty, paused);
04456          
04457          if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
04458             ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
04459             break;
04460          }
04461       }
04462       queue_unref(cur_queue);
04463    }
04464 
04465    ao2_unlock(queues);
04466    if (db_tree) {
04467       ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
04468       ast_db_freetree(db_tree);
04469    }
04470 }

static int reload_queue_rules ( int  reload  )  [static]

Definition at line 5410 of file app_queue.c.

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

Referenced by handle_queue_rule_reload(), and reload_queues().

05411 {
05412    struct ast_config *cfg;
05413    struct rule_list *rl_iter, *new_rl;
05414    struct penalty_rule *pr_iter;
05415    char *rulecat = NULL;
05416    struct ast_variable *rulevar = NULL;
05417    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
05418    
05419    if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
05420       ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
05421    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
05422       ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
05423       return AST_MODULE_LOAD_SUCCESS;
05424    } else {
05425       AST_LIST_LOCK(&rule_lists);
05426       while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
05427          while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
05428             ast_free(pr_iter);
05429          ast_free(rl_iter);
05430       }
05431       while ((rulecat = ast_category_browse(cfg, rulecat))) {
05432          if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
05433             ast_log(LOG_ERROR, "Memory allocation error while loading queuerules.conf! Aborting!\n");
05434             AST_LIST_UNLOCK(&rule_lists);
05435             return AST_MODULE_LOAD_FAILURE;
05436          } else {
05437             ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
05438             AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
05439             for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
05440                if(!strcasecmp(rulevar->name, "penaltychange")) {
05441                   insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
05442                } else {
05443                   ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
05444                }
05445          }
05446       }
05447       AST_LIST_UNLOCK(&rule_lists);
05448    }
05449 
05450    ast_config_destroy(cfg);
05451 
05452    return AST_MODULE_LOAD_SUCCESS;
05453 }

static int reload_queues ( int  reload  )  [static]

Definition at line 5456 of file app_queue.c.

References add_to_interfaces(), alloc_queue(), ao2_find(), AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), ao2_iterator_next(), ao2_link(), ao2_lock(), ao2_ref(), ao2_unlink(), ao2_unlock(), AST_APP_ARG, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_free, ast_log(), AST_MODULE_LOAD_FAILURE, AST_STANDARD_APP_ARGS, ast_strdup, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), clear_queue(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, create_queue_member(), call_queue::dead, member::delme, member::dynamic, call_queue::found, init_queue(), member::interface, ast_variable::lineno, LOG_NOTICE, LOG_WARNING, call_queue::membercount, call_queue::members, ast_variable::name, call_queue::name, ast_variable::next, OBJ_POINTER, OBJ_UNLINK, parse(), member::paused, queue_set_param(), QUEUE_STRATEGY_RINGALL, queue_unref(), queues, call_queue::realtime, reload_queue_rules(), remove_from_interfaces(), member::state_interface, member::status, strat2int(), call_queue::strategy, ast_variable::value, and var.

Referenced by load_module(), and reload().

05457 {
05458    struct call_queue *q;
05459    struct ast_config *cfg;
05460    char *cat, *tmp;
05461    struct ast_variable *var;
05462    struct member *cur, *newm;
05463    struct ao2_iterator mem_iter;
05464    int new;
05465    const char *general_val = NULL;
05466    char *parse;
05467    char *interface, *state_interface;
05468    char *membername = NULL;
05469    int penalty;
05470    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
05471    struct ao2_iterator queue_iter;
05472    AST_DECLARE_APP_ARGS(args,
05473       AST_APP_ARG(interface);
05474       AST_APP_ARG(penalty);
05475       AST_APP_ARG(membername);
05476       AST_APP_ARG(state_interface);
05477    );
05478 
05479    /*First things first. Let's load queuerules.conf*/
05480    if (reload_queue_rules(reload) == AST_MODULE_LOAD_FAILURE)
05481       return AST_MODULE_LOAD_FAILURE;
05482       
05483    if (!(cfg = ast_config_load("queues.conf", config_flags))) {
05484       ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
05485       return 0;
05486    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
05487       return 0;
05488    ao2_lock(queues);
05489    use_weight=0;
05490    /* Mark all queues as dead for the moment */
05491    queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
05492    while ((q = ao2_iterator_next(&queue_iter))) {
05493       if (!q->realtime) {
05494          q->dead = 1;
05495          q->found = 0;
05496       }
05497       queue_unref(q);
05498    }
05499 
05500    /* Chug through config file */
05501    cat = NULL;
05502    while ((cat = ast_category_browse(cfg, cat)) ) {
05503       if (!strcasecmp(cat, "general")) {  
05504          /* Initialize global settings */
05505          queue_keep_stats = 0;
05506          if ((general_val = ast_variable_retrieve(cfg, "general", "keepstats")))
05507             queue_keep_stats = ast_true(general_val);
05508          queue_persistent_members = 0;
05509          if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
05510             queue_persistent_members = ast_true(general_val);
05511          autofill_default = 0;
05512          if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
05513             autofill_default = ast_true(general_val);
05514          montype_default = 0;
05515          if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
05516             if (!strcasecmp(general_val, "mixmonitor"))
05517                montype_default = 1;
05518          }
05519          update_cdr = 0;
05520          if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
05521             update_cdr = ast_true(general_val);
05522          shared_lastcall = 0;
05523          if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
05524             shared_lastcall = ast_true(general_val);
05525       } else { /* Define queue */
05526          /* Look for an existing one */
05527          struct call_queue tmpq = {
05528             .name = cat,
05529          };
05530          if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
05531             /* Make one then */
05532             if (!(q = alloc_queue(cat))) {
05533                /* TODO: Handle memory allocation failure */
05534             }
05535             new = 1;
05536          } else
05537             new = 0;
05538          if (q) {
05539             const char *tmpvar = NULL;
05540             if (!new)
05541                ao2_lock(q);
05542             /* Check if a queue with this name already exists */
05543             if (q->found) {
05544                ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
05545                if (!new) {
05546                   ao2_unlock(q);
05547                   queue_unref(q);
05548                }
05549                continue;
05550             }
05551             /* Due to the fact that the "linear" strategy will have a different allocation
05552              * scheme for queue members, we must devise the queue's strategy before other initializations
05553              */
05554             if ((tmpvar = ast_variable_retrieve(cfg, cat, "strategy"))) {
05555                q->strategy = strat2int(tmpvar);
05556                if (q->strategy < 0) {
05557                   ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
05558                   tmpvar, q->name);
05559                   q->strategy = QUEUE_STRATEGY_RINGALL;
05560                }
05561             } else
05562                q->strategy = QUEUE_STRATEGY_RINGALL;
05563             /* Re-initialize the queue, and clear statistics */
05564             init_queue(q);
05565             if (!queue_keep_stats) 
05566                clear_queue(q);
05567             mem_iter = ao2_iterator_init(q->members, 0);
05568             while ((cur = ao2_iterator_next(&mem_iter))) {
05569                if (!cur->dynamic) {
05570                   cur->delme = 1;
05571                }
05572                ao2_ref(cur, -1);
05573             }
05574             for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05575                if (!strcasecmp(var->name, "member")) {
05576                   struct member tmpmem;
05577                   membername = NULL;
05578 
05579                   if (ast_strlen_zero(var->value)) {
05580                      ast_log(LOG_WARNING, "Empty queue member definition at line %d. Moving on!\n", var->lineno);
05581                      continue;
05582                   }
05583 
05584                   /* Add a new member */
05585                   if (!(parse = ast_strdup(var->value))) {
05586                      continue;
05587                   }
05588                   
05589                   AST_STANDARD_APP_ARGS(args, parse);
05590 
05591                   interface = args.interface;
05592                   if (!ast_strlen_zero(args.penalty)) {
05593                      tmp = args.penalty;
05594                      while (*tmp && *tmp < 33) tmp++;
05595                      penalty = atoi(tmp);
05596                      if (penalty < 0) {
05597                         penalty = 0;
05598                      }
05599                   } else
05600                      penalty = 0;
05601 
05602                   if (!ast_strlen_zero(args.membername)) {
05603                      membername = args.membername;
05604                      while (*membername && *membername < 33) membername++;
05605                   }
05606 
05607                   if (!ast_strlen_zero(args.state_interface)) {
05608                      state_interface = args.state_interface;
05609                      while (*state_interface && *state_interface < 33) state_interface++;
05610                   } else
05611                      state_interface = interface;
05612 
05613                   /* Find the old position in the list */
05614                   ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
05615                   cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
05616                   /* Only attempt removing from interfaces list if the new state_interface is different than the old one */
05617                   if (cur && strcasecmp(cur->state_interface, state_interface)) {
05618                      remove_from_interfaces(cur->state_interface, 0);
05619                   }
05620                   newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface);
05621                   if (!cur || (cur && strcasecmp(cur->state_interface, state_interface)))
05622                      add_to_interfaces(state_interface);
05623                   ao2_link(q->members, newm);
05624                   ao2_ref(newm, -1);
05625                   newm = NULL;
05626 
05627                   if (cur)
05628                      ao2_ref(cur, -1);
05629                   else {
05630                      q->membercount++;
05631                   }
05632                   ast_free(parse);
05633                } else {
05634                   queue_set_param(q, var->name, var->value, var->lineno, 1);
05635                }
05636             }
05637 
05638             /* Free remaining members marked as delme */
05639             mem_iter = ao2_iterator_init(q->members, 0);
05640             while ((cur = ao2_iterator_next(&mem_iter))) {
05641                if (! cur->delme) {
05642                   ao2_ref(cur, -1);
05643                   continue;
05644                }
05645                q->membercount--;
05646                ao2_unlink(q->members, cur);
05647                remove_from_interfaces(cur->interface, 0);
05648                ao2_ref(cur, -1);
05649             }
05650 
05651             if (new) {
05652                ao2_link(queues, q);
05653             } else 
05654                ao2_unlock(q);
05655             queue_unref(q);
05656          }
05657       }
05658    }
05659    ast_config_destroy(cfg);
05660    queue_iter = ao2_iterator_init(queues, 0);
05661    while ((q = ao2_iterator_next(&queue_iter))) {
05662       if (q->dead) {
05663          ao2_unlink(queues, q);
05664       } else {
05665          ao2_lock(q);
05666          mem_iter = ao2_iterator_init(q->members, 0);
05667          while ((cur = ao2_iterator_next(&mem_iter))) {
05668             if (cur->dynamic)
05669                q->membercount++;
05670             cur->status = ast_device_state(cur->state_interface);
05671             ao2_ref(cur, -1);
05672          }
05673          ao2_unlock(q);
05674       }
05675       queue_unref(q);
05676    }
05677    ao2_unlock(queues);
05678    return 1;
05679 }

static int remove_from_interfaces ( const char *  interface,
int  lock_queue_container 
) [static]

Definition at line 1049 of file app_queue.c.

References ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, member_interface::interface, and interface_exists_global().

Referenced by find_queue_by_name_rt(), free_members(), reload_queues(), remove_from_queue(), rt_handle_member_record(), and update_realtime_members().

01050 {
01051    struct member_interface *curint;
01052 
01053    if (interface_exists_global(interface, lock_queue_container))
01054       return 0;
01055 
01056    AST_LIST_LOCK(&interfaces);
01057    AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
01058       if (!strcasecmp(curint->interface, interface)) {
01059          ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
01060          AST_LIST_REMOVE_CURRENT(list);
01061          ast_free(curint);
01062          break;
01063       }
01064    }
01065    AST_LIST_TRAVERSE_SAFE_END;
01066    AST_LIST_UNLOCK(&interfaces);
01067 
01068    return 0;
01069 }

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

Remove member from queue.

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

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

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

04118 {
04119    struct call_queue *q, tmpq = {
04120       .name = queuename,   
04121    };
04122    struct member *mem, tmpmem;
04123    int res = RES_NOSUCHQUEUE;
04124 
04125    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
04126    if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
04127       ao2_lock(queues);
04128       ao2_lock(q);
04129       if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
04130          /* XXX future changes should beware of this assumption!! */
04131          if (!mem->dynamic) {
04132             ao2_ref(mem, -1);
04133             ao2_unlock(q);
04134             queue_unref(q);
04135             ao2_unlock(queues);
04136             return RES_NOT_DYNAMIC;
04137          }
04138          q->membercount--;
04139          manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
04140             "Queue: %s\r\n"
04141             "Location: %s\r\n"
04142             "MemberName: %s\r\n",
04143             q->name, mem->interface, mem->membername);
04144          ao2_unlink(q->members, mem);
04145          remove_from_interfaces(mem->state_interface, 0);
04146          ao2_ref(mem, -1);
04147 
04148          if (queue_persistent_members)
04149             dump_queue_members(q);
04150          
04151          res = RES_OKAY;
04152       } else {
04153          res = RES_EXISTS;
04154       }
04155       ao2_unlock(q);
04156       ao2_unlock(queues);
04157       queue_unref(q);
04158    }
04159 
04160    return res;
04161 }

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

Part 2 of ring_one.

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

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

References ast_cdr::accountcode, ast_channel::adsicpe, ast_cdr::amaflags, ao2_lock(), ao2_unlock(), ast_channel::appl, ast_call(), ast_cdr_busy(), ast_cdr_isset_unanswered(), ast_cdr_setdestchan(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, ast_free, ast_request(), ast_strdup, ast_strlen_zero(), ast_verb, ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_cdr::clid, compare_weight(), ast_channel::context, ast_channel::data, ast_cdr::dcontext, ast_channel::dialcontext, do_hang(), ast_cdr::dst, EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, callattempt::interface, ast_cdr::lastapp, callattempt::lastcall, ast_cdr::lastdata, callattempt::lastqueue, queue_ent::linpos, manager_event, callattempt::member, member::membername, ast_channel::name, call_queue::name, ast_channel::nativeformats, queue_ent::parent, member::paused, pbx_builtin_getvar_helper(), ast_channel::priority, QUEUE_EVENT_VARIABLES, call_queue::ringinuse, call_queue::rrpos, ast_cdr::src, member::state_interface, member::status, status, callattempt::stillgoing, ast_channel::uniqueid, update_status(), ast_cdr::userfield, vars2manager(), ast_channel::whentohangup, and call_queue::wrapuptime.

Referenced by ring_one().

02210 {
02211    int res;
02212    int status;
02213    char tech[256];
02214    char *location;
02215    const char *macrocontext, *macroexten;
02216 
02217    /* on entry here, we know that tmp->chan == NULL */
02218    if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
02219       (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
02220       ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 
02221             (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
02222       if (qe->chan->cdr)
02223          ast_cdr_busy(qe->chan->cdr);
02224       tmp->stillgoing = 0;
02225       (*busies)++;
02226       return 0;
02227    }
02228 
02229    if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
02230       ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
02231       if (qe->chan->cdr)
02232          ast_cdr_busy(qe->chan->cdr);
02233       tmp->stillgoing = 0;
02234       return 0;
02235    }
02236 
02237    if (tmp->member->paused) {
02238       ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
02239       if (qe->chan->cdr)
02240          ast_cdr_busy(qe->chan->cdr);
02241       tmp->stillgoing = 0;
02242       return 0;
02243    }
02244    if (use_weight && compare_weight(qe->parent,tmp->member)) {
02245       ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
02246       if (qe->chan->cdr)
02247          ast_cdr_busy(qe->chan->cdr);
02248       tmp->stillgoing = 0;
02249       (*busies)++;
02250       return 0;
02251    }
02252 
02253    ast_copy_string(tech, tmp->interface, sizeof(tech));
02254    if ((location = strchr(tech, '/')))
02255       *location++ = '\0';
02256    else
02257       location = "";
02258 
02259    /* Request the peer */
02260    tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
02261    if (!tmp->chan) {       /* If we can't, just go on to the next call */
02262       if (qe->chan->cdr)
02263          ast_cdr_busy(qe->chan->cdr);
02264       tmp->stillgoing = 0;
02265 
02266       update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface));
02267 
02268       ao2_lock(qe->parent);
02269       qe->parent->rrpos++;
02270       qe->linpos++;
02271       ao2_unlock(qe->parent);
02272 
02273 
02274       (*busies)++;
02275       return 0;
02276    }
02277    
02278    tmp->chan->appl = "AppQueue";
02279    tmp->chan->data = "(Outgoing Line)";
02280    tmp->chan->whentohangup = 0;
02281    if (tmp->chan->cid.cid_num)
02282       ast_free(tmp->chan->cid.cid_num);
02283    tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
02284    if (tmp->chan->cid.cid_name)
02285       ast_free(tmp->chan->cid.cid_name);
02286    tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
02287    if (tmp->chan->cid.cid_ani)
02288       ast_free(tmp->chan->cid.cid_ani);
02289    tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
02290 
02291    /* Inherit specially named variables from parent channel */
02292    ast_channel_inherit_variables(qe->chan, tmp->chan);
02293    ast_channel_datastore_inherit(qe->chan, tmp->chan);
02294 
02295    /* Presense of ADSI CPE on outgoing channel follows ours */
02296    tmp->chan->adsicpe = qe->chan->adsicpe;
02297 
02298    /* Inherit context and extension */
02299    ast_channel_lock(qe->chan);
02300    macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
02301    if (!ast_strlen_zero(macrocontext))
02302       ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext));
02303    else
02304       ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext));
02305    macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
02306    if (!ast_strlen_zero(macroexten))
02307       ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
02308    else
02309       ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
02310    if (ast_cdr_isset_unanswered()) {
02311       /* they want to see the unanswered dial attempts! */
02312       /* set up the CDR fields on all the CDRs to give sensical information */
02313       ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name);
02314       strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid);
02315       strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel);
02316       strcpy(tmp->chan->cdr->src, qe->chan->cdr->src);
02317       strcpy(tmp->chan->cdr->dst, qe->chan->exten);
02318       strcpy(tmp->chan->cdr->dcontext, qe->chan->context);
02319       strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp);
02320       strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata);
02321       tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags;
02322       strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode);
02323       strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
02324    }
02325    ast_channel_unlock(qe->chan);
02326 
02327    /* Place the call, but don't wait on the answer */
02328    if ((res = ast_call(tmp->chan, location, 0))) {
02329       /* Again, keep going even if there's an error */
02330       ast_debug(1, "ast call on peer returned %d\n", res);
02331       ast_verb(3, "Couldn't call %s\n", tmp->interface);
02332       do_hang(tmp);
02333       (*busies)++;
02334       update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface));
02335       return 0;
02336    } else if (qe->parent->eventwhencalled) {
02337       char vars[2048];
02338 
02339       manager_event(EVENT_FLAG_AGENT, "AgentCalled",
02340                "Queue: %s\r\n"
02341                "AgentCalled: %s\r\n"
02342                "AgentName: %s\r\n"
02343                "ChannelCalling: %s\r\n"
02344                "DestinationChannel: %s\r\n"
02345                "CallerIDNum: %s\r\n"
02346                "CallerIDName: %s\r\n"
02347                "Context: %s\r\n"
02348                "Extension: %s\r\n"
02349                "Priority: %d\r\n"
02350                "Uniqueid: %s\r\n"
02351                "%s",
02352                qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
02353                tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
02354                tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
02355                qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
02356                qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
02357       ast_verb(3, "Called %s\n", tmp->interface);
02358    }
02359 
02360    update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface));
02361    return 1;
02362 }

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

Place a call to a queue member.

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

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

Definition at line 2390 of file app_queue.c.

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

Referenced by try_calling(), and wait_for_answer().

02391 {
02392    int ret = 0;
02393 
02394    while (ret == 0) {
02395       struct callattempt *best = find_best(outgoing);
02396       if (!best) {
02397          ast_debug(1, "Nobody left to try ringing in queue\n");
02398          break;
02399       }
02400       if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
02401          struct callattempt *cur;
02402          /* Ring everyone who shares this best metric (for ringall) */
02403          for (cur = outgoing; cur; cur = cur->q_next) {
02404             if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
02405                ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
02406                ret |= ring_entry(qe, cur, busies);
02407             }
02408          }
02409       } else {
02410          /* Ring just the best channel */
02411          ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
02412          ret = ring_entry(qe, best, busies);
02413       }
02414    }
02415 
02416    return ret;
02417 }

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

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

Definition at line 2536 of file app_queue.c.

References ast_queue_log(), ast_verb, call_queue::autopause, queue_ent::chan, call_queue::name, queue_ent::parent, set_member_paused(), and ast_channel::uniqueid.

Referenced by wait_for_answer().

02537 {
02538    ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
02539    ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
02540    if (qe->parent->autopause && pause) {
02541       if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
02542          ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
02543       } else {
02544          ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
02545       }
02546    }
02547    return;
02548 }

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

RemoveQueueMember application.

Definition at line 4545 of file app_queue.c.

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

Referenced by load_module().

04546 {
04547    int res=-1;
04548    char *parse, *temppos = NULL;
04549    AST_DECLARE_APP_ARGS(args,
04550       AST_APP_ARG(queuename);
04551       AST_APP_ARG(interface);
04552       AST_APP_ARG(options);
04553    );
04554 
04555 
04556    if (ast_strlen_zero(data)) {
04557       ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n");
04558       return -1;
04559    }
04560 
04561    parse = ast_strdupa(data);
04562 
04563    AST_STANDARD_APP_ARGS(args, parse);
04564 
04565    if (ast_strlen_zero(args.interface)) {
04566       args.interface = ast_strdupa(chan->name);
04567       temppos = strrchr(args.interface, '-');
04568       if (temppos)
04569          *temppos = '\0';
04570    }
04571 
04572    switch (remove_from_queue(args.queuename, args.interface)) {
04573    case RES_OKAY:
04574       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
04575       ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
04576       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
04577       res = 0;
04578       break;
04579    case RES_EXISTS:
04580       ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
04581       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
04582       res = 0;
04583       break;
04584    case RES_NOSUCHQUEUE:
04585       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
04586       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
04587       res = 0;
04588       break;
04589    case RES_NOT_DYNAMIC:
04590       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
04591       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
04592       res = 0;
04593       break;
04594    }
04595 
04596    return res;
04597 }

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

Find rt member record to update otherwise create one.

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

Definition at line 1359 of file app_queue.c.

References add_to_interfaces(), ao2_find(), ao2_link(), ao2_ref(), ast_copy_string(), create_queue_member(), member::dead, member::interface, call_queue::membercount, call_queue::members, OBJ_POINTER, member::paused, member::penalty, member::realtime, remove_from_interfaces(), and member::state_interface.

Referenced by find_queue_by_name_rt(), and update_realtime_members().

01360 {
01361    struct member *m, tmpmem;
01362    int penalty = 0;
01363    int paused  = 0;
01364 
01365    if (penalty_str) {
01366       penalty = atoi(penalty_str);
01367       if (penalty < 0)
01368          penalty = 0;
01369    }
01370 
01371    if (paused_str) {
01372       paused = atoi(paused_str);
01373       if (paused < 0)
01374          paused = 0;
01375    }
01376 
01377    /* Find the member, or the place to put a new one. */
01378    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
01379    m = ao2_find(q->members, &tmpmem, OBJ_POINTER);
01380 
01381    /* Create a new one if not found, else update penalty */
01382    if (!m) {
01383       if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
01384          m->dead = 0;
01385          m->realtime = 1;
01386          add_to_interfaces(m->state_interface);
01387          ao2_link(q->members, m);
01388          ao2_ref(m, -1);
01389          m = NULL;
01390          q->membercount++;
01391       }
01392    } else {
01393       m->dead = 0;   /* Do not delete this one. */
01394       if (paused_str)
01395          m->paused = paused;
01396       if (strcasecmp(state_interface, m->state_interface)) {
01397          remove_from_interfaces(m->state_interface, 0);
01398          ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
01399          add_to_interfaces(m->state_interface);
01400       }
01401       m->penalty = penalty;
01402       ao2_ref(m, -1);
01403    }
01404 }

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

Playback announcement to queued members if peroid has elapsed.

Definition at line 2468 of file app_queue.c.

References AST_CONTROL_RINGING, ast_indicate(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_verb, queue_ent::chan, queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, MAX_PERIODIC_ANNOUNCEMENTS, queue_ent::moh, queue_ent::parent, call_queue::periodicannouncefrequency, play_file(), call_queue::sound_periodicannounce, ast_str::str, and valid_exit().

Referenced by queue_exec(), and wait_our_turn().

02469 {
02470    int res = 0;
02471    time_t now;
02472 
02473    /* Get the current time */
02474    time(&now);
02475 
02476    /* Check to see if it is time to announce */
02477    if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
02478       return 0;
02479 
02480    /* Stop the music on hold so we can play our own file */
02481    if (ringing)
02482       ast_indicate(qe->chan,-1);
02483    else
02484       ast_moh_stop(qe->chan);
02485 
02486    ast_verb(3, "Playing periodic announcement\n");
02487 
02488    /* Check to make sure we have a sound file. If not, reset to the first sound file */
02489    if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || 
02490       !qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound] ||
02491       ast_strlen_zero(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str)) {
02492       qe->last_periodic_announce_sound = 0;
02493    }
02494    
02495    /* play the announcement */
02496    res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str);
02497 
02498    if (res > 0 && !valid_exit(qe, res))
02499       res = 0;
02500 
02501    /* Resume Music on Hold if the caller is going to stay in the queue */
02502    if (!res) {
02503       if (ringing)
02504          ast_indicate(qe->chan, AST_CONTROL_RINGING);
02505       else
02506          ast_moh_start(qe->chan, qe->moh, NULL);
02507    }
02508 
02509    /* update last_periodic_announce_time */
02510    qe->last_periodic_announce_time = now;
02511 
02512    /* Update the current periodic announcement to the next announcement */
02513    qe->last_periodic_announce_sound++;
02514    
02515    return res;
02516 }

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

Definition at line 1852 of file app_queue.c.

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

Referenced by queue_exec(), and wait_our_turn().

01853 {
01854    int res = 0, avgholdmins, avgholdsecs;
01855    int say_thanks = 1;
01856    time_t now;
01857 
01858    /* Let minannouncefrequency seconds pass between the start of each position announcement */
01859    time(&now);
01860    if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
01861       return 0;
01862 
01863    /* If either our position has changed, or we are over the freq timer, say position */
01864    if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
01865       return 0;
01866 
01867    if (ringing) {
01868       ast_indicate(qe->chan,-1);
01869    } else {
01870       ast_moh_stop(qe->chan);
01871    }
01872    if (qe->parent->announceposition) {
01873       /* Say we're next, if we are */
01874       if (qe->pos == 1) {
01875          res = play_file(qe->chan, qe->parent->sound_next);
01876          if (res)
01877             goto playout;
01878          else
01879             goto posout;
01880       } else {
01881          res = play_file(qe->chan, qe->parent->sound_thereare);
01882          if (res)
01883             goto playout;
01884          res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
01885          if (res)
01886             goto playout;
01887          res = play_file(qe->chan, qe->parent->sound_calls);
01888          if (res)
01889             goto playout;
01890       }
01891    }
01892    /* Round hold time to nearest minute */
01893    avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
01894 
01895    /* If they have specified a rounding then round the seconds as well */
01896    if (qe->parent->roundingseconds) {
01897       avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
01898       avgholdsecs *= qe->parent->roundingseconds;
01899    } else {
01900       avgholdsecs = 0;
01901    }
01902 
01903    ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
01904 
01905    /* If the hold time is >1 min, if it's enabled, and if it's not
01906       supposed to be only once and we have already said it, say it */
01907     if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
01908         ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
01909         !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
01910       res = play_file(qe->chan, qe->parent->sound_holdtime);
01911       if (res)
01912          goto playout;
01913 
01914       if (avgholdmins >= 1) {
01915          res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
01916          if (res)
01917             goto playout;
01918 
01919          if (avgholdmins == 1) {
01920             res = play_file(qe->chan, qe->parent->sound_minute);
01921             if (res)
01922                goto playout;
01923          } else {
01924             res = play_file(qe->chan, qe->parent->sound_minutes);
01925             if (res)
01926                goto playout;
01927          }
01928       }
01929       if (avgholdsecs >= 1) {
01930          res = ast_say_number(qe->chan, avgholdmins > 1 ? avgholdsecs : avgholdmins * 60 + avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
01931          if (res)
01932             goto playout;
01933 
01934          res = play_file(qe->chan, qe->parent->sound_seconds);
01935          if (res)
01936             goto playout;
01937       }
01938    } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
01939       say_thanks = 0;
01940    }
01941 
01942 posout:
01943    if (qe->parent->announceposition) {
01944       ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
01945          qe->chan->name, qe->parent->name, qe->pos);
01946    }
01947    if (say_thanks) {
01948       res = play_file(qe->chan, qe->parent->sound_thanks);
01949    }
01950 
01951 playout:
01952 
01953    if ((res > 0 && !valid_exit(qe, res)))
01954       res = 0;
01955 
01956    /* Set our last_pos indicators */
01957    qe->last_pos = now;
01958    qe->last_pos_said = qe->pos;
01959 
01960    /* Don't restart music on hold if we're about to exit the caller from the queue */
01961    if (!res) {
01962                 if (ringing)
01963                         ast_indicate(qe->chan, AST_CONTROL_RINGING);
01964                 else
01965                         ast_moh_start(qe->chan, qe->moh, NULL);
01966    }
01967    return res;
01968 }

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

Send out AMI message with member call completion status information.

Definition at line 3122 of file app_queue.c.

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

Referenced by try_calling().

03125 {
03126    const char *reason = NULL; /* silence dumb compilers */
03127 
03128    if (!qe->parent->eventwhencalled)
03129       return;
03130 
03131    switch (rsn) {
03132    case CALLER:
03133       reason = "caller";
03134       break;
03135    case AGENT:
03136       reason = "agent";
03137       break;
03138    case TRANSFER:
03139       reason = "transfer";
03140       break;
03141    }
03142 
03143    manager_event(EVENT_FLAG_AGENT, "AgentComplete",
03144       "Queue: %s\r\n"
03145       "Uniqueid: %s\r\n"
03146       "Channel: %s\r\n"
03147       "Member: %s\r\n"
03148       "MemberName: %s\r\n"
03149       "HoldTime: %ld\r\n"
03150       "TalkTime: %ld\r\n"
03151       "Reason: %s\r\n"
03152       "%s",
03153       queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
03154       (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
03155       qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
03156 }

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

Definition at line 4225 of file app_queue.c.

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

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

04226 {
04227    int found = 0;
04228    struct call_queue *q;
04229    struct member *mem;
04230    struct ao2_iterator queue_iter;
04231    int failed;
04232 
04233    /* Special event for when all queues are paused - individual events still generated */
04234    /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
04235    if (ast_strlen_zero(queuename))
04236       ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
04237 
04238    queue_iter = ao2_iterator_init(queues, 0);
04239    while ((q = ao2_iterator_next(&queue_iter))) {
04240       ao2_lock(q);
04241       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
04242          if ((mem = interface_exists(q, interface))) {
04243             found++;
04244             if (mem->paused == paused) {
04245                ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
04246             }
04247             
04248             failed = 0;
04249             if (mem->realtime) {
04250                failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
04251             }
04252 
04253             if (failed) {
04254                ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface);
04255                ao2_ref(mem, -1);
04256                ao2_unlock(q);
04257                continue;
04258             }
04259 
04260             mem->paused = paused;
04261 
04262             if (queue_persistent_members)
04263                dump_queue_members(q);
04264 
04265             ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
04266             
04267             if (!ast_strlen_zero(reason)) {
04268                manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
04269                   "Queue: %s\r\n"
04270                   "Location: %s\r\n"
04271                   "MemberName: %s\r\n"
04272                   "Paused: %d\r\n"
04273                   "Reason: %s\r\n",
04274                      q->name, mem->interface, mem->membername, paused, reason);
04275             } else {
04276                manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
04277                   "Queue: %s\r\n"
04278                   "Location: %s\r\n"
04279                   "MemberName: %s\r\n"
04280                   "Paused: %d\r\n",
04281                      q->name, mem->interface, mem->membername, paused);
04282             }
04283             ao2_ref(mem, -1);
04284          }
04285       }
04286       ao2_unlock(q);
04287       queue_unref(q);
04288    }
04289    ao2_iterator_destroy(&queue_iter);
04290 
04291    return found ? RESULT_SUCCESS : RESULT_FAILURE;
04292 }

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

Definition at line 4295 of file app_queue.c.

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

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

04296 {
04297    int foundinterface = 0, foundqueue = 0;
04298    struct call_queue *q;
04299    struct member *mem;
04300    struct ao2_iterator queue_iter;
04301 
04302    if (penalty < 0) {
04303       ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty);
04304       return RESULT_FAILURE;
04305    }
04306 
04307    queue_iter = ao2_iterator_init(queues, 0);
04308    while ((q = ao2_iterator_next(&queue_iter))) {
04309       ao2_lock(q);
04310       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
04311          foundqueue++;
04312          if ((mem = interface_exists(q, interface))) {
04313             foundinterface++;
04314             mem->penalty = penalty;
04315             
04316             ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
04317             manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
04318                "Queue: %s\r\n"
04319                "Location: %s\r\n"
04320                "Penalty: %d\r\n",
04321                q->name, mem->interface, penalty);
04322             ao2_ref(mem, -1);
04323          }
04324       }
04325       ao2_unlock(q);
04326       queue_unref(q);
04327    }
04328    ao2_iterator_destroy(&queue_iter);
04329 
04330    if (foundinterface) {
04331       return RESULT_SUCCESS;
04332    } else if (!foundqueue) {
04333       ast_log (LOG_ERROR, "Invalid queuename\n"); 
04334    } else {
04335       ast_log (LOG_ERROR, "Invalid interface\n");
04336    }  
04337 
04338    return RESULT_FAILURE;
04339 }

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

sets the QUEUESTATUS channel variable

Definition at line 533 of file app_queue.c.

References pbx_builtin_setvar_helper(), queue_results, and text.

Referenced by queue_exec().

00534 {
00535    int i;
00536 
00537    for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
00538       if (queue_results[i].id == res) {
00539          pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
00540          return;
00541       }
00542    }
00543 }

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

Set variables of queue.

Definition at line 595 of file app_queue.c.

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

Referenced by end_bridge_callback(), queue_exec(), record_abandoned(), and try_calling().

00596 {
00597 
00598    char interfacevar[256]="";
00599    float sl = 0;
00600         
00601    if (q->setqueuevar) {
00602       sl = 0;
00603       if (q->callscompleted > 0) 
00604          sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
00605 
00606       snprintf(interfacevar, sizeof(interfacevar),
00607          "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
00608          q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->callscompleted, q->callsabandoned,  q->servicelevel, sl);
00609    
00610       pbx_builtin_setvar_multiple(chan, interfacevar); 
00611    }
00612 }

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

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

Definition at line 3226 of file app_queue.c.

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

Referenced by try_calling().

03227 {
03228    struct ast_datastore *ds;
03229    struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
03230 
03231    if (!qtds) {
03232       ast_log(LOG_WARNING, "Memory allocation error!\n");
03233       return NULL;
03234    }
03235 
03236    ast_channel_lock(qe->chan);
03237    if (!(ds = ast_channel_datastore_alloc(&queue_transfer_info, NULL))) {
03238       ast_channel_unlock(qe->chan);
03239       ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
03240       return NULL;
03241    }
03242 
03243    qtds->qe = qe;
03244    /* This member is refcounted in try_calling, so no need to add it here, too */
03245    qtds->member = member;
03246    qtds->starttime = starttime;
03247    qtds->callcompletedinsl = callcompletedinsl;
03248    ds->data = qtds;
03249    ast_channel_datastore_add(qe->chan, ds);
03250    ast_channel_unlock(qe->chan);
03251    return ds;
03252 }

static int statechange_queue ( const char *  dev,
enum ast_device_state  state 
) [static]

Producer of the statechange queue.

Definition at line 830 of file app_queue.c.

References ast_calloc, ast_cond_signal(), AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), statechange::dev, device_state, statechange::entry, and statechange::state.

00831 {
00832    struct statechange *sc;
00833 
00834    if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
00835       return 0;
00836 
00837    sc->state = state;
00838    strcpy(sc->dev, dev);
00839 
00840    ast_mutex_lock(&device_state.lock);
00841    AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
00842    ast_cond_signal(&device_state.cond);
00843    ast_mutex_unlock(&device_state.lock);
00844 
00845    return 0;
00846 }

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

Search for best metric and add to Linear queue.

Definition at line 2444 of file app_queue.c.

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

Referenced by try_calling().

02445 {
02446    struct callattempt *best = find_best(outgoing);
02447 
02448    if (best) {
02449       /* Ring just the best channel */
02450       ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
02451       qe->linpos = best->metric % 1000;
02452    } else {
02453       /* Just increment rrpos */
02454       if (qe->linwrapped) {
02455          /* No more channels, start over */
02456          qe->linpos = 0;
02457       } else {
02458          /* Prioritize next entry */
02459          qe->linpos++;
02460       }
02461    }
02462    qe->