Mon Mar 20 08:20:15 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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"

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

int __queues_show (int manager, int fd, int argc, char **argv, int queue_show)
int add_to_queue (char *queuename, char *interface, int penalty, int paused, int dump)
ast_call_queuealloc_queue (const char *queuename)
int aqm_exec (struct ast_channel *chan, void *data)
 AST_MUTEX_DEFINE_STATIC (qlock)
int background_file (struct queue_ent *qe, struct ast_channel *chan, char *filename)
int calc_metric (struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
void * changethread (void *data)
void clear_queue (struct ast_call_queue *q)
int compare_weight (struct ast_call_queue *rq, struct member *member)
char * complete_add_queue_member (char *line, char *word, int pos, int state)
char * complete_queue (char *line, char *word, int pos, int state)
char * complete_remove_queue_member (char *line, char *word, int pos, int state)
membercreate_queue_member (char *interface, int penalty, int paused)
char * description (void)
 Provides a description of the module.
void destroy_queue (struct ast_call_queue *q)
void dump_queue_members (struct ast_call_queue *pm_queue)
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.
void free_members (struct ast_call_queue *q, int all)
enum queue_member_status get_member_status (const struct ast_call_queue *q)
int handle_add_queue_member (int fd, int argc, char *argv[])
int handle_remove_queue_member (int fd, int argc, char *argv[])
void hangupcalls (struct localuser *outgoing, struct ast_channel *exception)
void init_queue (struct ast_call_queue *q)
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'.
char * int2strat (int strategy)
memberinterface_exists (struct ast_call_queue *q, char *interface)
int is_our_turn (struct queue_ent *qe)
int join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason)
char * key ()
 Returns the ASTERISK_GPL_KEY.
void leave_queue (struct queue_ent *qe)
int load_module (void)
 Initialize the module.
ast_call_queueload_realtime_queue (char *queuename)
int manager_add_queue_member (struct mansession *s, struct message *m)
int manager_pause_queue_member (struct mansession *s, struct message *m)
int manager_queues_show (struct mansession *s, struct message *m)
int manager_queues_status (struct mansession *s, struct message *m)
int manager_remove_queue_member (struct mansession *s, struct message *m)
int play_file (struct ast_channel *chan, char *filename)
int pqm_exec (struct ast_channel *chan, void *data)
int queue_exec (struct ast_channel *chan, void *data)
char * queue_function_qac (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
void queue_set_param (struct ast_call_queue *q, const char *param, const char *val, int linenum, int failunknown)
 Configure a queue parameter.
int queue_show (int fd, int argc, char **argv)
int queues_show (int fd, int argc, char **argv)
void recalc_holdtime (struct queue_ent *qe)
void record_abandoned (struct queue_ent *qe)
int reload (void)
 Reload stuff.
void reload_queue_members (void)
void reload_queues (void)
int remove_from_queue (char *queuename, char *interface)
void remove_queue (struct ast_call_queue *q)
int ring_entry (struct queue_ent *qe, struct localuser *tmp, int *busies)
int ring_one (struct queue_ent *qe, struct localuser *outgoing, int *busies)
int rqm_exec (struct ast_channel *chan, void *data)
void rt_handle_member_record (struct ast_call_queue *q, char *interface, const char *penalty_str)
int say_periodic_announcement (struct queue_ent *qe)
int say_position (struct queue_ent *qe)
int set_member_paused (char *queuename, char *interface, int paused)
void set_queue_result (struct ast_channel *chan, enum queue_result res)
int statechange_queue (const char *dev, int state, void *ign)
int store_next (struct queue_ent *qe, struct localuser *outgoing)
int strat2int (const char *strategy)
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.
int update_dial_status (struct ast_call_queue *q, struct member *member, int status)
int update_queue (struct ast_call_queue *q, struct member *member)
int update_status (struct ast_call_queue *q, struct member *member, int status)
int upqm_exec (struct ast_channel *chan, void *data)
int usecount (void)
 Provides a usecount.
int valid_exit (struct queue_ent *qe, char digit)
int wait_a_bit (struct queue_ent *qe)
localuserwait_for_answer (struct queue_ent *qe, struct localuser *outgoing, int *to, char *digit, int prebusies, int caller_disconnect)
int wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason)

Variables

