Sat Mar 24 23:26:33 2007

Asterisk developer's documentation


app_queue.c File Reference

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

#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.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 dependency graph for app_queue.c:

Go to the source code of this file.

Data Structures

struct  ast_call_queue
struct  localuser
 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  queue_ent
struct  statechange
struct  strategy

Defines

#define ANNOUNCEHOLDTIME_ALWAYS   1
#define ANNOUNCEHOLDTIME_ONCE   2
#define AST_MAX_WATCHERS   256
#define BUILD_WATCHERS
#define DEFAULT_RETRY   5
#define DEFAULT_TIMEOUT   15
#define PM_MAX_LEN   2048
#define QUEUE_EMPTY_NORMAL   1
#define QUEUE_EMPTY_STRICT   2
#define QUEUE_STRATEGY_FEWESTCALLS   3
#define QUEUE_STRATEGY_LEASTRECENT   2
#define QUEUE_STRATEGY_RANDOM   4
#define QUEUE_STRATEGY_RINGALL   0
#define QUEUE_STRATEGY_ROUNDROBIN   1
#define QUEUE_STRATEGY_RRMEMORY   5
#define RECHECK   1
#define RES_EXISTS   (-1)
#define RES_NOSUCHQUEUE   (-3)
#define RES_OKAY   0
#define RES_OUTOFMEMORY   (-2)

Enumerations

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 (int manager, int fd, int argc, char **argv, int queue_show)
static int add_to_queue (char *queuename, char *interface, int penalty, int paused, int dump)
static struct ast_call_queuealloc_queue (const char *queuename)
static int aqm_exec (struct ast_channel *chan, void *data)
 AST_MUTEX_DEFINE_STATIC (qlock)
static int background_file (struct queue_ent *qe, struct ast_channel *chan, char *filename)
static int calc_metric (struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
static void * changethread (void *data)
static void clear_queue (struct ast_call_queue *q)
static int compare_weight (struct ast_call_queue *rq, struct member *member)
static char * complete_add_queue_member (char *line, char *word, int pos, int state)
static char * complete_queue (char *line, char *word, int pos, int state)
static char * complete_remove_queue_member (char *line, char *word, int pos, int state)
static struct membercreate_queue_member (char *interface, int penalty, int paused)
char * description (void)
 Provides a description of the module.
static void destroy_queue (struct ast_call_queue *q)
static void dump_queue_members (struct ast_call_queue *pm_queue)
static struct ast_call_queuefind_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
 Reload a single queue via realtime.
static void free_members (struct ast_call_queue *q, int all)
static enum queue_member_status get_member_status (const struct ast_call_queue *q)
static int handle_add_queue_member (int fd, int argc, char *argv[])
static int handle_remove_queue_member (int fd, int argc, char *argv[])
static void hangupcalls (struct localuser *outgoing, struct ast_channel *exception)
static void init_queue (struct ast_call_queue *q)
static void insert_entry (struct ast_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 ast_call_queue *q, 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)
char * key ()
 Returns the ASTERISK_GPL_KEY.
static void leave_queue (struct queue_ent *qe)
int load_module (void)
 Initialize the module.
static struct ast_call_queueload_realtime_queue (char *queuename)
static int manager_add_queue_member (struct mansession *s, struct message *m)
static int manager_pause_queue_member (struct mansession *s, struct message *m)
static int manager_queues_show (struct mansession *s, struct message *m)
static int manager_queues_status (struct mansession *s, struct message *m)
static int manager_remove_queue_member (struct mansession *s, 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 queue_exec (struct ast_channel *chan, void *data)
static char * queue_function_qac (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
static void queue_set_param (struct ast_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 int queues_show (int fd, int argc, char **argv)
static void recalc_holdtime (struct queue_ent *qe)
static void record_abandoned (struct queue_ent *qe)
int reload (void)
 Reload stuff.
static void reload_queue_members (void)
static void reload_queues (void)
static int remove_from_queue (char *queuename, char *interface)
static void remove_queue (struct ast_call_queue *q)
static int ring_entry (struct queue_ent *qe, struct localuser *tmp, int *busies)
static int ring_one (struct queue_ent *qe, struct localuser *outgoing, int *busies)
static int rqm_exec (struct ast_channel *chan, void *data)
static void rt_handle_member_record (struct ast_call_queue *q, char *interface, const char *penalty_str)
static int say_periodic_announcement (struct queue_ent *qe)
static int say_position (struct queue_ent *qe)
static int set_member_paused (char *queuename, 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 localuser *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)
int unload_module (void)
 Cleanup all module structures, sockets, etc.
static int update_dial_status (struct ast_call_queue *q, struct member *member, int status)
static int update_queue (struct ast_call_queue *q, struct member *member)
static int update_status (struct ast_call_queue *q, struct member *member, int status)
static int upqm_exec (struct ast_channel *chan, void *data)
int usecount (void)
 Provides a usecount.
static int valid_exit (struct queue_ent *qe, char digit)
static int wait_a_bit (struct queue_ent *qe)
static struct localuserwait_for_answer (struct queue_ent *qe, struct localuser *outgoing, int *to, char *digit, int prebusies, int caller_disconnect)
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_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 char aqm_cmd_usage []
static struct ast_cli_entry cli_add_queue_member
static struct ast_cli_entry cli_remove_queue_member
static struct ast_cli_entry cli_show_queue
static struct ast_cli_entry cli_show_queues
static char * descrip
 LOCAL_USER_DECL
static const char * pm_family = "/Queue/PersistentMembers"
 Persistent Members astdb family.
static int queue_persistent_members = 0
 queues.conf [general] option
struct {
   int   alarm
   char *   description
   unsigned int   event_log:1
   enum queue_result   id
   char *   name
   char *   name
   char *   name
   rtpPayloadType   payloadType
   unsigned int   queue_log:1
   char *   subtype
   char *   text
   char *   type
   int   val
queue_results []
static struct ast_custom_function queueagentcount_function
static struct ast_call_queuequeues = NULL
static char rqm_cmd_usage []
static char show_queue_usage []
static char show_queues_usage []
static struct strategy strategies []
static char * synopsis = "Queue a call for a call queue"
static char * tdesc = "True Call Queueing"
static int use_weight = 0
 queues.conf per-queue weight option


Detailed Description

True call queues with optional send URL on answer.

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

Referenced by queue_set_param().

#define ANNOUNCEHOLDTIME_ONCE   2
 

Definition at line 309 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

#define AST_MAX_WATCHERS   256
 

Definition at line 1609 of file app_queue.c.

#define BUILD_WATCHERS
 

Definition at line 1611 of file app_queue.c.

Referenced by wait_for_answer().

#define DEFAULT_RETRY   5
 

Definition at line 112 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

#define DEFAULT_TIMEOUT   15
 

Definition at line 113 of file app_queue.c.

Referenced by queue_set_param().

#define PM_MAX_LEN   2048
 

Definition at line 225 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

#define QUEUE_EMPTY_NORMAL   1
 

Definition at line 306 of file app_queue.c.

Referenced by queue_set_param().

#define QUEUE_EMPTY_STRICT   2
 

Definition at line 307 of file app_queue.c.

Referenced by join_queue(), and queue_set_param().

#define QUEUE_STRATEGY_FEWESTCALLS   3
 

Definition at line 96 of file app_queue.c.

Referenced by calc_metric().

#define QUEUE_STRATEGY_LEASTRECENT   2
 

Definition at line 95 of file app_queue.c.

Referenced by calc_metric().

#define QUEUE_STRATEGY_RANDOM   4
 

Definition at line 97 of file app_queue.c.

Referenced by calc_metric().

#define QUEUE_STRATEGY_RINGALL   0
 

Definition at line 93 of file app_queue.c.

Referenced by calc_metric().

#define QUEUE_STRATEGY_ROUNDROBIN   1
 

Definition at line 94 of file app_queue.c.

Referenced by calc_metric().

#define QUEUE_STRATEGY_RRMEMORY   5
 

Definition at line 98 of file app_queue.c.

Referenced by calc_metric().

#define RECHECK   1
 

Definition at line 114 of file app_queue.c.

#define RES_EXISTS   (-1)
 

Definition at line 117 of file app_queue.c.

Referenced by add_to_queue(), aqm_exec(), handle_add_queue_member(), handle_remove_queue_member(), manager_add_queue_member(), manager_remove_queue_member(), and rqm_exec().

#define RES_NOSUCHQUEUE   (-3)
 

Definition at line 119 of file app_queue.c.

Referenced by add_to_queue(), aqm_exec(), handle_add_queue_member(), handle_remove_queue_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().

#define RES_OKAY   0
 

Definition at line 116 of file app_queue.c.

Referenced by add_to_queue(), aqm_exec(), handle_add_queue_member(), handle_remove_queue_member(), manager_add_queue_member(), manager_remove_queue_member(), and rqm_exec().

#define RES_OUTOFMEMORY   (-2)
 

Definition at line 118 of file app_queue.c.

Referenced by add_to_queue(), aqm_exec(), handle_add_queue_member(), handle_remove_queue_member(), manager_add_queue_member(), manager_remove_queue_member(), and rqm_exec().


Enumeration Type Documentation

enum queue_member_status
 

Enumerator:
QUEUE_NO_MEMBERS 
QUEUE_NO_REACHABLE_MEMBERS 
QUEUE_NORMAL 

Definition at line 421 of file app_queue.c.

00421                          {
00422    QUEUE_NO_MEMBERS,
00423    QUEUE_NO_REACHABLE_MEMBERS,
00424    QUEUE_NORMAL
00425 };

enum queue_result
 

Enumerator:
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 

Definition at line 233 of file app_queue.c.

00233                   {
00234    QUEUE_UNKNOWN = 0,
00235    QUEUE_TIMEOUT = 1,
00236    QUEUE_JOINEMPTY = 2,
00237    QUEUE_LEAVEEMPTY = 3,
00238    QUEUE_JOINUNAVAIL = 4,
00239    QUEUE_LEAVEUNAVAIL = 5,
00240    QUEUE_FULL = 6,
00241 };


Function Documentation

static int __queues_show int  manager,
int  fd,
int  argc,
char **  argv,
int  queue_show
[static]
 

Definition at line 3280 of file app_queue.c.

References ast_build_string(), ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), member::calls, ast_call_queue::callsabandoned, ast_call_queue::callscompleted, ast_call_queue::callscompletedinsl, queue_ent::chan, ast_call_queue::count, devstate2str(), member::dynamic, ast_call_queue::head, ast_call_queue::holdtime, int2strat(), member::interface, member::lastcall, load_realtime_queue(), ast_call_queue::lock, ast_call_queue::maxlen, ast_call_queue::members, ast_channel::name, ast_call_queue::name, queue_ent::next, member::next, ast_call_queue::next, member::paused, member::penalty, queue_ent::prio, queues, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_call_queue::servicelevel, queue_ent::start, member::status, ast_call_queue::strategy, and ast_call_queue::weight.

Referenced by manager_queues_show(), queue_show(), and queues_show().

03281 {
03282    struct ast_call_queue *q;
03283    struct queue_ent *qe;
03284    struct member *mem;
03285    int pos;
03286    time_t now;
03287    char max_buf[80];
03288    char *max;
03289    size_t max_left;
03290    float sl = 0;
03291    char *term = manager ? "\r\n" : "\n";
03292 
03293    time(&now);
03294    if ((!queue_show && argc != 2) || (queue_show && argc != 3))
03295       return RESULT_SHOWUSAGE;
03296 
03297    /* We only want to load realtime queues when a specific queue is asked for. */
03298    if (queue_show)
03299       load_realtime_queue(argv[2]);
03300 
03301    ast_mutex_lock(&qlock);
03302 
03303    q = queues;
03304    if (!q) {   
03305       ast_mutex_unlock(&qlock);
03306       if (queue_show)
03307          ast_cli(fd, "No such queue: %s.%s",argv[2], term);
03308       else
03309          ast_cli(fd, "No queues.%s", term);
03310       return RESULT_SUCCESS;
03311    }
03312    while (q) {
03313       ast_mutex_lock(&q->lock);
03314       if (queue_show) {
03315          if (strcasecmp(q->name, argv[2]) != 0) {
03316             ast_mutex_unlock(&q->lock);
03317             q = q->next;
03318             if (!q) {
03319                ast_cli(fd, "No such queue: %s.%s",argv[2], term);
03320                break;
03321             }
03322             continue;
03323          }
03324       }
03325       max_buf[0] = '\0';
03326       max = max_buf;
03327       max_left = sizeof(max_buf);
03328       if (q->maxlen)
03329          ast_build_string(&max, &max_left, "%d", q->maxlen);
03330       else
03331          ast_build_string(&max, &max_left, "unlimited");
03332       sl = 0;
03333       if(q->callscompleted > 0)
03334          sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
03335       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",
03336          q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
03337       if (q->members) {
03338          ast_cli(fd, "   Members: %s", term);
03339          for (mem = q->members; mem; mem = mem->next) {
03340             max_buf[0] = '\0';
03341             max = max_buf;
03342             max_left = sizeof(max_buf);
03343             if (mem->penalty)
03344                ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
03345             if (mem->dynamic)
03346                ast_build_string(&max, &max_left, " (dynamic)");
03347             if (mem->paused)
03348                ast_build_string(&max, &max_left, " (paused)");
03349             ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
03350             if (mem->calls) {
03351                ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
03352                       mem->calls, (long)(time(NULL) - mem->lastcall));
03353             } else
03354                ast_build_string(&max, &max_left, " has taken no calls yet");
03355             ast_cli(fd, "      %s%s%s", mem->interface, max_buf, term);
03356          }
03357       } else
03358          ast_cli(fd, "   No Members%s", term);
03359       if (q->head) {
03360          pos = 1;
03361          ast_cli(fd, "   Callers: %s", term);
03362          for (qe = q->head; qe; qe = qe->next) 
03363             ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, qe->chan->name,
03364                (long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio, term);
03365       } else
03366          ast_cli(fd, "   No Callers%s", term);
03367       ast_cli(fd, "%s", term);
03368       ast_mutex_unlock(&q->lock);
03369       q = q->next;
03370       if (queue_show)
03371          break;
03372    }
03373    ast_mutex_unlock(&qlock);
03374    return RESULT_SUCCESS;
03375 }

static int add_to_queue char *  queuename,
char *  interface,
int  penalty,
int  paused,
int  dump
[static]
 

Definition at line 2423 of file app_queue.c.

References 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(), ast_call_queue::lock, manager_event(), ast_call_queue::members, ast_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_add_queue_member(), and manager_add_queue_member().

02424 {
02425    struct ast_call_queue *q;
02426    struct member *new_member;
02427    int res = RES_NOSUCHQUEUE;
02428 
02429    /* \note Ensure the appropriate realtime queue is loaded.  Note that this
02430     * short-circuits if the queue is already in memory. */
02431    q = load_realtime_queue(queuename);
02432 
02433    ast_mutex_lock(&qlock);
02434 
02435    if (q) {
02436       ast_mutex_lock(&q->lock);
02437       if (interface_exists(q, interface) == NULL) {
02438          new_member = create_queue_member(interface, penalty, paused);
02439 
02440          if (new_member != NULL) {
02441             new_member->dynamic = 1;
02442             new_member->next = q->members;
02443             q->members = new_member;
02444             manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
02445                   "Queue: %s\r\n"
02446                   "Location: %s\r\n"
02447                   "Membership: %s\r\n"
02448                   "Penalty: %d\r\n"
02449                   "CallsTaken: %d\r\n"
02450                   "LastCall: %d\r\n"
02451                   "Status: %d\r\n"
02452                   "Paused: %d\r\n",
02453                   q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
02454                   new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
02455 
02456             if (dump)
02457                dump_queue_members(q);
02458 
02459             res = RES_OKAY;
02460          } else {
02461             res = RES_OUTOFMEMORY;
02462          }
02463       } else {
02464          res = RES_EXISTS;
02465       }
02466       ast_mutex_unlock(&q->lock);
02467    }
02468    ast_mutex_unlock(&qlock);
02469    return res;
02470 }

static struct ast_call_queue* alloc_queue const char *  queuename  )  [static]
 

Definition at line 547 of file app_queue.c.

References ast_mutex_init(), and malloc.

Referenced by reload_queues().

00548 {
00549    struct ast_call_queue *q;
00550 
00551    q = malloc(sizeof(*q));
00552    if (q) {
00553       memset(q, 0, sizeof(*q));
00554       ast_mutex_init(&q->lock);
00555       ast_copy_string(q->name, queuename, sizeof(q->name));
00556    }
00557    return q;
00558 }

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

Definition at line 2784 of file app_queue.c.

References add_to_queue(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), localuser::chan, ast_channel::context, localuser::interface, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::name, option_priority_jumping, parse(), pbx_builtin_setvar_helper(), queue_persistent_members, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.

Referenced by load_module().

02785 {
02786    int res=-1;
02787    struct localuser *u;
02788    char *parse, *temppos = NULL;
02789    int priority_jump = 0;
02790    AST_DECLARE_APP_ARGS(args,
02791       AST_APP_ARG(queuename);
02792       AST_APP_ARG(interface);
02793       AST_APP_ARG(penalty);
02794       AST_APP_ARG(options);
02795    );
02796    int penalty = 0;
02797 
02798    if (ast_strlen_zero(data)) {
02799       ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n");
02800       return -1;
02801    }
02802 
02803    LOCAL_USER_ADD(u);
02804 
02805    if (!(parse = ast_strdupa(data))) {
02806       ast_log(LOG_WARNING, "Memory Error!\n");
02807       LOCAL_USER_REMOVE(u);
02808       return -1;
02809    }
02810 
02811    AST_STANDARD_APP_ARGS(args, parse);
02812 
02813    if (ast_strlen_zero(args.interface)) {
02814       args.interface = ast_strdupa(chan->name);
02815       temppos = strrchr(args.interface, '-');
02816       if (temppos)
02817          *temppos = '\0';
02818    }
02819 
02820    if (!ast_strlen_zero(args.penalty)) {
02821       if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
02822          ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
02823          penalty = 0;
02824       }
02825    }
02826    
02827    if (args.options) {
02828       if (strchr(args.options, 'j'))
02829          priority_jump = 1;
02830    }
02831 
02832 
02833    switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) {
02834    case RES_OKAY:
02835       ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
02836       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
02837       res = 0;
02838       break;
02839    case RES_EXISTS:
02840       ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
02841       if (priority_jump || option_priority_jumping) 
02842          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
02843       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
02844       res = 0;
02845       break;
02846    case RES_NOSUCHQUEUE:
02847       ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
02848       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
02849       res = 0;
02850       break;
02851    case RES_OUTOFMEMORY:
02852       ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
02853       break;
02854    }
02855 
02856    LOCAL_USER_REMOVE(u);
02857    return res;
02858 }

