Wed Aug 15 01:24:35 2007

Asterisk developer's documentation


app_queue.c File Reference

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

#include "asterisk.h"
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.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 dependency graph for app_queue.c:

Go to the source code of this file.

Data Structures

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

Defines

#define ANNOUNCEHOLDTIME_ALWAYS   1
#define ANNOUNCEHOLDTIME_ONCE   2
#define AST_MAX_WATCHERS   256
#define DEFAULT_RETRY   5
#define DEFAULT_TIMEOUT   15
#define MAX_PERIODIC_ANNOUNCEMENTS   10
#define PM_MAX_LEN   8192
#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_OKAY   0
#define RES_OUTOFMEMORY   (-2)

Enumerations

enum  {
  QUEUE_STRATEGY_RINGALL = 0, QUEUE_STRATEGY_ROUNDROBIN, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_FEWESTCALLS,
  QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RRMEMORY
}
enum  queue_member_status { QUEUE_NO_MEMBERS, QUEUE_NO_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
}

Functions

static int __queues_show (struct mansession *s, int manager, int fd, int argc, char **argv)
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)
static struct
call_queue
alloc_queue (const char *queuename)
static int aqm_exec (struct ast_channel *chan, void *data)
static AST_LIST_HEAD_STATIC (queues, call_queue)
static AST_LIST_HEAD_STATIC (interfaces, member_interface)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"True Call Queueing",.load=load_module,.unload=unload_module,.reload=reload,)
static int calc_metric (struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
static void * changethread (void *data)
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_remove_member (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 struct membercreate_queue_member (const char *interface, const char *membername, int penalty, int paused)
static void destroy_queue (struct call_queue *q)
static void do_hang (struct callattempt *o)
 common hangup actions
static void dump_queue_members (struct call_queue *pm_queue)
static struct
callattempt
find_best (struct callattempt *outgoing)
 find the entry with the best metric, or NULL
static struct
call_queue
find_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
 Reload a single queue via realtime.
static void free_members (struct call_queue *q, int all)
static enum
queue_member_status 
get_member_status (struct call_queue *q, int max_penalty)
static int handle_queue_add_member (int fd, int argc, char *argv[])
static int handle_queue_remove_member (int fd, int argc, char *argv[])
static void hangupcalls (struct callattempt *outgoing, struct ast_channel *exception)
static void init_queue (struct call_queue *q)
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 char * int2strat (int strategy)
static struct memberinterface_exists (struct call_queue *q, const char *interface)
static int interface_exists_global (const char *interface)
static int is_our_turn (struct queue_ent *qe)
static int join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason)
static void leave_queue (struct queue_ent *qe)
static int load_module (void)
static struct
call_queue
load_realtime_queue (const char *queuename)
static int manager_add_queue_member (struct mansession *s, const struct message *m)
static int manager_pause_queue_member (struct mansession *s, const struct message *m)
static int manager_queues_show (struct mansession *s, const struct message *m)
static int manager_queues_status (struct mansession *s, const struct message *m)
static int manager_remove_queue_member (struct mansession *s, const struct message *m)
static int play_file (struct ast_channel *chan, char *filename)
static int pqm_exec (struct ast_channel *chan, void *data)
static int ql_exec (struct ast_channel *chan, void *data)
static int queue_exec (struct ast_channel *chan, void *data)
static int queue_function_qac (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
static int queue_function_queuememberlist (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
static int queue_function_queuewaitingcount (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
static void queue_set_param (struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
 Configure a queue parameter.
static int queue_show (int fd, int argc, char **argv)
static void recalc_holdtime (struct queue_ent *qe, int newholdtime)
static void record_abandoned (struct queue_ent *qe)
static int reload (void)
static void reload_queue_members (void)
static int reload_queues (void)
static int remove_from_interfaces (const char *interface)
static int remove_from_queue (const char *queuename, const char *interface)
static int ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies)
static int ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies)
static void rna (int rnatime, struct queue_ent *qe, char *interface, char *membername)
 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)
static void rr_dep_warning (void)
static void rt_handle_member_record (struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
static int say_periodic_announcement (struct queue_ent *qe)
static int say_position (struct queue_ent *qe)
static int set_member_paused (const char *queuename, const char *interface, int paused)
static void set_queue_result (struct ast_channel *chan, enum queue_result res)
static int statechange_queue (const char *dev, int state, void *ign)
static int store_next (struct queue_ent *qe, struct callattempt *outgoing)
static int strat2int (const char *strategy)
static int try_calling (struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on, const char *agi)
static int unload_module (void)
static int update_dial_status (struct call_queue *q, struct member *member, int status)
static int update_queue (struct call_queue *q, struct member *member, int callcompletedinsl)
static void update_realtime_members (struct call_queue *q)
static int update_status (struct call_queue *q, struct member *member, int status)
static int upqm_exec (struct ast_channel *chan, void *data)
static int valid_exit (struct queue_ent *qe, char digit)
static char * vars2manager (struct ast_channel *chan, char *vars, size_t len)
static int wait_a_bit (struct queue_ent *qe)
static struct
callattempt
wait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
static int wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason)

Variables

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 int autofill_default = 0
 queues.conf [general] option
static struct
ast_cli_entry 
cli_add_queue_member_deprecated
static struct
ast_cli_entry 
cli_queue []
static struct
ast_cli_entry 
cli_remove_queue_member_deprecated
static struct
ast_cli_entry 
cli_show_queue_deprecated
static char * descrip
static int montype_default = 0
 queues.conf [general] option
static const char * pm_family = "Queue/PersistentMembers"
 Persistent Members astdb family.
static char qam_cmd_usage []
static char qrm_cmd_usage []
static int queue_persistent_members = 0
 queues.conf [general] option
struct {
   enum queue_result   id
   char *   text
queue_results []
static char queue_show_usage []
static struct
ast_custom_function 
queueagentcount_function
static struct
ast_custom_function 
queuemembercount_function
static struct
ast_custom_function 
queuememberlist_function
static struct
ast_custom_function 
queuewaitingcount_function
static struct strategy strategies []
static char * synopsis = "Queue a call for a call queue"
static int use_weight = 0
 queues.conf per-queue weight option


Detailed Description

True call queues with optional send URL on answer.

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

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

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

Patch Version 1.07 2003-12-24 01

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

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

Definition in file app_queue.c.


Define Documentation

#define ANNOUNCEHOLDTIME_ALWAYS   1

Definition at line 339 of file app_queue.c.

Referenced by queue_set_param().

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 340 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

#define AST_MAX_WATCHERS   256

Definition at line 1904 of file app_queue.c.

#define DEFAULT_RETRY   5

Definition at line 117 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

#define DEFAULT_TIMEOUT   15

Definition at line 118 of file app_queue.c.

Referenced by queue_set_param().

#define MAX_PERIODIC_ANNOUNCEMENTS   10

Definition at line 120 of file app_queue.c.

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

#define PM_MAX_LEN   8192

Definition at line 240 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

#define QUEUE_EMPTY_NORMAL   1

Definition at line 337 of file app_queue.c.

Referenced by queue_set_param().

#define QUEUE_EMPTY_STRICT   2

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

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

#define RECHECK   1

Definition at line 119 of file app_queue.c.

Referenced by wait_our_turn().

#define RES_EXISTS   (-1)

Definition at line 123 of file app_queue.c.

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

#define RES_NOSUCHQUEUE   (-3)

Definition at line 125 of file app_queue.c.

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

#define RES_OKAY   0

Definition at line 122 of file app_queue.c.

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

#define RES_OUTOFMEMORY   (-2)

Definition at line 124 of file app_queue.c.

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


Enumeration Type Documentation

anonymous enum

Enumerator:
QUEUE_STRATEGY_RINGALL 
QUEUE_STRATEGY_ROUNDROBIN 
QUEUE_STRATEGY_LEASTRECENT 
QUEUE_STRATEGY_FEWESTCALLS 
QUEUE_STRATEGY_RANDOM 
QUEUE_STRATEGY_RRMEMORY 

Definition at line 96 of file app_queue.c.

enum queue_member_status

Enumerator:
QUEUE_NO_MEMBERS 
QUEUE_NO_REACHABLE_MEMBERS 
QUEUE_NORMAL 

Definition at line 474 of file app_queue.c.

00474                          {
00475    QUEUE_NO_MEMBERS,
00476    QUEUE_NO_REACHABLE_MEMBERS,
00477    QUEUE_NORMAL
00478 };

enum queue_result

Enumerator:
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 

Definition at line 254 of file app_queue.c.

00254                   {
00255    QUEUE_UNKNOWN = 0,
00256    QUEUE_TIMEOUT = 1,
00257    QUEUE_JOINEMPTY = 2,
00258    QUEUE_LEAVEEMPTY = 3,
00259    QUEUE_JOINUNAVAIL = 4,
00260    QUEUE_LEAVEUNAVAIL = 5,
00261    QUEUE_FULL = 6,
00262 };


Function Documentation

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

Definition at line 3939 of file app_queue.c.

References ast_build_string(), ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), astman_append(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, call_queue::count, devstate2str(), member::dynamic, call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, load_realtime_queue(), call_queue::lock, call_queue::maxlen, call_queue::members, call_queue::name, queue_ent::next, member::next, member::paused, member::penalty, queue_ent::prio, queue_show(), RESULT_SHOWUSAGE, RESULT_SUCCESS, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, and call_queue::weight.

Referenced by manager_queues_show(), and queue_show().

03940 {
03941    struct call_queue *q;
03942    struct queue_ent *qe;
03943    struct member *mem;
03944    int pos, queue_show;
03945    time_t now;
03946    char max_buf[80];
03947    char *max;
03948    size_t max_left;
03949    float sl = 0;
03950    char *term = manager ? "\r\n" : "\n";
03951 
03952    time(&now);
03953    if (argc == 2)
03954       queue_show = 0;
03955    else if (argc == 3)
03956       queue_show = 1;
03957    else
03958       return RESULT_SHOWUSAGE;
03959 
03960    /* We only want to load realtime queues when a specific queue is asked for. */
03961    if (queue_show)
03962       load_realtime_queue(argv[2]);
03963 
03964    AST_LIST_LOCK(&queues);
03965    if (AST_LIST_EMPTY(&queues)) {
03966       AST_LIST_UNLOCK(&queues);
03967       if (queue_show) {
03968          if (s)
03969             astman_append(s, "No such queue: %s.%s",argv[2], term);
03970          else
03971             ast_cli(fd, "No such queue: %s.%s",argv[2], term);
03972       } else {
03973          if (s)
03974             astman_append(s, "No queues.%s", term);
03975          else
03976             ast_cli(fd, "No queues.%s", term);
03977       }
03978       return RESULT_SUCCESS;
03979    }
03980    AST_LIST_TRAVERSE(&queues, q, list) {
03981       ast_mutex_lock(&q->lock);
03982       if (queue_show) {
03983          if (strcasecmp(q->name, argv[2]) != 0) {
03984             ast_mutex_unlock(&q->lock);
03985             if (!AST_LIST_NEXT(q, list)) {
03986                ast_cli(fd, "No such queue: %s.%s",argv[2], term);
03987                break;
03988             }
03989             continue;
03990          }
03991       }
03992       max_buf[0] = '\0';
03993       max = max_buf;
03994       max_left = sizeof(max_buf);
03995       if (q->maxlen)
03996          ast_build_string(&max, &max_left, "%d", q->maxlen);
03997       else
03998          ast_build_string(&max, &max_left, "unlimited");
03999       sl = 0;
04000       if (q->callscompleted > 0)
04001          sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
04002       if (s)
04003          astman_append(s, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
04004             q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight,
04005             q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
04006       else
04007          ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
04008             q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
04009       if (q->members) {
04010          if (s)
04011             astman_append(s, "   Members: %s", term);
04012          else
04013             ast_cli(fd, "   Members: %s", term);
04014          for (mem = q->members; mem; mem = mem->next) {
04015             max_buf[0] = '\0';
04016             max = max_buf;
04017             max_left = sizeof(max_buf);
04018             if (mem->penalty)
04019                ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
04020             if (mem->dynamic)
04021                ast_build_string(&max, &max_left, " (dynamic)");
04022             if (mem->paused)
04023                ast_build_string(&max, &max_left, " (paused)");
04024             ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
04025             if (mem->calls) {
04026                ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
04027                   mem->calls, (long) (time(NULL) - mem->lastcall));
04028             } else
04029                ast_build_string(&max, &max_left, " has taken no calls yet");
04030             if (s)
04031                astman_append(s, "      %s%s%s", mem->interface, max_buf, term);
04032             else
04033                ast_cli(fd, "      %s%s%s", mem->interface, max_buf, term);
04034          }
04035       } else if (s)
04036          astman_append(s, "   No Members%s", term);
04037       else  
04038          ast_cli(fd, "   No Members%s", term);
04039       if (q->head) {
04040          pos = 1;
04041          if (s)
04042             astman_append(s, "   Callers: %s", term);
04043          else
04044             ast_cli(fd, "   Callers: %s", term);
04045          for (qe = q->head; qe; qe = qe->next) {
04046             if (s)
04047                astman_append(s, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
04048                   pos++, qe->chan->name, (long) (now - qe->start) / 60,
04049                   (long) (now - qe->start) % 60, qe->prio, term);
04050             else
04051                ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
04052                   qe->chan->name, (long) (now - qe->start) / 60,
04053                   (long) (now - qe->start) % 60, qe->prio, term);
04054          }
04055       } else if (s)
04056          astman_append(s, "   No Callers%s", term);
04057       else
04058          ast_cli(fd, "   No Callers%s", term);
04059       if (s)
04060          astman_append(s, "%s", term);
04061       else
04062          ast_cli(fd, "%s", term);
04063       ast_mutex_unlock(&q->lock);
04064       if (queue_show)
04065          break;
04066    }
04067    AST_LIST_UNLOCK(&queues);
04068    return RESULT_SUCCESS;
04069 }

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

Definition at line 695 of file app_queue.c.

References ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), member_interface::interface, LOG_DEBUG, and option_debug.

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

00696 {
00697    struct member_interface *curint;
00698 
00699    AST_LIST_LOCK(&interfaces);
00700    AST_LIST_TRAVERSE(&interfaces, curint, list) {
00701       if (!strcasecmp(curint->interface, interface))
00702          break;
00703    }
00704 
00705    if (curint) {
00706       AST_LIST_UNLOCK(&interfaces);
00707       return 0;
00708    }
00709 
00710    if (option_debug)
00711       ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
00712    
00713    if ((curint = ast_calloc(1, sizeof(*curint)))) {
00714       ast_copy_string(curint->interface, interface, sizeof(curint->interface));
00715       AST_LIST_INSERT_HEAD(&interfaces, curint, list);
00716    }
00717    AST_LIST_UNLOCK(&interfaces);
00718 
00719    return 0;
00720 }

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

Definition at line 2885 of file app_queue.c.

References add_to_interfaces(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), member::calls, create_queue_member(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, interface_exists(), member::lastcall, load_realtime_queue(), call_queue::lock, manager_event(), call_queue::membercount, member::membername, call_queue::members, call_queue::name, member::next, member::paused, member::penalty, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and member::status.

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

02886 {
02887    struct call_queue *q;
02888    struct member *new_member;
02889    int res = RES_NOSUCHQUEUE;
02890 
02891    /* \note Ensure the appropriate realtime queue is loaded.  Note that this
02892     * short-circuits if the queue is already in memory. */
02893    if (!(q = load_realtime_queue(queuename)))
02894       return res;
02895 
02896    AST_LIST_LOCK(&queues);
02897 
02898    ast_mutex_lock(&q->lock);
02899    if (interface_exists(q, interface) == NULL) {
02900       add_to_interfaces(interface);
02901       if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
02902          new_member->dynamic = 1;
02903          new_member->next = q->members;
02904          q->members = new_member;
02905          q->membercount++;
02906          manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
02907             "Queue: %s\r\n"
02908             "Location: %s\r\n"
02909             "MemberName: %s\r\n"
02910             "Membership: %s\r\n"
02911             "Penalty: %d\r\n"
02912             "CallsTaken: %d\r\n"
02913             "LastCall: %d\r\n"
02914             "Status: %d\r\n"
02915             "Paused: %d\r\n",
02916             q->name, new_member->interface, new_member->membername,
02917             new_member->dynamic ? "dynamic" : "static",
02918             new_member->penalty, new_member->calls, (int) new_member->lastcall,
02919             new_member->status, new_member->paused);
02920          
02921          if (dump)
02922             dump_queue_members(q);
02923          
02924          res = RES_OKAY;
02925       } else {
02926          res = RES_OUTOFMEMORY;
02927       }
02928    } else {
02929       res = RES_EXISTS;
02930    }
02931    ast_mutex_unlock(&q->lock);
02932    AST_LIST_UNLOCK(&queues);
02933 
02934    return res;
02935 }

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

Definition at line 638 of file app_queue.c.

References ast_calloc, ast_mutex_init(), call_queue::lock, and call_queue::name.

Referenced by find_queue_by_name_rt(), and reload_queues().

00639 {
00640    struct call_queue *q;
00641 
00642    if ((q = ast_calloc(1, sizeof(*q)))) {
00643       ast_mutex_init(&q->lock);
00644       ast_copy_string(q->name, queuename, sizeof(q->name));
00645    }
00646    return q;
00647 }

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

Definition at line 3242 of file app_queue.c.

References add_to_queue(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_channel::context, ast_channel::exten, member_interface::interface, LOG_ERROR, LOG_NOTICE, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), ast_channel::priority, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.

Referenced by load_module().

03243 {
03244    int res=-1;
03245    struct ast_module_user *lu;
03246    char *parse, *temppos = NULL;
03247    int priority_jump = 0;
03248    AST_DECLARE_APP_ARGS(args,
03249       AST_APP_ARG(queuename);
03250       AST_APP_ARG(interface);
03251       AST_APP_ARG(penalty);
03252       AST_APP_ARG(options);
03253       AST_APP_ARG(membername);
03254    );
03255    int penalty = 0;
03256 
03257    if (ast_strlen_zero(data)) {
03258       ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n");
03259       return -1;
03260    }
03261 
03262    parse = ast_strdupa(data);
03263 
03264    AST_STANDARD_APP_ARGS(args, parse);
03265 
03266    lu = ast_module_user_add(chan);
03267 
03268    if (ast_strlen_zero(args.interface)) {
03269       args.interface = ast_strdupa(chan->name);
03270       temppos = strrchr(args.interface, '-');
03271       if (temppos)
03272          *temppos = '\0';
03273    }
03274 
03275    if (!ast_strlen_zero(args.penalty)) {
03276       if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
03277          ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
03278          penalty = 0;
03279       }
03280    }
03281    
03282    if (args.options) {
03283       if (strchr(args.options, 'j'))
03284          priority_jump = 1;
03285    }
03286 
03287    if (ast_strlen_zero(args.membername))
03288       args.membername = args.interface;
03289 
03290 
03291    switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) {
03292    case RES_OKAY:
03293       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
03294       ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
03295       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
03296       res = 0;
03297       break;
03298    case RES_EXISTS:
03299       ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
03300       if (priority_jump || ast_opt_priority_jumping)
03301          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
03302       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
03303       res = 0;
03304       break;
03305    case RES_NOSUCHQUEUE:
03306       ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
03307       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
03308       res = 0;
03309       break;
03310    case RES_OUTOFMEMORY:
03311       ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
03312       break;
03313    }
03314 
03315    ast_module_user_remove(lu);
03316 
03317    return res;
03318 }

static AST_LIST_HEAD_STATIC ( queues  ,
call_queue   
) [static]

static AST_LIST_HEAD_STATIC ( interfaces  ,
member_interface   
) [static]

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_DEFAULT  ,
"True Call Queueing"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

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

Definition at line 2290 of file app_queue.c.

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

Referenced by try_calling().