char * app = "Queue"
char * app_aqm = "AddQueueMember"
char * app_aqm_descrip
char * app_aqm_synopsis = "Dynamically adds queue members"
char * app_pqm = "PauseQueueMember"
char * app_pqm_descrip
char * app_pqm_synopsis = "Pauses a queue member"
char * app_rqm = "RemoveQueueMember"
char * app_rqm_descrip
char * app_rqm_synopsis = "Dynamically removes queue members"
char * app_upqm = "UnpauseQueueMember"
char * app_upqm_descrip
char * app_upqm_synopsis = "Unpauses a queue member"
char aqm_cmd_usage []
ast_cli_entry cli_add_queue_member
ast_cli_entry cli_remove_queue_member
ast_cli_entry cli_show_queue
ast_cli_entry cli_show_queues
char * descrip
 LOCAL_USER_DECL
const char * pm_family = "/Queue/PersistentMembers"
 Persistent Members astdb family.
int queue_persistent_members = 0
 queues.conf [general] option
struct {
   char *   text
queue_results []
ast_custom_function queueagentcount_function
ast_call_queuequeues = NULL
char rqm_cmd_usage []
char show_queue_usage []
char show_queues_usage []
strategy strategies []
char * synopsis = "Queue a call for a call queue"
char * tdesc = "True Call Queueing"
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.

#define ANNOUNCEHOLDTIME_ONCE   2
 

Definition at line 309 of file app_queue.c.

#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.

#define DEFAULT_RETRY   5
 

Definition at line 112 of file app_queue.c.

#define DEFAULT_TIMEOUT   15
 

Definition at line 113 of file app_queue.c.

#define PM_MAX_LEN   2048
 

Definition at line 225 of file app_queue.c.

Referenced by reload_queue_members().

#define QUEUE_EMPTY_NORMAL   1
 

Definition at line 306 of file app_queue.c.

#define QUEUE_EMPTY_STRICT   2
 

Definition at line 307 of file app_queue.c.

#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.

Referenced by wait_our_turn().

#define RES_EXISTS   (-1)
 

Definition at line 117 of file app_queue.c.

Referenced by 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 aqm_exec(), handle_add_queue_member(), handle_remove_queue_member(), manager_add_queue_member(), manager_remove_queue_member(), and rqm_exec().

#define RES_OKAY   0
 

Definition at line 116 of file app_queue.c.

Referenced by 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 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
 

Enumeration values:
QUEUE_NO_MEMBERS 
QUEUE_NO_REACHABLE_MEMBERS 
QUEUE_NORMAL 

Definition at line 421 of file app_queue.c.

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

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

enum queue_result
 

Enumeration values:
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 

Definition at line 233 of file app_queue.c.

Referenced by queue_exec().

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

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

Definition at line 3282 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, queue_show(), 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().

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

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, and member::status.

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

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 }

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 find_queue_by_name_rt(), and 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 }

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(), ast_channel::context, ast_channel::exten, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::name, pbx_builtin_setvar_helper(), ast_channel::priority, 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   ) 
 

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(), 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 }

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.

Referenced by try_calling().

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 }

void* changethread void *  data  )  [static]
 

Definition at line 453 of file app_queue.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, member::calls, statechange::dev, devstate2str(), member::dynamic, EVENT_FLAG_AGENT, free, member::interface, member::lastcall, ast_call_queue::lock, LOG_DEBUG, manager_event(), ast_call_queue::maskmemberstatus, ast_call_queue::members, ast_call_queue::name, member::next, ast_call_queue::next, member::paused, member::penalty, 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 }

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 find_queue_by_name_rt(), and reload_queues().

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

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, 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 }

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

Definition at line 3658 of file app_queue.c.

References complete_queue(), malloc, and strdup.

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

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

Definition at line 3389 of file app_queue.c.

References ast_mutex_lock(), ast_mutex_unlock(), ast_call_queue::name, ast_call_queue::next, and strdup.

Referenced by complete_add_queue_member(), and complete_remove_queue_member().

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

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

Definition at line 3726 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.

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

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(), member::interface, LOG_WARNING, malloc, member::paused, member::penalty, and member::status.

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

03858 {
03859    return tdesc;
03860 }

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 find_queue_by_name_rt(), leave_queue(), and reload_queues().

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

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, and pm_family.

Referenced by add_to_queue(), remove_from_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 }

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.