AST_MUTEX_DEFINE_STATIC qlock   ) 
 

static int background_file struct queue_ent qe,
struct ast_channel chan,
char *  filename
[static]
 

Definition at line 1544 of file app_queue.c.

References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_waitstream(), localuser::chan, ast_channel::language, and valid_exit().

Referenced by say_periodic_announcement().

01545 {
01546    int res;
01547 
01548    ast_stopstream(chan);
01549    res = ast_streamfile(chan, filename, chan->language);
01550 
01551    if (!res) {
01552       /* Wait for a keypress */
01553       res = ast_waitstream(chan, AST_DIGIT_ANY);
01554       if (res <= 0 || !valid_exit(qe, res))
01555          res = 0;
01556 
01557       /* Stop playback */
01558       ast_stopstream(chan);
01559    } else {
01560       res = 0;
01561    }
01562    
01563    /*if (res) {
01564       ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
01565       res = 0;
01566    }*/
01567 
01568    return res;
01569 }

static int calc_metric struct ast_call_queue q,
struct member mem,
int  pos,
struct queue_ent qe,
struct localuser tmp
[static]
 

Definition at line 1956 of file app_queue.c.

References ast_log(), member::calls, member::lastcall, LOG_WARNING, localuser::metric, member::penalty, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_ROUNDROBIN, QUEUE_STRATEGY_RRMEMORY, ast_call_queue::rrpos, ast_call_queue::strategy, and ast_call_queue::wrapped.

01957 {
01958    switch (q->strategy) {
01959    case QUEUE_STRATEGY_RINGALL:
01960       /* Everyone equal, except for penalty */
01961       tmp->metric = mem->penalty * 1000000;
01962       break;
01963    case QUEUE_STRATEGY_ROUNDROBIN:
01964       if (!pos) {
01965          if (!q->wrapped) {
01966             /* No more channels, start over */
01967             q->rrpos = 0;
01968          } else {
01969             /* Prioritize next entry */
01970             q->rrpos++;
01971          }
01972          q->wrapped = 0;
01973       }
01974       /* Fall through */
01975    case QUEUE_STRATEGY_RRMEMORY:
01976       if (pos < q->rrpos) {
01977          tmp->metric = 1000 + pos;
01978       } else {
01979          if (pos > q->rrpos)
01980             /* Indicate there is another priority */
01981             q->wrapped = 1;
01982          tmp->metric = pos;
01983       }
01984       tmp->metric += mem->penalty * 1000000;
01985       break;
01986    case QUEUE_STRATEGY_RANDOM:
01987       tmp->metric = rand() % 1000;
01988       tmp->metric += mem->penalty * 1000000;
01989       break;
01990    case QUEUE_STRATEGY_FEWESTCALLS:
01991       tmp->metric = mem->calls;
01992       tmp->metric += mem->penalty * 1000000;
01993       break;
01994    case QUEUE_STRATEGY_LEASTRECENT:
01995       if (!mem->lastcall)
01996          tmp->metric = 0;
01997       else
01998          tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
01999       tmp->metric += mem->penalty * 1000000;
02000       break;
02001    default:
02002       ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
02003       break;
02004    }
02005    return 0;
02006 }

static void* changethread void *  data  )  [static]
 

Definition at line 453 of file app_queue.c.

References ast_log(), ast_mutex_lock(), ast_strdupa, statechange::dev, devstate2str(), EVENT_FLAG_AGENT, free, ast_call_queue::lock, LOG_DEBUG, manager_event(), ast_call_queue::maskmemberstatus, ast_call_queue::members, ast_call_queue::name, ast_call_queue::next, option_debug, queues, statechange::state, and member::status.

Referenced by statechange_queue().

00454 {
00455    struct ast_call_queue *q;
00456    struct statechange *sc = data;
00457    struct member *cur;
00458    char *loc;
00459    char *technology;
00460 
00461    technology = ast_strdupa(sc->dev);
00462    loc = strchr(technology, '/');
00463    if (loc) {
00464       *loc = '\0';
00465       loc++;
00466    } else {
00467       free(sc);
00468       return NULL;
00469    }
00470    if (option_debug)
00471       ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
00472    ast_mutex_lock(&qlock);
00473    for (q = queues; q; q = q->next) {
00474       ast_mutex_lock(&q->lock);
00475       cur = q->members;
00476       while(cur) {
00477          if (!strcasecmp(sc->dev, cur->interface)) {
00478             if (cur->status != sc->state) {
00479                cur->status = sc->state;
00480                if (!q->maskmemberstatus) {
00481                   manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
00482                      "Queue: %s\r\n"
00483                      "Location: %s\r\n"
00484                      "Membership: %s\r\n"
00485                      "Penalty: %d\r\n"
00486                      "CallsTaken: %d\r\n"
00487                      "LastCall: %d\r\n"
00488                      "Status: %d\r\n"
00489                      "Paused: %d\r\n",
00490                   q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
00491                   cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
00492                }
00493             }
00494          }
00495          cur = cur->next;
00496       }
00497       ast_mutex_unlock(&q->lock);
00498    }
00499    ast_mutex_unlock(&qlock);
00500    free(sc);
00501    return NULL;
00502 }

static void clear_queue struct ast_call_queue q  )  [static]
 

Definition at line 587 of file app_queue.c.

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

Referenced by reload_queues().

00588 {
00589    q->holdtime = 0;
00590    q->callscompleted = 0;
00591    q->callsabandoned = 0;
00592    q->callscompletedinsl = 0;
00593    q->wrapuptime = 0;
00594 }

static int compare_weight struct ast_call_queue rq,
struct member member
[static]
 

Definition at line 1316 of file app_queue.c.

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

Referenced by ring_entry().

01317 {
01318    struct ast_call_queue *q;
01319    struct member *mem;
01320    int found = 0;
01321    
01322    /* &qlock and &rq->lock already set by try_calling()
01323     * to solve deadlock */
01324    for (q = queues; q; q = q->next) {
01325       if (q == rq) /* don't check myself, could deadlock */
01326          continue; 
01327       ast_mutex_lock(&q->lock);
01328       if (q->count && q->members) {
01329          for (mem = q->members; mem; mem = mem->next) {
01330             if (!strcmp(mem->interface, member->interface)) {
01331                ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
01332                if (q->weight > rq->weight) {
01333                   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);
01334                   found = 1;
01335                   break;
01336                }
01337             }
01338          }
01339       }
01340       ast_mutex_unlock(&q->lock);
01341       if (found) 
01342          break;
01343    }
01344    ast_mutex_unlock(&qlock);
01345    return found;
01346 }

static char* complete_add_queue_member char *  line,
char *  word,
int  pos,
int  state
[static]
 

Definition at line 3656 of file app_queue.c.

References complete_queue(), malloc, and strdup.

03657 {
03658    /* 0 - add; 1 - queue; 2 - member; 3 - <member>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty> */
03659    switch (pos) {
03660    case 3:
03661       /* Don't attempt to complete name of member (infinite possibilities) */
03662       return NULL;
03663    case 4:
03664       if (state == 0) {
03665          return strdup("to");
03666       } else {
03667          return NULL;
03668       }
03669    case 5:
03670       /* No need to duplicate code */
03671       return complete_queue(line, word, pos, state);
03672    case 6:
03673       if (state == 0) {
03674          return strdup("penalty");
03675       } else {
03676          return NULL;
03677       }
03678    case 7:
03679       if (state < 100) {   /* 0-99 */
03680          char *num = malloc(3);
03681          if (num) {
03682             sprintf(num, "%d", state);
03683          }
03684          return num;
03685       } else {
03686          return NULL;
03687       }
03688    default:
03689       return NULL;
03690    }
03691 }

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

Definition at line 3387 of file app_queue.c.

References ast_mutex_lock(), ast_call_queue::name, ast_call_queue::next, and queues.

Referenced by complete_add_queue_member(), and complete_remove_queue_member().

03388 {
03389    struct ast_call_queue *q;
03390    int which=0;
03391    
03392    ast_mutex_lock(&qlock);
03393    for (q = queues; q; q = q->next) {
03394       if (!strncasecmp(word, q->name, strlen(word))) {
03395          if (++which > state)
03396             break;
03397       }
03398    }
03399    ast_mutex_unlock(&qlock);
03400    return q ? strdup(q->name) : NULL;
03401 }

static char* complete_remove_queue_member char *  line,
char *  word,
int  pos,
int  state
[static]
 

Definition at line 3724 of file app_queue.c.

References ast_mutex_lock(), ast_mutex_unlock(), complete_queue(), member::interface, ast_call_queue::lock, ast_call_queue::members, member::next, ast_call_queue::next, queues, and strdup.

03725 {
03726    int which = 0;
03727    struct ast_call_queue *q;
03728    struct member *m;
03729 
03730    /* 0 - add; 1 - queue; 2 - member; 3 - <member>; 4 - to; 5 - <queue> */
03731    if ((pos > 5) || (pos < 3)) {
03732       return NULL;
03733    }
03734    if (pos == 4) {
03735       if (state == 0) {
03736          return strdup("from");
03737       } else {
03738          return NULL;
03739       }
03740    }
03741 
03742    if (pos == 5) {
03743       /* No need to duplicate code */
03744       return complete_queue(line, word, pos, state);
03745    }
03746 
03747    if (queues != NULL) {
03748       for (q = queues ; q ; q = q->next) {
03749          ast_mutex_lock(&q->lock);
03750          for (m = q->members ; m ; m = m->next) {
03751             if (++which > state) {
03752                ast_mutex_unlock(&q->lock);
03753                return strdup(m->interface);
03754             }
03755          }
03756          ast_mutex_unlock(&q->lock);
03757       }
03758    }
03759    return NULL;
03760 }

static struct member* create_queue_member char *  interface,
int  penalty,
int  paused
[static]
 

Definition at line 526 of file app_queue.c.

References ast_device_state(), ast_log(), LOG_WARNING, and malloc.

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

00527 {
00528    struct member *cur;
00529    
00530    /* Add a new member */
00531 
00532    cur = malloc(sizeof(struct member));
00533 
00534    if (cur) {
00535       memset(cur, 0, sizeof(struct member));
00536       cur->penalty = penalty;
00537       cur->paused = paused;
00538       ast_copy_string(cur->interface, interface, sizeof(cur->interface));
00539       if (!strchr(cur->interface, '/'))
00540          ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
00541       cur->status = ast_device_state(interface);
00542    }
00543 
00544    return cur;
00545 }

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 3855 of file app_queue.c.

References tdesc.

03856 {
03857    return tdesc;
03858 }

static void destroy_queue struct ast_call_queue q  )  [static]
 

Definition at line 776 of file app_queue.c.

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

Referenced by leave_queue(), and reload_queues().

00777 {
00778    free_members(q, 1);
00779    ast_mutex_destroy(&q->lock);
00780    free(q);
00781 }

static void dump_queue_members struct ast_call_queue pm_queue  )  [static]
 

Definition at line 2344 of file app_queue.c.

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

Referenced by add_to_queue(), and set_member_paused().

02345 {
02346    struct member *cur_member;
02347    char value[PM_MAX_LEN];
02348    int value_len = 0;
02349    int res;
02350 
02351    memset(value, 0, sizeof(value));
02352 
02353    if (!pm_queue)
02354       return;
02355 
02356    for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
02357       if (!cur_member->dynamic)
02358          continue;
02359 
02360       res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
02361                 cur_member->interface, cur_member->penalty, cur_member->paused,
02362                 cur_member->next ? "|" : "");
02363       if (res != strlen(value + value_len)) {
02364          ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
02365          break;
02366       }
02367       value_len += res;
02368    }
02369    
02370    if (value_len && !cur_member) {
02371       if (ast_db_put(pm_family, pm_queue->name, value))
02372          ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
02373    } else
02374       /* Delete the entry if the queue is empty or there is an error */
02375       ast_db_del(pm_family, pm_queue->name);
02376 }

static struct ast_call_queue* find_queue_by_name_rt const char *  queuename,
struct ast_variable queue_vars,
struct ast_config member_config
[static]
 

Reload a single queue via realtime.

Returns:
Return the queue, or NULL if it doesn't exist.
Note:
Should be called with the global qlock locked.

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

References member::interface, ast_call_queue::name, ast_call_queue::next, and queues.

00805 {
00806    struct ast_variable *v;
00807    struct ast_call_queue *q, *prev_q = NULL;
00808    struct member *m, *prev_m, *next_m;
00809    char *interface;
00810    char *tmp, *tmp_name;
00811    char tmpbuf[64];  /* Must be longer than the longest queue param name. */
00812 
00813    /* Find the queue in the in-core list (we will create a new one if not found). */
00814    for (q = queues; q; q = q->next) {
00815       if (!strcasecmp(q->name, queuename)) {
00816          break;
00817       }
00818       prev_q = q;
00819    }
00820 
00821    /* Static queues override realtime. */
00822    if (q) {
00823       ast_mutex_lock(&q->lock);
00824       if (!q->realtime) {
00825          if (q->dead) {
00826             ast_mutex_unlock(&q->lock);
00827             return NULL;
00828          } else {
00829             ast_mutex_unlock(&q->lock);
00830             return q;
00831          }
00832       }
00833    } else if (!member_config)
00834       /* Not found in the list, and it's not realtime ... */
00835       return NULL;
00836 
00837    /* Check if queue is defined in realtime. */
00838    if (!queue_vars) {
00839       /* Delete queue from in-core list if it has been deleted in realtime. */
00840       if (q) {
00841          /*! \note Hmm, can't seem to distinguish a DB failure from a not
00842             found condition... So we might delete an in-core queue
00843             in case of DB failure. */
00844          ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
00845 
00846          q->dead = 1;
00847          /* Delete if unused (else will be deleted when last caller leaves). */
00848          if (!q->count) {
00849             /* Delete. */
00850             if (!prev_q) {
00851                queues = q->next;
00852             } else {
00853                prev_q->next = q->next;
00854             }
00855             ast_mutex_unlock(&q->lock);
00856             destroy_queue(q);
00857          } else
00858             ast_mutex_unlock(&q->lock);
00859       }
00860       return NULL;
00861    }
00862 
00863    /* Create a new queue if an in-core entry does not exist yet. */
00864    if (!q) {
00865       q = alloc_queue(queuename);
00866       if (!q)
00867          return NULL;
00868       ast_mutex_lock(&q->lock);
00869       clear_queue(q);
00870       q->realtime = 1;
00871       q->next = queues;
00872       queues = q;
00873    }
00874    init_queue(q);    /* Ensure defaults for all parameters not set explicitly. */
00875 
00876    v = queue_vars;
00877    memset(tmpbuf, 0, sizeof(tmpbuf));
00878    while(v) {
00879       /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
00880       if((tmp = strchr(v->name, '_')) != NULL) {
00881          ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
00882          tmp_name = tmpbuf;
00883          tmp = tmp_name;
00884          while((tmp = strchr(tmp, '_')) != NULL)
00885             *tmp++ = '-';
00886       } else
00887          tmp_name = v->name;
00888       queue_set_param(q, tmp_name, v->value, -1, 0);
00889       v = v->next;
00890    }
00891 
00892    /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
00893    m = q->members;
00894    while (m) {
00895       if (!m->dynamic)
00896          m->dead = 1;
00897       m = m->next;
00898    }
00899 
00900    interface = ast_category_browse(member_config, NULL);
00901    while (interface) {
00902       rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty"));
00903       interface = ast_category_browse(member_config, interface);
00904    }
00905 
00906    /* Delete all realtime members that have been deleted in DB. */
00907    m = q->members;
00908    prev_m = NULL;
00909    while (m) {
00910       next_m = m->next;
00911       if (m->dead) {
00912          if (prev_m) {
00913             prev_m->next = next_m;
00914          } else {
00915             q->members = next_m;
00916          }
00917          free(m);
00918       } else {
00919          prev_m = m;
00920       }
00921       m = next_m;
00922    }
00923 
00924    ast_mutex_unlock(&q->lock);
00925 
00926    return q;
00927 }

static void free_members struct ast_call_queue q,
int  all
[static]
 

Definition at line 758 of file app_queue.c.

References member::dynamic, free, ast_call_queue::members, and member::next.

Referenced by destroy_queue(), and reload_queues().

00759 {
00760    /* Free non-dynamic members */
00761    struct member *curm, *next, *prev = NULL;
00762 
00763    for (curm = q->members; curm; curm = next) {
00764       next = curm->next;
00765       if (all || !curm->dynamic) {
00766          if (prev)
00767             prev->next = next;
00768          else
00769             q->members = next;
00770          free(curm);
00771       } else 
00772          prev = curm;
00773    }
00774 }