02291 {
02292    if (qe->max_penalty && (mem->penalty > qe->max_penalty))
02293       return -1;
02294 
02295    switch (q->strategy) {
02296    case QUEUE_STRATEGY_RINGALL:
02297       /* Everyone equal, except for penalty */
02298       tmp->metric = mem->penalty * 1000000;
02299       break;
02300    case QUEUE_STRATEGY_ROUNDROBIN:
02301       if (!pos) {
02302          if (!q->wrapped) {
02303             /* No more channels, start over */
02304             q->rrpos = 0;
02305          } else {
02306             /* Prioritize next entry */
02307             q->rrpos++;
02308          }
02309          q->wrapped = 0;
02310       }
02311       /* Fall through */
02312    case QUEUE_STRATEGY_RRMEMORY:
02313       if (pos < q->rrpos) {
02314          tmp->metric = 1000 + pos;
02315       } else {
02316          if (pos > q->rrpos)
02317             /* Indicate there is another priority */
02318             q->wrapped = 1;
02319          tmp->metric = pos;
02320       }
02321       tmp->metric += mem->penalty * 1000000;
02322       break;
02323    case QUEUE_STRATEGY_RANDOM:
02324       tmp->metric = ast_random() % 1000;
02325       tmp->metric += mem->penalty * 1000000;
02326       break;
02327    case QUEUE_STRATEGY_FEWESTCALLS:
02328       tmp->metric = mem->calls;
02329       tmp->metric += mem->penalty * 1000000;
02330       break;
02331    case QUEUE_STRATEGY_LEASTRECENT:
02332       if (!mem->lastcall)
02333          tmp->metric = 0;
02334       else
02335          tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
02336       tmp->metric += mem->penalty * 1000000;
02337       break;
02338    default:
02339       ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
02340       break;
02341    }
02342    return 0;
02343 }

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

Definition at line 514 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, member::calls, statechange::dev, devstate2str(), member::dynamic, EVENT_FLAG_AGENT, free, member::interface, member_interface::interface, member::lastcall, call_queue::lock, LOG_DEBUG, manager_event(), call_queue::maskmemberstatus, member::membername, call_queue::members, call_queue::name, member::next, option_debug, member::paused, member::penalty, statechange::state, and member::status.

Referenced by statechange_queue().

00515 {
00516    struct call_queue *q;
00517    struct statechange *sc = data;
00518    struct member *cur;
00519    struct member_interface *curint;
00520    char *loc;
00521    char *technology;
00522 
00523    technology = ast_strdupa(sc->dev);
00524    loc = strchr(technology, '/');
00525    if (loc) {
00526       *loc++ = '\0';
00527    } else {
00528       free(sc);
00529       return NULL;
00530    }
00531 
00532    AST_LIST_LOCK(&interfaces);
00533    AST_LIST_TRAVERSE(&interfaces, curint, list) {
00534       char *interface;
00535       char *slash_pos;
00536       interface = ast_strdupa(curint->interface);
00537       if ((slash_pos = strchr(interface, '/')))
00538          if ((slash_pos = strchr(slash_pos + 1, '/')))
00539             *slash_pos = '\0';
00540 
00541       if (!strcasecmp(interface, sc->dev))
00542          break;
00543    }
00544    AST_LIST_UNLOCK(&interfaces);
00545 
00546    if (!curint) {
00547       if (option_debug > 2)
00548          ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", technology, loc, sc->state, devstate2str(sc->state));
00549       free(sc);
00550       return NULL;
00551    }
00552 
00553    if (option_debug)
00554       ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
00555    AST_LIST_LOCK(&queues);
00556    AST_LIST_TRAVERSE(&queues, q, list) {
00557       ast_mutex_lock(&q->lock);
00558       for (cur = q->members; cur; cur = cur->next) {
00559          char *interface;
00560          char *slash_pos;
00561          interface = ast_strdupa(cur->interface);
00562          if ((slash_pos = strchr(interface, '/')))
00563             if ((slash_pos = strchr(slash_pos + 1, '/')))
00564                *slash_pos = '\0';
00565 
00566          if (strcasecmp(sc->dev, interface))
00567             continue;
00568 
00569          if (cur->status != sc->state) {
00570             cur->status = sc->state;
00571             if (q->maskmemberstatus)
00572                continue;
00573 
00574             manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
00575                "Queue: %s\r\n"
00576                "Location: %s\r\n"
00577                "MemberName: %s\r\n"
00578                "Membership: %s\r\n"
00579                "Penalty: %d\r\n"
00580                "CallsTaken: %d\r\n"
00581                "LastCall: %d\r\n"
00582                "Status: %d\r\n"
00583                "Paused: %d\r\n",
00584                q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static",
00585                cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
00586          }
00587       }
00588       ast_mutex_unlock(&q->lock);
00589    }
00590    AST_LIST_UNLOCK(&queues);
00591 
00592    free(sc);
00593 
00594    return NULL;
00595 }

static void clear_and_free_interfaces ( void   )  [static]

Definition at line 766 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.

Referenced by unload_module().

00767 {
00768    struct member_interface *curint;
00769 
00770    AST_LIST_LOCK(&interfaces);
00771    while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
00772       free(curint);
00773    AST_LIST_UNLOCK(&interfaces);
00774 }

static void clear_queue ( struct call_queue q  )  [static]

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

00687 {
00688    q->holdtime = 0;
00689    q->callscompleted = 0;
00690    q->callsabandoned = 0;
00691    q->callscompletedinsl = 0;
00692    q->wrapuptime = 0;
00693 }

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

Definition at line 1560 of file app_queue.c.

References AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), call_queue::count, member::interface, call_queue::lock, LOG_DEBUG, call_queue::members, call_queue::name, member::next, and call_queue::weight.

Referenced by ring_entry().

01561 {
01562    struct call_queue *q;
01563    struct member *mem;
01564    int found = 0;
01565    
01566    /* &qlock and &rq->lock already set by try_calling()
01567     * to solve deadlock */
01568    AST_LIST_TRAVERSE(&queues, q, list) {
01569       if (q == rq) /* don't check myself, could deadlock */
01570          continue;
01571       ast_mutex_lock(&q->lock);
01572       if (q->count && q->members) {
01573          for (mem = q->members; mem; mem = mem->next) {
01574             if (strcmp(mem->interface, member->interface))
01575                continue;
01576 
01577             ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
01578             if (q->weight > rq->weight) {
01579                ast_log(LOG_DEBUG, "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);
01580                found = 1;
01581                break;
01582             }
01583          }
01584       }
01585       ast_mutex_unlock(&q->lock);
01586       if (found)
01587          break;
01588    }
01589    return found;
01590 }

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

Definition at line 4076 of file app_queue.c.

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

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

04077 {
04078    struct call_queue *q;
04079    char *ret = NULL;
04080    int which = 0;
04081    int wordlen = strlen(word);
04082    
04083    AST_LIST_LOCK(&queues);
04084    AST_LIST_TRAVERSE(&queues, q, list) {
04085       if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
04086          ret = ast_strdup(q->name); 
04087          break;
04088       }
04089    }
04090    AST_LIST_UNLOCK(&queues);
04091 
04092    return ret;
04093 }

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

Definition at line 4368 of file app_queue.c.

References ast_malloc, ast_strdup, and complete_queue().

04369 {
04370    /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
04371    switch (pos) {
04372    case 3:  /* Don't attempt to complete name of interface (infinite possibilities) */
04373       return NULL;
04374    case 4:  /* only one possible match, "to" */
04375       return state == 0 ? ast_strdup("to") : NULL;
04376    case 5:  /* <queue> */
04377       return complete_queue(line, word, pos, state);
04378    case 6: /* only one possible match, "penalty" */
04379       return state == 0 ? ast_strdup("penalty") : NULL;
04380    case 7:
04381       if (state < 100) {   /* 0-99 */
04382          char *num;
04383          if ((num = ast_malloc(3))) {
04384             sprintf(num, "%d", state);
04385          }
04386          return num;
04387       } else {
04388          return NULL;
04389       }
04390    case 8: /* only one possible match, "as" */
04391       return state == 0 ? ast_strdup("as") : NULL;
04392    case 9:  /* Don't attempt to complete name of member (infinite possibilities) */
04393       return NULL;
04394    default:
04395       return NULL;
04396    }
04397 }

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

Definition at line 4431 of file app_queue.c.

References AST_LIST_EMPTY, AST_LIST_TRAVERSE, ast_mutex_lock(), ast_mutex_unlock(), ast_strdup, complete_queue(), member::interface, call_queue::lock, call_queue::members, and member::next.

04432 {
04433    int which = 0;
04434    struct call_queue *q;
04435    struct member *m;
04436 
04437    /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
04438    if (pos > 5 || pos < 3)
04439       return NULL;
04440    if (pos == 4)  /* only one possible match, 'from' */
04441       return state == 0 ? ast_strdup("from") : NULL;
04442 
04443    if (pos == 5)  /* No need to duplicate code */
04444       return complete_queue(line, word, pos, state);
04445 
04446    /* here is the case for 3, <member> */
04447    if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */
04448       AST_LIST_TRAVERSE(&queues, q, list) {
04449          ast_mutex_lock(&q->lock);
04450          for (m = q->members ; m ; m = m->next) {
04451             if (++which > state) {
04452                ast_mutex_unlock(&q->lock);
04453                return ast_strdup(m->interface);
04454             }
04455          }
04456          ast_mutex_unlock(&q->lock);
04457       }
04458    }
04459 
04460    return NULL;
04461 }

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

Definition at line 4095 of file app_queue.c.

References complete_queue().

04096 {
04097    if (pos == 2)
04098       return complete_queue(line, word, pos, state);
04099    return NULL;
04100 }

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

Definition at line 621 of file app_queue.c.

References ast_calloc, ast_device_state(), ast_log(), member::interface, LOG_WARNING, member::membername, member::paused, member::penalty, and member::status.

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

00622 {
00623    struct member *cur;
00624    
00625    if ((cur = ast_calloc(1, sizeof(*cur)))) {
00626       cur->penalty = penalty;
00627       cur->paused = paused;
00628       ast_copy_string(cur->interface, interface, sizeof(cur->interface));
00629       ast_copy_string(cur->membername, membername, sizeof(cur->membername));
00630       if (!strchr(cur->interface, '/'))
00631          ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
00632       cur->status = ast_device_state(interface);
00633    }
00634 
00635    return cur;
00636 }

static void destroy_queue ( struct call_queue q  )  [static]

Definition at line 993 of file app_queue.c.

References ast_mutex_destroy(), free, free_members(), and call_queue::lock.

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

00994 {
00995    free_members(q, 1);
00996    ast_mutex_destroy(&q->lock);
00997    free(q);
00998 }

static void do_hang ( struct callattempt o  )  [static]

common hangup actions

Definition at line 1593 of file app_queue.c.

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

Referenced by ring_entry(), and wait_for_answer().

01594 {
01595    o->stillgoing = 0;
01596    ast_hangup(o->chan);
01597    o->chan = NULL;
01598 }

static void dump_queue_members ( struct call_queue pm_queue  )  [static]

Definition at line 2795 of file app_queue.c.

References ast_db_del(), ast_db_put(), ast_log(), member::dynamic, member::interface, LOG_WARNING, member::membername, call_queue::members, call_queue::name, member::next, member::paused, member::penalty, and PM_MAX_LEN.

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

02796 {
02797    struct member *cur_member;
02798    char value[PM_MAX_LEN];
02799    int value_len = 0;
02800    int res;
02801 
02802    memset(value, 0, sizeof(value));
02803 
02804    if (!pm_queue)
02805       return;
02806 
02807    for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
02808       if (!cur_member->dynamic)
02809          continue;
02810 
02811       res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d;%s%s",
02812          cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername,
02813          cur_member->next ? "|" : "");
02814       if (res != strlen(value + value_len)) {
02815          ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
02816          break;
02817       }
02818       value_len += res;
02819    }
02820    
02821    if (value_len && !cur_member) {
02822       if (ast_db_put(pm_family, pm_queue->name, value))
02823          ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
02824    } else
02825       /* Delete the entry if the queue is empty or there is an error */
02826       ast_db_del(pm_family, pm_queue->name);
02827 }

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

find the entry with the best metric, or NULL

Definition at line 1756 of file app_queue.c.

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

01757 {
01758    struct callattempt *best = NULL, *cur;
01759 
01760    for (cur = outgoing; cur; cur = cur->q_next) {
01761       if (cur->stillgoing &&              /* Not already done */
01762          !cur->chan &&              /* Isn't already going */
01763          (!best || cur->metric < best->metric)) {     /* We haven't found one yet, or it's better */
01764          best = cur;
01765       }
01766    }
01767 
01768    return best;
01769 }

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.

Returns:
Return the queue, or NULL if it doesn't exist.
Note:
Should be called with the global qlock 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 1003 of file app_queue.c.

References alloc_queue(), ast_category_browse(), AST_LIST_INSERT_HEAD, AST_LIST_REMOVE, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_variable_retrieve(), clear_queue(), call_queue::count, member::dead, call_queue::dead, destroy_queue(), member::dynamic, free, init_queue(), member::interface, member_interface::interface, call_queue::lock, LOG_DEBUG, call_queue::membercount, call_queue::members, ast_variable::name, call_queue::name, member::next, ast_variable::next, queue_set_param(), QUEUE_STRATEGY_ROUNDROBIN, call_queue::realtime, remove_from_interfaces(), rr_dep_warning(), rt_handle_member_record(), S_OR, call_queue::strategy, and ast_variable::value.

Referenced by load_realtime_queue().

01004 {
01005    struct ast_variable *v;
01006    struct call_queue *q;
01007    struct member *m, *prev_m, *next_m;
01008    char *interface = NULL;
01009    char *tmp, *tmp_name;
01010    char tmpbuf[64];  /* Must be longer than the longest queue param name. */
01011 
01012    /* Find the queue in the in-core list (we will create a new one if not found). */
01013    AST_LIST_TRAVERSE(&queues, q, list) {
01014       if (!strcasecmp(q->name, queuename))
01015          break;
01016    }
01017 
01018    /* Static queues override realtime. */
01019    if (q) {
01020       ast_mutex_lock(&q->lock);
01021       if (!q->realtime) {
01022          if (q->dead) {
01023             ast_mutex_unlock(&q->lock);
01024             return NULL;
01025          } else {
01026             ast_mutex_unlock(&q->lock);
01027             return q;
01028          }
01029       }
01030    } else if (!member_config)
01031       /* Not found in the list, and it's not realtime ... */
01032       return NULL;
01033 
01034    /* Check if queue is defined in realtime. */
01035    if (!queue_vars) {
01036       /* Delete queue from in-core list if it has been deleted in realtime. */
01037       if (q) {
01038          /*! \note Hmm, can't seem to distinguish a DB failure from a not
01039             found condition... So we might delete an in-core queue
01040             in case of DB failure. */
01041          ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
01042 
01043          q->dead = 1;
01044          /* Delete if unused (else will be deleted when last caller leaves). */
01045          if (!q->count) {
01046             /* Delete. */
01047             AST_LIST_REMOVE(&queues, q, list);
01048             ast_mutex_unlock(&q->lock);
01049             destroy_queue(q);
01050          } else
01051             ast_mutex_unlock(&q->lock);
01052       }
01053       return NULL;
01054    }
01055 
01056    /* Create a new queue if an in-core entry does not exist yet. */
01057    if (!q) {
01058       if (!(q = alloc_queue(queuename)))
01059          return NULL;
01060       ast_mutex_lock(&q->lock);
01061       clear_queue(q);
01062       q->realtime = 1;
01063       AST_LIST_INSERT_HEAD(&queues, q, list);
01064    }
01065    init_queue(q);    /* Ensure defaults for all parameters not set explicitly. */
01066 
01067    memset(tmpbuf, 0, sizeof(tmpbuf));
01068    for (v = queue_vars; v; v = v->next) {
01069       /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
01070       if ((tmp = strchr(v->name, '_'))) {
01071          ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
01072          tmp_name = tmpbuf;
01073          tmp = tmp_name;
01074          while ((tmp = strchr(tmp, '_')))
01075             *tmp++ = '-';
01076       } else
01077          tmp_name = v->name;
01078       queue_set_param(q, tmp_name, v->value, -1, 0);
01079    }
01080 
01081    if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
01082       rr_dep_warning();
01083 
01084    /* Temporarily set non-dynamic members dead so we can detect deleted ones. 
01085     * Also set the membercount correctly for realtime*/
01086    for (m = q->members; m; m = m->next, q->membercount++) {
01087       if (!m->dynamic)
01088          m->dead = 1;
01089    }
01090 
01091    while ((interface = ast_category_browse(member_config, interface))) {
01092       rt_handle_member_record(q, interface,
01093          S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
01094          ast_variable_retrieve(member_config, interface, "penalty"),
01095          ast_variable_retrieve(member_config, interface, "paused"));
01096    }
01097 
01098    /* Delete all realtime members that have been deleted in DB. */
01099    m = q->members;
01100    prev_m = NULL;
01101    while (m) {
01102       next_m = m->next;
01103       if (m->dead) {
01104          if (prev_m) {
01105             prev_m->next = next_m;
01106          } else {
01107             q->members = next_m;
01108          }
01109          remove_from_interfaces(m->interface);
01110          q->membercount--;
01111          free(m);
01112       } else {
01113          prev_m = m;
01114       }
01115       m = next_m;
01116    }
01117 
01118    ast_mutex_unlock(&q->lock);
01119 
01120    return q;
01121 }

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

Definition at line 973 of file app_queue.c.

References member::dynamic, free, member::interface, call_queue::membercount, call_queue::members, member::next, and remove_from_interfaces().

Referenced by destroy_queue().

00974 {
00975    /* Free non-dynamic members */
00976    struct member *curm, *next, *prev = NULL;
00977 
00978    for (curm = q->members; curm; curm = next) {
00979       next = curm->next;
00980       if (all || !curm->dynamic) {
00981          if (prev)
00982             prev->next = next;
00983          else
00984             q->members = next;
00985          remove_from_interfaces(curm->interface);
00986          q->membercount--;
00987          free(curm);
00988       } else
00989          prev = curm;
00990    }
00991 }

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

Definition at line 480 of file app_queue.c.

References AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, ast_mutex_lock(), ast_mutex_unlock(), call_queue::lock, call_queue::members, member::next, member::paused, member::penalty, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NORMAL, and member::status.

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

00481 {
00482    struct member *member;
00483    enum queue_member_status result = QUEUE_NO_MEMBERS;
00484 
00485    ast_mutex_lock(&q->lock);
00486    for (member = q->members; member; member = member->next) {
00487       if (max_penalty && (member->penalty > max_penalty))
00488          continue;
00489 
00490       if (member->paused) continue;
00491 
00492       switch (member->status) {
00493       case AST_DEVICE_INVALID:
00494          /* nothing to do */
00495          break;
00496       case AST_DEVICE_UNAVAILABLE:
00497          result = QUEUE_NO_REACHABLE_MEMBERS;
00498          break;
00499       default:
00500          ast_mutex_unlock(&q->lock);
00501          return QUEUE_NORMAL;
00502       }
00503    }
00504    
00505    ast_mutex_unlock(&q->lock);
00506    return result;
00507 }

static int handle_queue_add_member ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 4312 of file app_queue.c.

References add_to_queue(), ast_cli(), ast_queue_log(), member_interface::interface, member::membername, member::penalty, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

