mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-25 15:08:53 +00:00
app_queue has now been doxygenified thanks to snuffy! The ony thing I changed
was the way that locks are referenced, since the old 1.2 names were still used in the comments. (closes issue #11997) Reported by: snuffy Patches: bug_11997_queue_doxy.diff uploaded by snuffy (license 35) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@107068 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
252
apps/app_queue.c
252
apps/app_queue.c
@@ -93,7 +93,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||||||
#include "asterisk/strings.h"
|
#include "asterisk/strings.h"
|
||||||
#include "asterisk/global_datastores.h"
|
#include "asterisk/global_datastores.h"
|
||||||
|
|
||||||
/* Please read before modifying this file.
|
/*!
|
||||||
|
* \par Please read before modifying this file.
|
||||||
* There are three locks which are regularly used
|
* There are three locks which are regularly used
|
||||||
* throughout this file, the queue list lock, the lock
|
* throughout this file, the queue list lock, the lock
|
||||||
* for each individual queue, and the interface list lock.
|
* for each individual queue, and the interface list lock.
|
||||||
@@ -132,17 +133,17 @@ static const struct strategy {
|
|||||||
|
|
||||||
#define DEFAULT_RETRY 5
|
#define DEFAULT_RETRY 5
|
||||||
#define DEFAULT_TIMEOUT 15
|
#define DEFAULT_TIMEOUT 15
|
||||||
#define RECHECK 1 /* Recheck every second to see we we're at the top yet */
|
#define RECHECK 1 /*!< Recheck every second to see we we're at the top yet */
|
||||||
#define MAX_PERIODIC_ANNOUNCEMENTS 10 /* The maximum periodic announcements we can have */
|
#define MAX_PERIODIC_ANNOUNCEMENTS 10 /*!< The maximum periodic announcements we can have */
|
||||||
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /* The minimum number of seconds between position announcements
|
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /*!< The minimum number of seconds between position announcements
|
||||||
The default value of 15 provides backwards compatibility */
|
The default value of 15 provides backwards compatibility */
|
||||||
#define MAX_QUEUE_BUCKETS 53
|
#define MAX_QUEUE_BUCKETS 53
|
||||||
|
|
||||||
#define RES_OKAY 0 /* Action completed */
|
#define RES_OKAY 0 /*!< Action completed */
|
||||||
#define RES_EXISTS (-1) /* Entry already exists */
|
#define RES_EXISTS (-1) /*!< Entry already exists */
|
||||||
#define RES_OUTOFMEMORY (-2) /* Out of memory */
|
#define RES_OUTOFMEMORY (-2) /*!< Out of memory */
|
||||||
#define RES_NOSUCHQUEUE (-3) /* No such queue */
|
#define RES_NOSUCHQUEUE (-3) /*!< No such queue */
|
||||||
#define RES_NOT_DYNAMIC (-4) /* Member is not dynamic */
|
#define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */
|
||||||
|
|
||||||
static char *app = "Queue";
|
static char *app = "Queue";
|
||||||
|
|
||||||
@@ -313,15 +314,16 @@ const struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*! \brief We define a custom "local user" structure because we
|
/*! \brief We define a custom "local user" structure because we
|
||||||
use it not only for keeping track of what is in use but
|
* use it not only for keeping track of what is in use but
|
||||||
also for keeping track of who we're dialing.
|
* also for keeping track of who we're dialing.
|
||||||
|
*
|
||||||
There are two "links" defined in this structure, q_next and call_next.
|
* There are two "links" defined in this structure, q_next and call_next.
|
||||||
q_next links ALL defined callattempt structures into a linked list. call_next is
|
* q_next links ALL defined callattempt structures into a linked list. call_next is
|
||||||
a link which allows for a subset of the callattempts to be traversed. This subset
|
* a link which allows for a subset of the callattempts to be traversed. This subset
|
||||||
is used in wait_for_answer so that irrelevant callattempts are not traversed. This
|
* is used in wait_for_answer so that irrelevant callattempts are not traversed. This
|
||||||
also is helpful so that queue logs are always accurate in the case where a call to
|
* also is helpful so that queue logs are always accurate in the case where a call to
|
||||||
a member times out, especially if using the ringall strategy. */
|
* a member times out, especially if using the ringall strategy.
|
||||||
|
*/
|
||||||
|
|
||||||
struct callattempt {
|
struct callattempt {
|
||||||
struct callattempt *q_next;
|
struct callattempt *q_next;
|
||||||
@@ -572,6 +574,7 @@ static inline struct call_queue *queue_unref(struct call_queue *q)
|
|||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Set variables of queue */
|
||||||
static void set_queue_variables(struct queue_ent *qe)
|
static void set_queue_variables(struct queue_ent *qe)
|
||||||
{
|
{
|
||||||
char interfacevar[256]="";
|
char interfacevar[256]="";
|
||||||
@@ -665,7 +668,12 @@ struct statechange {
|
|||||||
int state;
|
int state;
|
||||||
char dev[0];
|
char dev[0];
|
||||||
};
|
};
|
||||||
/*! \brief set a member's status based on device state of that member's state_interface*/
|
|
||||||
|
/*! \brief set a member's status based on device state of that member's state_interface.
|
||||||
|
*
|
||||||
|
* Lock interface list find sc, iterate through each queues queue_member list for member to
|
||||||
|
* update state inside queues
|
||||||
|
*/
|
||||||
static void *handle_statechange(struct statechange *sc)
|
static void *handle_statechange(struct statechange *sc)
|
||||||
{
|
{
|
||||||
struct call_queue *q;
|
struct call_queue *q;
|
||||||
@@ -750,9 +758,7 @@ static void *handle_statechange(struct statechange *sc)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*! \brief Data used by the device state thread */
|
||||||
* \brief Data used by the device state thread
|
|
||||||
*/
|
|
||||||
static struct {
|
static struct {
|
||||||
/*! Set to 1 to stop the thread */
|
/*! Set to 1 to stop the thread */
|
||||||
unsigned int stop:1;
|
unsigned int stop:1;
|
||||||
@@ -802,6 +808,7 @@ static void *device_state_thread(void *data)
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Producer of the statechange queue */
|
/*! \brief Producer of the statechange queue */
|
||||||
static int statechange_queue(const char *dev, enum ast_device_state state)
|
static int statechange_queue(const char *dev, enum ast_device_state state)
|
||||||
{
|
{
|
||||||
@@ -820,6 +827,7 @@ static int statechange_queue(const char *dev, enum ast_device_state state)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void device_state_cb(const struct ast_event *event, void *unused)
|
static void device_state_cb(const struct ast_event *event, void *unused)
|
||||||
{
|
{
|
||||||
enum ast_device_state state;
|
enum ast_device_state state;
|
||||||
@@ -890,6 +898,10 @@ static int member_cmp_fn(void *obj1, void *obj2, int flags)
|
|||||||
return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH;
|
return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Initialize Queue default values.
|
||||||
|
* \note the queue's lock must be held before executing this function
|
||||||
|
*/
|
||||||
static void init_queue(struct call_queue *q)
|
static void init_queue(struct call_queue *q)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -1048,7 +1060,15 @@ static void clear_and_free_interfaces(void)
|
|||||||
AST_LIST_UNLOCK(&interfaces);
|
AST_LIST_UNLOCK(&interfaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Note: call this with the rule_lists locked */
|
/*!
|
||||||
|
* \brief 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.
|
||||||
|
* \retval -1 on failure
|
||||||
|
* \retval 0 on success
|
||||||
|
* \note Call this with the rule_lists locked
|
||||||
|
*/
|
||||||
static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
|
static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
|
||||||
{
|
{
|
||||||
char *timestr, *maxstr, *minstr, *contentdup;
|
char *timestr, *maxstr, *minstr, *contentdup;
|
||||||
@@ -1121,12 +1141,13 @@ static int insert_penaltychange (const char *list_name, const char *content, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Configure a queue parameter.
|
/*! \brief Configure a queue parameter.
|
||||||
\par
|
*
|
||||||
For error reporting, line number is passed for .conf static configuration.
|
* The failunknown flag is set for config files (and static realtime) to show
|
||||||
For Realtime queues, linenum is -1.
|
* errors for unknown parameters. It is cleared for dynamic realtime to allow
|
||||||
The failunknown flag is set for config files (and static realtime) to show
|
* extra fields in the tables.
|
||||||
errors for unknown parameters. It is cleared for dynamic realtime to allow
|
* \note For error reporting, line number is passed for .conf static configuration,
|
||||||
extra fields in the tables. */
|
* for Realtime queues, linenum is -1.
|
||||||
|
*/
|
||||||
static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
|
static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
|
||||||
{
|
{
|
||||||
if (!strcasecmp(param, "musicclass") ||
|
if (!strcasecmp(param, "musicclass") ||
|
||||||
@@ -1293,6 +1314,12 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief 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.
|
||||||
|
*/
|
||||||
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 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)
|
||||||
{
|
{
|
||||||
struct member *m, tmpmem;
|
struct member *m, tmpmem;
|
||||||
@@ -1340,6 +1367,7 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Iterate through queue's member list and delete them */
|
||||||
static void free_members(struct call_queue *q, int all)
|
static void free_members(struct call_queue *q, int all)
|
||||||
{
|
{
|
||||||
/* Free non-dynamic members */
|
/* Free non-dynamic members */
|
||||||
@@ -1356,6 +1384,7 @@ static void free_members(struct call_queue *q, int all)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Free queue's member list then its string fields */
|
||||||
static void destroy_queue(void *obj)
|
static void destroy_queue(void *obj)
|
||||||
{
|
{
|
||||||
struct call_queue *q = obj;
|
struct call_queue *q = obj;
|
||||||
@@ -1386,9 +1415,16 @@ static struct call_queue *alloc_queue(const char *queuename)
|
|||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!\brief Reload a single queue via realtime.
|
/*!
|
||||||
\return Return the queue, or NULL if it doesn't exist.
|
* \brief Reload a single queue via realtime.
|
||||||
\note Should be called with the global qlock locked. */
|
*
|
||||||
|
* 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.
|
||||||
|
* \retval the queue,
|
||||||
|
* \retval NULL if it doesn't exist.
|
||||||
|
* \note Should be called with the "queues" container locked.
|
||||||
|
*/
|
||||||
static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
|
static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
|
||||||
{
|
{
|
||||||
struct ast_variable *v;
|
struct ast_variable *v;
|
||||||
@@ -1529,7 +1565,7 @@ static struct call_queue *load_realtime_queue(const char *queuename)
|
|||||||
q = ao2_find(queues, &tmpq, OBJ_POINTER);
|
q = ao2_find(queues, &tmpq, OBJ_POINTER);
|
||||||
|
|
||||||
if (!q || q->realtime) {
|
if (!q || q->realtime) {
|
||||||
/*! \note Load from realtime before taking the global qlock, to avoid blocking all
|
/*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
|
||||||
queue operations while waiting for the DB.
|
queue operations while waiting for the DB.
|
||||||
|
|
||||||
This will be two separate database transactions, so we might
|
This will be two separate database transactions, so we might
|
||||||
@@ -1707,6 +1743,11 @@ static int play_file(struct ast_channel *chan, const char *filename)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Check for valid exit from queue via goto
|
||||||
|
* \retval 0 if failure
|
||||||
|
* \retval 1 if successful
|
||||||
|
*/
|
||||||
static int valid_exit(struct queue_ent *qe, char digit)
|
static int valid_exit(struct queue_ent *qe, char digit)
|
||||||
{
|
{
|
||||||
int digitlen = strlen(qe->digits);
|
int digitlen = strlen(qe->digits);
|
||||||
@@ -1866,7 +1907,11 @@ static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
|
|||||||
ao2_unlock(qe->parent);
|
ao2_unlock(qe->parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Caller leaving queue.
|
||||||
|
*
|
||||||
|
* Search the queue to find the leaving client, if found remove from queue
|
||||||
|
* create manager event, move others up the queue.
|
||||||
|
*/
|
||||||
static void leave_queue(struct queue_ent *qe)
|
static void leave_queue(struct queue_ent *qe)
|
||||||
{
|
{
|
||||||
struct call_queue *q;
|
struct call_queue *q;
|
||||||
@@ -1921,7 +1966,7 @@ static void leave_queue(struct queue_ent *qe)
|
|||||||
queue_unref(q);
|
queue_unref(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hang up a list of outgoing calls */
|
/*! \brief Hang up a list of outgoing calls */
|
||||||
static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
|
static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
|
||||||
{
|
{
|
||||||
struct callattempt *oo;
|
struct callattempt *oo;
|
||||||
@@ -1987,8 +2032,11 @@ static int update_dial_status(struct call_queue *q, struct member *member, int s
|
|||||||
return update_status(q, member, status);
|
return update_status(q, member, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* traverse all defined queues which have calls waiting and contain this member
|
/*!
|
||||||
return 0 if no other queue has precedence (higher weight) or 1 if found */
|
* \brief traverse all defined queues which have calls waiting and contain this member
|
||||||
|
* \retval 0 if no other queue has precedence (higher weight)
|
||||||
|
* \retval 1 if found
|
||||||
|
*/
|
||||||
static int compare_weight(struct call_queue *rq, struct member *member)
|
static int compare_weight(struct call_queue *rq, struct member *member)
|
||||||
{
|
{
|
||||||
struct call_queue *q;
|
struct call_queue *q;
|
||||||
@@ -1996,7 +2044,7 @@ static int compare_weight(struct call_queue *rq, struct member *member)
|
|||||||
int found = 0;
|
int found = 0;
|
||||||
struct ao2_iterator queue_iter;
|
struct ao2_iterator queue_iter;
|
||||||
|
|
||||||
/* &qlock and &rq->lock already set by try_calling()
|
/* q's lock and rq's lock already set by try_calling()
|
||||||
* to solve deadlock */
|
* to solve deadlock */
|
||||||
queue_iter = ao2_iterator_init(queues, 0);
|
queue_iter = ao2_iterator_init(queues, 0);
|
||||||
while ((q = ao2_iterator_next(&queue_iter))) {
|
while ((q = ao2_iterator_next(&queue_iter))) {
|
||||||
@@ -2033,6 +2081,7 @@ static void do_hang(struct callattempt *o)
|
|||||||
o->chan = NULL;
|
o->chan = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief convert "\n" to "\nVariable: " ready for manager to use */
|
||||||
static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
|
static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
|
||||||
{
|
{
|
||||||
struct ast_str *buf = ast_str_alloca(len + 1);
|
struct ast_str *buf = ast_str_alloca(len + 1);
|
||||||
@@ -2070,10 +2119,19 @@ static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
|
|||||||
return vars;
|
return vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Part 2 of ring_one
|
/*!
|
||||||
|
* \brief Part 2 of ring_one
|
||||||
*
|
*
|
||||||
* Does error checking before attempting to request a channel and call a member. This
|
* Does error checking before attempting to request a channel and call a member.
|
||||||
* function is only called from ring_one
|
* 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
|
||||||
|
*
|
||||||
|
* \retval 1 on success to reach a free agent
|
||||||
|
* \retval 0 on failure to get agent.
|
||||||
*/
|
*/
|
||||||
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
|
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
|
||||||
{
|
{
|
||||||
@@ -2223,13 +2281,15 @@ static struct callattempt *find_best(struct callattempt *outgoing)
|
|||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Place a call to a queue member
|
/*!
|
||||||
|
* \brief Place a call to a queue member.
|
||||||
*
|
*
|
||||||
* Once metrics have been calculated for each member, this function is used
|
* 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
|
* to place a call to the appropriate member (or members). The low-level
|
||||||
* channel-handling and error detection is handled in ring_entry
|
* channel-handling and error detection is handled in ring_entry
|
||||||
*
|
*
|
||||||
* Returns 1 if a member was called successfully, 0 otherwise
|
* \retval 1 if a member was called successfully
|
||||||
|
* \retval 0 otherwise
|
||||||
*/
|
*/
|
||||||
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
|
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
|
||||||
{
|
{
|
||||||
@@ -2260,6 +2320,7 @@ static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *bus
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Search for best metric and add to Round Robbin queue */
|
||||||
static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
|
static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
|
||||||
{
|
{
|
||||||
struct callattempt *best = find_best(outgoing);
|
struct callattempt *best = find_best(outgoing);
|
||||||
@@ -2283,6 +2344,7 @@ static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Search for best metric and add to Linear queue */
|
||||||
static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
|
static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
|
||||||
{
|
{
|
||||||
struct callattempt *best = find_best(outgoing);
|
struct callattempt *best = find_best(outgoing);
|
||||||
@@ -2306,6 +2368,7 @@ static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Playback announcement to queued members if peroid has elapsed */
|
||||||
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
|
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
@@ -2356,6 +2419,7 @@ static int say_periodic_announcement(struct queue_ent *qe, int ringing)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Record that a caller gave up on waiting in queue */
|
||||||
static void record_abandoned(struct queue_ent *qe)
|
static void record_abandoned(struct queue_ent *qe)
|
||||||
{
|
{
|
||||||
ao2_lock(qe->parent);
|
ao2_lock(qe->parent);
|
||||||
@@ -2644,7 +2708,9 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|||||||
|
|
||||||
return peer;
|
return peer;
|
||||||
}
|
}
|
||||||
/*! \brief Check if we should start attempting to call queue members
|
|
||||||
|
/*!
|
||||||
|
* \brief Check if we should start attempting to call queue members.
|
||||||
*
|
*
|
||||||
* The behavior of this function is dependent first on whether autofill is enabled
|
* The behavior of this function is dependent first on whether autofill is enabled
|
||||||
* and second on whether the ring strategy is ringall. If autofill is not enabled,
|
* and second on whether the ring strategy is ringall. If autofill is not enabled,
|
||||||
@@ -2722,6 +2788,13 @@ static int is_our_turn(struct queue_ent *qe)
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief update rules for queues
|
||||||
|
*
|
||||||
|
* Calculate min/max penalties making sure if relative they stay within bounds.
|
||||||
|
* Update queues penalty and set dialplan vars, goto next list entry.
|
||||||
|
*/
|
||||||
static void update_qe_rule(struct queue_ent *qe)
|
static void update_qe_rule(struct queue_ent *qe)
|
||||||
{
|
{
|
||||||
int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value;
|
int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value;
|
||||||
@@ -2822,6 +2895,10 @@ static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *r
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief update the queue status
|
||||||
|
* \retval Always 0
|
||||||
|
*/
|
||||||
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
|
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
|
||||||
{
|
{
|
||||||
struct member *mem;
|
struct member *mem;
|
||||||
@@ -2861,6 +2938,8 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom
|
|||||||
* A numeric metric is given to each member depending on the ring strategy used
|
* 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
|
* by the queue. Members with lower metrics will be called before members with
|
||||||
* higher metrics
|
* higher metrics
|
||||||
|
* \retval -1 if penalties are exceeded
|
||||||
|
* \retval 0 otherwise
|
||||||
*/
|
*/
|
||||||
static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
|
static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
|
||||||
{
|
{
|
||||||
@@ -2925,6 +3004,7 @@ enum agent_complete_reason {
|
|||||||
TRANSFER
|
TRANSFER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*! \brief Send out AMI message with member call completion status information */
|
||||||
static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
|
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,
|
const struct ast_channel *peer, const struct member *member, time_t callstart,
|
||||||
char *vars, size_t vars_len, enum agent_complete_reason rsn)
|
char *vars, size_t vars_len, enum agent_complete_reason rsn)
|
||||||
@@ -2960,6 +3040,7 @@ static void send_agent_complete(const struct queue_ent *qe, const char *queuenam
|
|||||||
(long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
|
(long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
|
||||||
qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
|
qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
|
/*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
|
||||||
*
|
*
|
||||||
* Here is the process of this function
|
* Here is the process of this function
|
||||||
@@ -3648,10 +3729,9 @@ static struct member *interface_exists(struct call_queue *q, const char *interfa
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Dump all members in a specific queue to the database
|
/*! \brief Dump all members in a specific queue to the database
|
||||||
*
|
*
|
||||||
* <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
|
* <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static void dump_queue_members(struct call_queue *pm_queue)
|
static void dump_queue_members(struct call_queue *pm_queue)
|
||||||
{
|
{
|
||||||
@@ -3693,6 +3773,12 @@ static void dump_queue_members(struct call_queue *pm_queue)
|
|||||||
ast_db_del(pm_family, pm_queue->name);
|
ast_db_del(pm_family, pm_queue->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Remove member from queue
|
||||||
|
* \retval RES_NOT_DYNAMIC when they aren't a RT member
|
||||||
|
* \retval RES_NOSUCHQUEUE queue does not exist
|
||||||
|
* \retval RES_OKAY removed member from queue
|
||||||
|
* \retval RES_EXISTS queue exists but no members
|
||||||
|
*/
|
||||||
static int remove_from_queue(const char *queuename, const char *interface)
|
static int remove_from_queue(const char *queuename, const char *interface)
|
||||||
{
|
{
|
||||||
struct call_queue *q, tmpq = {
|
struct call_queue *q, tmpq = {
|
||||||
@@ -3735,14 +3821,20 @@ static int remove_from_queue(const char *queuename, const char *interface)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Add member to queue
|
||||||
|
* \retval RES_NOT_DYNAMIC when they aren't a RT member
|
||||||
|
* \retval RES_NOSUCHQUEUE queue does not exist
|
||||||
|
* \retval RES_OKAY added member from queue
|
||||||
|
* \retval RES_EXISTS queue exists but no members
|
||||||
|
* \retval RES_OUT_OF_MEMORY queue exists but not enough memory to create member
|
||||||
|
*/
|
||||||
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 int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
|
||||||
{
|
{
|
||||||
struct call_queue *q;
|
struct call_queue *q;
|
||||||
struct member *new_member, *old_member;
|
struct member *new_member, *old_member;
|
||||||
int res = RES_NOSUCHQUEUE;
|
int res = RES_NOSUCHQUEUE;
|
||||||
|
|
||||||
/* \note Ensure the appropriate realtime queue is loaded. Note that this
|
/*! \note Ensure the appropriate realtime queue is loaded. Note that this
|
||||||
* short-circuits if the queue is already in memory. */
|
* short-circuits if the queue is already in memory. */
|
||||||
if (!(q = load_realtime_queue(queuename)))
|
if (!(q = load_realtime_queue(queuename)))
|
||||||
return res;
|
return res;
|
||||||
@@ -3895,8 +3987,8 @@ static int set_member_penalty(char *queuename, char *interface, int penalty)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* \brief Gets members penalty.
|
/* \brief Gets members penalty.
|
||||||
*
|
* \return Return the members penalty or RESULT_FAILURE on error.
|
||||||
* \return Return the members penalty or RESULT_FAILURE on error. */
|
*/
|
||||||
static int get_member_penalty(char *queuename, char *interface)
|
static int get_member_penalty(char *queuename, char *interface)
|
||||||
{
|
{
|
||||||
int foundqueue = 0, penalty;
|
int foundqueue = 0, penalty;
|
||||||
@@ -3927,7 +4019,7 @@ static int get_member_penalty(char *queuename, char *interface)
|
|||||||
return RESULT_FAILURE;
|
return RESULT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reload dynamic queue members persisted into the astdb */
|
/*! \brief Reload dynamic queue members persisted into the astdb */
|
||||||
static void reload_queue_members(void)
|
static void reload_queue_members(void)
|
||||||
{
|
{
|
||||||
char *cur_ptr;
|
char *cur_ptr;
|
||||||
@@ -4024,6 +4116,7 @@ static void reload_queue_members(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief PauseQueueMember application */
|
||||||
static int pqm_exec(struct ast_channel *chan, void *data)
|
static int pqm_exec(struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
char *parse;
|
char *parse;
|
||||||
@@ -4035,7 +4128,7 @@ static int pqm_exec(struct ast_channel *chan, void *data)
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (ast_strlen_zero(data)) {
|
if (ast_strlen_zero(data)) {
|
||||||
ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options][|reason])\n");
|
ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4044,7 +4137,7 @@ static int pqm_exec(struct ast_channel *chan, void *data)
|
|||||||
AST_STANDARD_APP_ARGS(args, parse);
|
AST_STANDARD_APP_ARGS(args, parse);
|
||||||
|
|
||||||
if (ast_strlen_zero(args.interface)) {
|
if (ast_strlen_zero(args.interface)) {
|
||||||
ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options[|reason]])\n");
|
ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4059,6 +4152,7 @@ static int pqm_exec(struct ast_channel *chan, void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief UnPauseQueueMember application */
|
||||||
static int upqm_exec(struct ast_channel *chan, void *data)
|
static int upqm_exec(struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
char *parse;
|
char *parse;
|
||||||
@@ -4070,7 +4164,7 @@ static int upqm_exec(struct ast_channel *chan, void *data)
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (ast_strlen_zero(data)) {
|
if (ast_strlen_zero(data)) {
|
||||||
ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options[|reason]])\n");
|
ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4079,7 +4173,7 @@ static int upqm_exec(struct ast_channel *chan, void *data)
|
|||||||
AST_STANDARD_APP_ARGS(args, parse);
|
AST_STANDARD_APP_ARGS(args, parse);
|
||||||
|
|
||||||
if (ast_strlen_zero(args.interface)) {
|
if (ast_strlen_zero(args.interface)) {
|
||||||
ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options[|reason]])\n");
|
ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4094,6 +4188,7 @@ static int upqm_exec(struct ast_channel *chan, void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief RemoveQueueMember application */
|
||||||
static int rqm_exec(struct ast_channel *chan, void *data)
|
static int rqm_exec(struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
int res=-1;
|
int res=-1;
|
||||||
@@ -4106,7 +4201,7 @@ static int rqm_exec(struct ast_channel *chan, void *data)
|
|||||||
|
|
||||||
|
|
||||||
if (ast_strlen_zero(data)) {
|
if (ast_strlen_zero(data)) {
|
||||||
ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
|
ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4148,6 +4243,7 @@ static int rqm_exec(struct ast_channel *chan, void *data)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief AddQueueMember application */
|
||||||
static int aqm_exec(struct ast_channel *chan, void *data)
|
static int aqm_exec(struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
int res=-1;
|
int res=-1;
|
||||||
@@ -4163,7 +4259,7 @@ static int aqm_exec(struct ast_channel *chan, void *data)
|
|||||||
int penalty = 0;
|
int penalty = 0;
|
||||||
|
|
||||||
if (ast_strlen_zero(data)) {
|
if (ast_strlen_zero(data)) {
|
||||||
ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n");
|
ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,[interface],[penalty][,options][,membername]])\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4210,6 +4306,7 @@ static int aqm_exec(struct ast_channel *chan, void *data)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief QueueLog application */
|
||||||
static int ql_exec(struct ast_channel *chan, void *data)
|
static int ql_exec(struct ast_channel *chan, void *data)
|
||||||
{
|
{
|
||||||
char *parse;
|
char *parse;
|
||||||
@@ -4223,7 +4320,7 @@ static int ql_exec(struct ast_channel *chan, void *data)
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (ast_strlen_zero(data)) {
|
if (ast_strlen_zero(data)) {
|
||||||
ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n");
|
ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4233,7 +4330,7 @@ static int ql_exec(struct ast_channel *chan, void *data)
|
|||||||
|
|
||||||
if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
|
if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
|
||||||
|| ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
|
|| ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
|
||||||
ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n");
|
ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4243,6 +4340,7 @@ static int ql_exec(struct ast_channel *chan, void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Copy rule from global list into specified queue */
|
||||||
static void copy_rules(struct queue_ent *qe, const char *rulename)
|
static void copy_rules(struct queue_ent *qe, const char *rulename)
|
||||||
{
|
{
|
||||||
struct penalty_rule *pr_iter;
|
struct penalty_rule *pr_iter;
|
||||||
@@ -4556,6 +4654,11 @@ stop:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief create interface var with all queue details.
|
||||||
|
* \retval 0 on success
|
||||||
|
* \retval -1 on error
|
||||||
|
*/
|
||||||
static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int res = -1;
|
int res = -1;
|
||||||
@@ -4597,6 +4700,11 @@ static int queue_function_var(struct ast_channel *chan, const char *cmd, char *d
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Get number either busy / free or total members of a specific queue
|
||||||
|
* \retval number of members (busy / free / total)
|
||||||
|
* \retval -1 on error
|
||||||
|
*/
|
||||||
static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@@ -4646,6 +4754,11 @@ static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *d
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Get the total number of members in a specific queue (Deprecated)
|
||||||
|
* \retval number of members
|
||||||
|
* \retval -1 on error
|
||||||
|
*/
|
||||||
static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@@ -4684,7 +4797,7 @@ static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, cha
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue */
|
||||||
static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@@ -4696,7 +4809,7 @@ static int queue_function_queuewaitingcount(struct ast_channel *chan, const char
|
|||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
|
|
||||||
if (ast_strlen_zero(data)) {
|
if (ast_strlen_zero(data)) {
|
||||||
ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
|
ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4720,6 +4833,7 @@ static int queue_function_queuewaitingcount(struct ast_channel *chan, const char
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue */
|
||||||
static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct call_queue *q, tmpq = {
|
struct call_queue *q, tmpq = {
|
||||||
@@ -4767,8 +4881,7 @@ static int queue_function_queuememberlist(struct ast_channel *chan, const char *
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Dialplan function QUEUE_MEMBER_PENALTY()
|
/*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. */
|
||||||
* Gets the members penalty. */
|
|
||||||
static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int penalty;
|
int penalty;
|
||||||
@@ -4799,8 +4912,7 @@ static int queue_function_memberpenalty_read(struct ast_channel *chan, const cha
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Dialplan function QUEUE_MEMBER_PENALTY()
|
/*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. */
|
||||||
* Sets the members penalty. */
|
|
||||||
static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
|
static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
|
||||||
{
|
{
|
||||||
int penalty;
|
int penalty;
|
||||||
@@ -5177,6 +5289,12 @@ static void do_print(struct mansession *s, int fd, const char *str)
|
|||||||
ast_cli(fd, "%s\n", str);
|
ast_cli(fd, "%s\n", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Show queue(s) status and statistics
|
||||||
|
*
|
||||||
|
* List the queues strategy, calls processed, members logged in,
|
||||||
|
* other queue statistics such as avg hold time.
|
||||||
|
*/
|
||||||
static char *__queues_show(struct mansession *s, int fd, int argc, char **argv)
|
static char *__queues_show(struct mansession *s, int fd, int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct call_queue *q;
|
struct call_queue *q;
|
||||||
@@ -5354,7 +5472,7 @@ static int manager_queue_rule_show(struct mansession *s, const struct message *m
|
|||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dump summary of queue info */
|
/*! \brief Summary of queue info via the AMI */
|
||||||
static int manager_queues_summary(struct mansession *s, const struct message *m)
|
static int manager_queues_summary(struct mansession *s, const struct message *m)
|
||||||
{
|
{
|
||||||
time_t now;
|
time_t now;
|
||||||
@@ -5426,7 +5544,7 @@ static int manager_queues_summary(struct mansession *s, const struct message *m)
|
|||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dump queue status */
|
/*! \brief Queue status info via AMI */
|
||||||
static int manager_queues_status(struct mansession *s, const struct message *m)
|
static int manager_queues_status(struct mansession *s, const struct message *m)
|
||||||
{
|
{
|
||||||
time_t now;
|
time_t now;
|
||||||
|
Reference in New Issue
Block a user