static enum queue_member_status get_member_status const struct ast_call_queue q  )  [static]
 

Definition at line 427 of file app_queue.c.

References AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, ast_call_queue::members, member::next, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NORMAL, result, and member::status.

Referenced by join_queue().

00428 {
00429    struct member *member;
00430    enum queue_member_status result = QUEUE_NO_MEMBERS;
00431 
00432    for (member = q->members; member; member = member->next) {
00433       switch (member->status) {
00434       case AST_DEVICE_INVALID:
00435          /* nothing to do */
00436          break;
00437       case AST_DEVICE_UNAVAILABLE:
00438          result = QUEUE_NO_REACHABLE_MEMBERS;
00439          break;
00440       default:
00441          return QUEUE_NORMAL;
00442       }
00443    }
00444    
00445    return result;
00446 }

static int handle_add_queue_member int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 3609 of file app_queue.c.

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

03610 {
03611    char *queuename, *interface;
03612    int penalty;
03613 
03614    if ((argc != 6) && (argc != 8)) {
03615       return RESULT_SHOWUSAGE;
03616    } else if (strcmp(argv[4], "to")) {
03617       return RESULT_SHOWUSAGE;
03618    } else if ((argc == 8) && strcmp(argv[6], "penalty")) {
03619       return RESULT_SHOWUSAGE;
03620    }
03621 
03622    queuename = argv[5];
03623    interface = argv[3];
03624    if (argc == 8) {
03625       if (sscanf(argv[7], "%d", &penalty) == 1) {
03626          if (penalty < 0) {
03627             ast_cli(fd, "Penalty must be >= 0\n");
03628             penalty = 0;
03629          }
03630       } else {
03631          ast_cli(fd, "Penalty must be an integer >= 0\n");
03632          penalty = 0;
03633       }
03634    } else {
03635       penalty = 0;
03636    }
03637 
03638    switch (add_to_queue(queuename, interface, penalty, 0, queue_persistent_members)) {
03639    case RES_OKAY:
03640       ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
03641       return RESULT_SUCCESS;
03642    case RES_EXISTS:
03643       ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
03644       return RESULT_FAILURE;
03645    case RES_NOSUCHQUEUE:
03646       ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
03647       return RESULT_FAILURE;
03648    case RES_OUTOFMEMORY:
03649       ast_cli(fd, "Out of memory\n");
03650       return RESULT_FAILURE;
03651    default:
03652       return RESULT_FAILURE;
03653    }
03654 }

static int handle_remove_queue_member int  fd,
int  argc,
char *  argv[]
[static]
 

Definition at line 3693 of file app_queue.c.

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

03694 {
03695    char *queuename, *interface;
03696 
03697    if (argc != 6) {
03698       return RESULT_SHOWUSAGE;
03699    } else if (strcmp(argv[4], "from")) {
03700       return RESULT_SHOWUSAGE;
03701    }
03702 
03703    queuename = argv[5];
03704    interface = argv[3];
03705 
03706    switch (remove_from_queue(queuename, interface)) {
03707    case RES_OKAY:
03708       ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
03709       return RESULT_SUCCESS;
03710    case RES_EXISTS:
03711       ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
03712       return RESULT_FAILURE;
03713    case RES_NOSUCHQUEUE:
03714       ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
03715       return RESULT_FAILURE;
03716    case RES_OUTOFMEMORY:
03717       ast_cli(fd, "Out of memory\n");
03718       return RESULT_FAILURE;
03719    default:
03720       return RESULT_FAILURE;
03721    }
03722 }

static void hangupcalls struct localuser outgoing,
struct ast_channel exception
[static]
 

Definition at line 1255 of file app_queue.c.

References ast_hangup(), localuser::chan, free, and localuser::next.

01256 {
01257    struct localuser *oo;
01258 
01259    while(outgoing) {
01260       /* Hangup any existing lines we have open */
01261       if (outgoing->chan && (outgoing->chan != exception))
01262          ast_hangup(outgoing->chan);
01263       oo = outgoing;
01264       outgoing=outgoing->next;
01265       free(oo);
01266    }
01267 }

static void init_queue struct ast_call_queue q  )  [static]
 

Definition at line 560 of file app_queue.c.

References ast_call_queue::announce, ast_call_queue::announcefrequency, ast_call_queue::announceholdtime, ast_call_queue::context, ast_call_queue::dead, DEFAULT_RETRY, ast_call_queue::maxlen, ast_call_queue::moh, ast_call_queue::monfmt, ast_call_queue::periodicannouncefrequency, ast_call_queue::retry, ast_call_queue::roundingseconds, ast_call_queue::servicelevel, ast_call_queue::sound_calls, ast_call_queue::sound_holdtime, ast_call_queue::sound_lessthan, ast_call_queue::sound_minutes, ast_call_queue::sound_next, ast_call_queue::sound_periodicannounce, ast_call_queue::sound_reporthold, ast_call_queue::sound_seconds, ast_call_queue::sound_thanks, ast_call_queue::sound_thereare, and ast_call_queue::timeout.

Referenced by reload_queues().

00561 {
00562    q->dead = 0;
00563    q->retry = DEFAULT_RETRY;
00564    q->timeout = -1;
00565    q->maxlen = 0;
00566    q->announcefrequency = 0;
00567    q->announceholdtime = 0;
00568    q->roundingseconds = 0; /* Default - don't announce seconds */
00569    q->servicelevel = 0;
00570    q->moh[0] = '\0';
00571    q->announce[0] = '\0';
00572    q->context[0] = '\0';
00573    q->monfmt[0] = '\0';
00574    q->periodicannouncefrequency = 0;
00575    ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
00576    ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
00577    ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
00578    ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
00579    ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
00580    ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
00581    ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
00582    ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
00583    ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
00584    ast_copy_string(q->sound_periodicannounce, "queue-periodic-announce", sizeof(q->sound_periodicannounce));
00585 }

static void insert_entry struct ast_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 402 of file app_queue.c.

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

Referenced by join_queue().

00403 {
00404    struct queue_ent *cur;
00405 
00406    if (!q || !new)
00407       return;
00408    if (prev) {
00409       cur = prev->next;
00410       prev->next = new;
00411    } else {
00412       cur = q->head;
00413       q->head = new;
00414    }
00415    new->next = cur;
00416    new->parent = q;
00417    new->pos = ++(*pos);
00418    new->opos = *pos;
00419 }

static char* int2strat int  strategy  )  [static]
 

Definition at line 381 of file app_queue.c.

References name, and strategies.

Referenced by __queues_show().

00382 {
00383    int x;
00384    for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
00385       if (strategy == strategies[x].strategy)
00386          return strategies[x].name;
00387    }
00388    return "<unknown>";
00389 }

static struct member* interface_exists struct ast_call_queue q,
char *  interface
[static]
 

Definition at line 2326 of file app_queue.c.

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

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

02327 {
02328    struct member *mem;
02329 
02330    if (q)
02331       for (mem = q->members; mem; mem = mem->next)
02332          if (!strcasecmp(interface, mem->interface))
02333             return mem;
02334 
02335    return NULL;
02336 }

static int is_our_turn struct queue_ent qe  )  [static]
 

Definition at line 1863 of file app_queue.c.

References ast_log(), queue_ent::chan, ast_call_queue::head, LOG_DEBUG, ast_channel::name, option_debug, and queue_ent::parent.

Referenced by wait_our_turn().

01864 {
01865    struct queue_ent *ch;
01866    int res;
01867 
01868    /* Atomically read the parent head -- does not need a lock */
01869    ch = qe->parent->head;
01870    /* If we are now at the top of the head, break out */
01871    if (ch == qe) {
01872       if (option_debug)
01873          ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
01874       res = 1;
01875    } else {
01876       if (option_debug)
01877          ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
01878       res = 0;
01879    }
01880    return res;
01881 }

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

Definition at line 976 of file app_queue.c.

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

Referenced by queue_exec().

00977 {
00978    struct ast_call_queue *q;
00979    struct queue_ent *cur, *prev = NULL;
00980    int res = -1;
00981    int pos = 0;
00982    int inserted = 0;
00983    enum queue_member_status stat;
00984 
00985    q = load_realtime_queue(queuename);
00986    if (!q)
00987       return res;
00988 
00989    ast_mutex_lock(&qlock);
00990    ast_mutex_lock(&q->lock);
00991 
00992    /* This is our one */
00993    stat = get_member_status(q);
00994    if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
00995       *reason = QUEUE_JOINEMPTY;
00996    else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
00997       *reason = QUEUE_JOINUNAVAIL;
00998    else if (q->maxlen && (q->count >= q->maxlen))
00999       *reason = QUEUE_FULL;
01000    else {
01001       /* There's space for us, put us at the right position inside
01002        * the queue. 
01003        * Take into account the priority of the calling user */
01004       inserted = 0;
01005       prev = NULL;
01006       cur = q->head;
01007       while(cur) {
01008          /* We have higher priority than the current user, enter
01009           * before him, after all the other users with priority
01010           * higher or equal to our priority. */
01011          if ((!inserted) && (qe->prio > cur->prio)) {
01012             insert_entry(q, prev, qe, &pos);
01013             inserted = 1;
01014          }
01015          cur->pos = ++pos;
01016          prev = cur;
01017          cur = cur->next;
01018       }
01019       /* No luck, join at the end of the queue */
01020       if (!inserted)
01021          insert_entry(q, prev, qe, &pos);
01022       ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
01023       ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
01024       ast_copy_string(qe->context, q->context, sizeof(qe->context));
01025       q->count++;
01026       res = 0;
01027       manager_event(EVENT_FLAG_CALL, "Join", 
01028                "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
01029                qe->chan->name, 
01030                qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
01031                qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
01032                q->name, qe->pos, q->count );
01033 #if 0
01034 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
01035 #endif
01036    }
01037    ast_mutex_unlock(&q->lock);
01038    ast_mutex_unlock(&qlock);
01039    return res;
01040 }

char* key void   ) 
 

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

 char *key(void) {
         return ASTERISK_GPL_KEY;
 }

Returns:
ASTERISK_GPL_KEY

Definition at line 3867 of file app_queue.c.

References ASTERISK_GPL_KEY.

03868 {
03869    return ASTERISK_GPL_KEY;
03870 }

static void leave_queue struct queue_ent qe  )  [static]
 

Definition at line 1210 of file app_queue.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), queue_ent::chan, ast_call_queue::count, ast_call_queue::dead, destroy_queue(), EVENT_FLAG_CALL, ast_call_queue::head, ast_call_queue::lock, LOG_NOTICE, manager_event(), ast_call_queue::name, ast_channel::name, queue_ent::next, queue_ent::parent, queue_ent::pos, and remove_queue().

01211 {
01212    struct ast_call_queue *q;
01213    struct queue_ent *cur, *prev = NULL;
01214    int pos = 0;
01215 
01216    q = qe->parent;
01217    if (!q)
01218       return;
01219    ast_mutex_lock(&q->lock);
01220 
01221    prev = NULL;
01222    cur = q->head;
01223    while(cur) {
01224       if (cur == qe) {
01225          q->count--;
01226 
01227          /* Take us out of the queue */
01228          manager_event(EVENT_FLAG_CALL, "Leave",
01229             "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
01230             qe->chan->name, q->name,  q->count);
01231 #if 0
01232 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
01233 #endif
01234          /* Take us out of the queue */
01235          if (prev)
01236             prev->next = cur->next;
01237          else
01238             q->head = cur->next;
01239       } else {
01240          /* Renumber the people after us in the queue based on a new count */
01241          cur->pos = ++pos;
01242          prev = cur;
01243       }
01244       cur = cur->next;
01245    }
01246    ast_mutex_unlock(&q->lock);
01247    if (q->dead && !q->count) {   
01248       /* It's dead and nobody is in it, so kill it */
01249       remove_queue(q);
01250       destroy_queue(q);
01251    }
01252 }

int load_module void   ) 
 

Initialize the module.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
int Always 0.

Definition at line 3818 of file app_queue.c.

References app, app_aqm, app_aqm_descrip, app_aqm_synopsis, app_pqm, app_pqm_descrip, app_pqm_synopsis, app_rqm, app_rqm_descrip, app_rqm_synopsis, app_upqm, app_upqm_descrip, app_upqm_synopsis, aqm_exec(), ast_cli_register(), ast_custom_function_register(), ast_devstate_add(), ast_manager_register, ast_register_application(), cli_add_queue_member, cli_remove_queue_member, cli_show_queue, cli_show_queues, descrip, EVENT_FLAG_AGENT, manager_add_queue_member(), manager_pause_queue_member(), manager_queues_show(), manager_queues_status(), manager_remove_queue_member(), pqm_exec(), queue_exec(), queue_persistent_members, queueagentcount_function, reload_queue_members(), reload_queues(), rqm_exec(), statechange_queue(), synopsis, and upqm_exec().

03819 {
03820    int res;
03821    
03822    res = ast_register_application(app, queue_exec, synopsis, descrip);
03823    res |= ast_cli_register(&cli_show_queue);
03824    res |= ast_cli_register(&cli_show_queues);
03825    res |= ast_cli_register(&cli_add_queue_member);
03826    res |= ast_cli_register(&cli_remove_queue_member);
03827    res |= ast_devstate_add(statechange_queue, NULL);
03828    res |= ast_manager_register( "Queues", 0, manager_queues_show, "Queues" );
03829    res |= ast_manager_register( "QueueStatus", 0, manager_queues_status, "Queue Status" );
03830    res |= ast_manager_register( "QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue." );
03831    res |= ast_manager_register( "QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue." );
03832    res |= ast_manager_register( "QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable" );
03833    res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip) ;
03834    res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip) ;
03835    res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip) ;
03836    res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip) ;
03837    res |= ast_custom_function_register(&queueagentcount_function);
03838 
03839    if (!res) { 
03840       reload_queues();
03841       if (queue_persistent_members)
03842          reload_queue_members();
03843    }
03844 
03845    return res;
03846 }

static struct ast_call_queue* load_realtime_queue char *  queuename  )  [static]
 

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

References ast_mutex_lock(), ast_call_queue::name, ast_call_queue::next, and queues.

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

00930 {
00931    struct ast_variable *queue_vars = NULL;
00932    struct ast_config *member_config = NULL;
00933    struct ast_call_queue *q;
00934 
00935    /* Find the queue in the in-core list first. */
00936    ast_mutex_lock(&qlock);
00937    for (q = queues; q; q = q->next) {
00938       if (!strcasecmp(q->name, queuename)) {
00939          break;
00940       }
00941    }
00942    ast_mutex_unlock(&qlock);
00943 
00944    if (!q || q->realtime) {
00945       /*! \note Load from realtime before taking the global qlock, to avoid blocking all
00946          queue operations while waiting for the DB.
00947 
00948          This will be two separate database transactions, so we might
00949          see queue parameters as they were before another process
00950          changed the queue and member list as it was after the change.
00951          Thus we might see an empty member list when a queue is
00952          deleted. In practise, this is unlikely to cause a problem. */
00953 
00954       queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
00955       if (queue_vars) {
00956          member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
00957          if (!member_config) {
00958             ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
00959             return NULL;
00960          }
00961       }
00962 
00963       ast_mutex_lock(&qlock);
00964 
00965       q = find_queue_by_name_rt(queuename, queue_vars, member_config);
00966       if (member_config)
00967          ast_config_destroy(member_config);
00968       if (queue_vars)
00969          ast_variables_destroy(queue_vars);
00970 
00971       ast_mutex_unlock(&qlock);
00972    }
00973    return q;
00974 }

static int manager_add_queue_member struct mansession s,
struct message m
[static]
 

Definition at line 3505 of file app_queue.c.

References add_to_queue(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), member::interface, member::paused, member::penalty, queue_persistent_members, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and s.

Referenced by load_module().

03506 {
03507    char *queuename, *interface, *penalty_s, *paused_s;
03508    int paused, penalty = 0;
03509 
03510    queuename = astman_get_header(m, "Queue");
03511    interface = astman_get_header(m, "Interface");
03512    penalty_s = astman_get_header(m, "Penalty");
03513    paused_s = astman_get_header(m, "Paused");
03514 
03515    if (ast_strlen_zero(queuename)) {
03516       astman_send_error(s, m, "'Queue' not specified.");
03517       return 0;
03518    }
03519 
03520    if (ast_strlen_zero(interface)) {
03521       astman_send_error(s, m, "'Interface' not specified.");
03522       return 0;
03523    }
03524 
03525    if (ast_strlen_zero(penalty_s))
03526       penalty = 0;
03527    else if (sscanf(penalty_s, "%d", &penalty) != 1) {
03528       penalty = 0;
03529    }
03530 
03531    if (ast_strlen_zero(paused_s))
03532       paused = 0;
03533    else
03534       paused = abs(ast_true(paused_s));
03535 
03536    switch (add_to_queue(queuename, interface, penalty, paused, queue_persistent_members)) {
03537    case RES_OKAY:
03538       astman_send_ack(s, m, "Added interface to queue");
03539       break;
03540    case RES_EXISTS:
03541       astman_send_error(s, m, "Unable to add interface: Already there");
03542       break;
03543    case RES_NOSUCHQUEUE:
03544       astman_send_error(s, m, "Unable to add interface to queue: No such queue");
03545       break;
03546    case RES_OUTOFMEMORY:
03547       astman_send_error(s, m, "Out of memory");
03548       break;
03549    }
03550    return 0;
03551 }

static int manager_pause_queue_member struct mansession s,
struct message m
[static]
 