04313 {
04314    char *queuename, *interface, *membername;
04315    int penalty;
04316 
04317    if ((argc != 6) && (argc != 8) && (argc != 10)) {
04318       return RESULT_SHOWUSAGE;
04319    } else if (strcmp(argv[4], "to")) {
04320       return RESULT_SHOWUSAGE;
04321    } else if ((argc == 8) && strcmp(argv[6], "penalty")) {
04322       return RESULT_SHOWUSAGE;
04323    } else if ((argc == 10) && strcmp(argv[8], "as")) {
04324       return RESULT_SHOWUSAGE;
04325    }
04326 
04327    queuename = argv[5];
04328    interface = argv[3];
04329    if (argc >= 8) {
04330       if (sscanf(argv[7], "%d", &penalty) == 1) {
04331          if (penalty < 0) {
04332             ast_cli(fd, "Penalty must be >= 0\n");
04333             penalty = 0;
04334          }
04335       } else {
04336          ast_cli(fd, "Penalty must be an integer >= 0\n");
04337          penalty = 0;
04338       }
04339    } else {
04340       penalty = 0;
04341    }
04342 
04343    if (argc >= 10) {
04344       membername = argv[9];
04345    } else {
04346       membername = interface;
04347    }
04348 
04349    switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) {
04350    case RES_OKAY:
04351       ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
04352       ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
04353       return RESULT_SUCCESS;
04354    case RES_EXISTS:
04355       ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
04356       return RESULT_FAILURE;
04357    case RES_NOSUCHQUEUE:
04358       ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
04359       return RESULT_FAILURE;
04360    case RES_OUTOFMEMORY:
04361       ast_cli(fd, "Out of memory\n");
04362       return RESULT_FAILURE;
04363    default:
04364       return RESULT_FAILURE;
04365    }
04366 }

static int handle_queue_remove_member ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 4399 of file app_queue.c.

References ast_cli(), ast_queue_log(), member_interface::interface, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

04400 {
04401    char *queuename, *interface;
04402 
04403    if (argc != 6) {
04404       return RESULT_SHOWUSAGE;
04405    } else if (strcmp(argv[4], "from")) {
04406       return RESULT_SHOWUSAGE;
04407    }
04408 
04409    queuename = argv[5];
04410    interface = argv[3];
04411 
04412    switch (remove_from_queue(queuename, interface)) {
04413    case RES_OKAY:
04414       ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
04415       ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
04416       return RESULT_SUCCESS;
04417    case RES_EXISTS:
04418       ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
04419       return RESULT_FAILURE;
04420    case RES_NOSUCHQUEUE:
04421       ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
04422       return RESULT_FAILURE;
04423    case RES_OUTOFMEMORY:
04424       ast_cli(fd, "Out of memory\n");
04425       return RESULT_FAILURE;
04426    default:
04427       return RESULT_FAILURE;
04428    }
04429 }

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

Definition at line 1500 of file app_queue.c.

References ast_hangup(), callattempt::chan, free, and callattempt::q_next.

Referenced by try_calling().

01501 {
01502    struct callattempt *oo;
01503 
01504    while (outgoing) {
01505       /* Hangup any existing lines we have open */
01506       if (outgoing->chan && (outgoing->chan != exception))
01507          ast_hangup(outgoing->chan);
01508       oo = outgoing;
01509       outgoing = outgoing->q_next;
01510       free(oo);
01511    }
01512 }

static void init_queue ( struct call_queue q  )  [static]

Definition at line 649 of file app_queue.c.

References call_queue::announce, call_queue::announcefrequency, call_queue::announceholdtime, call_queue::autofill, call_queue::context, call_queue::dead, DEFAULT_RETRY, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, call_queue::membercount, call_queue::moh, call_queue::monfmt, call_queue::montype, call_queue::periodicannouncefrequency, call_queue::retry, call_queue::ringinuse, call_queue::roundingseconds, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_periodicannounce, call_queue::sound_reporthold, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, and call_queue::timeout.

Referenced by find_queue_by_name_rt(), and reload_queues().

00650 {
00651    int i;
00652 
00653    q->dead = 0;
00654    q->retry = DEFAULT_RETRY;
00655    q->timeout = -1;
00656    q->maxlen = 0;
00657    q->announcefrequency = 0;
00658    q->announceholdtime = 0;
00659    q->roundingseconds = 0; /* Default - don't announce seconds */
00660    q->servicelevel = 0;
00661    q->ringinuse = 1;
00662    q->setinterfacevar = 0;
00663    q->autofill = autofill_default;
00664    q->montype = montype_default;
00665    q->moh[0] = '\0';
00666    q->announce[0] = '\0';
00667    q->context[0] = '\0';
00668    q->monfmt[0] = '\0';
00669    q->periodicannouncefrequency = 0;
00670    q->membercount = 0;
00671    ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
00672    ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
00673    ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
00674    ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
00675    ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
00676    ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
00677    ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
00678    ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
00679    ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
00680    ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
00681    for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
00682       q->sound_periodicannounce[i][0]='\0';
00683    }
00684 }

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

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

Referenced by join_queue().

00456 {
00457    struct queue_ent *cur;
00458 
00459    if (!q || !new)
00460       return;
00461    if (prev) {
00462       cur = prev->next;
00463       prev->next = new;
00464    } else {
00465       cur = q->head;
00466       q->head = new;
00467    }
00468    new->next = cur;
00469    new->parent = q;
00470    new->pos = ++(*pos);
00471    new->opos = *pos;
00472 }

static char* int2strat ( int  strategy  )  [static]

Definition at line 430 of file app_queue.c.

References strategy::name, and strategies.

Referenced by __queues_show().

00431 {
00432    int x;
00433 
00434    for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
00435       if (strategy == strategies[x].strategy)
00436          return strategies[x].name;
00437    }
00438 
00439    return "<unknown>";
00440 }

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

Definition at line 2774 of file app_queue.c.

References member::interface, call_queue::members, and member::next.

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

02775 {
02776    struct member *mem;
02777 
02778    if (!q)
02779       return NULL;
02780 
02781    for (mem = q->members; mem; mem = mem->next) {
02782       if (!strcasecmp(interface, mem->interface))
02783          return mem;
02784    }
02785 
02786    return NULL;
02787 }

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

Definition at line 722 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), member::interface, call_queue::lock, call_queue::members, and member::next.

Referenced by remove_from_interfaces().

00723 {
00724    struct call_queue *q;
00725    struct member *mem;
00726    int ret = 0;
00727 
00728    AST_LIST_LOCK(&queues);
00729    AST_LIST_TRAVERSE(&queues, q, list) {
00730       ast_mutex_lock(&q->lock);
00731       for (mem = q->members; mem && !ret; mem = mem->next) {
00732          if (!strcasecmp(interface, mem->interface))
00733             ret = 1;
00734       }
00735       ast_mutex_unlock(&q->lock);
00736       if (ret)
00737          break;
00738    }
00739    AST_LIST_UNLOCK(&queues);
00740 
00741    return ret;
00742 }

static int is_our_turn ( struct queue_ent qe  )  [static]

Definition at line 2142 of file app_queue.c.

References AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), call_queue::autofill, queue_ent::chan, call_queue::head, call_queue::lock, LOG_DEBUG, call_queue::members, queue_ent::next, member::next, option_debug, queue_ent::parent, QUEUE_STRATEGY_RINGALL, member::status, and call_queue::strategy.

Referenced by queue_exec(), and wait_our_turn().

02143 {
02144    struct queue_ent *ch;
02145    struct member *cur;
02146    int avl = 0;
02147    int idx = 0;
02148    int res;
02149 
02150    if (!qe->parent->autofill) {
02151       /* Atomically read the parent head -- does not need a lock */
02152       ch = qe->parent->head;
02153       /* If we are now at the top of the head, break out */
02154       if (ch == qe) {
02155          if (option_debug)
02156             ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
02157          res = 1;
02158       } else {
02159          if (option_debug)
02160             ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
02161          res = 0;
02162       }  
02163 
02164    } else {
02165       /* This needs a lock. How many members are available to be served? */
02166       ast_mutex_lock(&qe->parent->lock);
02167          
02168       ch = qe->parent->head;
02169    
02170       if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
02171          if (option_debug)
02172             ast_log(LOG_DEBUG, "Even though there are %d available members, the strategy is ringall so only the head call is allowed in\n", avl);
02173          avl = 1;
02174       } else {
02175          for (cur = qe->parent->members; cur; cur = cur->next) {
02176             switch (cur->status) {
02177             case AST_DEVICE_NOT_INUSE:
02178             case AST_DEVICE_UNKNOWN:
02179                avl++;
02180                break;
02181             }
02182          }
02183       }
02184 
02185       if (option_debug)
02186          ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
02187    
02188       while ((idx < avl) && (ch) && (ch != qe)) {
02189          idx++;
02190          ch = ch->next;       
02191       }
02192    
02193       /* If the queue entry is within avl [the number of available members] calls from the top ... */
02194       if (ch && idx < avl) {
02195          if (option_debug)
02196             ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
02197          res = 1;
02198       } else {
02199          if (option_debug)
02200             ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
02201          res = 0;
02202       }
02203       
02204       ast_mutex_unlock(&qe->parent->lock);
02205    }
02206 
02207    return res;
02208 }

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

Definition at line 1221 of file app_queue.c.

References call_queue::announce, queue_ent::announce, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, call_queue::context, queue_ent::context, call_queue::count, EVENT_FLAG_CALL, get_member_status(), call_queue::head, insert_entry(), call_queue::joinempty, load_realtime_queue(), call_queue::lock, LOG_DEBUG, manager_event(), queue_ent::max_penalty, call_queue::maxlen, call_queue::moh, queue_ent::moh, call_queue::name, queue_ent::next, option_debug, queue_ent::pos, queue_ent::prio, QUEUE_EMPTY_STRICT, QUEUE_FULL, QUEUE_JOINEMPTY, QUEUE_JOINUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, and S_OR.

Referenced by queue_exec().

01222 {
01223    struct call_queue *q;
01224    struct queue_ent *cur, *prev = NULL;
01225    int res = -1;
01226    int pos = 0;
01227    int inserted = 0;
01228    enum queue_member_status stat;
01229 
01230    if (!(q = load_realtime_queue(queuename)))
01231       return res;
01232 
01233    AST_LIST_LOCK(&queues);
01234    ast_mutex_lock(&q->lock);
01235 
01236    /* This is our one */
01237    stat = get_member_status(q, qe->max_penalty);
01238    if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
01239       *reason = QUEUE_JOINEMPTY;
01240    else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
01241       *reason = QUEUE_JOINUNAVAIL;
01242    else if (q->maxlen && (q->count >= q->maxlen))
01243       *reason = QUEUE_FULL;
01244    else {
01245       /* There's space for us, put us at the right position inside
01246        * the queue.
01247        * Take into account the priority of the calling user */
01248       inserted = 0;
01249       prev = NULL;
01250       cur = q->head;
01251       while (cur) {
01252          /* We have higher priority than the current user, enter
01253           * before him, after all the other users with priority
01254           * higher or equal to our priority. */
01255          if ((!inserted) && (qe->prio > cur->prio)) {
01256             insert_entry(q, prev, qe, &pos);
01257             inserted = 1;
01258          }
01259          cur->pos = ++pos;
01260          prev = cur;
01261          cur = cur->next;
01262       }
01263       /* No luck, join at the end of the queue */
01264       if (!inserted)
01265          insert_entry(q, prev, qe, &pos);
01266       ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
01267       ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
01268       ast_copy_string(qe->context, q->context, sizeof(qe->context));
01269       q->count++;
01270       res = 0;
01271       manager_event(EVENT_FLAG_CALL, "Join",
01272          "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
01273          qe->chan->name,
01274          S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
01275          S_OR(qe->chan->cid.cid_name, "unknown"),
01276          q->name, qe->pos, q->count, qe->chan->uniqueid );
01277       if (option_debug)
01278          ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
01279    }
01280    ast_mutex_unlock(&q->lock);
01281    AST_LIST_UNLOCK(&queues);
01282 
01283    return res;
01284 }

static void leave_queue ( struct queue_ent qe  )  [static]

Definition at line 1456 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), queue_ent::chan, call_queue::count, call_queue::dead, destroy_queue(), EVENT_FLAG_CALL, call_queue::head, call_queue::lock, LOG_DEBUG, manager_event(), call_queue::name, queue_ent::next, option_debug, queue_ent::parent, and queue_ent::pos.

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

01457 {
01458    struct call_queue *q;
01459    struct queue_ent *cur, *prev = NULL;
01460    int pos = 0;
01461 
01462    if (!(q = qe->parent))
01463       return;
01464    ast_mutex_lock(&q->lock);
01465 
01466    prev = NULL;
01467    for (cur = q->head; cur; cur = cur->next) {
01468       if (cur == qe) {
01469          q->count--;
01470 
01471          /* Take us out of the queue */
01472          manager_event(EVENT_FLAG_CALL, "Leave",
01473             "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
01474             qe->chan->name, q->name,  q->count, qe->chan->uniqueid);
01475          if (option_debug)
01476             ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
01477          /* Take us out of the queue */
01478          if (prev)
01479             prev->next = cur->next;
01480          else
01481             q->head = cur->next;
01482       } else {
01483          /* Renumber the people after us in the queue based on a new count */
01484          cur->pos = ++pos;
01485          prev = cur;
01486       }
01487    }
01488    ast_mutex_unlock(&q->lock);
01489 
01490    if (q->dead && !q->count) {   
01491       /* It's dead and nobody is in it, so kill it */
01492       AST_LIST_LOCK(&queues);
01493       AST_LIST_REMOVE(&queues, q, list);
01494       AST_LIST_UNLOCK(&queues);
01495       destroy_queue(q);
01496    }
01497 }

static int load_module ( void   )  [static]

Definition at line 4537 of file app_queue.c.

References aqm_exec(), ast_cli_register_multiple(), ast_custom_function_register(), ast_devstate_add(), ast_manager_register, AST_MODULE_LOAD_DECLINE, ast_register_application(), cli_queue, EVENT_FLAG_AGENT, manager_add_queue_member(), manager_pause_queue_member(), manager_queues_show(), manager_queues_status(), manager_remove_queue_member(), pqm_exec(), ql_exec(), queue_exec(), queueagentcount_function, queuemembercount_function, queuememberlist_function, queuewaitingcount_function, reload_queue_members(), reload_queues(), rqm_exec(), statechange_queue(), and upqm_exec().

04538 {
04539    int res;
04540    if(!reload_queues())
04541       return AST_MODULE_LOAD_DECLINE;
04542    if (queue_persistent_members)
04543       reload_queue_members();
04544    ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
04545    res = ast_register_application(app, queue_exec, synopsis, descrip);
04546    res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip);
04547    res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip);
04548    res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip);
04549    res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip);
04550    res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip);
04551    res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues");
04552    res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status");
04553    res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue.");
04554    res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
04555    res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
04556    res |= ast_custom_function_register(&queueagentcount_function);
04557    res |= ast_custom_function_register(&queuemembercount_function);
04558    res |= ast_custom_function_register(&queuememberlist_function);
04559    res |= ast_custom_function_register(&queuewaitingcount_function);
04560    res |= ast_devstate_add(statechange_queue, NULL);
04561 
04562    return res;
04563 }

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

Note:
Load from realtime before taking the global qlock, 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 1123 of file app_queue.c.

References ast_config_destroy(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_load_realtime_multientry(), ast_log(), ast_variables_destroy(), find_queue_by_name_rt(), LOG_ERROR, call_queue::name, and call_queue::realtime.

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

01124 {
01125    struct ast_variable *queue_vars;
01126    struct ast_config *member_config = NULL;
01127    struct call_queue *q;
01128 
01129    /* Find the queue in the in-core list first. */
01130    AST_LIST_LOCK(&queues);
01131    AST_LIST_TRAVERSE(&queues, q, list) {
01132       if (!strcasecmp(q->name, queuename)) {
01133          break;
01134       }
01135    }
01136    AST_LIST_UNLOCK(&queues);
01137 
01138    if (!q || q->realtime) {
01139       /*! \note Load from realtime before taking the global qlock, to avoid blocking all
01140          queue operations while waiting for the DB.
01141 
01142          This will be two separate database transactions, so we might
01143          see queue parameters as they were before another process
01144          changed the queue and member list as it was after the change.
01145          Thus we might see an empty member list when a queue is
01146          deleted. In practise, this is unlikely to cause a problem. */
01147 
01148       queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
01149       if (queue_vars) {
01150          member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
01151          if (!member_config) {
01152             ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
01153             return NULL;
01154          }
01155       }
01156 
01157       AST_LIST_LOCK(&queues);
01158 
01159       q = find_queue_by_name_rt(queuename, queue_vars, member_config);
01160       if (member_config)
01161          ast_config_destroy(member_config);
01162       if (queue_vars)
01163          ast_variables_destroy(queue_vars);
01164 
01165       AST_LIST_UNLOCK(&queues);
01166    }
01167    return q;
01168 }

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

Definition at line 4205 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(), member_interface::interface, member::membername, member::paused, member::penalty, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.

Referenced by load_module().

04206 {
04207    const char *queuename, *interface, *penalty_s, *paused_s, *membername;
04208    int paused, penalty = 0;
04209 
04210    queuename = astman_get_header(m, "Queue");
04211    interface = astman_get_header(m, "Interface");
04212    penalty_s = astman_get_header(m, "Penalty");
04213    paused_s = astman_get_header(m, "Paused");
04214    membername = astman_get_header(m, "MemberName");
04215 
04216    if (ast_strlen_zero(queuename)) {
04217       astman_send_error(s, m, "'Queue' not specified.");
04218       return 0;
04219    }
04220 
04221    if (ast_strlen_zero(interface)) {
04222       astman_send_error(s, m, "'Interface' not specified.");
04223       return 0;
04224    }
04225 
04226    if (ast_strlen_zero(penalty_s))
04227       penalty = 0;
04228    else if (sscanf(penalty_s, "%d", &penalty) != 1)
04229       penalty = 0;
04230 
04231    if (ast_strlen_zero(paused_s))
04232       paused = 0;
04233    else
04234       paused = abs(ast_true(paused_s));
04235 
04236    if (ast_strlen_zero(membername))
04237       membername = interface;
04238 
04239    switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) {
04240    case RES_OKAY:
04241       ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
04242       astman_send_ack(s, m, "Added interface to queue");
04243       break;
04244    case RES_EXISTS:
04245       astman_send_error(s, m, "Unable to add interface: Already there");
04246       break;
04247    case RES_NOSUCHQUEUE:
04248       astman_send_error(s, m, "Unable to add interface to queue: No such queue");
04249       break;
04250    case RES_OUTOFMEMORY:
04251       astman_send_error(s, m, "Out of memory");
04252       break;
04253    }
04254 
04255    return 0;
04256 }

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

Definition at line 4289 of file app_queue.c.

References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), member_interface::interface, member::paused, and set_member_paused().

Referenced by load_module().

04290 {
04291    const char *queuename, *interface, *paused_s;
04292    int paused;
04293 
04294    interface = astman_get_header(m, "Interface");
04295    paused_s = astman_get_header(m, "Paused");
04296    queuename = astman_get_header(m, "Queue");   /* Optional - if not supplied, pause the given Interface in all queues */
04297 
04298    if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
04299       astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
04300       return 0;
04301    }
04302 
04303    paused = abs(ast_true(paused_s));
04304 
04305    if (set_member_paused(queuename, interface, paused))
04306       astman_send_error(s, m, "Interface not found");
04307    else
04308       astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
04309    return 0;
04310 }

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

Definition at line 4105 of file app_queue.c.

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

Referenced by load_module().

04106 {
04107    char *a[] = { "queue", "show" };
04108 
04109    __queues_show(s, 1, -1, 2, a);
04110    astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
04111 
04112    return RESULT_SUCCESS;
04113 }

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

Definition at line 4116 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_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, member::interface, member::lastcall, call_queue::lock, call_queue::maxlen, call_queue::members, call_queue::name, queue_ent::next, member::next, member::paused, member::penalty, RESULT_SUCCESS, S_OR, call_queue::servicelevel, queue_ent::start, member::status, and call_queue::weight.

Referenced by load_module().