Note:
Hmm, can't seem to distinguish a DB failure from a not found condition... So we might delete an in-core queue in case of DB failure.

Definition at line 804 of file app_queue.c.

References alloc_queue(), ast_category_browse(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_variable_retrieve(), clear_queue(), ast_call_queue::count, member::dead, ast_call_queue::dead, destroy_queue(), member::dynamic, free, init_queue(), ast_call_queue::lock, LOG_DEBUG, ast_call_queue::members, ast_variable::name, ast_call_queue::name, member::next, ast_variable::next, ast_call_queue::next, queue_set_param(), queues, ast_call_queue::realtime, rt_handle_member_record(), and ast_variable::value.

Referenced by load_realtime_queue().

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 }

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 }

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_member_status, result, and member::status.

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

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 }

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

Definition at line 3611 of file app_queue.c.

References add_to_queue(), ast_cli(), queue_persistent_members, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.

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

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

Definition at line 3695 of file app_queue.c.

References ast_cli(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY.

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

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.

Referenced by try_calling().

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 }

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, 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 find_queue_by_name_rt(), and 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 }

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 }

char* int2strat int  strategy  )  [static]
 

Definition at line 381 of file app_queue.c.

References strategy::name, strategies, and strategy::strategy.

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 }

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 }

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, and queue_ent::parent.

Referenced by queue_exec(), and 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 }

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

Definition at line 976 of file app_queue.c.

References ast_call_queue::announce, 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, ast_call_queue::context, 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, ast_call_queue::moh, queue_ent::moh, ast_call_queue::name, ast_channel::name, queue_ent::next, queue_ent::pos, queue_ent::prio, and queue_member_status.

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

03870 {
03871    return ASTERISK_GPL_KEY;
03872 }

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().

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

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 3820 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(), queueagentcount_function, reload_queue_members(), reload_queues(), rqm_exec(), statechange_queue(), synopsis, and upqm_exec().

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

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_config_destroy(), ast_load_realtime(), ast_load_realtime_multientry(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_variables_destroy(), find_queue_by_name_rt(), LOG_ERROR, ast_call_queue::name, and ast_call_queue::next.

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) {
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 }

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

Definition at line 3507 of file app_queue.c.

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

Referenced by load_module().

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

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

Definition at line 3584 of file app_queue.c.

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

Referenced by load_module().

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

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

Definition at line 3408 of file app_queue.c.

References __queues_show(), ast_cli(), mansession::fd, and s.

Referenced by load_module().

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

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

Definition at line 3418 of file app_queue.c.

References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), member::calls, ast_call_queue::callsabandoned, ast_call_queue::callscompleted, ast_call_queue::callscompletedinsl, queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_call_queue::count, member::dynamic, mansession::fd, ast_call_queue::head, ast_call_queue::holdtime, member::interface, member::lastcall, 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, s, ast_call_queue::servicelevel, queue_ent::start, member::status, and ast_call_queue::weight.

Referenced by load_module().

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

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

Definition at line 3555 of file app_queue.c.

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

Referenced by load_module().

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

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(), and ast_channel::language.

Referenced by say_position(), and try_calling().

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 }

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(), ast_channel::context, ast_channel::exten, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, pbx_builtin_setvar_helper(), ast_channel::priority, 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 }

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_moh_stop(), ast_queue_log(), ast_stopstream(), ast_strlen_zero(), ast_verbose(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, queue_ent::expire, get_member_status(), is_our_turn(), join_queue(), leave_queue(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_debug, option_verbose, pbx_builtin_getvar_helper(), queue_member_status, queue_result, record_abandoned(), say_periodic_announcement(), say_position(), set_queue_result(), queue_ent::start, strsep(), try_calling(), ast_channel::uniqueid, valid_exit(), VERBOSE_PREFIX_3, wait_a_bit(), 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                res = -1;
02958             }
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                   res = -1;
03056                }
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                   res = -1;
03068                }
03069                ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
03070                                         record_abandoned(&qe);
03071                reason = QUEUE_TIMEOUT;
03072                res = 0;
03073                break;
03074             }
03075             /* Since this is a priority queue and 
03076              * it is not sure that we are still at the head
03077              * of the queue, go and check for our turn again.
03078              */
03079             if (!is_our_turn(&qe)) {
03080                if (option_debug)
03081                   ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
03082                         qe.chan->name);
03083                goto check_turns;
03084             }
03085          }
03086       }
03087       /* Don't allow return code > 0 */
03088       if (res >= 0 && res != AST_PBX_KEEPALIVE) {
03089          res = 0; 
03090          if (ringing) {
03091             ast_indicate(chan, -1);
03092          } else {
03093             ast_moh_stop(chan);
03094          }        
03095          ast_stopstream(chan);
03096       }
03097       leave_queue(&qe);
03098       if (reason != QUEUE_UNKNOWN)
03099          set_queue_result(chan, reason);
03100    } else {
03101       ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
03102       set_queue_result(chan, reason);
03103       res = 0;
03104    }
03105    LOCAL_USER_REMOVE(u);
03106    return res;
03107 }

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