Definition at line 3582 of file app_queue.c.

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

Referenced by load_module().

03583 {
03584    char *queuename, *interface, *paused_s;
03585    int paused;
03586 
03587    interface = astman_get_header(m, "Interface");
03588    paused_s = astman_get_header(m, "Paused");
03589    queuename = astman_get_header(m, "Queue");   /* Optional - if not supplied, pause the given Interface in all queues */
03590 
03591    if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
03592       astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
03593       return 0;
03594    }
03595 
03596    paused = abs(ast_true(paused_s));
03597 
03598    if (set_member_paused(queuename, interface, paused))
03599       astman_send_error(s, m, "Interface not found");
03600    else
03601       if (paused)
03602          astman_send_ack(s, m, "Interface paused successfully");
03603       else
03604          astman_send_ack(s, m, "Interface unpaused successfully");
03605 
03606    return 0;
03607 }

static int manager_queues_show struct mansession s,
struct message m
[static]
 

Definition at line 3406 of file app_queue.c.

References __queues_show(), ast_cli(), RESULT_SUCCESS, and s.

Referenced by load_module().

03407 {
03408    char *a[] = { "show", "queues" };
03409    __queues_show(1, s->fd, 2, a, 0);
03410    ast_cli(s->fd, "\r\n\r\n");   /* Properly terminate Manager output */
03411 
03412    return RESULT_SUCCESS;
03413 } 

static int manager_queues_status struct mansession s,
struct message m
[static]
 

Definition at line 3416 of file app_queue.c.

References ast_cli(), ast_mutex_lock(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), member::calls, ast_call_queue::callsabandoned, ast_call_queue::callscompleted, ast_call_queue::callscompletedinsl, ast_call_queue::count, member::dynamic, ast_call_queue::holdtime, member::interface, member::lastcall, ast_call_queue::lock, ast_call_queue::maxlen, ast_call_queue::members, ast_call_queue::name, member::next, ast_call_queue::next, member::paused, member::penalty, queues, s, ast_call_queue::servicelevel, member::status, and ast_call_queue::weight.

Referenced by load_module().

03417 {
03418    time_t now;
03419    int pos;
03420    char *id = astman_get_header(m,"ActionID");
03421    char *queuefilter = astman_get_header(m,"Queue");
03422    char *memberfilter = astman_get_header(m,"Member");
03423    char idText[256] = "";
03424    struct ast_call_queue *q;
03425    struct queue_ent *qe;
03426    float sl = 0;
03427    struct member *mem;
03428 
03429    astman_send_ack(s, m, "Queue status will follow");
03430    time(&now);
03431    ast_mutex_lock(&qlock);
03432    if (!ast_strlen_zero(id)) {
03433       snprintf(idText,256,"ActionID: %s\r\n",id);
03434    }
03435    for (q = queues; q; q = q->next) {
03436       ast_mutex_lock(&q->lock);
03437 
03438       /* List queue properties */
03439       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
03440          if(q->callscompleted > 0)
03441             sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
03442          ast_cli(s->fd, "Event: QueueParams\r\n"
03443                   "Queue: %s\r\n"
03444                   "Max: %d\r\n"
03445                   "Calls: %d\r\n"
03446                   "Holdtime: %d\r\n"
03447                   "Completed: %d\r\n"
03448                   "Abandoned: %d\r\n"
03449                   "ServiceLevel: %d\r\n"
03450                   "ServicelevelPerf: %2.1f\r\n"
03451                   "Weight: %d\r\n"
03452                   "%s"
03453                   "\r\n",
03454                      q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
03455                      q->callsabandoned, q->servicelevel, sl, q->weight, idText);
03456          /* List Queue Members */
03457          for (mem = q->members; mem; mem = mem->next) {
03458             if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
03459                ast_cli(s->fd, "Event: QueueMember\r\n"
03460                   "Queue: %s\r\n"
03461                   "Location: %s\r\n"
03462                   "Membership: %s\r\n"
03463                   "Penalty: %d\r\n"
03464                   "CallsTaken: %d\r\n"
03465                   "LastCall: %d\r\n"
03466                   "Status: %d\r\n"
03467                   "Paused: %d\r\n"
03468                   "%s"
03469                   "\r\n",
03470                      q->name, mem->interface, mem->dynamic ? "dynamic" : "static",
03471                      mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
03472             }
03473          }
03474          /* List Queue Entries */
03475          pos = 1;
03476          for (qe = q->head; qe; qe = qe->next) {
03477             ast_cli(s->fd, "Event: QueueEntry\r\n"
03478                "Queue: %s\r\n"
03479                "Position: %d\r\n"
03480                "Channel: %s\r\n"
03481                "CallerID: %s\r\n"
03482                "CallerIDName: %s\r\n"
03483                "Wait: %ld\r\n"
03484                "%s"
03485                "\r\n", 
03486                   q->name, pos++, qe->chan->name, 
03487                   qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
03488                   qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
03489                   (long)(now - qe->start), idText);
03490          }
03491       }
03492       ast_mutex_unlock(&q->lock);
03493    }
03494    ast_mutex_unlock(&qlock);
03495 
03496    ast_cli(s->fd,
03497       "Event: QueueStatusComplete\r\n"
03498       "%s"
03499       "\r\n",idText);
03500 
03501 
03502    return RESULT_SUCCESS;
03503 }

static int manager_remove_queue_member struct mansession s,
struct message m
[static]
 

Definition at line 3553 of file app_queue.c.

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

Referenced by load_module().

03554 {
03555    char *queuename, *interface;
03556 
03557    queuename = astman_get_header(m, "Queue");
03558    interface = astman_get_header(m, "Interface");
03559 
03560    if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
03561       astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
03562       return 0;
03563    }
03564 
03565    switch (remove_from_queue(queuename, interface)) {
03566    case RES_OKAY:
03567       astman_send_ack(s, m, "Removed interface from queue");
03568       break;
03569    case RES_EXISTS:
03570       astman_send_error(s, m, "Unable to remove interface: Not there");
03571       break;
03572    case RES_NOSUCHQUEUE:
03573       astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
03574       break;
03575    case RES_OUTOFMEMORY:
03576       astman_send_error(s, m, "Out of memory");
03577       break;
03578    }
03579    return 0;
03580 }

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

Definition at line 1042 of file app_queue.c.

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

Referenced by say_position().

01043 {
01044    int res;
01045 
01046    ast_stopstream(chan);
01047    res = ast_streamfile(chan, filename, chan->language);
01048 
01049    if (!res)
01050       res = ast_waitstream(chan, AST_DIGIT_ANY);
01051    else
01052       res = 0;
01053 
01054    ast_stopstream(chan);
01055 
01056    return res;
01057 }

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

Definition at line 2605 of file app_queue.c.

References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), localuser::chan, ast_channel::context, localuser::interface, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, option_priority_jumping, parse(), pbx_builtin_setvar_helper(), and set_member_paused().

Referenced by load_module().

02606 {
02607    struct localuser *u;
02608    char *parse;
02609    int priority_jump = 0;
02610    AST_DECLARE_APP_ARGS(args,
02611       AST_APP_ARG(queuename);
02612       AST_APP_ARG(interface);
02613       AST_APP_ARG(options);
02614    );
02615 
02616    if (ast_strlen_zero(data)) {
02617       ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
02618       return -1;
02619    }
02620 
02621    LOCAL_USER_ADD(u);
02622 
02623    if (!(parse = ast_strdupa(data))) {
02624       ast_log(LOG_WARNING, "Memory Error!\n");
02625       LOCAL_USER_REMOVE(u);
02626       return -1;
02627    }
02628 
02629    AST_STANDARD_APP_ARGS(args, parse);
02630 
02631    if (args.options) {
02632       if (strchr(args.options, 'j'))
02633          priority_jump = 1;
02634    }
02635 
02636    if (ast_strlen_zero(args.interface)) {
02637       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
02638       LOCAL_USER_REMOVE(u);
02639       return -1;
02640    }
02641 
02642    if (set_member_paused(args.queuename, args.interface, 1)) {
02643       ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
02644       if (priority_jump || option_priority_jumping) {
02645          if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
02646             pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
02647             LOCAL_USER_REMOVE(u);
02648             return 0;
02649          }
02650       }
02651       LOCAL_USER_REMOVE(u);
02652       pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
02653       return -1;
02654    }
02655 
02656    LOCAL_USER_REMOVE(u);
02657    pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
02658    return 0;
02659 }

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

Definition at line 2860 of file app_queue.c.

References AST_CONTROL_RINGING, ast_indicate(), ast_log(), ast_moh_start(), ast_queue_log(), ast_strlen_zero(), ast_verbose(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, join_queue(), LOCAL_USER_ADD, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_debug, option_verbose, pbx_builtin_getvar_helper(), QUEUE_UNKNOWN, record_abandoned(), strsep(), ast_channel::uniqueid, valid_exit(), VERBOSE_PREFIX_3, and wait_our_turn().

Referenced by load_module().

02861 {
02862    int res=-1;
02863    int ringing=0;
02864    struct localuser *u;
02865    char *queuename;
02866    char info[512];
02867    char *info_ptr = info;
02868    char *options = NULL;
02869    char *url = NULL;
02870    char *announceoverride = NULL;
02871    char *user_priority;
02872    int prio;
02873    char *queuetimeoutstr = NULL;
02874    enum queue_result reason = QUEUE_UNKNOWN;
02875 
02876    /* whether to exit Queue application after the timeout hits */
02877    int go_on = 0;
02878 
02879    /* Our queue entry */
02880    struct queue_ent qe;
02881    
02882    if (ast_strlen_zero(data)) {
02883       ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
02884       return -1;
02885    }
02886 
02887    LOCAL_USER_ADD(u);
02888 
02889    /* Setup our queue entry */
02890    memset(&qe, 0, sizeof(qe));
02891    qe.start = time(NULL);
02892    
02893    /* Parse our arguments XXX Check for failure XXX */
02894    ast_copy_string(info, (char *) data, sizeof(info));
02895    queuename = strsep(&info_ptr, "|");
02896    options = strsep(&info_ptr, "|");
02897    url = strsep(&info_ptr, "|");
02898    announceoverride = strsep(&info_ptr, "|");
02899    queuetimeoutstr = info_ptr;
02900 
02901    /* set the expire time based on the supplied timeout; */
02902    if (queuetimeoutstr)
02903       qe.expire = qe.start + atoi(queuetimeoutstr);
02904    else
02905       qe.expire = 0;
02906 
02907    /* Get the priority from the variable ${QUEUE_PRIO} */
02908    user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
02909    if (user_priority) {
02910       if (sscanf(user_priority, "%d", &prio) == 1) {
02911          if (option_debug)
02912             ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
02913                chan->name, prio);
02914       } else {
02915          ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
02916             user_priority, chan->name);
02917          prio = 0;
02918       }
02919    } else {
02920       if (option_debug > 2)
02921          ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
02922       prio = 0;
02923    }
02924 
02925    if (options && (strchr(options, 'r')))
02926       ringing = 1;
02927 
02928    if (option_debug)  
02929       ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
02930          queuename, options, url, announceoverride, (long)qe.expire, (int)prio);
02931 
02932    qe.chan = chan;
02933    qe.prio = (int)prio;
02934    qe.last_pos_said = 0;
02935    qe.last_pos = 0;
02936    qe.last_periodic_announce_time = time(NULL);
02937    if (!join_queue(queuename, &qe, &reason)) {
02938       ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "",
02939                chan->cid.cid_num ? chan->cid.cid_num : "");
02940 check_turns:
02941       if (ringing) {
02942          ast_indicate(chan, AST_CONTROL_RINGING);
02943       } else {
02944          ast_moh_start(chan, qe.moh);
02945       }
02946       for (;;) {
02947          /* This is the wait loop for callers 2 through maxlen */
02948 
02949          res = wait_our_turn(&qe, ringing, &reason);
02950          /* If they hungup, return immediately */
02951          if (res < 0) {
02952             /* Record this abandoned call */
02953             record_abandoned(&qe);
02954             ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
02955             if (option_verbose > 2) {
02956                ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
02957             }
02958             res = -1;
02959             break;
02960          }
02961          if (!res) 
02962             break;
02963          if (valid_exit(&qe, res)) {
02964             ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
02965             break;
02966          }
02967       }
02968       if (!res) {
02969          int makeannouncement = 0;
02970          for (;;) {
02971             /* This is the wait loop for the head caller*/
02972             /* To exit, they may get their call answered; */
02973             /* they may dial a digit from the queue context; */
02974             /* or, they may timeout. */
02975 
02976             enum queue_member_status stat;
02977 
02978             /* Leave if we have exceeded our queuetimeout */
02979             if (qe.expire && (time(NULL) > qe.expire)) {
02980                record_abandoned(&qe);
02981                reason = QUEUE_TIMEOUT;
02982                res = 0;
02983                ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
02984                break;
02985             }
02986 
02987             if (makeannouncement) {
02988                /* Make a position announcement, if enabled */
02989                if (qe.parent->announcefrequency && !ringing)
02990                   res = say_position(&qe);
02991                if (res && valid_exit(&qe, res)) {
02992                   ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
02993                   break;
02994                }
02995 
02996             }
02997             makeannouncement = 1;
02998 
02999             /* Make a periodic announcement, if enabled */
03000             if (qe.parent->periodicannouncefrequency && !ringing)
03001                res = say_periodic_announcement(&qe);
03002 
03003             if (res && valid_exit(&qe, res)) {
03004                ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
03005                break;
03006             }
03007 
03008             /* Try calling all queue members for 'timeout' seconds */
03009             res = try_calling(&qe, options, announceoverride, url, &go_on);
03010             if (res) {
03011                if (res < 0) {
03012                   if (!qe.handled) {
03013                      record_abandoned(&qe);
03014                      ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
03015                   }
03016                } else if (res > 0)
03017                   ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
03018                break;
03019             }
03020 
03021             stat = get_member_status(qe.parent);
03022 
03023             /* leave the queue if no agents, if enabled */
03024             if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
03025                record_abandoned(&qe);
03026                reason = QUEUE_LEAVEEMPTY;
03027                res = 0;
03028                break;
03029             }
03030 
03031             /* leave the queue if no reachable agents, if enabled */
03032             if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
03033                record_abandoned(&qe);
03034                reason = QUEUE_LEAVEUNAVAIL;
03035                res = 0;
03036                break;
03037             }
03038 
03039             /* Leave if we have exceeded our queuetimeout */
03040             if (qe.expire && (time(NULL) > qe.expire)) {
03041                record_abandoned(&qe);
03042                reason = QUEUE_TIMEOUT;
03043                res = 0;
03044                ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);   
03045                break;
03046             }
03047 
03048             /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
03049             res = wait_a_bit(&qe);
03050             if (res < 0) {
03051                record_abandoned(&qe);
03052                ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
03053                if (option_verbose > 2) {
03054                   ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
03055                }
03056                res = -1;
03057                break;
03058             }
03059             if (res && valid_exit(&qe, res)) {
03060                ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
03061                break;
03062             }
03063             /* exit after 'timeout' cycle if 'n' option enabled */
03064             if (go_on) {
03065                if (option_verbose > 2)
03066                   ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
03067                ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
03068                record_abandoned(&qe);
03069                reason = QUEUE_TIMEOUT;
03070                res = 0;
03071                break;
03072             }
03073             /* Since this is a priority queue and 
03074              * it is not sure that we are still at the head
03075              * of the queue, go and check for our turn again.
03076              */
03077             if (!is_our_turn(&qe)) {
03078                if (option_debug)
03079                   ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
03080                         qe.chan->name);
03081                goto check_turns;
03082             }
03083          }
03084       }
03085       /* Don't allow return code > 0 */
03086       if (res >= 0 && res != AST_PBX_KEEPALIVE) {
03087          res = 0; 
03088          if (ringing) {
03089             ast_indicate(chan, -1);
03090          } else {
03091             ast_moh_stop(chan);
03092          }        
03093          ast_stopstream(chan);
03094       }
03095       leave_queue(&qe);
03096       if (reason != QUEUE_UNKNOWN)
03097          set_queue_result(chan, reason);
03098    } else {
03099       ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
03100       set_queue_result(chan, reason);
03101       res = 0;
03102    }
03103    LOCAL_USER_REMOVE(u);
03104    return res;
03105 }

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

Definition at line 3107 of file app_queue.c.

References ast_log(), ast_mutex_lock(), ast_strlen_zero(), LOCAL_USER_ACF_ADD, LOCAL_USER_REMOVE, ast_call_queue::lock, LOG_ERROR, ast_call_queue::name, ast_call_queue::next, and queues.

03108 {
03109    int count = 0;
03110    struct ast_call_queue *q;
03111    struct localuser *u;
03112    struct member *m;
03113 
03114    LOCAL_USER_ACF_ADD(u);
03115 
03116    ast_copy_string(buf, "0", len);
03117    
03118    if (ast_strlen_zero(data)) {
03119       ast_log(LOG_ERROR, "QUEUEAGENTCOUNT requires an argument: queuename\n");
03120       LOCAL_USER_REMOVE(u);
03121       return buf;
03122    }
03123 
03124    ast_mutex_lock(&qlock);
03125 
03126    /* Find the right queue */
03127    for (q = queues; q; q = q->next) {
03128       if (!strcasecmp(q->name, data)) {
03129          ast_mutex_lock(&q->lock);
03130          break;
03131       }
03132    }
03133 
03134    ast_mutex_unlock(&qlock);
03135 
03136    if (q) {
03137       for (m = q->members; m; m = m->next) {
03138          /* Count the agents who are logged in and presently answering calls */
03139          if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
03140             count++;
03141          }
03142       }
03143       ast_mutex_unlock(&q->lock);
03144    }
03145 
03146    snprintf(buf, len, "%d", count);
03147    LOCAL_USER_REMOVE(u);
03148    return buf;
03149 }