04117 {
04118    time_t now;
04119    int pos;
04120    const char *id = astman_get_header(m,"ActionID");
04121    const char *queuefilter = astman_get_header(m,"Queue");
04122    const char *memberfilter = astman_get_header(m,"Member");
04123    char idText[256] = "";
04124    struct call_queue *q;
04125    struct queue_ent *qe;
04126    float sl = 0;
04127    struct member *mem;
04128 
04129    astman_send_ack(s, m, "Queue status will follow");
04130    time(&now);
04131    AST_LIST_LOCK(&queues);
04132    if (!ast_strlen_zero(id))
04133       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
04134 
04135    AST_LIST_TRAVERSE(&queues, q, list) {
04136       ast_mutex_lock(&q->lock);
04137 
04138       /* List queue properties */
04139       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
04140          sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
04141          astman_append(s, "Event: QueueParams\r\n"
04142             "Queue: %s\r\n"
04143             "Max: %d\r\n"
04144             "Calls: %d\r\n"
04145             "Holdtime: %d\r\n"
04146             "Completed: %d\r\n"
04147             "Abandoned: %d\r\n"
04148             "ServiceLevel: %d\r\n"
04149             "ServicelevelPerf: %2.1f\r\n"
04150             "Weight: %d\r\n"
04151             "%s"
04152             "\r\n",
04153             q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
04154             q->callsabandoned, q->servicelevel, sl, q->weight, idText);
04155          /* List Queue Members */
04156          for (mem = q->members; mem; mem = mem->next) {
04157             if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
04158                astman_append(s, "Event: QueueMember\r\n"
04159                   "Queue: %s\r\n"
04160                   "Location: %s\r\n"
04161                   "Membership: %s\r\n"
04162                   "Penalty: %d\r\n"
04163                   "CallsTaken: %d\r\n"
04164                   "LastCall: %d\r\n"
04165                   "Status: %d\r\n"
04166                   "Paused: %d\r\n"
04167                   "%s"
04168                   "\r\n",
04169                   q->name, mem->interface, mem->dynamic ? "dynamic" : "static",
04170                   mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
04171             }
04172          }
04173          /* List Queue Entries */
04174          pos = 1;
04175          for (qe = q->head; qe; qe = qe->next) {
04176             astman_append(s, "Event: QueueEntry\r\n"
04177                "Queue: %s\r\n"
04178                "Position: %d\r\n"
04179                "Channel: %s\r\n"
04180                "CallerID: %s\r\n"
04181                "CallerIDName: %s\r\n"
04182                "Wait: %ld\r\n"
04183                "%s"
04184                "\r\n",
04185                q->name, pos++, qe->chan->name,
04186                S_OR(qe->chan->cid.cid_num, "unknown"),
04187                S_OR(qe->chan->cid.cid_name, "unknown"),
04188                (long) (now - qe->start), idText);
04189          }
04190       }
04191       ast_mutex_unlock(&q->lock);
04192    }
04193 
04194    astman_append(s,
04195       "Event: QueueStatusComplete\r\n"
04196       "%s"
04197       "\r\n",idText);
04198 
04199    AST_LIST_UNLOCK(&queues);
04200 
04201 
04202    return RESULT_SUCCESS;
04203 }

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

Definition at line 4258 of file app_queue.c.

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

Referenced by load_module().

04259 {
04260    const char *queuename, *interface;
04261 
04262    queuename = astman_get_header(m, "Queue");
04263    interface = astman_get_header(m, "Interface");
04264 
04265    if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
04266       astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
04267       return 0;
04268    }
04269 
04270    switch (remove_from_queue(queuename, interface)) {
04271    case RES_OKAY:
04272       ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
04273       astman_send_ack(s, m, "Removed interface from queue");
04274       break;
04275    case RES_EXISTS:
04276       astman_send_error(s, m, "Unable to remove interface: Not there");
04277       break;
04278    case RES_NOSUCHQUEUE:
04279       astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
04280       break;
04281    case RES_OUTOFMEMORY:
04282       astman_send_error(s, m, "Out of memory");
04283       break;
04284    }
04285 
04286    return 0;
04287 }

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

Definition at line 1286 of file app_queue.c.

References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), and ast_waitstream().

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

01287 {
01288    int res;
01289 
01290    ast_stopstream(chan);
01291 
01292    res = ast_streamfile(chan, filename, chan->language);
01293    if (!res)
01294       res = ast_waitstream(chan, AST_DIGIT_ANY);
01295 
01296    ast_stopstream(chan);
01297 
01298    return res;
01299 }

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

Definition at line 3074 of file app_queue.c.

References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_channel::context, ast_channel::exten, member_interface::interface, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), ast_channel::priority, and set_member_paused().

Referenced by load_module().

03075 {
03076    struct ast_module_user *lu;
03077    char *parse;
03078    int priority_jump = 0;
03079    AST_DECLARE_APP_ARGS(args,
03080       AST_APP_ARG(queuename);
03081       AST_APP_ARG(interface);
03082       AST_APP_ARG(options);
03083    );
03084 
03085    if (ast_strlen_zero(data)) {
03086       ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
03087       return -1;
03088    }
03089 
03090    parse = ast_strdupa(data);
03091 
03092    AST_STANDARD_APP_ARGS(args, parse);
03093 
03094    lu = ast_module_user_add(chan);
03095 
03096    if (args.options) {
03097       if (strchr(args.options, 'j'))
03098          priority_jump = 1;
03099    }
03100 
03101    if (ast_strlen_zero(args.interface)) {
03102       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
03103       ast_module_user_remove(lu);
03104       return -1;
03105    }
03106 
03107    if (set_member_paused(args.queuename, args.interface, 1)) {
03108       ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
03109       if (priority_jump || ast_opt_priority_jumping) {
03110          if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
03111             pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
03112             ast_module_user_remove(lu);
03113             return 0;
03114          }
03115       }
03116       ast_module_user_remove(lu);
03117       pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
03118       return -1;
03119    }
03120 
03121    ast_module_user_remove(lu);
03122    pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
03123 
03124    return 0;
03125 }

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

Definition at line 3320 of file app_queue.c.

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

Referenced by load_module().

03321 {
03322    struct ast_module_user *u;
03323    char *parse;
03324 
03325    AST_DECLARE_APP_ARGS(args,
03326       AST_APP_ARG(queuename);
03327       AST_APP_ARG(uniqueid);
03328       AST_APP_ARG(membername);
03329       AST_APP_ARG(event);
03330       AST_APP_ARG(params);
03331    );
03332 
03333    if (ast_strlen_zero(data)) {
03334       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n");
03335       return -1;
03336    }
03337 
03338    u = ast_module_user_add(chan);
03339 
03340    parse = ast_strdupa(data);
03341 
03342    AST_STANDARD_APP_ARGS(args, parse);
03343 
03344    if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
03345        || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
03346       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n");
03347       ast_module_user_remove(u);
03348       return -1;
03349    }
03350 
03351    ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 
03352       "%s", args.params ? args.params : "");
03353 
03354    ast_module_user_remove(u);
03355 
03356    return 0;
03357 }

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

Definition at line 3359 of file app_queue.c.

References call_queue::announcefrequency, AST_APP_ARG, AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_moh_start(), ast_moh_stop(), AST_PBX_KEEPALIVE, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verbose(), 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_DEBUG, LOG_WARNING, queue_ent::max_penalty, call_queue::membercount, queue_ent::moh, queue_ent::opos, option_debug, option_verbose, queue_ent::parent, parse(), pbx_builtin_getvar_helper(), call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::prio, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), S_OR, say_periodic_announcement(), say_position(), set_queue_result(), queue_ent::start, try_calling(), update_realtime_members(), queue_ent::valid_digits, VERBOSE_PREFIX_3, wait_a_bit(), and wait_our_turn().

Referenced by load_module().

03360 {
03361    int res=-1;
03362    int ringing=0;
03363    struct ast_module_user *lu;
03364    const char *user_priority;
03365    const char *max_penalty_str;
03366    int prio;
03367    int max_penalty;
03368    enum queue_result reason = QUEUE_UNKNOWN;
03369    /* whether to exit Queue application after the timeout hits */
03370    int go_on = 0;
03371    char *parse;
03372    AST_DECLARE_APP_ARGS(args,
03373       AST_APP_ARG(queuename);
03374       AST_APP_ARG(options);
03375       AST_APP_ARG(url);
03376       AST_APP_ARG(announceoverride);
03377       AST_APP_ARG(queuetimeoutstr);
03378       AST_APP_ARG(agi);
03379    );
03380    /* Our queue entry */
03381    struct queue_ent qe;
03382    
03383    if (ast_strlen_zero(data)) {
03384       ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n");
03385       return -1;
03386    }
03387    
03388    parse = ast_strdupa(data);
03389    AST_STANDARD_APP_ARGS(args, parse);
03390 
03391    lu = ast_module_user_add(chan);
03392 
03393    /* Setup our queue entry */
03394    memset(&qe, 0, sizeof(qe));
03395    qe.start = time(NULL);
03396 
03397    /* set the expire time based on the supplied timeout; */
03398    if (args.queuetimeoutstr)
03399       qe.expire = qe.start + atoi(args.queuetimeoutstr);
03400    else
03401       qe.expire = 0;
03402 
03403    /* Get the priority from the variable ${QUEUE_PRIO} */
03404    user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
03405    if (user_priority) {
03406       if (sscanf(user_priority, "%d", &prio) == 1) {
03407          if (option_debug)
03408             ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
03409                chan->name, prio);
03410       } else {
03411          ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
03412             user_priority, chan->name);
03413          prio = 0;
03414       }
03415    } else {
03416       if (option_debug > 2)
03417          ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
03418       prio = 0;
03419    }
03420 
03421    /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
03422    if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
03423       if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
03424          if (option_debug)
03425             ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
03426                chan->name, max_penalty);
03427       } else {
03428          ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
03429             max_penalty_str, chan->name);
03430          max_penalty = 0;
03431       }
03432    } else {
03433       max_penalty = 0;
03434    }
03435 
03436    if (args.options && (strchr(args.options, 'r')))
03437       ringing = 1;
03438 
03439    if (option_debug)
03440       ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
03441          args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
03442 
03443    qe.chan = chan;
03444    qe.prio = prio;
03445    qe.max_penalty = max_penalty;
03446    qe.last_pos_said = 0;
03447    qe.last_pos = 0;
03448    qe.last_periodic_announce_time = time(NULL);
03449    qe.last_periodic_announce_sound = 0;
03450    qe.valid_digits = 0;
03451    if (!join_queue(args.queuename, &qe, &reason)) {
03452       int makeannouncement = 0;
03453 
03454       ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
03455          S_OR(chan->cid.cid_num, ""));
03456 check_turns:
03457       if (ringing) {
03458          ast_indicate(chan, AST_CONTROL_RINGING);
03459       } else {
03460          ast_moh_start(chan, qe.moh, NULL);
03461       }
03462 
03463       /* This is the wait loop for callers 2 through maxlen */
03464       res = wait_our_turn(&qe, ringing, &reason);
03465       if (res)
03466          goto stop;
03467 
03468       for (;;) {
03469          /* This is the wait loop for the head caller*/
03470          /* To exit, they may get their call answered; */
03471          /* they may dial a digit from the queue context; */
03472          /* or, they may timeout. */
03473 
03474          enum queue_member_status stat;
03475 
03476          /* Leave if we have exceeded our queuetimeout */
03477          if (qe.expire && (time(NULL) > qe.expire)) {
03478             record_abandoned(&qe);
03479             reason = QUEUE_TIMEOUT;
03480             res = 0;
03481             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
03482             break;
03483          }
03484 
03485          if (makeannouncement) {
03486             /* Make a position announcement, if enabled */
03487             if (qe.parent->announcefrequency && !ringing)
03488                if ((res = say_position(&qe)))
03489                   goto stop;
03490 
03491          }
03492          makeannouncement = 1;
03493 
03494          /* Make a periodic announcement, if enabled */
03495          if (qe.parent->periodicannouncefrequency && !ringing)
03496             if ((res = say_periodic_announcement(&qe)))
03497                goto stop;
03498 
03499          /* Try calling all queue members for 'timeout' seconds */
03500          res = try_calling(&qe, args.options, args.announceoverride, args.url, &go_on, args.agi);
03501          if (res)
03502             goto stop;
03503 
03504          stat = get_member_status(qe.parent, qe.max_penalty);
03505 
03506          /* exit after 'timeout' cycle if 'n' option enabled */
03507          if (go_on >= qe.parent->membercount) {
03508             if (option_verbose > 2)
03509                ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
03510             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
03511             record_abandoned(&qe);
03512             reason = QUEUE_TIMEOUT;
03513             res = 0;
03514             break;
03515          }
03516 
03517          /* leave the queue if no agents, if enabled */
03518          if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
03519             record_abandoned(&qe);
03520             reason = QUEUE_LEAVEEMPTY;
03521             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
03522             res = 0;
03523             break;
03524          }
03525 
03526          /* leave the queue if no reachable agents, if enabled */
03527          if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
03528             record_abandoned(&qe);
03529             reason = QUEUE_LEAVEUNAVAIL;
03530             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
03531             res = 0;
03532             break;
03533          }
03534 
03535          /* Leave if we have exceeded our queuetimeout */
03536          if (qe.expire && (time(NULL) > qe.expire)) {
03537             record_abandoned(&qe);
03538             reason = QUEUE_TIMEOUT;
03539             res = 0;
03540             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
03541             break;
03542          }
03543 
03544          /* If using dynamic realtime members, we should regenerate the member list for this queue */
03545          update_realtime_members(qe.parent);
03546 
03547          /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
03548          res = wait_a_bit(&qe);
03549          if (res)
03550             goto stop;
03551 
03552 
03553          /* Since this is a priority queue and
03554           * it is not sure that we are still at the head
03555           * of the queue, go and check for our turn again.
03556           */
03557          if (!is_our_turn(&qe)) {
03558             if (option_debug)
03559                ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
03560                   qe.chan->name);
03561             goto check_turns;
03562          }
03563       }
03564 
03565 stop:
03566       if (res) {
03567          if (res < 0) {
03568             if (!qe.handled) {
03569                record_abandoned(&qe);
03570                ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
03571                   "%d|%d|%ld", qe.pos, qe.opos,
03572                   (long) time(NULL) - qe.start);
03573             }
03574             res = -1;
03575          } else if (qe.valid_digits) {
03576             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
03577                "%s|%d", qe.digits, qe.pos);
03578          }
03579       }
03580 
03581       /* Don't allow return code > 0 */
03582       if (res >= 0 && res != AST_PBX_KEEPALIVE) {
03583          res = 0; 
03584          if (ringing) {
03585             ast_indicate(chan, -1);
03586          } else {
03587             ast_moh_stop(chan);
03588          }        
03589          ast_stopstream(chan);
03590       }
03591       leave_queue(&qe);
03592       if (reason != QUEUE_UNKNOWN)
03593          set_queue_result(chan, reason);
03594    } else {
03595       ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
03596       set_queue_result(chan, reason);
03597       res = 0;
03598    }
03599    ast_module_user_remove(lu);
03600 
03601    return res;
03602 }

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

Definition at line 3604 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), call_queue::lock, LOG_ERROR, LOG_WARNING, call_queue::membercount, and call_queue::name.

03605 {
03606    int count = 0;
03607    struct call_queue *q;
03608    struct ast_module_user *lu;
03609 
03610    buf[0] = '\0';
03611    
03612    if (ast_strlen_zero(data)) {
03613       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
03614       return -1;
03615    }
03616 
03617    lu = ast_module_user_add(chan);
03618    
03619    AST_LIST_LOCK(&queues);
03620    AST_LIST_TRAVERSE(&queues, q, list) {
03621       if (!strcasecmp(q->name, data)) {
03622          ast_mutex_lock(&q->lock);
03623          break;
03624       }
03625    }
03626    AST_LIST_UNLOCK(&queues);
03627 
03628    if (q) {
03629       count = q->membercount;
03630       ast_mutex_unlock(&q->lock);
03631    } else
03632       ast_log(LOG_WARNING, "queue %s was not found\n", data);
03633 
03634    snprintf(buf, len, "%d", count);
03635    ast_module_user_remove(lu);
03636 
03637    return 0;
03638 }

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

Definition at line 3675 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), member::interface, call_queue::lock, LOG_ERROR, LOG_WARNING, call_queue::members, call_queue::name, and member::next.

03676 {
03677    struct ast_module_user *u;
03678    struct call_queue *q;
03679    struct member *m;
03680 
03681    /* Ensure an otherwise empty list doesn't return garbage */
03682    buf[0] = '\0';
03683 
03684    if (ast_strlen_zero(data)) {
03685       ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
03686       return -1;
03687    }
03688    
03689    u = ast_module_user_add(chan);
03690 
03691    AST_LIST_LOCK(&queues);
03692    AST_LIST_TRAVERSE(&queues, q, list) {
03693       if (!strcasecmp(q->name, data)) {
03694          ast_mutex_lock(&q->lock);
03695          break;
03696       }
03697    }
03698    AST_LIST_UNLOCK(&queues);
03699 
03700    if (q) {
03701       int buflen = 0, count = 0;
03702 
03703       for (m = q->members; m; m = m->next) {
03704          /* strcat() is always faster than printf() */
03705          if (count++) {
03706             strncat(buf + buflen, ",", len - buflen - 1);
03707             buflen++;
03708          }
03709          strncat(buf + buflen, m->interface, len - buflen - 1);
03710          buflen += strlen(m->interface);
03711          /* Safeguard against overflow (negative length) */
03712          if (buflen >= len - 2) {
03713             ast_log(LOG_WARNING, "Truncating list\n");
03714             break;
03715          }
03716       }
03717       ast_mutex_unlock(&q->lock);
03718    } else
03719       ast_log(LOG_WARNING, "queue %s was not found\n", data);
03720 
03721    /* We should already be terminated, but let's make sure. */
03722    buf[len - 1] = '\0';
03723    ast_module_user_remove(u);
03724 
03725    return 0;
03726 }

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

Definition at line 3640 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), call_queue::count, call_queue::lock, LOG_ERROR, LOG_WARNING, and call_queue::name.

03641 {
03642    int count = 0;
03643    struct call_queue *q;
03644    struct ast_module_user *lu;
03645 
03646    buf[0] = '\0';
03647    
03648    if (ast_strlen_zero(data)) {
03649       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
03650       return -1;
03651    }
03652 
03653    lu = ast_module_user_add(chan);
03654    
03655    AST_LIST_LOCK(&queues);
03656    AST_LIST_TRAVERSE(&queues, q, list) {
03657       if (!strcasecmp(q->name, data)) {
03658          ast_mutex_lock(&q->lock);
03659          break;
03660       }
03661    }
03662    AST_LIST_UNLOCK(&queues);
03663 
03664    if (q) {
03665       count = q->count;
03666       ast_mutex_unlock(&q->lock);
03667    } else
03668       ast_log(LOG_WARNING, "queue %s was not found\n", data);
03669 
03670    snprintf(buf, len, "%d", count);
03671    ast_module_user_remove(lu);
03672    return 0;
03673 }

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

Configure a queue parameter.

For error reporting, line number is passed for .conf static configuration. For Realtime queues, linenum is -1. The failunknown flag is set for config files (and static realtime) to show errors for unknown parameters. It is cleared for dynamic realtime to allow extra fields in the tables.

Definition at line 783 of file app_queue.c.

References call_queue::announce, call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, ast_log(), ast_strdupa, ast_true(), call_queue::autofill, call_queue::autopause, call_queue::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::moh, call_queue::monfmt, call_queue::monjoin, call_queue::montype, call_queue::name, call_queue::periodicannouncefrequency, QUEUE_EMPTY_NORMAL, QUEUE_EMPTY_STRICT, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_RINGALL, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::roundingseconds, s, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_periodicannounce, call_queue::sound_reporthold, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, 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().