Definition at line 3109 of file app_queue.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), LOCAL_USER_ACF_ADD, LOCAL_USER_REMOVE, ast_call_queue::lock, LOG_ERROR, ast_call_queue::members, ast_call_queue::name, member::next, ast_call_queue::next, and member::status.

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

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, ast_log(), ast_true(), ast_call_queue::context, 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, 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, val, ast_call_queue::weight, and ast_call_queue::wrapuptime.

Referenced by find_queue_by_name_rt(), and 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 }

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

Definition at line 3384 of file app_queue.c.

References __queues_show().

Referenced by __queues_show().

03385 {
03386    return __queues_show(0, fd, argc, argv, 1);
03387 }

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

Definition at line 3379 of file app_queue.c.

References __queues_show().

03380 {
03381    return __queues_show(0, fd, argc, argv, 0);
03382 }

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.

Referenced by try_calling().

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 }

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(), and try_calling().

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

References reload_queues().

03852 {
03853    reload_queues();
03854    return 0;
03855 }

void reload_queue_members void   )  [static]
 

Definition at line 2516 of file app_queue.c.

References add_to_queue(), ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), ast_db_entry::key, ast_call_queue::lock, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_call_queue::name, ast_call_queue::next, ast_db_entry::next, pm_family, PM_MAX_LEN, and strsep().

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 }

void reload_queues void   )  [static]
 

Definition at line 3160 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_variable::lineno, ast_call_queue::lock, LOG_NOTICE, LOG_WARNING, ast_call_queue::members, ast_variable::name, ast_call_queue::name, ast_variable::next, member::next, ast_call_queue::next, queue_persistent_members, queue_set_param(), queues, member::status, use_weight, ast_variable::value, and var.

Referenced by load_module(), and reload().

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

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

Definition at line 2378 of file app_queue.c.

References ast_mutex_lock(), ast_mutex_unlock(), dump_queue_members(), EVENT_FLAG_AGENT, free, member::interface, interface_exists(), ast_call_queue::lock, manager_event(), ast_call_queue::members, ast_call_queue::name, member::next, and ast_call_queue::next.

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 }

void remove_queue struct ast_call_queue q  )  [static]
 

Definition at line 783 of file app_queue.c.

References ast_mutex_lock(), ast_mutex_unlock(), 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 }

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_verbose, queue_ent::parent, member::paused, ast_channel::priority, 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 }

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, queue_ent::parent, ring_entry(), localuser::stillgoing, and ast_call_queue::strategy.

Referenced by try_calling(), and 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 }

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(), ast_channel::context, ast_channel::exten, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::name, pbx_builtin_setvar_helper(), ast_channel::priority, 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 }

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.

Referenced by find_queue_by_name_rt().

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 }

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.

Referenced by queue_exec(), and wait_our_turn().

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 }

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, 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.

Referenced by queue_exec(), and wait_our_turn().

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 }

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_mutex_unlock(), 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, and member::paused.

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 }

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.

Referenced by queue_exec().

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 }

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, and statechange::state.

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 }

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, queue_ent::parent, ast_call_queue::rrpos, localuser::stillgoing, and ast_call_queue::wrapped.

Referenced by try_calling().

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 }

int strat2int const char *  strategy  )  [static]
 

Definition at line 391 of file app_queue.c.