static void queue_set_param struct ast_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 603 of file app_queue.c.

References ast_call_queue::announce, ast_call_queue::announcefrequency, ast_call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, ast_log(), ast_true(), ast_call_queue::context, DEFAULT_RETRY, DEFAULT_TIMEOUT, ast_call_queue::eventwhencalled, ast_call_queue::joinempty, ast_call_queue::leavewhenempty, LOG_WARNING, ast_call_queue::maskmemberstatus, ast_call_queue::maxlen, ast_call_queue::memberdelay, ast_call_queue::moh, ast_call_queue::monfmt, ast_call_queue::monjoin, ast_call_queue::name, ast_call_queue::periodicannouncefrequency, QUEUE_EMPTY_NORMAL, QUEUE_EMPTY_STRICT, ast_call_queue::reportholdtime, ast_call_queue::retry, ast_call_queue::roundingseconds, ast_call_queue::servicelevel, ast_call_queue::sound_calls, ast_call_queue::sound_holdtime, ast_call_queue::sound_lessthan, ast_call_queue::sound_minutes, ast_call_queue::sound_next, ast_call_queue::sound_periodicannounce, ast_call_queue::sound_reporthold, ast_call_queue::sound_seconds, ast_call_queue::sound_thanks, ast_call_queue::sound_thereare, strat2int(), ast_call_queue::strategy, ast_call_queue::timeout, ast_call_queue::timeoutrestart, use_weight, ast_call_queue::weight, and ast_call_queue::wrapuptime.

Referenced by reload_queues().

00604 {
00605    if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
00606       ast_copy_string(q->moh, val, sizeof(q->moh));
00607    } else if (!strcasecmp(param, "announce")) {
00608       ast_copy_string(q->announce, val, sizeof(q->announce));
00609    } else if (!strcasecmp(param, "context")) {
00610       ast_copy_string(q->context, val, sizeof(q->context));
00611    } else if (!strcasecmp(param, "timeout")) {
00612       q->timeout = atoi(val);
00613       if (q->timeout < 0)
00614          q->timeout = DEFAULT_TIMEOUT;
00615    } else if (!strcasecmp(param, "monitor-join")) {
00616       q->monjoin = ast_true(val);
00617    } else if (!strcasecmp(param, "monitor-format")) {
00618       ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
00619    } else if (!strcasecmp(param, "queue-youarenext")) {
00620       ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
00621    } else if (!strcasecmp(param, "queue-thereare")) {
00622       ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
00623    } else if (!strcasecmp(param, "queue-callswaiting")) {
00624       ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
00625    } else if (!strcasecmp(param, "queue-holdtime")) {
00626       ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
00627    } else if (!strcasecmp(param, "queue-minutes")) {
00628       ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
00629    } else if (!strcasecmp(param, "queue-seconds")) {
00630       ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
00631    } else if (!strcasecmp(param, "queue-lessthan")) {
00632       ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
00633    } else if (!strcasecmp(param, "queue-thankyou")) {
00634       ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
00635    } else if (!strcasecmp(param, "queue-reporthold")) {
00636       ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
00637    } else if (!strcasecmp(param, "announce-frequency")) {
00638       q->announcefrequency = atoi(val);
00639    } else if (!strcasecmp(param, "announce-round-seconds")) {
00640       q->roundingseconds = atoi(val);
00641       if (q->roundingseconds>60 || q->roundingseconds<0) {
00642          if (linenum >= 0) {
00643             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
00644                "using 0 instead for queue '%s' at line %d of queues.conf\n",
00645                val, param, q->name, linenum);
00646          } else {
00647             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
00648                "using 0 instead for queue '%s'\n", val, param, q->name);
00649          }
00650          q->roundingseconds=0;
00651       }
00652    } else if (!strcasecmp(param, "announce-holdtime")) {
00653       if (!strcasecmp(val, "once"))
00654          q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
00655       else if (ast_true(val))
00656          q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
00657       else
00658          q->announceholdtime = 0;
00659     } else if (!strcasecmp(param, "periodic-announce")) {
00660       ast_copy_string(q->sound_periodicannounce, val, sizeof(q->sound_periodicannounce));
00661    } else if (!strcasecmp(param, "periodic-announce-frequency")) {
00662       q->periodicannouncefrequency = atoi(val);
00663    } else if (!strcasecmp(param, "retry")) {
00664       q->retry = atoi(val);
00665       if (q->retry < 0)
00666          q->retry = DEFAULT_RETRY;
00667    } else if (!strcasecmp(param, "wrapuptime")) {
00668       q->wrapuptime = atoi(val);
00669    } else if (!strcasecmp(param, "maxlen")) {
00670       q->maxlen = atoi(val);
00671       if (q->maxlen < 0)
00672          q->maxlen = 0;
00673    } else if (!strcasecmp(param, "servicelevel")) {
00674       q->servicelevel= atoi(val);
00675    } else if (!strcasecmp(param, "strategy")) {
00676       q->strategy = strat2int(val);
00677       if (q->strategy < 0) {
00678          ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
00679             val, q->name);
00680          q->strategy = 0;
00681       }
00682    } else if (!strcasecmp(param, "joinempty")) {
00683       if (!strcasecmp(val, "strict"))
00684          q->joinempty = QUEUE_EMPTY_STRICT;
00685       else if (ast_true(val))
00686          q->joinempty = QUEUE_EMPTY_NORMAL;
00687       else
00688          q->joinempty = 0;
00689    } else if (!strcasecmp(param, "leavewhenempty")) {
00690       if (!strcasecmp(val, "strict"))
00691          q->leavewhenempty = QUEUE_EMPTY_STRICT;
00692       else if (ast_true(val))
00693          q->leavewhenempty = QUEUE_EMPTY_NORMAL;
00694       else
00695          q->leavewhenempty = 0;
00696    } else if (!strcasecmp(param, "eventmemberstatus")) {
00697       q->maskmemberstatus = !ast_true(val);
00698    } else if (!strcasecmp(param, "eventwhencalled")) {
00699       q->eventwhencalled = ast_true(val);
00700    } else if (!strcasecmp(param, "reportholdtime")) {
00701       q->reportholdtime = ast_true(val);
00702    } else if (!strcasecmp(param, "memberdelay")) {
00703       q->memberdelay = atoi(val);
00704    } else if (!strcasecmp(param, "weight")) {
00705       q->weight = atoi(val);
00706       if (q->weight)
00707          use_weight++;
00708       /* With Realtime queues, if the last queue using weights is deleted in realtime,
00709          we will not see any effect on use_weight until next reload. */
00710    } else if (!strcasecmp(param, "timeoutrestart")) {
00711       q->timeoutrestart = ast_true(val);
00712    } else if(failunknown) {
00713       if (linenum >= 0) {
00714          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
00715             q->name, param, linenum);
00716       } else {
00717          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
00718       }
00719    }
00720 }

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

Definition at line 3382 of file app_queue.c.

References __queues_show().

03383 {
03384    return __queues_show(0, fd, argc, argv, 1);
03385 }

static int queues_show int  fd,
int  argc,
char **  argv
[static]
 

Definition at line 3377 of file app_queue.c.

References __queues_show().

03378 {
03379    return __queues_show(0, fd, argc, argv, 0);
03380 }

static void recalc_holdtime struct queue_ent qe  )  [static]
 

Definition at line 1191 of file app_queue.c.

References ast_mutex_lock(), ast_mutex_unlock(), ast_call_queue::callscompletedinsl, ast_call_queue::holdtime, ast_call_queue::lock, queue_ent::parent, ast_call_queue::servicelevel, and queue_ent::start.

01192 {
01193    int oldvalue, newvalue;
01194 
01195    /* Calculate holdtime using a recursive boxcar filter */
01196    /* Thanks to SRT for this contribution */
01197    /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
01198 
01199    newvalue = time(NULL) - qe->start;
01200 
01201    ast_mutex_lock(&qe->parent->lock);
01202    if (newvalue <= qe->parent->servicelevel)
01203       qe->parent->callscompletedinsl++;
01204    oldvalue = qe->parent->holdtime;
01205    qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
01206    ast_mutex_unlock(&qe->parent->lock);
01207 }

static void record_abandoned struct queue_ent qe  )  [static]
 

Definition at line 1601 of file app_queue.c.

References ast_mutex_lock(), ast_mutex_unlock(), ast_call_queue::callsabandoned, ast_call_queue::lock, and queue_ent::parent.

Referenced by queue_exec().

01602 {
01603    ast_mutex_lock(&qe->parent->lock);
01604    qe->parent->callsabandoned++;
01605    ast_mutex_unlock(&qe->parent->lock);
01606 }

int reload void   ) 
 

Reload stuff.

This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.

Returns:
The return value is not used.

Definition at line 3849 of file app_queue.c.

References reload_queues().

03850 {
03851    reload_queues();
03852    return 0;
03853 }

static void reload_queue_members void   )  [static]
 

Definition at line 2516 of file app_queue.c.

References ast_db_gettree(), ast_mutex_lock(), ast_mutex_unlock(), member::interface, ast_db_entry::key, ast_call_queue::lock, ast_call_queue::name, ast_call_queue::next, ast_db_entry::next, member::paused, member::penalty, pm_family, PM_MAX_LEN, and queues.

Referenced by load_module().

02517 {
02518    char *cur_ptr; 
02519    char *queue_name;
02520    char *member;
02521    char *interface;
02522    char *penalty_tok;
02523    int penalty = 0;
02524    char *paused_tok;
02525    int paused = 0;
02526    struct ast_db_entry *db_tree;
02527    struct ast_db_entry *entry;
02528    struct ast_call_queue *cur_queue;
02529    char queue_data[PM_MAX_LEN];
02530 
02531    ast_mutex_lock(&qlock);
02532 
02533    /* Each key in 'pm_family' is the name of a queue */
02534    db_tree = ast_db_gettree(pm_family, NULL);
02535    for (entry = db_tree; entry; entry = entry->next) {
02536 
02537       queue_name = entry->key + strlen(pm_family) + 2;
02538 
02539       cur_queue = queues;
02540       while (cur_queue) {
02541          ast_mutex_lock(&cur_queue->lock);
02542          if (!strcmp(queue_name, cur_queue->name))
02543             break;
02544          ast_mutex_unlock(&cur_queue->lock);
02545          cur_queue = cur_queue->next;
02546       }
02547 
02548       if (!cur_queue) {
02549          /* If the queue no longer exists, remove it from the
02550           * database */
02551          ast_db_del(pm_family, queue_name);
02552          continue;
02553       } else
02554          ast_mutex_unlock(&cur_queue->lock);
02555 
02556       if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
02557          continue;
02558 
02559       cur_ptr = queue_data;
02560       while ((member = strsep(&cur_ptr, "|"))) {
02561          if (ast_strlen_zero(member))
02562             continue;
02563 
02564          interface = strsep(&member, ";");
02565          penalty_tok = strsep(&member, ";");
02566          paused_tok = strsep(&member, ";");
02567 
02568          if (!penalty_tok) {
02569             ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
02570             break;
02571          }
02572          penalty = strtol(penalty_tok, NULL, 10);
02573          if (errno == ERANGE) {
02574             ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
02575             break;
02576          }
02577          
02578          if (!paused_tok) {
02579             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
02580             break;
02581          }
02582          paused = strtol(paused_tok, NULL, 10);
02583          if ((errno == ERANGE) || paused < 0 || paused > 1) {
02584             ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
02585             break;
02586          }
02587 
02588          if (option_debug)
02589             ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Penalty: %d  Paused: %d\n", queue_name, interface, penalty, paused);
02590          
02591          if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
02592             ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
02593             break;
02594          }
02595       }
02596    }
02597 
02598    ast_mutex_unlock(&qlock);
02599    if (db_tree) {
02600       ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
02601       ast_db_freetree(db_tree);
02602    }
02603 }

static void reload_queues void   )  [static]
 

Definition at line 3158 of file app_queue.c.

References alloc_queue(), ast_category_browse(), ast_config_destroy(), ast_config_load(), ast_device_state(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), cfg, clear_queue(), ast_call_queue::count, create_queue_member(), ast_call_queue::dead, destroy_queue(), free_members(), init_queue(), member::interface, ast_call_queue::lock, LOG_NOTICE, LOG_WARNING, ast_call_queue::members, ast_call_queue::name, member::next, ast_call_queue::next, member::penalty, queue_persistent_members, queue_set_param(), queues, member::status, and var.

Referenced by load_module(), and reload().

03159 {
03160    struct ast_call_queue *q, *ql, *qn;
03161    struct ast_config *cfg;
03162    char *cat, *tmp;
03163    struct ast_variable *var;
03164    struct member *prev, *cur;
03165    int new;
03166    char *general_val = NULL;
03167    char interface[80];
03168    int penalty;
03169    
03170    cfg = ast_config_load("queues.conf");
03171    if (!cfg) {
03172       ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
03173       return;
03174    }
03175    memset(interface, 0, sizeof(interface));
03176    ast_mutex_lock(&qlock);
03177    use_weight=0;
03178    /* Mark all queues as dead for the moment */
03179    q = queues;
03180    while(q) {
03181       q->dead = 1;
03182       q = q->next;
03183    }
03184    /* Chug through config file */
03185    cat = ast_category_browse(cfg, NULL);
03186    while(cat) {
03187       if (!strcasecmp(cat, "general")) {  
03188          /* Initialize global settings */
03189          queue_persistent_members = 0;
03190          if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
03191             queue_persistent_members = ast_true(general_val);
03192       } else { /* Define queue */
03193          /* Look for an existing one */
03194          q = queues;
03195          while(q) {
03196             if (!strcmp(q->name, cat))
03197                break;
03198             q = q->next;
03199          }
03200          if (!q) {
03201             /* Make one then */
03202             q = alloc_queue(cat);
03203             new = 1;
03204          } else
03205             new = 0;
03206          if (q) {
03207             if (!new)
03208                ast_mutex_lock(&q->lock);
03209             /* Re-initialize the queue, and clear statistics */
03210             init_queue(q);
03211             clear_queue(q);
03212             free_members(q, 0);
03213             prev = q->members;
03214             if (prev) {
03215                /* find the end of any dynamic members */
03216                while(prev->next)
03217                   prev = prev->next;
03218             }
03219             var = ast_variable_browse(cfg, cat);
03220             while(var) {
03221                if (!strcasecmp(var->name, "member")) {
03222                   /* Add a new member */
03223                   ast_copy_string(interface, var->value, sizeof(interface));
03224                   if ((tmp = strchr(interface, ','))) {
03225                      *tmp = '\0';
03226                      tmp++;
03227                      penalty = atoi(tmp);
03228                      if (penalty < 0) {
03229                         penalty = 0;
03230                      }
03231                   } else
03232                      penalty = 0;
03233                   cur = create_queue_member(interface, penalty, 0);
03234                   if (cur) {
03235                      if (prev)
03236                         prev->next = cur;
03237                      else
03238                         q->members = cur;
03239                      prev = cur;
03240                   }
03241                } else {
03242                   queue_set_param(q, var->name, var->value, var->lineno, 1);
03243                }
03244                var = var->next;
03245             }
03246             if (!new) 
03247                ast_mutex_unlock(&q->lock);
03248             if (new) {
03249                q->next = queues;
03250                queues = q;
03251             }
03252          }
03253       }
03254       cat = ast_category_browse(cfg, cat);
03255    }
03256    ast_config_destroy(cfg);
03257    q = queues;
03258    ql = NULL;
03259    while(q) {
03260       qn = q->next;
03261       if (q->dead) {
03262          if (ql)
03263             ql->next = q->next;
03264          else
03265             queues = q->next;
03266          if (!q->count) {
03267             destroy_queue(q);
03268          } else
03269             ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
03270       } else {
03271          for (cur = q->members; cur; cur = cur->next)
03272             cur->status = ast_device_state(cur->interface);
03273          ql = q;
03274       }
03275       q = qn;
03276    }
03277    ast_mutex_unlock(&qlock);
03278 }

static int remove_from_queue char *  queuename,
char *  interface
[static]
 

Definition at line 2378 of file app_queue.c.

References ast_mutex_lock(), interface_exists(), ast_call_queue::lock, ast_call_queue::members, ast_call_queue::name, member::next, ast_call_queue::next, queues, and RES_NOSUCHQUEUE.

Referenced by handle_remove_queue_member(), manager_remove_queue_member(), and rqm_exec().

02379 {
02380    struct ast_call_queue *q;
02381    struct member *last_member, *look;
02382    int res = RES_NOSUCHQUEUE;
02383 
02384    ast_mutex_lock(&qlock);
02385    for (q = queues ; q ; q = q->next) {
02386       ast_mutex_lock(&q->lock);
02387       if (!strcmp(q->name, queuename)) {
02388          if ((last_member = interface_exists(q, interface))) {
02389             if ((look = q->members) == last_member) {
02390                q->members = last_member->next;
02391             } else {
02392                while (look != NULL) {
02393                   if (look->next == last_member) {
02394                      look->next = last_member->next;
02395                      break;
02396                   } else {
02397                       look = look->next;
02398                   }
02399                }
02400             }
02401             manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
02402                   "Queue: %s\r\n"
02403                   "Location: %s\r\n",
02404                q->name, last_member->interface);
02405             free(last_member);
02406 
02407             if (queue_persistent_members)
02408                dump_queue_members(q);
02409 
02410             res = RES_OKAY;
02411          } else {
02412             res = RES_EXISTS;
02413          }
02414          ast_mutex_unlock(&q->lock);
02415          break;
02416       }
02417       ast_mutex_unlock(&q->lock);
02418    }
02419    ast_mutex_unlock(&qlock);
02420    return res;
02421 }