00784 {
00785    if (!strcasecmp(param, "musicclass") || 
00786       !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
00787       ast_copy_string(q->moh, val, sizeof(q->moh));
00788    } else if (!strcasecmp(param, "announce")) {
00789       ast_copy_string(q->announce, val, sizeof(q->announce));
00790    } else if (!strcasecmp(param, "context")) {
00791       ast_copy_string(q->context, val, sizeof(q->context));
00792    } else if (!strcasecmp(param, "timeout")) {
00793       q->timeout = atoi(val);
00794       if (q->timeout < 0)
00795          q->timeout = DEFAULT_TIMEOUT;
00796    } else if (!strcasecmp(param, "ringinuse")) {
00797       q->ringinuse = ast_true(val);
00798    } else if (!strcasecmp(param, "setinterfacevar")) {
00799       q->setinterfacevar = ast_true(val);
00800    } else if (!strcasecmp(param, "monitor-join")) {
00801       q->monjoin = ast_true(val);
00802    } else if (!strcasecmp(param, "monitor-format")) {
00803       ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
00804    } else if (!strcasecmp(param, "queue-youarenext")) {
00805       ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
00806    } else if (!strcasecmp(param, "queue-thereare")) {
00807       ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
00808    } else if (!strcasecmp(param, "queue-callswaiting")) {
00809       ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
00810    } else if (!strcasecmp(param, "queue-holdtime")) {
00811       ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
00812    } else if (!strcasecmp(param, "queue-minutes")) {
00813       ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
00814    } else if (!strcasecmp(param, "queue-seconds")) {
00815       ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
00816    } else if (!strcasecmp(param, "queue-lessthan")) {
00817       ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
00818    } else if (!strcasecmp(param, "queue-thankyou")) {
00819       ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
00820    } else if (!strcasecmp(param, "queue-reporthold")) {
00821       ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
00822    } else if (!strcasecmp(param, "announce-frequency")) {
00823       q->announcefrequency = atoi(val);
00824    } else if (!strcasecmp(param, "announce-round-seconds")) {
00825       q->roundingseconds = atoi(val);
00826       if (q->roundingseconds>60 || q->roundingseconds<0) {
00827          if (linenum >= 0) {
00828             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
00829                "using 0 instead for queue '%s' at line %d of queues.conf\n",
00830                val, param, q->name, linenum);
00831          } else {
00832             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
00833                "using 0 instead for queue '%s'\n", val, param, q->name);
00834          }
00835          q->roundingseconds=0;
00836       }
00837    } else if (!strcasecmp(param, "announce-holdtime")) {
00838       if (!strcasecmp(val, "once"))
00839          q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
00840       else if (ast_true(val))
00841          q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
00842       else
00843          q->announceholdtime = 0;
00844    } else if (!strcasecmp(param, "periodic-announce")) {
00845       if (strchr(val, '|')) {
00846          char *s, *buf = ast_strdupa(val);
00847          unsigned int i = 0;
00848 
00849          while ((s = strsep(&buf, "|"))) {
00850             ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i]));
00851             i++;
00852             if (i == MAX_PERIODIC_ANNOUNCEMENTS)
00853                break;
00854          }
00855       } else {
00856          ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0]));
00857       }
00858    } else if (!strcasecmp(param, "periodic-announce-frequency")) {
00859       q->periodicannouncefrequency = atoi(val);
00860    } else if (!strcasecmp(param, "retry")) {
00861       q->retry = atoi(val);
00862       if (q->retry <= 0)
00863          q->retry = DEFAULT_RETRY;
00864    } else if (!strcasecmp(param, "wrapuptime")) {
00865       q->wrapuptime = atoi(val);
00866    } else if (!strcasecmp(param, "autofill")) {
00867       q->autofill = ast_true(val);
00868    } else if (!strcasecmp(param, "monitor-type")) {
00869       if (!strcasecmp(val, "mixmonitor"))
00870          q->montype = 1;
00871    } else if (!strcasecmp(param, "autopause")) {
00872       q->autopause = ast_true(val);
00873    } else if (!strcasecmp(param, "maxlen")) {
00874       q->maxlen = atoi(val);
00875       if (q->maxlen < 0)
00876          q->maxlen = 0;
00877    } else if (!strcasecmp(param, "servicelevel")) {
00878       q->servicelevel= atoi(val);
00879    } else if (!strcasecmp(param, "strategy")) {
00880       q->strategy = strat2int(val);
00881       if (q->strategy < 0) {
00882          ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
00883             val, q->name);
00884          q->strategy = QUEUE_STRATEGY_RINGALL;
00885       }
00886    } else if (!strcasecmp(param, "joinempty")) {
00887       if (!strcasecmp(val, "strict"))
00888          q->joinempty = QUEUE_EMPTY_STRICT;
00889       else if (ast_true(val))
00890          q->joinempty = QUEUE_EMPTY_NORMAL;
00891       else
00892          q->joinempty = 0;
00893    } else if (!strcasecmp(param, "leavewhenempty")) {
00894       if (!strcasecmp(val, "strict"))
00895          q->leavewhenempty = QUEUE_EMPTY_STRICT;
00896       else if (ast_true(val))
00897          q->leavewhenempty = QUEUE_EMPTY_NORMAL;
00898       else
00899          q->leavewhenempty = 0;
00900    } else if (!strcasecmp(param, "eventmemberstatus")) {
00901       q->maskmemberstatus = !ast_true(val);
00902    } else if (!strcasecmp(param, "eventwhencalled")) {
00903       if (!strcasecmp(val, "vars")) {
00904          q->eventwhencalled = QUEUE_EVENT_VARIABLES;
00905       } else {
00906          q->eventwhencalled = ast_true(val);
00907       }
00908    } else if (!strcasecmp(param, "reportholdtime")) {
00909       q->reportholdtime = ast_true(val);
00910    } else if (!strcasecmp(param, "memberdelay")) {
00911       q->memberdelay = atoi(val);
00912    } else if (!strcasecmp(param, "weight")) {
00913       q->weight = atoi(val);
00914       if (q->weight)
00915          use_weight++;
00916       /* With Realtime queues, if the last queue using weights is deleted in realtime,
00917          we will not see any effect on use_weight until next reload. */
00918    } else if (!strcasecmp(param, "timeoutrestart")) {
00919       q->timeoutrestart = ast_true(val);
00920    } else if (failunknown) {
00921       if (linenum >= 0) {
00922          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
00923             q->name, param, linenum);
00924       } else {
00925          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
00926       }
00927    }
00928 }

static int queue_show ( int  fd,
int  argc,
char **  argv 
) [static]

Definition at line 4071 of file app_queue.c.

References __queues_show().

Referenced by __queues_show().

04072 {
04073    return __queues_show(NULL, 0, fd, argc, argv);
04074 }

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

Definition at line 1441 of file app_queue.c.

References ast_mutex_lock(), ast_mutex_unlock(), call_queue::holdtime, call_queue::lock, and queue_ent::parent.

Referenced by try_calling().

01442 {
01443    int oldvalue;
01444 
01445    /* Calculate holdtime using a recursive boxcar filter */
01446    /* Thanks to SRT for this contribution */
01447    /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
01448 
01449    ast_mutex_lock(&qe->parent->lock);
01450    oldvalue = qe->parent->holdtime;
01451    qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
01452    ast_mutex_unlock(&qe->parent->lock);
01453 }

static void record_abandoned ( struct queue_ent qe  )  [static]

Definition at line 1871 of file app_queue.c.

References ast_mutex_lock(), ast_mutex_unlock(), call_queue::callsabandoned, queue_ent::chan, EVENT_FLAG_AGENT, call_queue::lock, manager_event(), call_queue::name, queue_ent::opos, queue_ent::parent, queue_ent::pos, and queue_ent::start.

Referenced by queue_exec(), and try_calling().

01872 {
01873    ast_mutex_lock(&qe->parent->lock);
01874    manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
01875       "Queue: %s\r\n"
01876       "Uniqueid: %s\r\n"
01877       "Position: %d\r\n"
01878       "OriginalPosition: %d\r\n"
01879       "HoldTime: %d\r\n",
01880       qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
01881 
01882    qe->parent->callsabandoned++;
01883    ast_mutex_unlock(&qe->parent->lock);
01884 }

static int reload ( void   )  [static]

Definition at line 4565 of file app_queue.c.

References reload_queues().

04566 {
04567    reload_queues();
04568    return 0;
04569 }

static void reload_queue_members ( void   )  [static]

Definition at line 2979 of file app_queue.c.

References add_to_queue(), ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), ERANGE, member_interface::interface, ast_db_entry::key, load_realtime_queue(), call_queue::lock, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, member::membername, call_queue::name, ast_db_entry::next, option_debug, member::paused, member::penalty, PM_MAX_LEN, RES_OUTOFMEMORY, and strsep().

Referenced by load_module().

02980 {
02981    char *cur_ptr; 
02982    char *queue_name;
02983    char *member;
02984    char *interface;
02985    char *membername;
02986    char *penalty_tok;
02987    int penalty = 0;
02988    char *paused_tok;
02989    int paused = 0;
02990    struct ast_db_entry *db_tree;
02991    struct ast_db_entry *entry;
02992    struct call_queue *cur_queue;
02993    char queue_data[PM_MAX_LEN];
02994 
02995    AST_LIST_LOCK(&queues);
02996 
02997    /* Each key in 'pm_family' is the name of a queue */
02998    db_tree = ast_db_gettree(pm_family, NULL);
02999    for (entry = db_tree; entry; entry = entry->next) {
03000 
03001       queue_name = entry->key + strlen(pm_family) + 2;
03002 
03003       AST_LIST_TRAVERSE(&queues, cur_queue, list) {
03004          ast_mutex_lock(&cur_queue->lock);
03005          if (!strcmp(queue_name, cur_queue->name))
03006             break;
03007          ast_mutex_unlock(&cur_queue->lock);
03008       }
03009       
03010       if (!cur_queue)
03011          cur_queue = load_realtime_queue(queue_name);
03012 
03013       if (!cur_queue) {
03014          /* If the queue no longer exists, remove it from the
03015           * database */
03016          ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
03017          ast_db_del(pm_family, queue_name);
03018          continue;
03019       } else
03020          ast_mutex_unlock(&cur_queue->lock);
03021 
03022       if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
03023          continue;
03024 
03025       cur_ptr = queue_data;
03026       while ((member = strsep(&cur_ptr, "|"))) {
03027          if (ast_strlen_zero(member))
03028             continue;
03029 
03030          interface = strsep(&member, ";");
03031          penalty_tok = strsep(&member, ";");
03032          paused_tok = strsep(&member, ";");
03033          membername = strsep(&member, ";");
03034 
03035          if (!penalty_tok) {
03036             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
03037             break;
03038          }
03039          penalty = strtol(penalty_tok, NULL, 10);
03040          if (errno == ERANGE) {
03041             ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
03042             break;
03043          }
03044          
03045          if (!paused_tok) {
03046             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
03047             break;
03048          }
03049          paused = strtol(paused_tok, NULL, 10);
03050          if ((errno == ERANGE) || paused < 0 || paused > 1) {
03051             ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
03052             break;
03053          }
03054          if (ast_strlen_zero(membername))
03055             membername = interface;
03056 
03057          if (option_debug)
03058             ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Name: %s  Penalty: %d  Paused: %d\n", queue_name, interface, membername, penalty, paused);
03059          
03060          if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) {
03061             ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
03062             break;
03063          }
03064       }
03065    }
03066 
03067    AST_LIST_UNLOCK(&queues);
03068    if (db_tree) {
03069       ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
03070       ast_db_freetree(db_tree);
03071    }
03072 }

static int reload_queues ( void   )  [static]

Definition at line 3765 of file app_queue.c.

References add_to_interfaces(), alloc_queue(), AST_APP_ARG, ast_category_browse(), ast_config_destroy(), ast_config_load(), AST_DECLARE_APP_ARGS, ast_device_state(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_NONSTANDARD_APP_ARGS, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), clear_queue(), call_queue::count, create_queue_member(), call_queue::dead, member::delme, destroy_queue(), member::dynamic, free, init_queue(), member::interface, member_interface::interface, ast_variable::lineno, call_queue::lock, LOG_DEBUG, LOG_NOTICE, call_queue::membercount, member::membername, call_queue::members, ast_variable::name, call_queue::name, ast_variable::next, member::next, parse(), member::paused, member::penalty, queue_set_param(), QUEUE_STRATEGY_ROUNDROBIN, remove_from_interfaces(), rr_dep_warning(), member::status, call_queue::strategy, ast_variable::value, and var.

Referenced by load_module(), and reload().

03766 {
03767    struct call_queue *q;
03768    struct ast_config *cfg;
03769    char *cat, *tmp;
03770    struct ast_variable *var;
03771    struct member *prev, *cur, *newm, *next;
03772    int new;
03773    const char *general_val = NULL;
03774    char parse[80];
03775    char *interface;
03776    char *membername;
03777    int penalty;
03778    AST_DECLARE_APP_ARGS(args,
03779       AST_APP_ARG(interface);
03780       AST_APP_ARG(penalty);
03781       AST_APP_ARG(membername);
03782    );
03783    
03784    if (!(cfg = ast_config_load("queues.conf"))) {
03785       ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
03786       return 0;
03787    }
03788    AST_LIST_LOCK(&queues);
03789    use_weight=0;
03790    /* Mark all queues as dead for the moment */
03791    AST_LIST_TRAVERSE(&queues, q, list)
03792       q->dead = 1;
03793 
03794    /* Chug through config file */
03795    cat = NULL;
03796    while ((cat = ast_category_browse(cfg, cat)) ) {
03797       if (!strcasecmp(cat, "general")) {  
03798          /* Initialize global settings */
03799          queue_persistent_members = 0;
03800          if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
03801             queue_persistent_members = ast_true(general_val);
03802          autofill_default = 0;
03803          if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
03804             autofill_default = ast_true(general_val);
03805          montype_default = 0;
03806          if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type")))
03807             if (!strcasecmp(general_val, "mixmonitor"))
03808                montype_default = 1;
03809       } else { /* Define queue */
03810          /* Look for an existing one */
03811          AST_LIST_TRAVERSE(&queues, q, list) {
03812             if (!strcmp(q->name, cat))
03813                break;
03814          }
03815          if (!q) {
03816             /* Make one then */
03817             if (!(q = alloc_queue(cat))) {
03818                /* TODO: Handle memory allocation failure */
03819             }
03820             new = 1;
03821          } else
03822             new = 0;
03823          if (q) {
03824             if (!new)
03825                ast_mutex_lock(&q->lock);
03826             /* Re-initialize the queue, and clear statistics */
03827             init_queue(q);
03828             clear_queue(q);
03829             for (cur = q->members; cur; cur = cur->next) {
03830                if (!cur->dynamic) {
03831                   cur->delme = 1;
03832                }
03833             }
03834             for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
03835                if (!strcasecmp(var->name, "member")) {
03836                   /* Add a new member */
03837                   ast_copy_string(parse, var->value, sizeof(parse));
03838                   
03839                   AST_NONSTANDARD_APP_ARGS(args, parse, ',');
03840 
03841                   interface = args.interface;
03842                   if(!ast_strlen_zero(args.penalty)) {
03843                      tmp = args.penalty;
03844                      while (*tmp && *tmp < 33) tmp++;
03845                      penalty = atoi(tmp);
03846                      if (penalty < 0) {
03847                         penalty = 0;
03848                      }
03849                   } else
03850                      penalty = 0;
03851 
03852                   if (!ast_strlen_zero(args.membername)) {
03853                      membername = args.membername;
03854                      while (*membername && *membername < 33) membername++;
03855                   } else
03856                      membername = interface;
03857 
03858                   /* Find the old position in the list */
03859                   for (prev = NULL, cur = q->members; cur; prev = cur, cur = cur->next) {
03860                      if (!strcmp(cur->interface, interface)) {
03861                         break;
03862                      }
03863                   }
03864 
03865                   newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0);
03866 
03867                   if (cur) {
03868                      /* Delete it now */
03869                      newm->next = cur->next;
03870                      if (prev) {
03871                         prev->next = newm;
03872                      } else {
03873                         q->members = newm;
03874                      }
03875                      free(cur);
03876                   } else {
03877                      /* Add them to the master int list if necessary */
03878                      add_to_interfaces(interface);
03879                      newm->next = q->members;
03880                      q->members = newm;
03881                   }
03882                   q->membercount++;
03883                } else {
03884                   queue_set_param(q, var->name, var->value, var->lineno, 1);
03885                }
03886             }
03887 
03888             /* Free remaining members marked as delme */
03889             for (prev = NULL, cur = q->members;
03890                  cur;
03891                  cur = next) {
03892                next = cur->next;
03893 
03894                if (!cur->delme) {
03895                   prev = cur;
03896                   continue;
03897                }
03898 
03899                if (prev)
03900                   prev->next = next;
03901                else
03902                   q->members = next;
03903 
03904                remove_from_interfaces(cur->interface);
03905                q->membercount--;
03906                free(cur);
03907             }
03908 
03909             if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
03910                rr_dep_warning();
03911 
03912             if (new) {
03913                AST_LIST_INSERT_HEAD(&queues, q, list);
03914             } else
03915                ast_mutex_unlock(&q->lock);
03916          }
03917       }
03918    }
03919    ast_config_destroy(cfg);
03920    AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
03921       if (q->dead) {
03922          AST_LIST_REMOVE_CURRENT(&queues, list);
03923          if (!q->count)
03924             destroy_queue(q);
03925          else
03926             ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n");
03927       } else {
03928          ast_mutex_lock(&q->lock);
03929          for (cur = q->members; cur; cur = cur->next)
03930             cur->status = ast_device_state(cur->interface);
03931          ast_mutex_unlock(&q->lock);
03932       }
03933    }
03934    AST_LIST_TRAVERSE_SAFE_END;
03935    AST_LIST_UNLOCK(&queues);
03936    return 1;
03937 }

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

Definition at line 744 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), free, member_interface::interface, interface_exists_global(), LOG_DEBUG, and option_debug.

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

00745 {
00746    struct member_interface *curint;
00747 
00748    AST_LIST_LOCK(&interfaces);
00749    AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
00750       if (!strcasecmp(curint->interface, interface)) {
00751          if (!interface_exists_global(interface)) {
00752             if (option_debug)
00753                ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
00754             AST_LIST_REMOVE_CURRENT(&interfaces, list);
00755             free(curint);
00756          }
00757          break;
00758       }
00759    }
00760    AST_LIST_TRAVERSE_SAFE_END;
00761    AST_LIST_UNLOCK(&interfaces);
00762 
00763    return 0;
00764 }

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

Definition at line 2829 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), dump_queue_members(), EVENT_FLAG_AGENT, free, member::interface, interface_exists(), call_queue::lock, manager_event(), call_queue::membercount, member::membername, call_queue::members, call_queue::name, member::next, remove_from_interfaces(), RES_EXISTS, RES_NOSUCHQUEUE, and RES_OKAY.

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

02830 {
02831    struct call_queue *q;
02832    struct member *last_member, *look;
02833    int res = RES_NOSUCHQUEUE;
02834 
02835    AST_LIST_LOCK(&queues);
02836    AST_LIST_TRAVERSE(&queues, q, list) {
02837       ast_mutex_lock(&q->lock);
02838       if (strcmp(q->name, queuename)) {
02839          ast_mutex_unlock(&q->lock);
02840          continue;
02841       }
02842 
02843       if ((last_member = interface_exists(q, interface))) {
02844          if ((look = q->members) == last_member) {
02845             q->members = last_member->next;
02846             q->membercount--;
02847          } else {
02848             while (look != NULL) {
02849                if (look->next == last_member) {
02850                   look->next = last_member->next;
02851                   q->membercount--;
02852                   break;
02853                } else {
02854                   look = look->next;
02855                }
02856             }
02857          }
02858          manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
02859             "Queue: %s\r\n"
02860             "Location: %s\r\n"
02861             "MemberName: %s\r\n",
02862             q->name, last_member->interface, last_member->membername);
02863          free(last_member);
02864          
02865          if (queue_persistent_members)
02866             dump_queue_members(q);
02867          
02868          res = RES_OKAY;
02869       } else {
02870          res = RES_EXISTS;
02871       }
02872       ast_mutex_unlock(&q->lock);
02873       break;
02874    }
02875 
02876    if (res == RES_OKAY)
02877       remove_from_interfaces(interface);
02878 
02879    AST_LIST_UNLOCK(&queues);
02880 
02881    return res;
02882 }

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

Definition at line 1635 of file app_queue.c.