References name, strategies, and strategy::strategy.

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 }

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_channel::_softhangup, ast_channel::_state, queue_ent::announce, ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_make_compatible(), ast_channel_sendurl(), ast_channel_setoption(), ast_channel_supports_html(), AST_DIGIT_ANY, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_REDIRECT, ast_hangup(), ast_log(), ast_moh_stop(), ast_monitor_setjoinfiles(), ast_monitor_start(), ast_mutex_lock(), ast_mutex_unlock(), AST_OPTION_TONE_VERIFY, ast_queue_log(), ast_safe_sleep(), ast_say_number(), ast_set_flag, ast_strlen_zero(), ast_test_flag, calc_metric(), ast_channel::cdr, localuser::chan, queue_ent::chan, ast_channel::context, EVENT_FLAG_AGENT, ast_call_queue::eventwhencalled, ast_channel::exten, queue_ent::handled, hangupcalls(), member::interface, ast_channel::language, member::lastcall, leave_queue(), ast_call_queue::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, malloc, manager_event(), localuser::member, ast_call_queue::memberdelay, ast_call_queue::members, ast_call_queue::monfmt, ast_call_queue::monjoin, ast_call_queue::name, ast_channel::name, member::next, queue_ent::opos, queue_ent::parent, pbx_builtin_getvar_helper(), play_file(), queue_ent::pos, recalc_holdtime(), record_abandoned(), ast_call_queue::reportholdtime, ring_one(), ast_call_queue::sound_lessthan, ast_call_queue::sound_minutes, ast_call_queue::sound_reporthold, queue_ent::start, member::status, store_next(), ast_call_queue::strategy, ast_call_queue::timeout, ast_channel::type, ast_cdr::uniqueid, ast_channel::uniqueid, update_queue(), and wait_for_answer().

Referenced by queue_exec().

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 3794 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, and statechange_queue().

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

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

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.

Referenced by try_calling().

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 }

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 }

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(), ast_channel::context, ast_channel::exten, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, pbx_builtin_setvar_helper(), ast_channel::priority, 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 3862 of file app_queue.c.

References STANDARD_USECOUNT.

03863 {
03864    int res;
03865    STANDARD_USECOUNT(res);
03866    return res;
03867 }

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 }

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.

Referenced by queue_exec().

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 }

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_OFFHOOK, AST_CONTROL_RINGING, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_strlen_zero(), ast_verbose(), ast_waitfor_n(), 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_call_queue::timeoutrestart, update_dial_status(), valid_exit(), and VERBOSE_PREFIX_3.

Referenced by dial_exec_full(), and try_calling().

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 }

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_call_queue::announcefrequency, ast_queue_log(), ast_waitfordigit(), queue_ent::chan, queue_ent::expire, get_member_status(), is_our_turn(), leave_queue(), ast_call_queue::leavewhenempty, ast_call_queue::name, queue_ent::parent, ast_call_queue::periodicannouncefrequency, queue_ent::pos, queue_member_status, RECHECK, say_periodic_announcement(), say_position(), and ast_channel::uniqueid.

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.

Referenced by load_module(), and unload_module().

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 3780 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 3783 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 3790 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 3776 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 3768 of file app_queue.c.

Referenced by load_module(), and unload_module().

char* descrip [static]
 

Definition at line 127 of file app_queue.c.

Referenced by load_module().

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(), manager_add_queue_member(), and reload_queues().

const { ... } queue_results[]
 

Referenced by set_queue_result().

struct ast_custom_function queueagentcount_function [static]
 

Definition at line 3153 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 complete_remove_queue_member(), find_queue_by_name_rt(), reload_queues(), and remove_queue().

char rqm_cmd_usage[] [static]
 

Initial value:

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

Definition at line 3787 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 3772 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 3764 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.

Referenced by load_module().

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 __ast_cli_generator(), _sip_show_peer(), add_text(), agent_sendtext(), alsa_text(), ast_cli_completion_matches(), ast_cli_generator(), ast_cli_generatornummatches(), ast_sendtext(), build_reply_digest(), check_auth(), find_sip_method(), handle_response(), iax2_sendtext(), oss_text(), parse_sip_options(), phone_send_text(), reqprep(), sendtext_exec(), set_icon(), set_queue_result(), set_title(), sip_alloc(), sip_sendtext(), sip_show_channel(), transmit_diallednumber(), transmit_displaymessage(), transmit_displaynotify(), transmit_displaypromptstatus(), transmit_message_with_text(), and zt_sendtext().

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(), reload_queues(), and ring_entry().


Generated on Mon Mar 20 08:20:16 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1