static void remove_queue struct ast_call_queue q  )  [static]
 

Definition at line 783 of file app_queue.c.

References ast_mutex_lock(), ast_call_queue::next, and queues.

Referenced by leave_queue().

00784 {
00785    struct ast_call_queue *cur, *prev = NULL;
00786 
00787    ast_mutex_lock(&qlock);
00788    for (cur = queues; cur; cur = cur->next) {
00789       if (cur == q) {
00790          if (prev)
00791             prev->next = cur->next;
00792          else
00793             queues = cur->next;
00794       } else {
00795          prev = cur;
00796       }
00797    }
00798    ast_mutex_unlock(&qlock);
00799 }

static int ring_entry struct queue_ent qe,
struct localuser tmp,
int *  busies
[static]
 

Definition at line 1348 of file app_queue.c.

References ast_channel::adsicpe, ast_channel::appl, ast_call(), ast_cdr_busy(), ast_channel_inherit_variables(), ast_hangup(), ast_log(), ast_request(), ast_verbose(), ast_channel::cdr, localuser::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, EVENT_FLAG_AGENT, ast_call_queue::eventwhencalled, ast_channel::exten, free, localuser::interface, localuser::lastcall, LOG_DEBUG, LOG_NOTICE, manager_event(), localuser::member, ast_channel::name, ast_call_queue::name, ast_channel::nativeformats, localuser::oldstatus, option_debug, option_verbose, queue_ent::parent, member::paused, ast_channel::priority, member::status, localuser::stillgoing, strdup, update_dial_status(), use_weight, VERBOSE_PREFIX_3, ast_channel::whentohangup, and ast_call_queue::wrapuptime.

Referenced by ring_one().

01349 {
01350    int res;
01351    int status;
01352    char tech[256];
01353    char *location;
01354 
01355    if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
01356       if (option_debug)
01357          ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
01358       if (qe->chan->cdr)
01359          ast_cdr_busy(qe->chan->cdr);
01360       tmp->stillgoing = 0;
01361       (*busies)++;
01362       return 0;
01363    }
01364    
01365    if (tmp->member->paused) {
01366       if (option_debug)
01367          ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
01368       if (qe->chan->cdr)
01369          ast_cdr_busy(qe->chan->cdr);
01370       tmp->stillgoing = 0;
01371       return 0;
01372    }
01373    if (use_weight && compare_weight(qe->parent,tmp->member)) {
01374       ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
01375       if (qe->chan->cdr)
01376          ast_cdr_busy(qe->chan->cdr);
01377       tmp->stillgoing = 0;
01378       (*busies)++;
01379       return 0;
01380    }
01381 
01382    ast_copy_string(tech, tmp->interface, sizeof(tech));
01383    if ((location = strchr(tech, '/')))
01384       *location++ = '\0';
01385    else
01386       location = "";
01387 
01388    /* Request the peer */
01389    tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
01390    if (!tmp->chan) {       /* If we can't, just go on to the next call */
01391 #if 0
01392       ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
01393 #endif         
01394       if (qe->chan->cdr)
01395          ast_cdr_busy(qe->chan->cdr);
01396       tmp->stillgoing = 0;
01397       update_dial_status(qe->parent, tmp->member, status);
01398       (*busies)++;
01399       return 0;
01400    } else if (status != tmp->oldstatus) 
01401       update_dial_status(qe->parent, tmp->member, status);
01402    
01403    tmp->chan->appl = "AppQueue";
01404    tmp->chan->data = "(Outgoing Line)";
01405    tmp->chan->whentohangup = 0;
01406    if (tmp->chan->cid.cid_num)
01407       free(tmp->chan->cid.cid_num);
01408    tmp->chan->cid.cid_num = NULL;
01409    if (tmp->chan->cid.cid_name)
01410       free(tmp->chan->cid.cid_name);
01411    tmp->chan->cid.cid_name = NULL;
01412    if (tmp->chan->cid.cid_ani)
01413       free(tmp->chan->cid.cid_ani);
01414    tmp->chan->cid.cid_ani = NULL;
01415    if (qe->chan->cid.cid_num)
01416       tmp->chan->cid.cid_num = strdup(qe->chan->cid.cid_num);
01417    if (qe->chan->cid.cid_name)
01418       tmp->chan->cid.cid_name = strdup(qe->chan->cid.cid_name);
01419    if (qe->chan->cid.cid_ani)
01420       tmp->chan->cid.cid_ani = strdup(qe->chan->cid.cid_ani);
01421 
01422    /* Inherit specially named variables from parent channel */
01423    ast_channel_inherit_variables(qe->chan, tmp->chan);
01424 
01425    /* Presense of ADSI CPE on outgoing channel follows ours */
01426    tmp->chan->adsicpe = qe->chan->adsicpe;
01427 
01428    /* Place the call, but don't wait on the answer */
01429    res = ast_call(tmp->chan, location, 0);
01430    if (res) {
01431       /* Again, keep going even if there's an error */
01432       if (option_debug)
01433          ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
01434       else if (option_verbose > 2)
01435          ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
01436       ast_hangup(tmp->chan);
01437       tmp->chan = NULL;
01438       tmp->stillgoing = 0;
01439       (*busies)++;
01440       return 0;
01441    } else {
01442       if (qe->parent->eventwhencalled) {
01443          manager_event(EVENT_FLAG_AGENT, "AgentCalled",
01444                   "AgentCalled: %s\r\n"
01445                   "ChannelCalling: %s\r\n"
01446                   "CallerID: %s\r\n"
01447                   "CallerIDName: %s\r\n"
01448                   "Context: %s\r\n"
01449                   "Extension: %s\r\n"
01450                   "Priority: %d\r\n",
01451                   tmp->interface, qe->chan->name,
01452                   tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
01453                   tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
01454                   qe->chan->context, qe->chan->exten, qe->chan->priority);
01455       }
01456       if (option_verbose > 2)
01457          ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
01458    }
01459    return 1;
01460 }

static int ring_one struct queue_ent qe,
struct localuser outgoing,
int *  busies
[static]
 

Definition at line 1462 of file app_queue.c.

References ast_log(), localuser::chan, localuser::interface, LOG_DEBUG, localuser::metric, localuser::next, option_debug, queue_ent::parent, ring_entry(), localuser::stillgoing, and ast_call_queue::strategy.

Referenced by wait_for_answer().

01463 {
01464    struct localuser *cur;
01465    struct localuser *best;
01466    int bestmetric=0;
01467 
01468    do {
01469       best = NULL;
01470       cur = outgoing;
01471       while(cur) {
01472          if (cur->stillgoing &&              /* Not already done */
01473             !cur->chan &&              /* Isn't already going */
01474             (!best || (cur->metric < bestmetric))) {  /* We haven't found one yet, or it's better */
01475                bestmetric = cur->metric;
01476                best = cur;
01477          }
01478          cur = cur->next;
01479       }
01480       if (best) {
01481          if (!qe->parent->strategy) {
01482             /* Ring everyone who shares this best metric (for ringall) */
01483             cur = outgoing;
01484             while(cur) {
01485                if (cur->stillgoing && !cur->chan && (cur->metric <= bestmetric)) {
01486                   if (option_debug)
01487                      ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
01488                   ring_entry(qe, cur, busies);
01489                }
01490                cur = cur->next;
01491             }
01492          } else {
01493             /* Ring just the best channel */
01494             if (option_debug)
01495                ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
01496             ring_entry(qe, best, busies);
01497          }
01498       }
01499    } while (best && !best->chan);
01500    if (!best) {
01501       if (option_debug)
01502          ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
01503       return 0;
01504    }
01505    return 1;
01506 }

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

Definition at line 2717 of file app_queue.c.

References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), localuser::chan, ast_channel::context, localuser::interface, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::name, option_priority_jumping, parse(), pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.

Referenced by load_module().

02718 {
02719    int res=-1;
02720    struct localuser *u;
02721    char *parse, *temppos = NULL;
02722    int priority_jump = 0;
02723    AST_DECLARE_APP_ARGS(args,
02724       AST_APP_ARG(queuename);
02725       AST_APP_ARG(interface);
02726       AST_APP_ARG(options);
02727    );
02728 
02729 
02730    if (ast_strlen_zero(data)) {
02731       ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
02732       return -1;
02733    }
02734 
02735    LOCAL_USER_ADD(u);
02736 
02737    if (!(parse = ast_strdupa(data))) {
02738       ast_log(LOG_WARNING, "Memory Error!\n");
02739       LOCAL_USER_REMOVE(u);
02740       return -1;
02741    }
02742 
02743    AST_STANDARD_APP_ARGS(args, parse);
02744 
02745    if (ast_strlen_zero(args.interface)) {
02746       args.interface = ast_strdupa(chan->name);
02747       temppos = strrchr(args.interface, '-');
02748       if (temppos)
02749          *temppos = '\0';
02750    }
02751 
02752    if (args.options) {
02753       if (strchr(args.options, 'j'))
02754          priority_jump = 1;
02755    }
02756 
02757    switch (remove_from_queue(args.queuename, args.interface)) {
02758    case RES_OKAY:
02759       ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
02760       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
02761       res = 0;
02762       break;
02763    case RES_EXISTS:
02764       ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
02765       if (priority_jump || option_priority_jumping) 
02766          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
02767       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
02768       res = 0;
02769       break;
02770    case RES_NOSUCHQUEUE:
02771       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
02772       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
02773       res = 0;
02774       break;
02775    case RES_OUTOFMEMORY:
02776       ast_log(LOG_ERROR, "Out of memory\n");
02777       break;
02778    }
02779 
02780    LOCAL_USER_REMOVE(u);
02781    return res;
02782 }

static void rt_handle_member_record struct ast_call_queue q,
char *  interface,
const char *  penalty_str
[static]
 

Definition at line 722 of file app_queue.c.

References create_queue_member(), member::dead, member::interface, ast_call_queue::members, member::next, and member::penalty.

00723 {
00724    struct member *m, *prev_m;
00725    int penalty = 0;
00726 
00727    if(penalty_str) {
00728       penalty = atoi(penalty_str);
00729       if(penalty < 0)
00730          penalty = 0;
00731    }
00732 
00733    /* Find the member, or the place to put a new one. */
00734    prev_m = NULL;
00735    m = q->members;
00736    while (m && strcmp(m->interface, interface)) {
00737       prev_m = m;
00738       m = m->next;
00739    }
00740 
00741    /* Create a new one if not found, else update penalty */
00742    if (!m) {
00743       m = create_queue_member(interface, penalty, 0);
00744       if (m) {
00745          m->dead = 0;
00746          if (prev_m) {
00747             prev_m->next = m;
00748          } else {
00749             q->members = m;
00750          }
00751       }
00752    } else {
00753       m->dead = 0;   /* Do not delete this one. */
00754       m->penalty = penalty;
00755    }
00756 }

static int say_periodic_announcement struct queue_ent qe  )  [static]
 

Definition at line 1571 of file app_queue.c.

References ast_moh_start(), ast_moh_stop(), ast_verbose(), background_file(), queue_ent::chan, queue_ent::last_periodic_announce_time, queue_ent::moh, option_verbose, queue_ent::parent, ast_call_queue::periodicannouncefrequency, ast_call_queue::sound_periodicannounce, and VERBOSE_PREFIX_3.

01572 {
01573    int res = 0;
01574    time_t now;
01575 
01576    /* Get the current time */
01577    time(&now);
01578 
01579    /* Check to see if it is time to announce */
01580    if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
01581       return 0;
01582 
01583    /* Stop the music on hold so we can play our own file */
01584    ast_moh_stop(qe->chan);
01585 
01586    if (option_verbose > 2)
01587       ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
01588 
01589    /* play the announcement */
01590    res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce);
01591 
01592    /* Resume Music on Hold */
01593    ast_moh_start(qe->chan, qe->moh);
01594 
01595    /* update last_periodic_announce_time */
01596    qe->last_periodic_announce_time = now;
01597 
01598    return res;
01599 }

static int say_position struct queue_ent qe  )  [static]
 

Definition at line 1090 of file app_queue.c.

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

01091 {
01092    int res = 0, avgholdmins, avgholdsecs;
01093    time_t now;
01094 
01095    /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
01096    time(&now);
01097    if ( (now - qe->last_pos) < 15 )
01098       return 0;
01099 
01100    /* If either our position has changed, or we are over the freq timer, say position */
01101    if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
01102       return 0;
01103 
01104    ast_moh_stop(qe->chan);
01105    /* Say we're next, if we are */
01106    if (qe->pos == 1) {
01107       res = play_file(qe->chan, qe->parent->sound_next);
01108       if (res && valid_exit(qe, res))
01109          goto playout;
01110       else
01111          goto posout;
01112    } else {
01113       res = play_file(qe->chan, qe->parent->sound_thereare);
01114       if (res && valid_exit(qe, res))
01115          goto playout;
01116       res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
01117       if (res && valid_exit(qe, res))
01118          goto playout;
01119       res = play_file(qe->chan, qe->parent->sound_calls);
01120       if (res && valid_exit(qe, res))
01121          goto playout;
01122    }
01123    /* Round hold time to nearest minute */
01124    avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
01125 
01126    /* If they have specified a rounding then round the seconds as well */
01127    if(qe->parent->roundingseconds) {
01128       avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
01129       avgholdsecs*= qe->parent->roundingseconds;
01130    } else {
01131       avgholdsecs=0;
01132    }
01133 
01134    if (option_verbose > 2)
01135       ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
01136 
01137    /* If the hold time is >1 min, if it's enabled, and if it's not
01138       supposed to be only once and we have already said it, say it */
01139    if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
01140        (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
01141       res = play_file(qe->chan, qe->parent->sound_holdtime);
01142       if (res && valid_exit(qe, res))
01143          goto playout;
01144 
01145       if (avgholdmins>0) {
01146          if (avgholdmins < 2) {
01147             res = play_file(qe->chan, qe->parent->sound_lessthan);
01148             if (res && valid_exit(qe, res))
01149                goto playout;
01150 
01151             res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
01152             if (res && valid_exit(qe, res))
01153                goto playout;
01154          } else {
01155             res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
01156             if (res && valid_exit(qe, res))
01157                goto playout;
01158          }
01159          
01160          res = play_file(qe->chan, qe->parent->sound_minutes);
01161          if (res && valid_exit(qe, res))
01162             goto playout;
01163       }
01164       if (avgholdsecs>0) {
01165          res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
01166          if (res && valid_exit(qe, res))
01167             goto playout;
01168 
01169          res = play_file(qe->chan, qe->parent->sound_seconds);
01170          if (res && valid_exit(qe, res))
01171             goto playout;
01172       }
01173 
01174    }
01175 
01176  posout:
01177    if (option_verbose > 2)
01178       ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
01179              qe->chan->name, qe->parent->name, qe->pos);
01180    res = play_file(qe->chan, qe->parent->sound_thanks);
01181 
01182  playout:
01183    /* Set our last_pos indicators */
01184    qe->last_pos = now;
01185    qe->last_pos_said = qe->pos;
01186    ast_moh_start(qe->chan, qe->moh);
01187 
01188    return res;
01189 }

static int set_member_paused char *  queuename,
char *  interface,
int  paused
[static]
 

Definition at line 2472 of file app_queue.c.

References ast_log(), ast_mutex_lock(), ast_queue_log(), ast_strlen_zero(), dump_queue_members(), EVENT_FLAG_AGENT, member::interface, interface_exists(), ast_call_queue::lock, LOG_DEBUG, manager_event(), ast_call_queue::name, ast_call_queue::next, member::paused, queue_persistent_members, and queues.

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

02473 {
02474    int found = 0;
02475    struct ast_call_queue *q;
02476    struct member *mem;
02477 
02478    /* Special event for when all queues are paused - individual events still generated */
02479 
02480    if (ast_strlen_zero(queuename))
02481       ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
02482 
02483    ast_mutex_lock(&qlock);
02484    for (q = queues ; q ; q = q->next) {
02485       ast_mutex_lock(&q->lock);
02486       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
02487          if ((mem = interface_exists(q, interface))) {
02488             found++;
02489             if (mem->paused == paused)
02490                ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
02491             mem->paused = paused;
02492 
02493             if (queue_persistent_members)
02494                dump_queue_members(q);
02495 
02496             ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
02497 
02498             manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
02499                "Queue: %s\r\n"
02500                "Location: %s\r\n"
02501                "Paused: %d\r\n",
02502                   q->name, mem->interface, paused);
02503          }
02504       }
02505       ast_mutex_unlock(&q->lock);
02506    }
02507    ast_mutex_unlock(&qlock);
02508 
02509    if (found)
02510       return RESULT_SUCCESS;
02511    else
02512       return RESULT_FAILURE;
02513 }

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

Definition at line 369 of file app_queue.c.

References pbx_builtin_setvar_helper(), queue_results, and text.

00370 {
00371    int i;
00372 
00373    for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
00374       if (queue_results[i].id == res) {
00375          pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
00376          return;
00377       }
00378    }
00379 }

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

Definition at line 504 of file app_queue.c.

References ast_log(), ast_pthread_create, changethread(), statechange::dev, free, LOG_WARNING, malloc, statechange::state, and t.

Referenced by load_module(), and unload_module().