References ast_channel::adsicpe, ast_channel::appl, ast_call(), ast_cdr_busy(), ast_channel_inherit_variables(), AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_request(), ast_strdup, ast_verbose(), ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, compare_weight(), ast_channel::context, ast_channel::data, do_hang(), EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, free, callattempt::interface, callattempt::lastcall, call_queue::lock, LOG_DEBUG, manager_event(), callattempt::member, call_queue::name, ast_channel::nativeformats, callattempt::oldstatus, option_debug, option_verbose, queue_ent::parent, member::paused, ast_channel::priority, QUEUE_EVENT_VARIABLES, call_queue::ringinuse, call_queue::rrpos, member::status, callattempt::stillgoing, update_dial_status(), vars2manager(), VERBOSE_PREFIX_3, ast_channel::whentohangup, and call_queue::wrapuptime.

Referenced by ring_one().

01636 {
01637    int res;
01638    int status;
01639    char tech[256];
01640    char *location;
01641 
01642    /* on entry here, we know that tmp->chan == NULL */
01643    if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
01644       if (option_debug)
01645          ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
01646       if (qe->chan->cdr)
01647          ast_cdr_busy(qe->chan->cdr);
01648       tmp->stillgoing = 0;
01649       (*busies)++;
01650       return 0;
01651    }
01652 
01653    if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
01654       if (option_debug)
01655          ast_log(LOG_DEBUG, "%s in use, can't receive call\n", tmp->interface);
01656       if (qe->chan->cdr)
01657          ast_cdr_busy(qe->chan->cdr);
01658       tmp->stillgoing = 0;
01659       return 0;
01660    }
01661 
01662    if (tmp->member->paused) {
01663       if (option_debug)
01664          ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
01665       if (qe->chan->cdr)
01666          ast_cdr_busy(qe->chan->cdr);
01667       tmp->stillgoing = 0;
01668       return 0;
01669    }
01670    if (use_weight && compare_weight(qe->parent,tmp->member)) {
01671       ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
01672       if (qe->chan->cdr)
01673          ast_cdr_busy(qe->chan->cdr);
01674       tmp->stillgoing = 0;
01675       (*busies)++;
01676       return 0;
01677    }
01678 
01679    ast_copy_string(tech, tmp->interface, sizeof(tech));
01680    if ((location = strchr(tech, '/')))
01681       *location++ = '\0';
01682    else
01683       location = "";
01684 
01685    /* Request the peer */
01686    tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
01687    if (!tmp->chan) {       /* If we can't, just go on to the next call */
01688       if (qe->chan->cdr)
01689          ast_cdr_busy(qe->chan->cdr);
01690       tmp->stillgoing = 0;
01691       update_dial_status(qe->parent, tmp->member, status);
01692 
01693       ast_mutex_lock(&qe->parent->lock);
01694       qe->parent->rrpos++;
01695       ast_mutex_unlock(&qe->parent->lock);
01696 
01697       (*busies)++;
01698       return 0;
01699    } else if (status != tmp->oldstatus)
01700       update_dial_status(qe->parent, tmp->member, status);
01701    
01702    tmp->chan->appl = "AppQueue";
01703    tmp->chan->data = "(Outgoing Line)";
01704    tmp->chan->whentohangup = 0;
01705    if (tmp->chan->cid.cid_num)
01706       free(tmp->chan->cid.cid_num);
01707    tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
01708    if (tmp->chan->cid.cid_name)
01709       free(tmp->chan->cid.cid_name);
01710    tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
01711    if (tmp->chan->cid.cid_ani)
01712       free(tmp->chan->cid.cid_ani);
01713    tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
01714 
01715    /* Inherit specially named variables from parent channel */
01716    ast_channel_inherit_variables(qe->chan, tmp->chan);
01717 
01718    /* Presense of ADSI CPE on outgoing channel follows ours */
01719    tmp->chan->adsicpe = qe->chan->adsicpe;
01720 
01721    /* Place the call, but don't wait on the answer */
01722    if ((res = ast_call(tmp->chan, location, 0))) {
01723       /* Again, keep going even if there's an error */
01724       if (option_debug)
01725          ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
01726       if (option_verbose > 2)
01727          ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
01728       do_hang(tmp);
01729       (*busies)++;
01730       return 0;
01731    } else if (qe->parent->eventwhencalled) {
01732       char vars[2048];
01733 
01734       manager_event(EVENT_FLAG_AGENT, "AgentCalled",
01735                "AgentCalled: %s\r\n"
01736                "ChannelCalling: %s\r\n"
01737                "CallerID: %s\r\n"
01738                "CallerIDName: %s\r\n"
01739                "Context: %s\r\n"
01740                "Extension: %s\r\n"
01741                "Priority: %d\r\n"
01742                "%s",
01743                tmp->interface, qe->chan->name,
01744                tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
01745                tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
01746                qe->chan->context, qe->chan->exten, qe->chan->priority,
01747                qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
01748       if (option_verbose > 2)
01749          ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
01750    }
01751 
01752    return 1;
01753 }

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

Definition at line 1771 of file app_queue.c.

References ast_log(), callattempt::chan, find_best(), callattempt::interface, LOG_DEBUG, callattempt::metric, option_debug, 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().

01772 {
01773    int ret = 0;
01774 
01775    while (ret == 0) {
01776       struct callattempt *best = find_best(outgoing);
01777       if (!best) {
01778          if (option_debug)
01779             ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
01780          break;
01781       }
01782       if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
01783          struct callattempt *cur;
01784          /* Ring everyone who shares this best metric (for ringall) */
01785          for (cur = outgoing; cur; cur = cur->q_next) {
01786             if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
01787                if (option_debug)
01788                   ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
01789                ring_entry(qe, cur, busies);
01790             }
01791          }
01792       } else {
01793          /* Ring just the best channel */
01794          if (option_debug)
01795             ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
01796          ring_entry(qe, best, busies);
01797       }
01798       if (best->chan) /* break out with result = 1 */
01799          ret = 1;
01800    }
01801 
01802    return ret;
01803 }

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

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

Definition at line 1887 of file app_queue.c.

References ast_queue_log(), ast_verbose(), call_queue::autopause, queue_ent::chan, call_queue::name, option_verbose, queue_ent::parent, set_member_paused(), and VERBOSE_PREFIX_3.

Referenced by wait_for_answer().

01888 {
01889    if (option_verbose > 2)
01890       ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
01891    ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
01892    if (qe->parent->autopause) {
01893       if (!set_member_paused(qe->parent->name, interface, 1)) {
01894          if (option_verbose > 2)
01895             ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
01896       } else {
01897          if (option_verbose > 2)
01898             ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
01899       }
01900    }
01901    return;
01902 }

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

Definition at line 3180 of file app_queue.c.

References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_channel::context, ast_channel::exten, member_interface::interface, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), ast_channel::priority, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, and RES_OKAY.

Referenced by load_module().

03181 {
03182    int res=-1;
03183    struct ast_module_user *lu;
03184    char *parse, *temppos = NULL;
03185    int priority_jump = 0;
03186    AST_DECLARE_APP_ARGS(args,
03187       AST_APP_ARG(queuename);
03188       AST_APP_ARG(interface);
03189       AST_APP_ARG(options);
03190    );
03191 
03192 
03193    if (ast_strlen_zero(data)) {
03194       ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
03195       return -1;
03196    }
03197 
03198    parse = ast_strdupa(data);
03199 
03200    AST_STANDARD_APP_ARGS(args, parse);
03201 
03202    lu = ast_module_user_add(chan);
03203 
03204    if (ast_strlen_zero(args.interface)) {
03205       args.interface = ast_strdupa(chan->name);
03206       temppos = strrchr(args.interface, '-');
03207       if (temppos)
03208          *temppos = '\0';
03209    }
03210 
03211    if (args.options) {
03212       if (strchr(args.options, 'j'))
03213          priority_jump = 1;
03214    }
03215 
03216    switch (remove_from_queue(args.queuename, args.interface)) {
03217    case RES_OKAY:
03218       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
03219       ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
03220       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
03221       res = 0;
03222       break;
03223    case RES_EXISTS:
03224       ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
03225       if (priority_jump || ast_opt_priority_jumping)
03226          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
03227       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
03228       res = 0;
03229       break;
03230    case RES_NOSUCHQUEUE:
03231       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
03232       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
03233       res = 0;
03234       break;
03235    }
03236 
03237    ast_module_user_remove(lu);
03238 
03239    return res;
03240 }

static void rr_dep_warning ( void   )  [static]

Definition at line 408 of file app_queue.c.

References ast_log(), and LOG_NOTICE.

Referenced by find_queue_by_name_rt(), and reload_queues().

00409 {
00410    static unsigned int warned = 0;
00411 
00412    if (!warned) {
00413       ast_log(LOG_NOTICE, "The 'roundrobin' queue strategy is deprecated. Please use the 'rrmemory' strategy instead.\n");
00414       warned = 1;
00415    }
00416 }

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

Definition at line 930 of file app_queue.c.

References add_to_interfaces(), create_queue_member(), member::dead, member::interface, call_queue::membercount, call_queue::members, member::next, member::paused, and member::penalty.

Referenced by find_queue_by_name_rt(), and update_realtime_members().

00931 {
00932    struct member *m, *prev_m;
00933    int penalty = 0;
00934    int paused  = 0;
00935 
00936    if (penalty_str) {
00937       penalty = atoi(penalty_str);
00938       if (penalty < 0)
00939          penalty = 0;
00940    }
00941 
00942    if (paused_str) {
00943       paused = atoi(paused_str);
00944       if (paused < 0)
00945          paused = 0;
00946    }
00947 
00948    /* Find the member, or the place to put a new one. */
00949    for (m = q->members, prev_m = NULL;
00950       m && strcmp(m->interface, interface);
00951       prev_m = m, m = m->next);
00952 
00953    /* Create a new one if not found, else update penalty */
00954    if (!m) {
00955       if ((m = create_queue_member(interface, membername, penalty, paused))) {
00956          m->dead = 0;
00957          add_to_interfaces(interface);
00958          if (prev_m) {
00959             prev_m->next = m;
00960          } else {
00961             q->members = m;
00962          }
00963          q->membercount++;
00964       }
00965    } else {
00966       m->dead = 0;   /* Do not delete this one. */
00967       if (paused_str)
00968          m->paused = paused;
00969       m->penalty = penalty;
00970    }
00971 }

static int say_periodic_announcement ( struct queue_ent qe  )  [static]

Definition at line 1829 of file app_queue.c.

References ast_moh_start(), ast_moh_stop(), ast_verbose(), queue_ent::chan, queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, MAX_PERIODIC_ANNOUNCEMENTS, queue_ent::moh, option_verbose, queue_ent::parent, call_queue::periodicannouncefrequency, play_file(), call_queue::sound_periodicannounce, valid_exit(), and VERBOSE_PREFIX_3.

Referenced by queue_exec(), and wait_our_turn().

01830 {
01831    int res = 0;
01832    time_t now;
01833 
01834    /* Get the current time */
01835    time(&now);
01836 
01837    /* Check to see if it is time to announce */
01838    if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
01839       return 0;
01840 
01841    /* Stop the music on hold so we can play our own file */
01842    ast_moh_stop(qe->chan);
01843 
01844    if (option_verbose > 2)
01845       ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
01846 
01847    /* Check to make sure we have a sound file. If not, reset to the first sound file */
01848    if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
01849       qe->last_periodic_announce_sound = 0;
01850    }
01851    
01852    /* play the announcement */
01853    res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
01854 
01855    if (res > 0 && !valid_exit(qe, res))
01856       res = 0;
01857 
01858    /* Resume Music on Hold if the caller is going to stay in the queue */
01859    if (!res)
01860       ast_moh_start(qe->chan, qe->moh, NULL);
01861 
01862    /* update last_periodic_announce_time */
01863    qe->last_periodic_announce_time = now;
01864 
01865    /* Update the current periodic announcement to the next announcement */
01866    qe->last_periodic_announce_sound++;
01867    
01868    return res;
01869 }

static int say_position ( struct queue_ent qe  )  [static]

Definition at line 1334 of file app_queue.c.

References call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ONCE, AST_DIGIT_ANY, ast_moh_start(), ast_moh_stop(), ast_say_number(), ast_verbose(), queue_ent::chan, call_queue::holdtime, queue_ent::last_pos, queue_ent::last_pos_said, queue_ent::moh, call_queue::name, option_verbose, queue_ent::parent, play_file(), queue_ent::pos, call_queue::roundingseconds, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, queue_ent::start, valid_exit(), and VERBOSE_PREFIX_3.

Referenced by queue_exec(), and wait_our_turn().

01335 {
01336    int res = 0, avgholdmins, avgholdsecs;
01337    time_t now;
01338 
01339    /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
01340    time(&now);
01341    if ((now - qe->last_pos) < 15)
01342       return 0;
01343 
01344    /* If either our position has changed, or we are over the freq timer, say position */
01345    if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
01346       return 0;
01347 
01348    ast_moh_stop(qe->chan);
01349    /* Say we're next, if we are */
01350    if (qe->pos == 1) {
01351       res = play_file(qe->chan, qe->parent->sound_next);
01352       if (res)
01353          goto playout;
01354       else
01355          goto posout;
01356    } else {
01357       res = play_file(qe->chan, qe->parent->sound_thereare);
01358       if (res)
01359          goto playout;
01360       res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
01361       if (res)
01362          goto playout;
01363       res = play_file(qe->chan, qe->parent->sound_calls);
01364       if (res)
01365          goto playout;
01366    }
01367    /* Round hold time to nearest minute */
01368    avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
01369 
01370    /* If they have specified a rounding then round the seconds as well */
01371    if (qe->parent->roundingseconds) {
01372       avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
01373       avgholdsecs *= qe->parent->roundingseconds;
01374    } else {
01375       avgholdsecs = 0;
01376    }
01377 
01378    if (option_verbose > 2)
01379       ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
01380 
01381    /* If the hold time is >1 min, if it's enabled, and if it's not
01382       supposed to be only once and we have already said it, say it */
01383    if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
01384       (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
01385       res = play_file(qe->chan, qe->parent->sound_holdtime);
01386       if (res)
01387          goto playout;
01388 
01389       if (avgholdmins > 0) {
01390          if (avgholdmins < 2) {
01391             res = play_file(qe->chan, qe->parent->sound_lessthan);
01392             if (res)
01393                goto playout;
01394 
01395             res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
01396             if (res)
01397                goto playout;
01398          } else {
01399             res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
01400             if (res)
01401                goto playout;
01402          }
01403          
01404          res = play_file(qe->chan, qe->parent->sound_minutes);
01405          if (res)
01406             goto playout;
01407       }
01408       if (avgholdsecs>0) {
01409          res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
01410          if (res)
01411             goto playout;
01412 
01413          res = play_file(qe->chan, qe->parent->sound_seconds);
01414          if (res)
01415             goto playout;
01416       }
01417 
01418    }
01419 
01420 posout:
01421    if (option_verbose > 2)
01422       ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
01423          qe->chan->name, qe->parent->name, qe->pos);
01424    res = play_file(qe->chan, qe->parent->sound_thanks);
01425 
01426 playout:
01427    if (res > 0 && !valid_exit(qe, res))
01428       res = 0;
01429 
01430    /* Set our last_pos indicators */
01431    qe->last_pos = now;
01432    qe->last_pos_said = qe->pos;
01433 
01434    /* Don't restart music on hold if we're about to exit the caller from the queue */
01435    if (!res)
01436       ast_moh_start(qe->chan, qe->moh, NULL);
01437 
01438    return res;
01439 }

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

Definition at line 2937 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_strlen_zero(), dump_queue_members(), EVENT_FLAG_AGENT, member::interface, interface_exists(), call_queue::lock, LOG_DEBUG, manager_event(), member::membername, call_queue::name, member::paused, RESULT_FAILURE, and RESULT_SUCCESS.

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

02938 {
02939    int found = 0;
02940    struct call_queue *q;
02941    struct member *mem;
02942 
02943    /* Special event for when all queues are paused - individual events still generated */
02944    /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
02945    if (ast_strlen_zero(queuename))
02946       ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
02947 
02948    AST_LIST_LOCK(&queues);
02949    AST_LIST_TRAVERSE(&queues, q, list) {
02950       ast_mutex_lock(&q->lock);
02951       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
02952          if ((mem = interface_exists(q, interface))) {
02953             found++;
02954             if (mem->paused == paused)
02955                ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
02956             mem->paused = paused;
02957 
02958             if (queue_persistent_members)
02959                dump_queue_members(q);
02960 
02961             ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
02962 
02963             manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
02964                "Queue: %s\r\n"
02965                "Location: %s\r\n"
02966                "MemberName: %s\r\n"
02967                "Paused: %d\r\n",
02968                   q->name, mem->interface, mem->membername, paused);
02969          }
02970       }
02971       ast_mutex_unlock(&q->lock);
02972    }
02973    AST_LIST_UNLOCK(&queues);
02974 
02975    return found ? RESULT_SUCCESS : RESULT_FAILURE;
02976 }

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

Definition at line 418 of file app_queue.c.

References pbx_builtin_setvar_helper(), queue_results, and text.

Referenced by queue_exec().

00419 {
00420    int i;
00421 
00422    for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
00423       if (queue_results[i].id == res) {
00424          pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
00425          return;
00426       }
00427    }
00428 }

static int statechange_queue ( const char *  dev,
int  state,
void *  ign 
) [static]

Definition at line 597 of file app_queue.c.

References ast_calloc, ast_log(), ast_pthread_create_background, changethread(), statechange::dev, free, LOG_WARNING, statechange::state, and t.

Referenced by load_module(), and unload_module().

00598 {
00599    /* Avoid potential for deadlocks by spawning a new thread to handle
00600       the event */
00601    struct statechange *sc;
00602    pthread_t t;
00603    pthread_attr_t attr;
00604 
00605    if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
00606       return 0;
00607 
00608    sc->state = state;
00609    strcpy(sc->dev, dev);
00610    pthread_attr_init(&attr);
00611    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00612    if (ast_pthread_create_background(&t, &attr, changethread, sc)) {
00613       ast_log(LOG_WARNING, "Failed to create update thread!\n");
00614       free(sc);
00615    }
00616    pthread_attr_destroy(&attr);
00617 
00618    return 0;
00619 }

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

Definition at line 1805 of file app_queue.c.

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

Referenced by try_calling().

01806 {
01807    struct callattempt *best = find_best(outgoing);
01808 
01809    if (best) {
01810       /* Ring just the best channel */
01811       if (option_debug)
01812          ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
01813       qe->parent->rrpos = best->metric % 1000;
01814    } else {
01815       /* Just increment rrpos */
01816       if (qe->parent->wrapped) {
01817          /* No more channels, start over */
01818          qe->parent->rrpos = 0;
01819       } else {
01820          /* Prioritize next entry */
01821          qe->parent->rrpos++;
01822       }
01823    }
01824    qe->parent->wrapped = 0;
01825 
01826    return 0;
01827 }

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

Definition at line 442 of file app_queue.c.

References name, and strategies.

Referenced by queue_set_param().

00443 {
00444    int x;
00445 
00446    for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
00447       if (!strcasecmp(strategy, strategies[x].name))
00448          return strategies[x].strategy;
00449    }
00450 
00451    return -1;
00452 }

static int try_calling ( struct queue_ent qe,
const char *  options,
char *  announceoverride,
const char *  url,
int *  go_on,
const char *  agi 
) [static]

Definition at line 2345 of file app_queue.c.