00505 {
00506    /* Avoid potential for deadlocks by spawning a new thread to handle
00507       the event */
00508    struct statechange *sc;
00509    pthread_t t;
00510    pthread_attr_t attr;
00511 
00512    sc = malloc(sizeof(struct statechange) + strlen(dev) + 1);
00513    if (sc) {
00514       sc->state = state;
00515       strcpy(sc->dev, dev);
00516       pthread_attr_init(&attr);
00517       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00518       if (ast_pthread_create(&t, &attr, changethread, sc)) {
00519          ast_log(LOG_WARNING, "Failed to create update thread!\n");
00520          free(sc);
00521       }
00522    }
00523    return 0;
00524 }

static int store_next struct queue_ent qe,
struct localuser outgoing
[static]
 

Definition at line 1508 of file app_queue.c.

References ast_log(), localuser::chan, localuser::interface, LOG_DEBUG, localuser::metric, localuser::next, option_debug, queue_ent::parent, ast_call_queue::rrpos, localuser::stillgoing, and ast_call_queue::wrapped.

01509 {
01510    struct localuser *cur;
01511    struct localuser *best;
01512    int bestmetric=0;
01513 
01514    best = NULL;
01515    cur = outgoing;
01516    while(cur) {
01517       if (cur->stillgoing &&              /* Not already done */
01518          !cur->chan &&              /* Isn't already going */
01519          (!best || (cur->metric < bestmetric))) {  /* We haven't found one yet, or it's better */
01520             bestmetric = cur->metric;
01521             best = cur;
01522       }
01523       cur = cur->next;
01524    }
01525    if (best) {
01526       /* Ring just the best channel */
01527       if (option_debug)
01528          ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
01529       qe->parent->rrpos = best->metric % 1000;
01530    } else {
01531       /* Just increment rrpos */
01532       if (qe->parent->wrapped) {
01533          /* No more channels, start over */
01534          qe->parent->rrpos = 0;
01535       } else {
01536          /* Prioritize next entry */
01537          qe->parent->rrpos++;
01538       }
01539    }
01540    qe->parent->wrapped = 0;
01541    return 0;
01542 }

static int strat2int const char *  strategy  )  [static]
 

Definition at line 391 of file app_queue.c.

References name, and strategies.

Referenced by queue_set_param().

00392 {
00393    int x;
00394    for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
00395       if (!strcasecmp(strategy, strategies[x].name))
00396          return strategies[x].strategy;
00397    }
00398    return -1;
00399 }

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

Definition at line 2008 of file app_queue.c.

References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_REDIRECT, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_set_flag, queue_ent::parent, queue_ent::start, and ast_call_queue::timeout.

02009 {
02010    struct member *cur;
02011    struct localuser *outgoing=NULL, *tmp = NULL;
02012    int to;
02013    char restofit[AST_MAX_EXTENSION];
02014    char oldexten[AST_MAX_EXTENSION]="";
02015    char oldcontext[AST_MAX_CONTEXT]="";
02016    char queuename[256]="";
02017    char *newnum;
02018    char *monitorfilename;
02019    struct ast_channel *peer;
02020    struct ast_channel *which;
02021    struct localuser *lpeer;
02022    struct member *member;
02023    int res = 0, bridge = 0;
02024    int numbusies = 0;
02025    int x=0;
02026    char *announce = NULL;
02027    char digit = 0;
02028    time_t callstart;
02029    time_t now = time(NULL);
02030    struct ast_bridge_config bridge_config;
02031    char nondataquality = 1;
02032 
02033    memset(&bridge_config, 0, sizeof(bridge_config));
02034    time(&now);
02035       
02036    for (; options && *options; options++)
02037       switch (*options) {
02038       case 't':
02039          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
02040          break;
02041       case 'T':
02042          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
02043          break;
02044       case 'w':
02045          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
02046          break;
02047       case 'W':
02048          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
02049          break;
02050       case 'd':
02051          nondataquality = 0;
02052          break;
02053       case 'h':
02054          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
02055          break;
02056       case 'H':
02057          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
02058          break;
02059       case 'n':
02060          if ((now - qe->start >= qe->parent->timeout))
02061             *go_on = 1;
02062          break;
02063       }
02064 
02065    /* Hold the lock while we setup the outgoing calls */
02066    if (use_weight) 
02067       ast_mutex_lock(&qlock);
02068    ast_mutex_lock(&qe->parent->lock);
02069    if (option_debug)
02070       ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 
02071                      qe->chan->name);
02072    ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
02073    cur = qe->parent->members;
02074    if (!ast_strlen_zero(qe->announce))
02075       announce = qe->announce;
02076    if (!ast_strlen_zero(announceoverride))
02077       announce = announceoverride;
02078 
02079    while(cur) {
02080       tmp = malloc(sizeof(*tmp));
02081       if (!tmp) {
02082          ast_mutex_unlock(&qe->parent->lock);
02083          if (use_weight) 
02084             ast_mutex_unlock(&qlock);
02085          ast_log(LOG_WARNING, "Out of memory\n");
02086          goto out;
02087       }
02088       memset(tmp, 0, sizeof(*tmp));
02089       tmp->stillgoing = -1;
02090       if (option_debug) {
02091          if (url)
02092             ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
02093          else 
02094             ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
02095       }
02096 
02097       tmp->member = cur;      /* Never directly dereference!  Could change on reload */
02098       tmp->oldstatus = cur->status;
02099       tmp->lastcall = cur->lastcall;
02100       ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
02101       /* If we're dialing by extension, look at the extension to know what to dial */
02102       if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) {
02103          newnum++;
02104          strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
02105          snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
02106          if (option_debug)
02107             ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
02108       }
02109       /* Special case: If we ring everyone, go ahead and ring them, otherwise
02110          just calculate their metric for the appropriate strategy */
02111       calc_metric(qe->parent, cur, x++, qe, tmp);
02112       /* Put them in the list of outgoing thingies...  We're ready now. 
02113          XXX If we're forcibly removed, these outgoing calls won't get
02114          hung up XXX */
02115       tmp->next = outgoing;
02116       outgoing = tmp;      
02117       /* If this line is up, don't try anybody else */
02118       if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
02119          break;
02120 
02121       cur = cur->next;
02122    }
02123    if (qe->parent->timeout)
02124       to = qe->parent->timeout * 1000;
02125    else
02126       to = -1;
02127    ring_one(qe, outgoing, &numbusies);
02128    ast_mutex_unlock(&qe->parent->lock);
02129    if (use_weight) 
02130       ast_mutex_unlock(&qlock);
02131    lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT));
02132    ast_mutex_lock(&qe->parent->lock);
02133    if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
02134       store_next(qe, outgoing);
02135    }
02136    ast_mutex_unlock(&qe->parent->lock);
02137    if (lpeer)
02138       peer = lpeer->chan;
02139    else
02140       peer = NULL;
02141    if (!peer) {
02142       if (to) {
02143          /* Musta gotten hung up */
02144          res = -1;
02145       } else {
02146          res = digit;
02147       }
02148       if (option_debug)
02149          ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
02150       goto out;
02151    }
02152    if (peer) {
02153       /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
02154          we will always return with -1 so that it is hung up properly after the 
02155          conversation.  */
02156       qe->handled++;
02157       if (!strcmp(qe->chan->type,"Zap"))
02158          ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
02159       if (!strcmp(peer->type,"Zap"))
02160          ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
02161       /* Update parameters for the queue */
02162       recalc_holdtime(qe);
02163       member = lpeer->member;
02164       hangupcalls(outgoing, peer);
02165       outgoing = NULL;
02166       if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
02167          int res2;
02168          res2 = ast_autoservice_start(qe->chan);
02169          if (!res2) {
02170             if (qe->parent->memberdelay) {
02171                ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
02172                res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
02173             }
02174             if (!res2 && announce) {
02175                if (play_file(peer, announce))
02176                   ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
02177             }
02178             if (!res2 && qe->parent->reportholdtime) {
02179                if (!play_file(peer, qe->parent->sound_reporthold)) {
02180                   int holdtime;
02181 
02182                   time(&now);
02183                   holdtime = abs((now - qe->start) / 60);
02184                   if (holdtime < 2) {
02185                      play_file(peer, qe->parent->sound_lessthan);
02186                      ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
02187                   } else 
02188                      ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
02189                   play_file(peer, qe->parent->sound_minutes);
02190                }
02191             }
02192          }
02193          res2 |= ast_autoservice_stop(qe->chan);
02194          if (peer->_softhangup) {
02195             /* Agent must have hung up */
02196             ast_log(LOG_WARNING, "Agent on %s hungup on the customer.  They're going to be pissed.\n", peer->name);
02197             ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
02198             record_abandoned(qe);
02199             if (qe->parent->eventwhencalled) {
02200                manager_event(EVENT_FLAG_AGENT, "AgentDump",
02201                         "Queue: %s\r\n"
02202                         "Uniqueid: %s\r\n"
02203                         "Channel: %s\r\n"
02204                         "Member: %s\r\n",
02205                         queuename, qe->chan->uniqueid, peer->name, member->interface);
02206             }
02207             ast_hangup(peer);
02208             goto out;
02209          } else if (res2) {
02210             /* Caller must have hung up just before being connected*/
02211             ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
02212             ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02213             record_abandoned(qe);
02214             ast_hangup(peer);
02215             return -1;
02216          }
02217       }
02218       /* Stop music on hold */
02219       ast_moh_stop(qe->chan);
02220       /* If appropriate, log that we have a destination channel */
02221       if (qe->chan->cdr)
02222          ast_cdr_setdestchan(qe->chan->cdr, peer->name);
02223       /* Make sure channels are compatible */
02224       res = ast_channel_make_compatible(qe->chan, peer);
02225       if (res < 0) {
02226          ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
02227          ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
02228       record_abandoned(qe);
02229          ast_hangup(peer);
02230          return -1;
02231       }
02232       /* Begin Monitoring */
02233       if (qe->parent->monfmt && *qe->parent->monfmt) {
02234          monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
02235          if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
02236             which = qe->chan;
02237          else
02238             which = peer;
02239          if (monitorfilename)
02240             ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
02241          else if (qe->chan->cdr) 
02242             ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
02243          else {
02244             /* Last ditch effort -- no CDR, make up something */
02245             char tmpid[256];
02246             snprintf(tmpid, sizeof(tmpid), "chan-%x", rand());
02247             ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
02248          }
02249          if (qe->parent->monjoin)
02250             ast_monitor_setjoinfiles(which, 1);
02251       }
02252       /* Drop out of the queue at this point, to prepare for next caller */
02253       leave_queue(qe);        
02254       if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
02255          if (option_debug)
02256             ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
02257          ast_channel_sendurl(peer, url);
02258       }
02259       ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
02260       if (qe->parent->eventwhencalled)
02261          manager_event(EVENT_FLAG_AGENT, "AgentConnect",
02262                   "Queue: %s\r\n"
02263                   "Uniqueid: %s\r\n"
02264                   "Channel: %s\r\n"
02265                   "Member: %s\r\n"
02266                   "Holdtime: %ld\r\n",
02267                   queuename, qe->chan->uniqueid, peer->name, member->interface,
02268                   (long)time(NULL) - qe->start);
02269       ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
02270       ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
02271       time(&callstart);
02272 
02273       bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
02274 
02275       if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
02276          ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
02277       } else if (qe->chan->_softhangup) {
02278          ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
02279                   (long)(callstart - qe->start), (long)(time(NULL) - callstart));
02280          if (qe->parent->eventwhencalled)
02281             manager_event(EVENT_FLAG_AGENT, "AgentComplete",
02282                      "Queue: %s\r\n"
02283                      "Uniqueid: %s\r\n"
02284                      "Channel: %s\r\n"
02285                      "Member: %s\r\n"
02286                      "HoldTime: %ld\r\n"
02287                      "TalkTime: %ld\r\n"
02288                      "Reason: caller\r\n",
02289                      queuename, qe->chan->uniqueid, peer->name, member->interface,
02290                      (long)(callstart - qe->start), (long)(time(NULL) - callstart));
02291       } else {
02292          ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
02293          if (qe->parent->eventwhencalled)
02294             manager_event(EVENT_FLAG_AGENT, "AgentComplete",
02295                      "Queue: %s\r\n"
02296                      "Uniqueid: %s\r\n"
02297                      "Channel: %s\r\n"
02298                      "HoldTime: %ld\r\n"
02299                      "TalkTime: %ld\r\n"
02300                      "Reason: agent\r\n",
02301                      queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start),
02302                      (long)(time(NULL) - callstart));
02303       }
02304 
02305       if(bridge != AST_PBX_NO_HANGUP_PEER)
02306          ast_hangup(peer);
02307       update_queue(qe->parent, member);
02308       if (bridge == 0) 
02309          res = 1; /* JDG: bridge successfull, leave app_queue */
02310       else 
02311          res = bridge; /* bridge error, stay in the queue */
02312    }  
02313 out:
02314    hangupcalls(outgoing, NULL);
02315    return res;
02316 }

int unload_module void   ) 
 

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
Zero on success, or non-zero on error.

Definition at line 3792 of file app_queue.c.

References app, app_aqm, app_pqm, app_rqm, app_upqm, ast_cli_unregister(), ast_custom_function_unregister(), ast_devstate_del(), ast_manager_unregister(), ast_unregister_application(), cli_add_queue_member, cli_remove_queue_member, cli_show_queue, cli_show_queues, queueagentcount_function, STANDARD_HANGUP_LOCALUSERS, and statechange_queue().

03793 {
03794    int res;
03795 
03796    res = ast_cli_unregister(&cli_show_queue);
03797    res |= ast_cli_unregister(&cli_show_queues);
03798    res |= ast_cli_unregister(&cli_add_queue_member);
03799    res |= ast_cli_unregister(&cli_remove_queue_member);
03800    res |= ast_manager_unregister("Queues");
03801    res |= ast_manager_unregister("QueueStatus");
03802    res |= ast_manager_unregister("QueueAdd");
03803    res |= ast_manager_unregister("QueueRemove");
03804    res |= ast_manager_unregister("QueuePause");
03805    ast_devstate_del(statechange_queue, NULL);
03806    res |= ast_unregister_application(app_aqm);
03807    res |= ast_unregister_application(app_rqm);
03808    res |= ast_unregister_application(app_pqm);
03809    res |= ast_unregister_application(app_upqm);
03810    res |= ast_custom_function_unregister(&queueagentcount_function);
03811    res |= ast_unregister_application(app);
03812 
03813    STANDARD_HANGUP_LOCALUSERS;
03814 
03815    return res;
03816 }

static int update_dial_status struct ast_call_queue q,
struct member member,
int  status
[static]
 

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

01302 {
01303    if (status == AST_CAUSE_BUSY)
01304       status = AST_DEVICE_BUSY;
01305    else if (status == AST_CAUSE_UNREGISTERED)
01306       status = AST_DEVICE_UNAVAILABLE;
01307    else if (status == AST_CAUSE_NOSUCHDRIVER)
01308       status = AST_DEVICE_INVALID;
01309    else
01310       status = AST_DEVICE_UNKNOWN;
01311    return update_status(q, member, status);
01312 }

static int update_queue struct ast_call_queue q,
struct member member
[static]
 

Definition at line 1935 of file app_queue.c.

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

01936 {
01937    struct member *cur;
01938 
01939    /* Since a reload could have taken place, we have to traverse the list to
01940       be sure it's still valid */
01941    ast_mutex_lock(&q->lock);
01942    cur = q->members;
01943    while(cur) {
01944       if (member == cur) {
01945          time(&cur->lastcall);
01946          cur->calls++;
01947          break;
01948       }
01949       cur = cur->next;
01950    }
01951    q->callscompleted++;
01952    ast_mutex_unlock(&q->lock);
01953    return 0;
01954 }

static int update_status struct ast_call_queue q,
struct member member,
int  status
[static]
 

Definition at line 1269 of file app_queue.c.

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

Referenced by update_dial_status().

01270 {
01271    struct member *cur;
01272 
01273    /* Since a reload could have taken place, we have to traverse the list to
01274       be sure it's still valid */
01275    ast_mutex_lock(&q->lock);
01276    cur = q->members;
01277    while(cur) {
01278       if (member == cur) {
01279          cur->status = status;
01280          if (!q->maskmemberstatus) {
01281             manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
01282                "Queue: %s\r\n"
01283                "Location: %s\r\n"
01284                "Membership: %s\r\n"
01285                "Penalty: %d\r\n"
01286                "CallsTaken: %d\r\n"
01287                "LastCall: %d\r\n"
01288                "Status: %d\r\n"
01289                "Paused: %d\r\n",
01290             q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
01291             cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
01292          }
01293          break;
01294       }
01295       cur = cur->next;
01296    }
01297    ast_mutex_unlock(&q->lock);
01298    return 0;
01299 }

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

Definition at line 2661 of file app_queue.c.

References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), localuser::chan, ast_channel::context, localuser::interface, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, option_priority_jumping, parse(), pbx_builtin_setvar_helper(), and set_member_paused().

Referenced by load_module().

02662 {
02663    struct localuser *u;
02664    char *parse;
02665    int priority_jump = 0;
02666    AST_DECLARE_APP_ARGS(args,
02667       AST_APP_ARG(queuename);
02668       AST_APP_ARG(interface);
02669       AST_APP_ARG(options);
02670    );
02671 
02672    if (ast_strlen_zero(data)) {
02673       ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
02674       return -1;
02675    }
02676 
02677    LOCAL_USER_ADD(u);
02678 
02679    if (!(parse = ast_strdupa(data))) {
02680       ast_log(LOG_WARNING, "Memory Error!\n");
02681       LOCAL_USER_REMOVE(u);
02682       return -1;
02683    }
02684 
02685    AST_STANDARD_APP_ARGS(args, parse);
02686 
02687    if (args.options) {
02688       if (strchr(args.options, 'j'))
02689          priority_jump = 1;
02690    }
02691 
02692    if (ast_strlen_zero(args.interface)) {
02693       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
02694       LOCAL_USER_REMOVE(u);
02695       return -1;
02696    }
02697 
02698    if (set_member_paused(args.queuename, args.interface, 0)) {
02699       ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
02700       if (priority_jump || option_priority_jumping) {
02701          if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
02702             pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
02703             LOCAL_USER_REMOVE(u);
02704             return 0;
02705          }
02706       }
02707       LOCAL_USER_REMOVE(u);
02708       pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
02709       return -1;
02710    }
02711 
02712    LOCAL_USER_REMOVE(u);
02713    pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
02714    return 0;
02715 }