References ast_channel::_softhangup, ast_channel::_state, queue_ent::announce, ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_calloc, ast_cdr_setdestchan(), ast_channel_make_compatible(), ast_channel_sendurl(), ast_channel_setoption(), ast_channel_supports_html(), AST_DEVICE_NOT_INUSE, AST_DIGIT_ANY, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_REDIRECT, ast_hangup(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_moh_stop(), ast_monitor_setjoinfiles(), ast_monitor_start(), ast_mutex_lock(), ast_mutex_unlock(), AST_OPTION_TONE_VERIFY, AST_PBX_NO_HANGUP_PEER, ast_queue_log(), ast_random(), ast_safe_sleep(), ast_say_number(), ast_set_flag, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, calc_metric(), ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_channel::context, EVENT_FLAG_AGENT, call_queue::eventwhencalled, queue_ent::expire, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, free, queue_ent::handled, hangupcalls(), member::interface, callattempt::interface, member::lastcall, callattempt::lastcall, leave_queue(), call_queue::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, manager_event(), callattempt::member, call_queue::membercount, call_queue::memberdelay, member::membername, call_queue::members, call_queue::monfmt, call_queue::monjoin, call_queue::montype, call_queue::name, member::next, callattempt::oldstatus, queue_ent::opos, option_debug, queue_ent::parent, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pbx_substitute_variables_helper(), play_file(), queue_ent::pos, callattempt::q_next, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_ROUNDROBIN, QUEUE_STRATEGY_RRMEMORY, recalc_holdtime(), record_abandoned(), call_queue::reportholdtime, ring_one(), call_queue::servicelevel, call_queue::setinterfacevar, call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_reporthold, queue_ent::start, member::status, callattempt::stillgoing, store_next(), call_queue::strategy, ast_channel::tech, call_queue::timeout, ast_channel_tech::type, ast_cdr::uniqueid, update_queue(), valid_exit(), vars2manager(), and wait_for_answer().

Referenced by queue_exec().

02346 {
02347    struct member *cur;
02348    struct callattempt *outgoing = NULL; /* the list of calls we are building */
02349    int to;
02350    char oldexten[AST_MAX_EXTENSION]="";
02351    char oldcontext[AST_MAX_CONTEXT]="";
02352    char queuename[256]="";
02353    struct ast_channel *peer;
02354    struct ast_channel *which;
02355    struct callattempt *lpeer;
02356    struct member *member;
02357    struct ast_app *app;
02358    int res = 0, bridge = 0;
02359    int numbusies = 0;
02360    int x=0;
02361    char *announce = NULL;
02362    char digit = 0;
02363    time_t callstart;
02364    time_t now = time(NULL);
02365    struct ast_bridge_config bridge_config;
02366    char nondataquality = 1;
02367    char *agiexec = NULL;
02368    int ret = 0;
02369    const char *monitorfilename;
02370    const char *monitor_exec;
02371    const char *monitor_options;
02372    char tmpid[256], tmpid2[256];
02373    char meid[1024], meid2[1024];
02374    char mixmonargs[1512];
02375    struct ast_app *mixmonapp = NULL;
02376    char *p;
02377    char vars[2048];
02378    int forwardsallowed = 1;
02379    int callcompletedinsl;
02380    int noption = 0;
02381 
02382    memset(&bridge_config, 0, sizeof(bridge_config));
02383    time(&now);
02384       
02385    for (; options && *options; options++)
02386       switch (*options) {
02387       case 't':
02388          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
02389          break;
02390       case 'T':
02391          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
02392          break;
02393       case 'w':
02394          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
02395          break;
02396       case 'W':
02397          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
02398          break;
02399       case 'd':
02400          nondataquality = 0;
02401          break;
02402       case 'h':
02403          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
02404          break;
02405       case 'H':
02406          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
02407          break;
02408       case 'n':
02409          if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY)
02410             (*go_on)++;
02411          else
02412             *go_on = qe->parent->membercount;
02413          noption = 1;
02414          break;
02415       case 'i':
02416          forwardsallowed = 0;
02417          break;
02418       }
02419 
02420    if(!noption)
02421       *go_on = -1;
02422 
02423    /* Hold the lock while we setup the outgoing calls */
02424    if (use_weight)
02425       AST_LIST_LOCK(&queues);
02426    ast_mutex_lock(&qe->parent->lock);
02427    if (option_debug)
02428       ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
02429                      qe->chan->name);
02430    ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
02431    cur = qe->parent->members;
02432    if (!ast_strlen_zero(qe->announce))
02433       announce = qe->announce;
02434    if (!ast_strlen_zero(announceoverride))
02435       announce = announceoverride;
02436 
02437    for (; cur; cur = cur->next) {
02438       struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
02439 
02440       if (!tmp) {
02441          ast_mutex_unlock(&qe->parent->lock);
02442          if (use_weight)
02443             AST_LIST_UNLOCK(&queues);
02444          goto out;
02445       }
02446       tmp->stillgoing = -1;
02447       tmp->member = cur;      /* Never directly dereference!  Could change on reload */
02448       tmp->oldstatus = cur->status;
02449       tmp->lastcall = cur->lastcall;
02450       ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
02451       /* Special case: If we ring everyone, go ahead and ring them, otherwise
02452          just calculate their metric for the appropriate strategy */
02453       if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
02454          /* Put them in the list of outgoing thingies...  We're ready now.
02455             XXX If we're forcibly removed, these outgoing calls won't get
02456             hung up XXX */
02457          tmp->q_next = outgoing;
02458          outgoing = tmp;      
02459          /* If this line is up, don't try anybody else */
02460          if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
02461             break;
02462       } else {
02463          free(tmp);
02464       }
02465    }
02466    if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
02467       to = (qe->expire - now) * 1000;
02468    else
02469       to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
02470    ring_one(qe, outgoing, &numbusies);
02471    ast_mutex_unlock(&qe->parent->lock);
02472    if (use_weight)
02473       AST_LIST_UNLOCK(&queues);
02474    lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
02475    ast_mutex_lock(&qe->parent->lock);
02476    if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
02477       store_next(qe, outgoing);
02478    }
02479    ast_mutex_unlock(&qe->parent->lock);
02480    peer = lpeer ? lpeer->chan : NULL;
02481    if (!peer) {
02482       if (to) {
02483          /* Must gotten hung up */
02484          res = -1;
02485       } else {
02486          res = digit;
02487          if (res > 0 && !valid_exit(qe, res))
02488             res = 0;
02489       }
02490       if (option_debug)
02491          ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
02492    } else { /* peer is valid */
02493       /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
02494          we will always return with -1 so that it is hung up properly after the
02495          conversation.  */
02496       qe->handled++;
02497       if (!strcmp(qe->chan->tech->type, "Zap"))
02498          ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
02499       if (!strcmp(peer->tech->type, "Zap"))
02500          ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
02501       /* Update parameters for the queue */
02502       time(&now);
02503       recalc_holdtime(qe, (now - qe->start));
02504       ast_mutex_lock(&qe->parent->lock);
02505       callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
02506       ast_mutex_unlock(&qe->parent->lock);
02507       member = lpeer->member;
02508       hangupcalls(outgoing, peer);
02509       outgoing = NULL;
02510       if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
02511          int res2;
02512 
02513          res2 = ast_autoservice_start(qe->chan);
02514          if (!res2) {
02515             if (qe->parent->memberdelay) {
02516                ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
02517                res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
02518             }
02519             if (!res2 && announce) {
02520                if (play_file(peer, announce))
02521                   ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
02522             }
02523             if (!res2 && qe->parent->reportholdtime) {
02524                if (!play_file(peer, qe->parent->sound_reporthold)) {
02525                   int holdtime;
02526 
02527                   time(&now);
02528                   holdtime = abs((now - qe->start) / 60);
02529                   if (holdtime < 2) {
02530                      play_file(peer, qe->parent->sound_lessthan);
02531                      ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
02532                   } else
02533                      ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
02534                   play_file(peer, qe->parent->sound_minutes);
02535                }
02536             }
02537          }
02538          res2 |= ast_autoservice_stop(qe->chan);
02539          if (peer->_softhangup) {
02540             /* Agent must have hung up */
02541             ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
02542             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
02543             record_abandoned(qe);
02544             if (qe->parent->eventwhencalled)
02545                manager_event(EVENT_FLAG_AGENT, "AgentDump",
02546                      "Queue: %s\r\n"
02547                      "Uniqueid: %s\r\n"
02548                      "Channel: %s\r\n"
02549                      "Member: %s\r\n"
02550                      "MemberName: %s\r\n"
02551                      "%s",
02552                      queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
02553                      qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
02554             ast_hangup(peer);
02555             goto out;
02556          } else if (res2) {
02557             /* Caller must have hung up just before being connected*/
02558             ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
02559             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02560             record_abandoned(qe);
02561             ast_hangup(peer);
02562             return -1;
02563          }
02564       }
02565       /* Stop music on hold */
02566       ast_moh_stop(qe->chan);
02567       /* If appropriate, log that we have a destination channel */
02568       if (qe->chan->cdr)
02569          ast_cdr_setdestchan(qe->chan->cdr, peer->name);
02570       /* Make sure channels are compatible */
02571       res = ast_channel_make_compatible(qe->chan, peer);
02572       if (res < 0) {
02573          ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
02574          ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
02575          record_abandoned(qe);
02576          ast_hangup(peer);
02577          return -1;
02578       }
02579       /* Begin Monitoring */
02580       if (qe->parent->monfmt && *qe->parent->monfmt) {
02581          if (!qe->parent->montype) {
02582             if (option_debug)
02583                ast_log(LOG_DEBUG, "Starting Monitor as requested.\n");
02584             monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
02585             if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
02586                which = qe->chan;
02587             else
02588                which = peer;
02589             if (monitorfilename)
02590                ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
02591             else if (qe->chan->cdr)
02592                ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
02593             else {
02594                /* Last ditch effort -- no CDR, make up something */
02595                snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
02596                ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
02597             }
02598             if (qe->parent->monjoin)
02599                ast_monitor_setjoinfiles(which, 1);
02600          } else {
02601             if (option_debug)
02602                ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n");
02603             monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
02604             if (!monitorfilename) {
02605                if (qe->chan->cdr)
02606                   ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1);
02607                else
02608                   snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
02609             } else {
02610                ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1);
02611                for (p = tmpid2; *p ; p++) {
02612                   if (*p == '^' && *(p+1) == '{') {
02613                      *p = '$';
02614                   }
02615                }
02616 
02617                memset(tmpid, 0, sizeof(tmpid));
02618                pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
02619             }
02620 
02621             monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
02622             monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
02623 
02624             if (monitor_exec) {
02625                ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1);
02626                for (p = meid2; *p ; p++) {
02627                   if (*p == '^' && *(p+1) == '{') {
02628                      *p = '$';
02629                   }
02630                }
02631 
02632                memset(meid, 0, sizeof(meid));
02633                pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
02634             }
02635    
02636             snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt);
02637 
02638             mixmonapp = pbx_findapp("MixMonitor");
02639 
02640             if (strchr(tmpid2, '|')) {
02641                ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
02642                mixmonapp = NULL;
02643             }
02644 
02645             if (!monitor_options)
02646                monitor_options = "";
02647             
02648             if (strchr(monitor_options, '|')) {
02649                ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
02650                mixmonapp = NULL;
02651             }
02652 
02653             if (mixmonapp) {
02654                if (!ast_strlen_zero(monitor_exec))
02655                   snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
02656                else
02657                   snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options);
02658                   
02659                if (option_debug)
02660                   ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
02661 
02662                ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
02663 
02664             } else
02665                ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
02666 
02667          }
02668       }
02669       /* Drop out of the queue at this point, to prepare for next caller */
02670       leave_queue(qe);        
02671       if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
02672          if (option_debug)
02673             ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
02674          ast_channel_sendurl(peer, url);
02675       }
02676       if (qe->parent->setinterfacevar)
02677             pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface);
02678       if (!ast_strlen_zero(agi)) {
02679          if (option_debug)
02680             ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi);
02681          app = pbx_findapp("agi");
02682          if (app) {
02683             agiexec = ast_strdupa(agi);
02684             ret = pbx_exec(qe->chan, app, agiexec);
02685          } else
02686             ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
02687       }
02688       ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid);
02689       if (qe->parent->eventwhencalled)
02690          manager_event(EVENT_FLAG_AGENT, "AgentConnect",
02691                "Queue: %s\r\n"
02692                "Uniqueid: %s\r\n"
02693                "Channel: %s\r\n"
02694                "Member: %s\r\n"
02695                "MemberName: %s\r\n"
02696                "Holdtime: %ld\r\n"
02697                "BridgedChannel: %s\r\n"
02698                "%s",
02699                queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
02700                (long)time(NULL) - qe->start, peer->uniqueid,
02701                qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
02702       ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
02703       ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
02704       time(&callstart);
02705 
02706       if (member->status == AST_DEVICE_NOT_INUSE)
02707          ast_log(LOG_WARNING, "The device state of this queue member, %s, is still 'Not in Use' when it probably should not be! Please check UPGRADE.txt for correct configuration settings.\n", member->membername);
02708          
02709 
02710       bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
02711 
02712       if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
02713          ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
02714             qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
02715             (long) (time(NULL) - callstart));
02716       } else if (qe->chan->_softhangup) {
02717          ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
02718             (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
02719          if (qe->parent->eventwhencalled)
02720             manager_event(EVENT_FLAG_AGENT, "AgentComplete",
02721                   "Queue: %s\r\n"
02722                   "Uniqueid: %s\r\n"
02723                   "Channel: %s\r\n"
02724                   "Member: %s\r\n"
02725                   "MemberName: %s\r\n"
02726                   "HoldTime: %ld\r\n"
02727                   "TalkTime: %ld\r\n"
02728                   "Reason: caller\r\n"
02729                   "%s",
02730                   queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
02731                   (long)(callstart - qe->start), (long)(time(NULL) - callstart),
02732                   qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
02733       } else {
02734          ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
02735             (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
02736          if (qe->parent->eventwhencalled)
02737             manager_event(EVENT_FLAG_AGENT, "AgentComplete",
02738                   "Queue: %s\r\n"
02739                   "Uniqueid: %s\r\n"
02740                   "Channel: %s\r\n"
02741                   "MemberName: %s\r\n"
02742                   "HoldTime: %ld\r\n"
02743                   "TalkTime: %ld\r\n"
02744                   "Reason: agent\r\n"
02745                   "%s",
02746                   queuename, qe->chan->uniqueid, peer->name, member->membername, (long)(callstart - qe->start),
02747                   (long)(time(NULL) - callstart),
02748                   qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
02749       }
02750 
02751       if (bridge != AST_PBX_NO_HANGUP_PEER)
02752          ast_hangup(peer);
02753       update_queue(qe->parent, member, callcompletedinsl);
02754       res = bridge ? bridge : 1;
02755    }
02756 out:
02757    hangupcalls(outgoing, NULL);
02758 
02759    return res;
02760 }

static int unload_module ( void   )  [static]

Definition at line 4507 of file app_queue.c.

References ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_devstate_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_unregister_application(), clear_and_free_interfaces(), cli_queue, queueagentcount_function, queuemembercount_function, queuememberlist_function, queuewaitingcount_function, and statechange_queue().

04508 {
04509    int res;
04510 
04511    ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
04512    res = ast_manager_unregister("QueueStatus");
04513    res |= ast_manager_unregister("Queues");
04514    res |= ast_manager_unregister("QueueStatus");
04515    res |= ast_manager_unregister("QueueAdd");
04516    res |= ast_manager_unregister("QueueRemove");
04517    res |= ast_manager_unregister("QueuePause");
04518    res |= ast_unregister_application(app_aqm);
04519    res |= ast_unregister_application(app_rqm);
04520    res |= ast_unregister_application(app_pqm);
04521    res |= ast_unregister_application(app_upqm);
04522    res |= ast_unregister_application(app_ql);
04523    res |= ast_unregister_application(app);
04524    res |= ast_custom_function_unregister(&queueagentcount_function);
04525    res |= ast_custom_function_unregister(&queuemembercount_function);
04526    res |= ast_custom_function_unregister(&queuememberlist_function);
04527    res |= ast_custom_function_unregister(&queuewaitingcount_function);
04528    ast_devstate_del(statechange_queue, NULL);
04529 
04530    ast_module_user_hangup_all();
04531 
04532    clear_and_free_interfaces();
04533 
04534    return res;
04535 }

static int update_dial_status ( struct call_queue q,
struct member member,
int  status 
) [static]

Definition at line 1545 of file app_queue.c.

References AST_CAUSE_BUSY, AST_CAUSE_NOSUCHDRIVER, AST_CAUSE_UNREGISTERED, AST_DEVICE_BUSY, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, and update_status().

Referenced by ring_entry(), and wait_for_answer().

01546 {
01547    if (status == AST_CAUSE_BUSY)
01548       status = AST_DEVICE_BUSY;
01549    else if (status == AST_CAUSE_UNREGISTERED)
01550       status = AST_DEVICE_UNAVAILABLE;
01551    else if (status == AST_CAUSE_NOSUCHDRIVER)
01552       status = AST_DEVICE_INVALID;
01553    else
01554       status = AST_DEVICE_UNKNOWN;
01555    return update_status(q, member, status);
01556 }

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

Definition at line 2267 of file app_queue.c.

References ast_mutex_lock(), ast_mutex_unlock(), member::calls, call_queue::callscompleted, call_queue::callscompletedinsl, member::lastcall, call_queue::lock, call_queue::members, and member::next.

Referenced by try_calling().

02268 {
02269    struct member *cur;
02270 
02271    /* Since a reload could have taken place, we have to traverse the list to
02272       be sure it's still valid */
02273    ast_mutex_lock(&q->lock);
02274    cur = q->members;
02275    while (cur) {
02276       if (member == cur) {
02277          time(&cur->lastcall);
02278          cur->calls++;
02279          break;
02280       }
02281       cur = cur->next;
02282    }
02283    q->callscompleted++;
02284    if (callcompletedinsl)
02285       q->callscompletedinsl++;
02286    ast_mutex_unlock(&q->lock);
02287    return 0;
02288 }

static void update_realtime_members ( struct call_queue q  )  [static]

Definition at line 1170 of file app_queue.c.

References ast_category_browse(), ast_load_realtime_multientry(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_variable_retrieve(), member::dead, member::dynamic, free, member::interface, member_interface::interface, call_queue::lock, LOG_DEBUG, call_queue::membercount, call_queue::members, call_queue::name, member::next, option_debug, remove_from_interfaces(), rt_handle_member_record(), and S_OR.

Referenced by queue_exec().

01171 {
01172    struct ast_config *member_config = NULL;
01173    struct member *m, *prev_m, *next_m;
01174    char *interface = NULL;
01175 
01176    member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL);
01177    if (!member_config) {
01178       /*This queue doesn't have realtime members*/
01179       if (option_debug > 2)
01180          ast_log(LOG_DEBUG, "Queue %s has no realtime members defined. No need for update\n", q->name);
01181       return;
01182    }
01183 
01184    ast_mutex_lock(&q->lock);
01185    
01186    /* Temporarily set non-dynamic members dead so we can detect deleted ones.*/ 
01187    for (m = q->members; m; m = m->next) {
01188       if (!m->dynamic)
01189          m->dead = 1;
01190    }
01191 
01192    while ((interface = ast_category_browse(member_config, interface))) {
01193       rt_handle_member_record(q, interface,
01194          S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
01195          ast_variable_retrieve(member_config, interface, "penalty"),
01196          ast_variable_retrieve(member_config, interface, "paused"));
01197    }
01198 
01199    /* Delete all realtime members that have been deleted in DB. */
01200    m = q->members;
01201    prev_m = NULL;
01202    while (m) {
01203       next_m = m->next;
01204       if (m->dead) {
01205          if (prev_m) {
01206             prev_m->next = next_m;
01207          } else {
01208             q->members = next_m;
01209          }
01210          remove_from_interfaces(m->interface);
01211          q->membercount--;
01212          free(m);
01213       } else {
01214          prev_m = m;
01215       }
01216       m = next_m;
01217    }
01218    ast_mutex_unlock(&q->lock);
01219 }

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

Definition at line 1514 of file app_queue.c.

References ast_mutex_lock(), ast_mutex_unlock(), member::calls, member::dynamic, EVENT_FLAG_AGENT, member::interface, member::lastcall, call_queue::lock, manager_event(), call_queue::maskmemberstatus, member::membername, call_queue::members, call_queue::name, member::next, member::paused, member::penalty, and member::status.

Referenced by update_dial_status().

01515 {
01516    struct member *cur;
01517 
01518    /* Since a reload could have taken place, we have to traverse the list to
01519       be sure it's still valid */
01520    ast_mutex_lock(&q->lock);
01521    for (cur = q->members; cur; cur = cur->next) {
01522       if (member != cur)
01523          continue;
01524 
01525       cur->status = status;
01526       if (!q->maskmemberstatus) {
01527          manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
01528             "Queue: %s\r\n"
01529             "Location: %s\r\n"
01530             "MemberName: %s\r\n"
01531             "Membership: %s\r\n"
01532             "Penalty: %d\r\n"
01533             "CallsTaken: %d\r\n"
01534             "LastCall: %d\r\n"
01535             "Status: %d\r\n"
01536             "Paused: %d\r\n",
01537             q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static",
01538             cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
01539       }
01540    }
01541    ast_mutex_unlock(&q->lock);
01542    return 0;
01543 }

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

Definition at line 3127 of file app_queue.c.

References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_channel::context, ast_channel::exten, member_interface::interface, LOG_WARNING, parse(), pbx_builtin_setvar_helper(), ast_channel::priority, and set_member_paused().

Referenced by load_module().

03128 {
03129    struct ast_module_user *lu;
03130    char *parse;
03131    int priority_jump = 0;
03132    AST_DECLARE_APP_ARGS(args,
03133       AST_APP_ARG(queuename);
03134       AST_APP_ARG(interface);
03135       AST_APP_ARG(options);
03136    );
03137 
03138    if (ast_strlen_zero(data)) {
03139       ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
03140       return -1;
03141    }
03142 
03143    parse = ast_strdupa(data);
03144 
03145    AST_STANDARD_APP_ARGS(args, parse);
03146 
03147    lu = ast_module_user_add(chan);
03148 
03149    if (args.options) {
03150       if (strchr(args.options, 'j'))
03151          priority_jump = 1;
03152    }
03153 
03154    if (ast_strlen_zero(args.interface)) {
03155       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
03156       ast_module_user_remove(lu);
03157       return -1;
03158    }
03159 
03160    if (set_member_paused(args.queuename, args.interface, 0)) {
03161       ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
03162       if (priority_jump || ast_opt_priority_jumping) {
03163          if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
03164             pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
03165             ast_module_user_remove(lu);
03166             return 0;
03167          }
03168       }
03169       ast_module_user_remove(lu);
03170       pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
03171       return -1;
03172    }
03173 
03174    ast_module_user_remove(lu);
03175    pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
03176 
03177    return 0;
03178 }

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

Definition at line 1301 of file app_queue.c.

References ast_canmatch_extension(), ast_goto_if_exists(), ast_strlen_zero(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, queue_ent::context, queue_ent::digits, and queue_ent::valid_digits.

Referenced by say_periodic_announcement(), say_position(), try_calling(), wait_a_bit(), wait_for_answer(), and wait_our_turn().

01302 {
01303    int digitlen = strlen(qe->digits);
01304 
01305    /* Prevent possible buffer overflow */
01306    if (digitlen < sizeof(qe->digits) - 2) {
01307       qe->digits[digitlen] = digit;
01308       qe->digits[digitlen + 1] = '\0';
01309    } else {
01310       qe->digits[0] = '\0';
01311       return 0;
01312    }
01313 
01314    /* If there's no context to goto, short-circuit */
01315    if (ast_strlen_zero(qe->context))
01316       return 0;
01317 
01318    /* If the extension is bad, then reset the digits to blank */
01319    if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
01320       qe->digits[0] = '\0';
01321       return 0;
01322    }
01323 
01324    /* We have an exact match */
01325    if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
01326       qe->valid_digits = 1;
01327       /* Return 1 on a successful goto */
01328       return 1;
01329    }
01330 
01331    return 0;
01332 }

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