int usecount void   ) 
 

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
The module's usecount.

Definition at line 3860 of file app_queue.c.

References STANDARD_USECOUNT.

03861 {
03862    int res;
03863    STANDARD_USECOUNT(res);
03864    return res;
03865 }

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

Definition at line 1059 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, and queue_ent::digits.

Referenced by background_file(), queue_exec(), say_position(), and wait_for_answer().

01060 {
01061    int digitlen = strlen(qe->digits);
01062 
01063    /* Prevent possible buffer overflow */
01064    if (digitlen < sizeof(qe->digits) - 2) {
01065       qe->digits[digitlen] = digit;
01066       qe->digits[digitlen + 1] = '\0';
01067    } else {
01068       qe->digits[0] = '\0';
01069       return 0;
01070    }
01071 
01072    /* If there's no context to goto, short-circuit */
01073    if (ast_strlen_zero(qe->context))
01074       return 0;
01075 
01076    /* If the extension is bad, then reset the digits to blank */
01077    if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
01078       qe->digits[0] = '\0';
01079       return 0;
01080    }
01081 
01082    /* We have an exact match */
01083    if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
01084       /* Return 1 on a successful goto */
01085       return 1;
01086    }
01087    return 0;
01088 }

static int wait_a_bit struct queue_ent qe  )  [static]
 

Definition at line 2318 of file app_queue.c.

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

02319 {
02320    /* Don't need to hold the lock while we setup the outgoing calls */
02321    int retrywait = qe->parent->retry * 1000;
02322 
02323    return ast_waitfordigit(qe->chan, retrywait);
02324 }

static struct localuser* wait_for_answer struct queue_ent qe,
struct localuser outgoing,
int *  to,
char *  digit,
int  prebusies,
int  caller_disconnect
[static]
 

Definition at line 1631 of file app_queue.c.

References ast_channel::_state, ast_channel::accountcode, ast_call(), ast_cdr_busy(), 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_FRAME_VOICE, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_WATCHERS, ast_read(), ast_request(), AST_STATE_UP, ast_strlen_zero(), ast_verbose(), ast_waitfor_n(), BUILD_WATCHERS, ast_channel::call_forward, ast_channel::cdr, ast_channel::cdrflags, localuser::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, ast_channel::exten, ast_frame::frametype, free, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_channel::macroexten, malloc, localuser::member, ast_channel::name, ast_call_queue::name, ast_channel::nativeformats, localuser::next, localuser::oldstatus, option_verbose, queue_ent::parent, ring_one(), localuser::stillgoing, ast_call_queue::strategy, strdup, ast_frame::subclass, ast_channel::tech, ast_call_queue::timeoutrestart, update_dial_status(), valid_exit(), and VERBOSE_PREFIX_3.

01632 {
01633    char *queue = qe->parent->name;
01634    struct localuser *o;
01635    int found;
01636    int numlines;
01637    int status;
01638    int sentringing = 0;
01639    int numbusies = prebusies;
01640    int numnochan = 0;
01641    int stillgoing = 0;
01642    int orig = *to;
01643    struct ast_frame *f;
01644    struct localuser *peer = NULL;
01645    struct ast_channel *watchers[AST_MAX_WATCHERS];
01646    int pos;
01647    struct ast_channel *winner;
01648    struct ast_channel *in = qe->chan;
01649    
01650    while(*to && !peer) {
01651       BUILD_WATCHERS;
01652       if ((found < 0) && stillgoing && !qe->parent->strategy) {
01653          /* On "ringall" strategy we only move to the next penalty level
01654             when *all* ringing phones are done in the current penalty level */
01655          ring_one(qe, outgoing, &numbusies);
01656          BUILD_WATCHERS;
01657       }
01658       if (found < 0) {
01659          if (numlines == (numbusies + numnochan)) {
01660             ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
01661          } else {
01662             ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
01663          }
01664          *to = 0;
01665          return NULL;
01666       }
01667       winner = ast_waitfor_n(watchers, pos, to);
01668       o = outgoing;
01669       while(o) {
01670          if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
01671             if (!peer) {
01672                if (option_verbose > 2)
01673                   ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
01674                peer = o;
01675             }
01676          } else if (o->chan && (o->chan == winner)) {
01677             if (!ast_strlen_zero(o->chan->call_forward)) {
01678                char tmpchan[256]="";
01679                char *stuff;
01680                char *tech;
01681                ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
01682                if ((stuff = strchr(tmpchan, '/'))) {
01683                   *stuff = '\0';
01684                   stuff++;
01685                   tech = tmpchan;
01686                } else {
01687                   snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
01688                   stuff = tmpchan;
01689                   tech = "Local";
01690                }
01691                /* Before processing channel, go ahead and check for forwarding */
01692                if (option_verbose > 2)
01693                   ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
01694                /* Setup parameters */
01695                o->chan = ast_request(tech, in->nativeformats, stuff, &status);
01696                if (status != o->oldstatus) 
01697                   update_dial_status(qe->parent, o->member, status);                
01698                if (!o->chan) {
01699                   ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
01700                   o->stillgoing = 0;
01701                   numnochan++;
01702                } else {
01703                   if (o->chan->cid.cid_num)
01704                      free(o->chan->cid.cid_num);
01705                   o->chan->cid.cid_num = NULL;
01706                   if (o->chan->cid.cid_name)
01707                      free(o->chan->cid.cid_name);
01708                   o->chan->cid.cid_name = NULL;
01709 
01710                   if (in->cid.cid_num) {
01711                      o->chan->cid.cid_num = strdup(in->cid.cid_num);
01712                      if (!o->chan->cid.cid_num)
01713                         ast_log(LOG_WARNING, "Out of memory\n");  
01714                   }
01715                   if (in->cid.cid_name) {
01716                      o->chan->cid.cid_name = strdup(in->cid.cid_name);
01717                      if (!o->chan->cid.cid_name)
01718                         ast_log(LOG_WARNING, "Out of memory\n");  
01719                   }
01720                   ast_copy_string(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode));
01721                   o->chan->cdrflags = in->cdrflags;
01722 
01723                   if (in->cid.cid_ani) {
01724                      if (o->chan->cid.cid_ani)
01725                         free(o->chan->cid.cid_ani);
01726                      o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1);
01727                      if (o->chan->cid.cid_ani)
01728                         strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
01729                      else
01730                         ast_log(LOG_WARNING, "Out of memory\n");
01731                   }
01732                   if (o->chan->cid.cid_rdnis) 
01733                      free(o->chan->cid.cid_rdnis);
01734                   if (!ast_strlen_zero(in->macroexten))
01735                      o->chan->cid.cid_rdnis = strdup(in->macroexten);
01736                   else
01737                      o->chan->cid.cid_rdnis = strdup(in->exten);
01738                   if (ast_call(o->chan, tmpchan, 0)) {
01739                      ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
01740                      o->stillgoing = 0;
01741                      ast_hangup(o->chan);
01742                      o->chan = NULL;
01743                      numnochan++;
01744                   }
01745                }
01746                /* Hangup the original channel now, in case we needed it */
01747                ast_hangup(winner);
01748                continue;
01749             }
01750             f = ast_read(winner);
01751             if (f) {
01752                if (f->frametype == AST_FRAME_CONTROL) {
01753                   switch(f->subclass) {
01754                   case AST_CONTROL_ANSWER:
01755                      /* This is our guy if someone answered. */
01756                      if (!peer) {
01757                         if (option_verbose > 2)
01758                            ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
01759                         peer = o;
01760                      }
01761                      break;
01762                   case AST_CONTROL_BUSY:
01763                      if (option_verbose > 2)
01764                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
01765                      o->stillgoing = 0;
01766                      if (in->cdr)
01767                         ast_cdr_busy(in->cdr);
01768                      ast_hangup(o->chan);
01769                      o->chan = NULL;
01770                      if (qe->parent->strategy) {
01771                         if (qe->parent->timeoutrestart)
01772                            *to = orig;
01773                         ring_one(qe, outgoing, &numbusies);
01774                      }
01775                      numbusies++;
01776                      break;
01777                   case AST_CONTROL_CONGESTION:
01778                      if (option_verbose > 2)
01779                         ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
01780                      o->stillgoing = 0;
01781                      if (in->cdr)
01782                         ast_cdr_busy(in->cdr);
01783                      ast_hangup(o->chan);
01784                      o->chan = NULL;
01785                      if (qe->parent->strategy) {
01786                         if (qe->parent->timeoutrestart)
01787                            *to = orig;
01788                         ring_one(qe, outgoing, &numbusies);
01789                      }
01790                      numbusies++;
01791                      break;
01792                   case AST_CONTROL_RINGING:
01793                      if (option_verbose > 2)
01794                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
01795                      if (!sentringing) {
01796 #if 0
01797                         ast_indicate(in, AST_CONTROL_RINGING);
01798 #endif                        
01799                         sentringing++;
01800                      }
01801                      break;
01802                   case AST_CONTROL_OFFHOOK:
01803                      /* Ignore going off hook */
01804                      break;
01805                   default:
01806                      ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
01807                   }
01808                }
01809                ast_frfree(f);
01810             } else {
01811                o->stillgoing = 0;
01812                ast_hangup(o->chan);
01813                o->chan = NULL;
01814                if (qe->parent->strategy) {
01815                   if (qe->parent->timeoutrestart)
01816                      *to = orig;
01817                   ring_one(qe, outgoing, &numbusies);
01818                }
01819             }
01820          }
01821          o = o->next;
01822       }
01823       if (winner == in) {
01824          f = ast_read(in);
01825 #if 0
01826          if (f && (f->frametype != AST_FRAME_VOICE))
01827                printf("Frame type: %d, %d\n", f->frametype, f->subclass);
01828          else if (!f || (f->frametype != AST_FRAME_VOICE))
01829             printf("Hangup received on %s\n", in->name);
01830 #endif
01831          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
01832             /* Got hung up */
01833             *to=-1;
01834             if (f)
01835                ast_frfree(f);
01836             return NULL;
01837          }
01838          if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
01839             if (option_verbose > 3)
01840                ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
01841             *to=0;
01842             ast_frfree(f);
01843             return NULL;
01844          }
01845          if ((f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
01846             if (option_verbose > 3)
01847                ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
01848             *to=0;
01849             *digit=f->subclass;
01850             ast_frfree(f);
01851             return NULL;
01852          }
01853          ast_frfree(f);
01854       }
01855       if (!*to && (option_verbose > 2))
01856          ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
01857    }
01858 
01859    return peer;
01860    
01861 }

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

Definition at line 1883 of file app_queue.c.

References ast_queue_log(), is_our_turn(), and QUEUE_TIMEOUT.

Referenced by queue_exec().

01884 {
01885    int res = 0;
01886 
01887    /* This is the holding pen for callers 2 through maxlen */
01888    for (;;) {
01889       enum queue_member_status stat;
01890 
01891       if (is_our_turn(qe))
01892          break;
01893 
01894       /* If we have timed out, break out */
01895       if (qe->expire && (time(NULL) > qe->expire)) {
01896          *reason = QUEUE_TIMEOUT;
01897          ast_queue_log(qe->parent->name, qe->chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe->pos);
01898          break;
01899       }
01900 
01901       stat = get_member_status(qe->parent);
01902 
01903       /* leave the queue if no agents, if enabled */
01904       if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
01905          *reason = QUEUE_LEAVEEMPTY;
01906          leave_queue(qe);
01907          break;
01908       }
01909 
01910       /* leave the queue if no reachable agents, if enabled */
01911       if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
01912          *reason = QUEUE_LEAVEUNAVAIL;
01913          leave_queue(qe);
01914          break;
01915       }
01916 
01917       /* Make a position announcement, if enabled */
01918       if (qe->parent->announcefrequency && !ringing)
01919          res = say_position(qe);
01920       if (res)
01921          break;
01922 
01923       /* Make a periodic announcement, if enabled */
01924       if (qe->parent->periodicannouncefrequency && !ringing)
01925          res = say_periodic_announcement(qe);
01926 
01927       /* Wait a second before checking again */
01928       if (!res) res = ast_waitfordigit(qe->chan, RECHECK * 1000);
01929       if (res)
01930          break;
01931    }
01932    return res;
01933 }


Variable Documentation

char* app = "Queue" [static]
 

Definition at line 123 of file app_queue.c.

char* app_aqm = "AddQueueMember" [static]
 

Definition at line 153 of file app_queue.c.

Referenced by load_module(), and unload_module().

char* app_aqm_descrip [static]
 

Definition at line 155 of file app_queue.c.

Referenced by load_module().

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

Definition at line 154 of file app_queue.c.

Referenced by load_module().

char* app_pqm = "PauseQueueMember" [static]
 

Definition at line 185 of file app_queue.c.

Referenced by load_module(), and unload_module().

char* app_pqm_descrip [static]
 

Definition at line 187 of file app_queue.c.

Referenced by load_module().

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

Definition at line 186 of file app_queue.c.

Referenced by load_module().

char* app_rqm = "RemoveQueueMember" [static]
 

Definition at line 169 of file app_queue.c.

Referenced by load_module(), and unload_module().

char* app_rqm_descrip [static]
 

Definition at line 171 of file app_queue.c.

Referenced by load_module().

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

Definition at line 170 of file app_queue.c.

Referenced by load_module().

char* app_upqm = "UnpauseQueueMember" [static]
 

Definition at line 207 of file app_queue.c.

Referenced by load_module(), and unload_module().

char* app_upqm_descrip [static]
 

Definition at line 209 of file app_queue.c.

Referenced by load_module().

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

Definition at line 208 of file app_queue.c.

Referenced by load_module().

char aqm_cmd_usage[] [static]
 

Initial value:

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

Definition at line 3778 of file app_queue.c.

struct ast_cli_entry cli_add_queue_member [static]
 

Initial value:

 {
   { "add", "queue", "member", NULL }, handle_add_queue_member,
   "Add a channel to a specified queue", aqm_cmd_usage, complete_add_queue_member }

Definition at line 3781 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry cli_remove_queue_member [static]
 

Initial value:

 {
   { "remove", "queue", "member", NULL }, handle_remove_queue_member,
   "Removes a channel from a specified queue", rqm_cmd_usage, complete_remove_queue_member }

Definition at line 3788 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry cli_show_queue [static]
 

Initial value:

 {
   { "show", "queue", NULL }, queue_show, 
   "Show status of a specified queue", show_queue_usage, complete_queue }

Definition at line 3774 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry cli_show_queues [static]
 

Initial value:

 {
   { "show", "queues", NULL }, queues_show, 
   "Show status of queues", show_queues_usage, NULL }

Definition at line 3766 of file app_queue.c.

Referenced by load_module(), and unload_module().

char* descrip [static]
 

Definition at line 127 of file app_queue.c.

enum queue_result id
 

Definition at line 244 of file app_queue.c.

Referenced by _sip_show_peers(), aPGSQL_clear(), aPGSQL_connect(), aPGSQL_disconnect(), aPGSQL_fetch(), aPGSQL_query(), aPGSQL_reset(), config_odbc(), and manager_iax2_show_peers().

LOCAL_USER_DECL
 

Definition at line 271 of file app_queue.c.

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

Persistent Members astdb family.

Definition at line 223 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

int queue_persistent_members = 0 [static]
 

queues.conf [general] option

Definition at line 228 of file app_queue.c.

Referenced by aqm_exec(), handle_add_queue_member(), load_module(), manager_add_queue_member(), reload_queues(), and set_member_paused().

const { ... } queue_results[]
 

Referenced by set_queue_result().

struct ast_custom_function queueagentcount_function [static]
 

Definition at line 3151 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_call_queue* queues = NULL [static]
 

Definition at line 366 of file app_queue.c.

Referenced by __queues_show(), changethread(), compare_weight(), complete_queue(), complete_remove_queue_member(), find_queue_by_name_rt(), load_realtime_queue(), manager_queues_status(), queue_function_qac(), reload_queue_members(), reload_queues(), remove_from_queue(), remove_queue(), and set_member_paused().

char rqm_cmd_usage[] [static]
 

Initial value:

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

Definition at line 3785 of file app_queue.c.

char show_queue_usage[] [static]
 

Initial value:

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

Definition at line 3770 of file app_queue.c.

char show_queues_usage[] [static]
 

Initial value:

 
"Usage: show queues\n"
"       Provides summary information on call queues.\n"

Definition at line 3762 of file app_queue.c.

struct strategy strategies[] [static]
 

Referenced by int2strat(), and strat2int().

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

Definition at line 125 of file app_queue.c.

char* tdesc = "True Call Queueing" [static]
 

Definition at line 121 of file app_queue.c.

char* text
 

Definition at line 245 of file app_queue.c.

Referenced by _sip_show_peer(), build_reply_digest(), check_auth(), find_sip_method(), handle_response(), 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 231 of file app_queue.c.

Referenced by queue_set_param(), and ring_entry().


Generated on Sat Mar 24 23:26:34 2007 for Asterisk - the Open Source PBX by  doxygen 1.4.6