Definition at line 1600 of file app_queue.c.

References pbx_builtin_serialize_variables().

Referenced by ring_entry(), and try_calling().

01601 {
01602    char *tmp = alloca(len);
01603 
01604    if (pbx_builtin_serialize_variables(chan, tmp, len)) {
01605       int i, j;
01606 
01607       /* convert "\n" to "\nVariable: " */
01608       strcpy(vars, "Variable: ");
01609 
01610       for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
01611          vars[j] = tmp[i];
01612 
01613          if (tmp[i + 1] == '\0')
01614             break;
01615          if (tmp[i] == '\n') {
01616             vars[j] = '\r';
01617             vars[++j] = '\n';
01618 
01619             ast_copy_string(&(vars[j]), "Variable: ", len - j);
01620             j += 9;
01621          }
01622       }
01623       if (j > len - 1)
01624          j = len - 1;
01625       vars[j - 2] = '\r';
01626       vars[j - 1] = '\n';
01627       vars[j] = '\0';
01628    } else {
01629       /* there are no channel variables; leave it blank */
01630       *vars = '\0';
01631    }
01632    return vars;
01633 }

static int wait_a_bit ( struct queue_ent qe  )  [static]

Definition at line 2762 of file app_queue.c.

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

Referenced by queue_exec().

02763 {
02764    /* Don't need to hold the lock while we setup the outgoing calls */
02765    int retrywait = qe->parent->retry * 1000;
02766 
02767    int res = ast_waitfordigit(qe->chan, retrywait);
02768    if (res > 0 && !valid_exit(qe, res))
02769       res = 0;
02770 
02771    return res;
02772 }

static struct callattempt* wait_for_answer ( struct queue_ent qe,
struct callattempt outgoing,
int *  to,
char *  digit,
int  prebusies,
int  caller_disconnect,
int  forwardsallowed 
) [static, read]

Definition at line 1906 of file app_queue.c.

References ast_channel::_state, accountcode, ast_call(), ast_cdr_busy(), ast_channel_inherit_variables(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_OFFHOOK, AST_CONTROL_RINGING, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_WATCHERS, ast_read(), ast_request(), AST_STATE_UP, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_verbose(), ast_waitfor_n(), ast_channel::cdr, ast_channel::cdrflags, callattempt::chan, queue_ent::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_channel::context, do_hang(), ast_channel::exten, f, ast_frame::frametype, free, member::interface, LOG_DEBUG, LOG_NOTICE, ast_channel::macroexten, callattempt::member, member::membername, call_queue::name, ast_channel::nativeformats, callattempt::oldstatus, option_verbose, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), rna(), S_OR, starttime, callattempt::stillgoing, call_queue::strategy, ast_frame::subclass, ast_channel::tech, call_queue::timeoutrestart, update_dial_status(), valid_exit(), and VERBOSE_PREFIX_3.

01907 {
01908    char *queue = qe->parent->name;
01909    struct callattempt *o;
01910    int status;
01911    int sentringing = 0;
01912    int numbusies = prebusies;
01913    int numnochan = 0;
01914    int stillgoing = 0;
01915    int orig = *to;
01916    struct ast_frame *f;
01917    struct callattempt *peer = NULL;
01918    struct ast_channel *winner;
01919    struct ast_channel *in = qe->chan;
01920    char on[80] = "";
01921    char membername[80] = "";
01922    long starttime = 0;
01923    long endtime = 0; 
01924 
01925    starttime = (long) time(NULL);
01926    
01927    while (*to && !peer) {
01928       int numlines, retry, pos = 1;
01929       struct ast_channel *watchers[AST_MAX_WATCHERS];
01930       watchers[0] = in;
01931 
01932       for (retry = 0; retry < 2; retry++) {
01933          numlines = 0;
01934          for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
01935             if (o->stillgoing) { /* Keep track of important channels */
01936                stillgoing = 1;
01937                if (o->chan)
01938                   watchers[pos++] = o->chan;
01939             }
01940             numlines++;
01941          }
01942          if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
01943             (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
01944             break;
01945          /* On "ringall" strategy we only move to the next penalty level
01946             when *all* ringing phones are done in the current penalty level */
01947          ring_one(qe, outgoing, &numbusies);
01948          /* and retry... */
01949       }
01950       if (pos == 1 /* not found */) {
01951          if (numlines == (numbusies + numnochan)) {
01952             ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
01953          } else {
01954             ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
01955          }
01956          *to = 0;
01957          return NULL;
01958       }
01959       winner = ast_waitfor_n(watchers, pos, to);
01960       for (o = outgoing; o; o = o->q_next) {
01961          if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
01962             if (!peer) {
01963                if (option_verbose > 2)
01964                   ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
01965                peer = o;
01966             }
01967          } else if (o->chan && (o->chan == winner)) {
01968 
01969             ast_copy_string(on, o->member->interface, sizeof(on));
01970             ast_copy_string(membername, o->member->membername, sizeof(membername));
01971 
01972             if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
01973                if (option_verbose > 2)
01974                   ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
01975                numnochan++;
01976                do_hang(o);
01977                winner = NULL;
01978                continue;
01979             } else if (!ast_strlen_zero(o->chan->call_forward)) {
01980                char tmpchan[256];
01981                char *stuff;
01982                char *tech;
01983 
01984                ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
01985                if ((stuff = strchr(tmpchan, '/'))) {
01986                   *stuff++ = '\0';
01987                   tech = tmpchan;
01988                } else {
01989                   snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
01990                   stuff = tmpchan;
01991                   tech = "Local";
01992                }
01993                /* Before processing channel, go ahead and check for forwarding */
01994                if (option_verbose > 2)
01995                   ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
01996                /* Setup parameters */
01997                o->chan = ast_request(tech, in->nativeformats, stuff, &status);
01998                if (status != o->oldstatus)
01999                   update_dial_status(qe->parent, o->member, status);                
02000                if (!o->chan) {
02001                   ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
02002                   o->stillgoing = 0;
02003                   numnochan++;
02004                } else {
02005                   ast_channel_inherit_variables(in, o->chan);
02006                   if (o->chan->cid.cid_num)
02007                      free(o->chan->cid.cid_num);
02008                   o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
02009 
02010                   if (o->chan->cid.cid_name)
02011                      free(o->chan->cid.cid_name);
02012                   o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
02013 
02014                   ast_string_field_set(o->chan, accountcode, in->accountcode);
02015                   o->chan->cdrflags = in->cdrflags;
02016 
02017                   if (in->cid.cid_ani) {
02018                      if (o->chan->cid.cid_ani)
02019                         free(o->chan->cid.cid_ani);
02020                      o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
02021                   }
02022                   if (o->chan->cid.cid_rdnis)
02023                      free(o->chan->cid.cid_rdnis);
02024                   o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
02025                   if (ast_call(o->chan, tmpchan, 0)) {
02026                      ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
02027                      do_hang(o);
02028                      numnochan++;
02029                   }
02030                }
02031                /* Hangup the original channel now, in case we needed it */
02032                ast_hangup(winner);
02033                continue;
02034             }
02035             f = ast_read(winner);
02036             if (f) {
02037                if (f->frametype == AST_FRAME_CONTROL) {
02038                   switch (f->subclass) {
02039                   case AST_CONTROL_ANSWER:
02040                      /* This is our guy if someone answered. */
02041                      if (!peer) {
02042                         if (option_verbose > 2)
02043                            ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
02044                         peer = o;
02045                      }
02046                      break;
02047                   case AST_CONTROL_BUSY:
02048                      if (option_verbose > 2)
02049                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
02050                      if (in->cdr)
02051                         ast_cdr_busy(in->cdr);
02052                      do_hang(o);
02053                      endtime = (long)time(NULL);
02054                      endtime -= starttime;
02055                      rna(endtime*1000, qe, on, membername);
02056                      if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02057                         if (qe->parent->timeoutrestart)
02058                            *to = orig;
02059                         ring_one(qe, outgoing, &numbusies);
02060                      }
02061                      numbusies++;
02062                      break;
02063                   case AST_CONTROL_CONGESTION:
02064                      if (option_verbose > 2)
02065                         ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
02066                      if (in->cdr)
02067                         ast_cdr_busy(in->cdr);
02068                      endtime = (long)time(NULL);
02069                      endtime -= starttime;
02070                      rna(endtime*1000, qe, on, membername);
02071                      do_hang(o);
02072                      if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02073                         if (qe->parent->timeoutrestart)
02074                            *to = orig;
02075                         ring_one(qe, outgoing, &numbusies);
02076                      }
02077                      numbusies++;
02078                      break;
02079                   case AST_CONTROL_RINGING:
02080                      if (option_verbose > 2)
02081                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
02082                      if (!sentringing) {
02083 #if 0
02084                         ast_indicate(in, AST_CONTROL_RINGING);
02085 #endif                        
02086                         sentringing++;
02087                      }
02088                      break;
02089                   case AST_CONTROL_OFFHOOK:
02090                      /* Ignore going off hook */
02091                      break;
02092                   default:
02093                      ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
02094                   }
02095                }
02096                ast_frfree(f);
02097             } else {
02098                endtime = (long) time(NULL) - starttime;
02099                rna(endtime * 1000, qe, on, membername);
02100                do_hang(o);
02101                if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02102                   if (qe->parent->timeoutrestart)
02103                      *to = orig;
02104                   ring_one(qe, outgoing, &numbusies);
02105                }
02106             }
02107          }
02108       }
02109       if (winner == in) {
02110          f = ast_read(in);
02111          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
02112             /* Got hung up */
02113             *to = -1;
02114             if (f)
02115                ast_frfree(f);
02116             return NULL;
02117          }
02118          if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
02119             if (option_verbose > 3)
02120                ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
02121             *to = 0;
02122             ast_frfree(f);
02123             return NULL;
02124          }
02125          if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
02126             if (option_verbose > 3)
02127                ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
02128             *to = 0;
02129             *digit = f->subclass;
02130             ast_frfree(f);
02131             return NULL;
02132          }
02133          ast_frfree(f);
02134       }
02135       if (!*to)
02136          rna(orig, qe, on, membername);
02137    }
02138 
02139    return peer;
02140 }

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

Definition at line 2210 of file app_queue.c.

References call_queue::announcefrequency, ast_queue_log(), ast_waitfordigit(), queue_ent::chan, queue_ent::expire, get_member_status(), is_our_turn(), leave_queue(), call_queue::leavewhenempty, queue_ent::max_penalty, call_queue::name, queue_ent::opos, queue_ent::parent, call_queue::periodicannouncefrequency, queue_ent::pos, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, RECHECK, say_periodic_announcement(), say_position(), queue_ent::start, and valid_exit().

Referenced by queue_exec().

02211 {
02212    int res = 0;
02213 
02214    /* This is the holding pen for callers 2 through maxlen */
02215    for (;;) {
02216       enum queue_member_status stat;
02217 
02218       if (is_our_turn(qe))
02219          break;
02220 
02221       /* If we have timed out, break out */
02222       if (qe->expire && (time(NULL) > qe->expire)) {
02223          *reason = QUEUE_TIMEOUT;
02224          break;
02225       }
02226 
02227       stat = get_member_status(qe->parent, qe->max_penalty);
02228 
02229       /* leave the queue if no agents, if enabled */
02230       if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
02231          *reason = QUEUE_LEAVEEMPTY;
02232          ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02233          leave_queue(qe);
02234          break;
02235       }
02236 
02237       /* leave the queue if no reachable agents, if enabled */
02238       if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
02239          *reason = QUEUE_LEAVEUNAVAIL;
02240          ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02241          leave_queue(qe);
02242          break;
02243       }
02244 
02245       /* Make a position announcement, if enabled */
02246       if (qe->parent->announcefrequency && !ringing &&
02247          (res = say_position(qe)))
02248          break;
02249 
02250       /* Make a periodic announcement, if enabled */
02251       if (qe->parent->periodicannouncefrequency && !ringing &&
02252          (res = say_periodic_announcement(qe)))
02253          break;
02254 
02255       /* Wait a second before checking again */
02256       if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
02257          if (res > 0 && !valid_exit(qe, res))
02258             res = 0;
02259          else
02260             break;
02261       }
02262    }
02263 
02264    return res;
02265 }


Variable Documentation

char* app = "Queue" [static]

Definition at line 127 of file app_queue.c.

char* app_aqm = "AddQueueMember" [static]

Definition at line 161 of file app_queue.c.

char* app_aqm_descrip [static]

Definition at line 163 of file app_queue.c.

char* app_aqm_synopsis = "Dynamically adds queue members" [static]

Definition at line 162 of file app_queue.c.

char* app_pqm = "PauseQueueMember" [static]

Definition at line 193 of file app_queue.c.

char* app_pqm_descrip [static]

Definition at line 195 of file app_queue.c.

char* app_pqm_synopsis = "Pauses a queue member" [static]

Definition at line 194 of file app_queue.c.

char* app_ql = "QueueLog" [static]

Definition at line 230 of file app_queue.c.

char* app_ql_descrip [static]

Initial value:

"   QueueLog(queuename|uniqueid|agent|event[|additionalinfo]):\n"
"Allows you to write your own events into the queue log\n"
"Example: QueueLog(101|${UNIQUEID}|${AGENT}|WENTONBREAK|600)\n"

Definition at line 232 of file app_queue.c.

char* app_ql_synopsis = "Writes to the queue_log" [static]

Definition at line 231 of file app_queue.c.

char* app_rqm = "RemoveQueueMember" [static]

Definition at line 177 of file app_queue.c.

char* app_rqm_descrip [static]

Definition at line 179 of file app_queue.c.

char* app_rqm_synopsis = "Dynamically removes queue members" [static]

Definition at line 178 of file app_queue.c.

char* app_upqm = "UnpauseQueueMember" [static]

Definition at line 215 of file app_queue.c.

char* app_upqm_descrip [static]

Definition at line 217 of file app_queue.c.

char* app_upqm_synopsis = "Unpauses a queue member" [static]

Definition at line 216 of file app_queue.c.

int autofill_default = 0 [static]

queues.conf [general] option

Definition at line 249 of file app_queue.c.

struct ast_cli_entry cli_add_queue_member_deprecated [static]

Initial value:

 {
   { "add", "queue", "member", NULL },
   handle_queue_add_member, NULL,
   NULL, complete_queue_add_member }

Definition at line 4478 of file app_queue.c.

struct ast_cli_entry cli_queue[] [static]

Definition at line 4488 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry cli_remove_queue_member_deprecated [static]

Initial value:

 {
   { "remove", "queue", "member", NULL },
   handle_queue_remove_member, NULL,
   NULL, complete_queue_remove_member }

Definition at line 4483 of file app_queue.c.

struct ast_cli_entry cli_show_queue_deprecated [static]

Initial value:

 {
   { "show", "queue", NULL },
   queue_show, NULL,
   NULL, complete_queue_show }

Definition at line 4473 of file app_queue.c.

char* descrip [static]

Definition at line 131 of file app_queue.c.

enum queue_result id

Definition at line 265 of file app_queue.c.

Referenced by _sip_show_peers().

int montype_default = 0 [static]

queues.conf [general] option

Definition at line 252 of file app_queue.c.

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

Persistent Members astdb family.

Definition at line 238 of file app_queue.c.

char qam_cmd_usage[] [static]

Initial value:

"Usage: queue add member <channel> to <queue> [penalty <penalty>]\n"

Definition at line 4467 of file app_queue.c.

char qrm_cmd_usage[] [static]

Initial value:

"Usage: queue remove member <channel> from <queue>\n"

Definition at line 4470 of file app_queue.c.

int queue_persistent_members = 0 [static]

queues.conf [general] option

Definition at line 243 of file app_queue.c.

struct { ... } queue_results[]

Referenced by set_queue_result().

char queue_show_usage[] [static]

Initial value:

"Usage: queue show\n"
"       Provides summary information on a specified queue.\n"

Definition at line 4463 of file app_queue.c.

struct ast_custom_function queueagentcount_function [static]

Definition at line 3728 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuemembercount_function [static]

Definition at line 3738 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuememberlist_function [static]

Definition at line 3756 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuewaitingcount_function [static]

Definition at line 3747 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct strategy strategies[] [static]

Referenced by int2strat(), and strat2int().

char* synopsis = "Queue a call for a call queue" [static]

Definition at line 129 of file app_queue.c.

char* text

Definition at line 266 of file app_queue.c.

Referenced by _sip_show_peer(), build_reply_digest(), check_auth(), handle_response(), method_match(), parse_sip_options(), reqprep(), sendtext_exec(), set_queue_result(), sip_alloc(), and sip_show_channel().

int use_weight = 0 [static]

queues.conf per-queue weight option

Definition at line 246 of file app_queue.c.


Generated on Wed Aug 15 01:24:36 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3