Sat Mar 24 22:55:36 2007

Asterisk developer's documentation


app_queue.c File Reference

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

#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
#include "asterisk/monitor.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"

Include dependency graph for app_queue.c:

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

enum  queue_member_status { QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NORMAL }
enum  queue_result {
  QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, QUEUE_JOINEMPTY = 2, QUEUE_LEAVEEMPTY = 3,
  QUEUE_JOINUNAVAIL = 4, QUEUE_LEAVEUNAVAIL = 5, QUEUE_FULL = 6
}

Functions

static int __queues_show (int manager, int fd, int argc, char **argv, int queue_show)
static int add_to_interfaces (char *interface)
static int add_to_queue (char *queuename, char *interface, int penalty, int paused, int dump)
static struct call_queuealloc_queue (const char *queuename)
static int aqm_exec (struct ast_channel *chan, void *data)
static AST_LIST_HEAD_STATIC (interfaces, member_interface)
 AST_MUTEX_DEFINE_STATIC (qlock)
static int background_file (struct queue_ent *qe, struct ast_channel *chan, char *filename)
static int calc_metric (struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
static void * changethread (void *data)
static void clear_and_free_interfaces (void)
static void clear_queue (struct call_queue *q)
static int compare_weight (struct call_queue *rq, struct member *member)
static char * complete_add_queue_member (char *line, char *word, int pos, int state)
static char * complete_queue (char *line, char *word, int pos, int state)
static char * complete_remove_queue_member (char *line, char *word, int pos, int state)
static struct membercreate_queue_member (char *interface, int penalty, int paused)
char * description (void)
 Provides a description of the module.
static void destroy_queue (struct call_queue *q)
static void dump_queue_members (struct call_queue *pm_queue)
static struct call_queuefind_queue_by_name_rt (const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
 Reload a single queue via realtime.
static void free_members (struct call_queue *q, int all)
static enum queue_member_status get_member_status (const struct call_queue *q)
static int handle_add_queue_member (int fd, int argc, char *argv[])
static int handle_remove_queue_member (int fd, int argc, char *argv[])
static void hangupcalls (struct localuser *outgoing, struct ast_channel *exception)
static void init_queue (struct call_queue *q)
static void insert_entry (struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
 Insert the 'new' entry after the 'prev' entry of queue 'q'.
static char * int2strat (int strategy)
static struct memberinterface_exists (struct call_queue *q, char *interface)
static int interface_exists_global (char *interface)
static int is_our_turn (struct queue_ent *qe)
static int join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason)
char * key ()
 Returns the ASTERISK_GPL_KEY.
static void leave_queue (struct queue_ent *qe)
int load_module (void)
 Initialize the module.
static struct call_queueload_realtime_queue (char *queuename)
static int manager_add_queue_member (struct mansession *s, struct message *m)
static int manager_pause_queue_member (struct mansession *s, struct message *m)
static int manager_queues_show (struct mansession *s, struct message *m)
static int manager_queues_status (struct mansession *s, struct message *m)
static int manager_remove_queue_member (struct mansession *s, struct message *m)
static int play_file (struct ast_channel *chan, char *filename)
static int pqm_exec (struct ast_channel *chan, void *data)
static int queue_exec (struct ast_channel *chan, void *data)
static char * queue_function_qac (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
static void queue_set_param (struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
 Configure a queue parameter.
static int queue_show (int fd, int argc, char **argv)
static int queues_show (int fd, int argc, char **argv)
static void recalc_holdtime (struct queue_ent *qe)
static void record_abandoned (struct queue_ent *qe)
int reload (void)
 Reload stuff.
static void reload_queue_members (void)
static void reload_queues (void)
static int remove_from_interfaces (char *interface)
static int remove_from_queue (char *queuename, char *interface)
static void remove_queue (struct call_queue *q)
static int ring_entry (struct queue_ent *qe, struct localuser *tmp, int *busies)
static int ring_one (struct queue_ent *qe, struct localuser *outgoing, int *busies)
static int rqm_exec (struct ast_channel *chan, void *data)
static void rt_handle_member_record (struct call_queue *q, char *interface, const char *penalty_str)
static int say_periodic_announcement (struct queue_ent *qe)
static int say_position (struct queue_ent *qe)
static int set_member_paused (char *queuename, char *interface, int paused)
static void set_queue_result (struct ast_channel *chan, enum queue_result res)
static int statechange_queue (const char *dev, int state, void *ign)
static int store_next (struct queue_ent *qe, struct localuser *outgoing)
static int strat2int (const char *strategy)
static int try_calling (struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on)
int unload_module (void)
 Cleanup all module structures, sockets, etc.
static int update_dial_status (struct call_queue *q, struct member *member, int status)
static int update_queue (struct call_queue *q, struct member *member)
static int update_status (struct call_queue *q, struct member *member, int status)
static int upqm_exec (struct ast_channel *chan, void *data)
int usecount (void)
 Provides a usecount.
static int valid_exit (struct queue_ent *qe, char digit)
static int wait_a_bit (struct queue_ent *qe)
static struct localuserwait_for_answer (struct queue_ent *qe, struct localuser *outgoing, int *to, char *digit, int prebusies, int caller_disconnect)
static int wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason)

Variables

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


Detailed Description

True call queues with optional send URL on answer.

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

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

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

Patch Version 1.07 2003-12-24 01

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

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

Definition in file app_queue.c.


Define Documentation

#define ANNOUNCEHOLDTIME_ALWAYS   1

Definition at line 316 of file app_queue.c.

Referenced by queue_set_param().

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 317 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

#define AST_MAX_WATCHERS   256

Definition at line 1738 of file app_queue.c.

#define BUILD_WATCHERS

Definition at line 1740 of file app_queue.c.

Referenced by wait_for_answer().

#define DEFAULT_RETRY   5

Definition at line 112 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

#define DEFAULT_TIMEOUT   15

Definition at line 113 of file app_queue.c.

Referenced by queue_set_param().

#define PM_MAX_LEN   2048

Definition at line 225 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

#define QUEUE_EMPTY_NORMAL   1

Definition at line 314 of file app_queue.c.

Referenced by queue_set_param().

#define QUEUE_EMPTY_STRICT   2

Definition at line 315 of file app_queue.c.

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

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

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

#define RES_NOSUCHQUEUE   (-3)

Definition at line 119 of file app_queue.c.

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

#define RES_OKAY   0

Definition at line 116 of file app_queue.c.

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

#define RES_OUTOFMEMORY   (-2)

Definition at line 118 of file app_queue.c.

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


Enumeration Type Documentation

enum queue_member_status

Enumerator:
QUEUE_NO_MEMBERS 
QUEUE_NO_REACHABLE_MEMBERS 
QUEUE_NORMAL 

Definition at line 429 of file app_queue.c.

00429                          {
00430    QUEUE_NO_MEMBERS,
00431    QUEUE_NO_REACHABLE_MEMBERS,
00432    QUEUE_NORMAL
00433 };

enum queue_result

Enumerator:
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 

Definition at line 233 of file app_queue.c.

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


Function Documentation

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

Definition at line 3444 of file app_queue.c.

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

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

03445 {
03446    struct call_queue *q;
03447    struct queue_ent *qe;
03448    struct member *mem;
03449    int pos;
03450    time_t now;
03451    char max_buf[80];
03452    char *max;
03453    size_t max_left;
03454    float sl = 0;
03455    char *term = manager ? "\r\n" : "\n";
03456 
03457    time(&now);
03458    if ((!queue_show && argc != 2) || (queue_show && argc != 3))
03459       return RESULT_SHOWUSAGE;
03460 
03461    /* We only want to load realtime queues when a specific queue is asked for. */
03462    if (queue_show)
03463       load_realtime_queue(argv[2]);
03464 
03465    ast_mutex_lock(&qlock);
03466 
03467    q = queues;
03468    if (!q) {   
03469       ast_mutex_unlock(&qlock);
03470       if (queue_show)
03471          ast_cli(fd, "No such queue: %s.%s",argv[2], term);
03472       else
03473          ast_cli(fd, "No queues.%s", term);
03474       return RESULT_SUCCESS;
03475    }
03476    while (q) {
03477       ast_mutex_lock(&q->lock);
03478       if (queue_show) {
03479          if (strcasecmp(q->name, argv[2]) != 0) {
03480             ast_mutex_unlock(&q->lock);
03481             q = q->next;
03482             if (!q) {
03483                ast_cli(fd, "No such queue: %s.%s",argv[2], term);
03484                break;
03485             }
03486             continue;
03487          }
03488       }
03489       max_buf[0] = '\0';
03490       max = max_buf;
03491       max_left = sizeof(max_buf);
03492       if (q->maxlen)
03493          ast_build_string(&max, &max_left, "%d", q->maxlen);
03494       else
03495          ast_build_string(&max, &max_left, "unlimited");
03496       sl = 0;
03497       if(q->callscompleted > 0)
03498          sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
03499       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",
03500          q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
03501       if (q->members) {
03502          ast_cli(fd, "   Members: %s", term);
03503          for (mem = q->members; mem; mem = mem->next) {
03504             max_buf[0] = '\0';
03505             max = max_buf;
03506             max_left = sizeof(max_buf);
03507             if (mem->penalty)
03508                ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
03509             if (mem->dynamic)
03510                ast_build_string(&max, &max_left, " (dynamic)");
03511             if (mem->paused)
03512                ast_build_string(&max, &max_left, " (paused)");
03513             ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
03514             if (mem->calls) {
03515                ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
03516                       mem->calls, (long)(time(NULL) - mem->lastcall));
03517             } else
03518                ast_build_string(&max, &max_left, " has taken no calls yet");
03519             ast_cli(fd, "      %s%s%s", mem->interface, max_buf, term);
03520          }
03521       } else
03522          ast_cli(fd, "   No Members%s", term);
03523       if (q->head) {
03524          pos = 1;
03525          ast_cli(fd, "   Callers: %s", term);
03526          for (qe = q->head; qe; qe = qe->next) 
03527             ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, qe->chan->name,
03528                (long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio, term);
03529       } else
03530          ast_cli(fd, "   No Callers%s", term);
03531       ast_cli(fd, "%s", term);
03532       ast_mutex_unlock(&q->lock);
03533       q = q->next;
03534       if (queue_show)
03535          break;
03536    }
03537    ast_mutex_unlock(&qlock);
03538    return RESULT_SUCCESS;
03539 }

static int add_to_interfaces ( char *  interface  )  [static]

Definition at line 622 of file app_queue.c.

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

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

00623 {
00624    struct member_interface *curint;
00625 
00626    if (!interface)
00627       return 0;
00628 
00629    AST_LIST_LOCK(&interfaces);
00630    AST_LIST_TRAVERSE(&interfaces, curint, list) {
00631       if (!strcasecmp(curint->interface, interface))
00632          break; 
00633    }
00634 
00635    if (curint) {
00636       AST_LIST_UNLOCK(&interfaces);
00637       return 0;
00638    }
00639 
00640    if (option_debug)
00641       ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
00642    
00643    if ((curint = malloc(sizeof(*curint)))) {
00644       memset(curint, 0, sizeof(*curint));
00645       ast_copy_string(curint->interface, interface, sizeof(curint->interface));
00646       AST_LIST_INSERT_HEAD(&interfaces, curint, list);
00647    }
00648    AST_LIST_UNLOCK(&interfaces);
00649 
00650    return 0;
00651 }

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

Definition at line 2550 of file app_queue.c.

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

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

02551 {
02552    struct call_queue *q;
02553    struct member *new_member;
02554    int res = RES_NOSUCHQUEUE;
02555 
02556    /* \note Ensure the appropriate realtime queue is loaded.  Note that this
02557     * short-circuits if the queue is already in memory. */
02558    q = load_realtime_queue(queuename);
02559 
02560    ast_mutex_lock(&qlock);
02561 
02562    if (q) {
02563       ast_mutex_lock(&q->lock);
02564       if (interface_exists(q, interface) == NULL) {
02565 
02566          add_to_interfaces(interface);
02567 
02568          new_member = create_queue_member(interface, penalty, paused);
02569 
02570          if (new_member != NULL) {
02571             new_member->dynamic = 1;
02572             new_member->next = q->members;
02573             q->members = new_member;
02574             manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
02575                   "Queue: %s\r\n"
02576                   "Location: %s\r\n"
02577                   "Membership: %s\r\n"
02578                   "Penalty: %d\r\n"
02579                   "CallsTaken: %d\r\n"
02580                   "LastCall: %d\r\n"
02581                   "Status: %d\r\n"
02582                   "Paused: %d\r\n",
02583                   q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
02584                   new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
02585 
02586             if (dump)
02587                dump_queue_members(q);
02588 
02589             res = RES_OKAY;
02590          } else {
02591             res = RES_OUTOFMEMORY;
02592          }
02593       } else {
02594          res = RES_EXISTS;
02595       }
02596       ast_mutex_unlock(&q->lock);
02597    }
02598    ast_mutex_unlock(&qlock);
02599    return res;
02600 }

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

Definition at line 573 of file app_queue.c.

References ast_mutex_init(), and malloc.

Referenced by reload_queues().

00574 {
00575    struct call_queue *q;
00576 
00577    q = malloc(sizeof(*q));
00578    if (q) {
00579       memset(q, 0, sizeof(*q));
00580       ast_mutex_init(&q->lock);
00581       ast_copy_string(q->name, queuename, sizeof(q->name));
00582    }
00583    return q;
00584 }

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

Definition at line 2914 of file app_queue.c.

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

Referenced by load_module().

02915 {
02916    int res=-1;
02917    struct localuser *u;
02918    char *parse, *temppos = NULL;
02919    int priority_jump = 0;
02920    AST_DECLARE_APP_ARGS(args,
02921       AST_APP_ARG(queuename);
02922       AST_APP_ARG(interface);
02923       AST_APP_ARG(penalty);
02924       AST_APP_ARG(options);
02925    );
02926    int penalty = 0;
02927 
02928    if (ast_strlen_zero(data)) {
02929       ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n");
02930       return -1;
02931    }
02932 
02933    LOCAL_USER_ADD(u);
02934 
02935    if (!(parse = ast_strdupa(data))) {
02936       ast_log(LOG_WARNING, "Memory Error!\n");
02937       LOCAL_USER_REMOVE(u);
02938       return -1;
02939    }
02940 
02941    AST_STANDARD_APP_ARGS(args, parse);
02942 
02943    if (ast_strlen_zero(args.interface)) {
02944       args.interface = ast_strdupa(chan->name);
02945       temppos = strrchr(args.interface, '-');
02946       if (temppos)
02947          *temppos = '\0';
02948    }
02949 
02950    if (!ast_strlen_zero(args.penalty)) {
02951       if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
02952          ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
02953          penalty = 0;
02954       }
02955    }
02956    
02957    if (args.options) {
02958       if (strchr(args.options, 'j'))
02959          priority_jump = 1;
02960    }
02961 
02962 
02963    switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) {
02964    case RES_OKAY:
02965       ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
02966       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
02967       res = 0;
02968       break;
02969    case RES_EXISTS:
02970       ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
02971       if (priority_jump || option_priority_jumping) 
02972          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
02973       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
02974       res = 0;
02975       break;
02976    case RES_NOSUCHQUEUE:
02977       ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
02978       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
02979       res = 0;
02980       break;
02981    case RES_OUTOFMEMORY:
02982       ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
02983       break;
02984    }
02985 
02986    LOCAL_USER_REMOVE(u);
02987    return res;
02988 }

static AST_LIST_HEAD_STATIC ( interfaces  ,
member_interface   
) [static]

AST_MUTEX_DEFINE_STATIC ( qlock   ) 

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

Definition at line 1672 of file app_queue.c.

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

Referenced by say_periodic_announcement().

01673 {
01674    int res;
01675 
01676    ast_stopstream(chan);
01677    res = ast_streamfile(chan, filename, chan->language);
01678 
01679    if (!res) {
01680       /* Wait for a keypress */
01681       res = ast_waitstream(chan, AST_DIGIT_ANY);
01682       if (res < 0 || !valid_exit(qe, res))
01683          res = 0;
01684 
01685       /* Stop playback */
01686       ast_stopstream(chan);
01687    } else {
01688       res = 0;
01689    }
01690    
01691    /*if (res) {
01692       ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
01693       res = 0;
01694    }*/
01695 
01696    return res;
01697 }

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

Definition at line 2084 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, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.

Referenced by try_calling().

02085 {
02086    switch (q->strategy) {
02087    case QUEUE_STRATEGY_RINGALL:
02088       /* Everyone equal, except for penalty */
02089       tmp->metric = mem->penalty * 1000000;
02090       break;
02091    case QUEUE_STRATEGY_ROUNDROBIN:
02092       if (!pos) {
02093          if (!q->wrapped) {
02094             /* No more channels, start over */
02095             q->rrpos = 0;
02096          } else {
02097             /* Prioritize next entry */
02098             q->rrpos++;
02099          }
02100          q->wrapped = 0;
02101       }
02102       /* Fall through */
02103    case QUEUE_STRATEGY_RRMEMORY:
02104       if (pos < q->rrpos) {
02105          tmp->metric = 1000 + pos;
02106       } else {
02107          if (pos > q->rrpos)
02108             /* Indicate there is another priority */
02109             q->wrapped = 1;
02110          tmp->metric = pos;
02111       }
02112       tmp->metric += mem->penalty * 1000000;
02113       break;
02114    case QUEUE_STRATEGY_RANDOM:
02115       tmp->metric = rand() % 1000;
02116       tmp->metric += mem->penalty * 1000000;
02117       break;
02118    case QUEUE_STRATEGY_FEWESTCALLS:
02119       tmp->metric = mem->calls;
02120       tmp->metric += mem->penalty * 1000000;
02121       break;
02122    case QUEUE_STRATEGY_LEASTRECENT:
02123       if (!mem->lastcall)
02124          tmp->metric = 0;
02125       else
02126          tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
02127       tmp->metric += mem->penalty * 1000000;
02128       break;
02129    default:
02130       ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
02131       break;
02132    }
02133    return 0;
02134 }

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

Definition at line 463 of file app_queue.c.

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

Referenced by statechange_queue().

00464 {
00465    struct call_queue *q;
00466    struct statechange *sc = data;
00467    struct member *cur;
00468    struct member_interface *curint;
00469    char *loc;
00470    char *technology;
00471 
00472    technology = ast_strdupa(sc->dev);
00473    loc = strchr(technology, '/');
00474    if (loc) {
00475       *loc++ = '\0';
00476    } else {
00477       free(sc);
00478       return NULL;
00479    }
00480 
00481    AST_LIST_LOCK(&interfaces);
00482    AST_LIST_TRAVERSE(&interfaces, curint, list) {
00483       if (!strcasecmp(curint->interface, sc->dev))
00484          break;
00485    }
00486    AST_LIST_UNLOCK(&interfaces);
00487    
00488    if (!curint) {
00489       if (option_debug)
00490          ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", technology, loc, sc->state, devstate2str(sc->state));
00491       free(sc);
00492       return NULL;
00493         }
00494 
00495    if (option_debug)
00496       ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
00497    ast_mutex_lock(&qlock);
00498    for (q = queues; q; q = q->next) {
00499       ast_mutex_lock(&q->lock);
00500       for (cur = q->members; cur; cur = cur->next) {
00501          if (strcasecmp(sc->dev, cur->interface))
00502             continue;
00503 
00504          if (cur->status != sc->state) {
00505             cur->status = sc->state;
00506             if (q->maskmemberstatus)
00507                continue;
00508 
00509             manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
00510                      "Queue: %s\r\n"
00511                      "Location: %s\r\n"
00512                      "Membership: %s\r\n"
00513                      "Penalty: %d\r\n"
00514                      "CallsTaken: %d\r\n"
00515                      "LastCall: %d\r\n"
00516                      "Status: %d\r\n"
00517                      "Paused: %d\r\n",
00518                      q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
00519                      cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
00520          }
00521       }
00522       ast_mutex_unlock(&q->lock);
00523    }
00524    ast_mutex_unlock(&qlock);
00525 
00526    return NULL;
00527 }

static void clear_and_free_interfaces ( void   )  [static]

Definition at line 701 of file app_queue.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, free, and list.

Referenced by unload_module().

00702 {
00703    struct member_interface *curint;
00704 
00705    AST_LIST_LOCK(&interfaces);
00706    while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
00707       free(curint);
00708    AST_LIST_UNLOCK(&interfaces);
00709 }

static void clear_queue ( struct call_queue q  )  [static]

Definition at line 613 of file app_queue.c.

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

Referenced by reload_queues().

00614 {
00615    q->holdtime = 0;
00616    q->callscompleted = 0;
00617    q->callsabandoned = 0;
00618    q->callscompletedinsl = 0;
00619    q->wrapuptime = 0;
00620 }

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

Definition at line 1439 of file app_queue.c.

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

Referenced by ring_entry().

01440 {
01441    struct call_queue *q;
01442    struct member *mem;
01443    int found = 0;
01444    
01445    /* &qlock and &rq->lock already set by try_calling()
01446     * to solve deadlock */
01447    for (q = queues; q; q = q->next) {
01448       if (q == rq) /* don't check myself, could deadlock */
01449          continue; 
01450       ast_mutex_lock(&q->lock);
01451       if (q->count && q->members) {
01452          for (mem = q->members; mem; mem = mem->next) {
01453             if (!strcmp(mem->interface, member->interface)) {
01454                ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
01455                if (q->weight > rq->weight) {
01456                   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);
01457                   found = 1;
01458                   break;
01459                }
01460             }
01461          }
01462       }
01463       ast_mutex_unlock(&q->lock);
01464       if (found) 
01465          break;
01466    }
01467    ast_mutex_unlock(&qlock);
01468    return found;
01469 }

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

Definition at line 3820 of file app_queue.c.

References complete_queue(), malloc, and strdup.

03821 {
03822    /* 0 - add; 1 - queue; 2 - member; 3 - <member>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty> */
03823    switch (pos) {
03824    case 3:
03825       /* Don't attempt to complete name of member (infinite possibilities) */
03826       return NULL;
03827    case 4:
03828       if (state == 0) {
03829          return strdup("to");
03830       } else {
03831          return NULL;
03832       }
03833    case 5:
03834       /* No need to duplicate code */
03835       return complete_queue(line, word, pos, state);
03836    case 6:
03837       if (state == 0) {
03838          return strdup("penalty");
03839       } else {
03840          return NULL;
03841       }
03842    case 7:
03843       if (state < 100) {   /* 0-99 */
03844          char *num = malloc(3);
03845          if (num) {
03846             sprintf(num, "%d", state);
03847          }
03848          return num;
03849       } else {
03850          return NULL;
03851       }
03852    default:
03853       return NULL;
03854    }
03855 }

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

Definition at line 3551 of file app_queue.c.

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

Referenced by complete_add_queue_member(), and complete_remove_queue_member().

03552 {
03553    struct call_queue *q;
03554    int which=0;
03555    
03556    ast_mutex_lock(&qlock);
03557    for (q = queues; q; q = q->next) {
03558       if (!strncasecmp(word, q->name, strlen(word))) {
03559          if (++which > state)
03560             break;
03561       }
03562    }
03563    ast_mutex_unlock(&qlock);
03564    return q ? strdup(q->name) : NULL;
03565 }

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

Definition at line 3888 of file app_queue.c.

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

03889 {
03890    int which = 0;
03891    struct call_queue *q;
03892    struct member *m;
03893 
03894    /* 0 - add; 1 - queue; 2 - member; 3 - <member>; 4 - to; 5 - <queue> */
03895    if ((pos > 5) || (pos < 3)) {
03896       return NULL;
03897    }
03898    if (pos == 4) {
03899       if (state == 0) {
03900          return strdup("from");
03901       } else {
03902          return NULL;
03903       }
03904    }
03905 
03906    if (pos == 5) {
03907       /* No need to duplicate code */
03908       return complete_queue(line, word, pos, state);
03909    }
03910 
03911    if (queues != NULL) {
03912       for (q = queues ; q ; q = q->next) {
03913          ast_mutex_lock(&q->lock);
03914          for (m = q->members ; m ; m = m->next) {
03915             if (++which > state) {
03916                ast_mutex_unlock(&q->lock);
03917                return strdup(m->interface);
03918             }
03919          }
03920          ast_mutex_unlock(&q->lock);
03921       }
03922    }
03923    return NULL;
03924 }

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

Definition at line 552 of file app_queue.c.

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

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

00553 {
00554    struct member *cur;
00555    
00556    /* Add a new member */
00557 
00558    cur = malloc(sizeof(struct member));
00559 
00560    if (cur) {
00561       memset(cur, 0, sizeof(struct member));
00562       cur->penalty = penalty;
00563       cur->paused = paused;
00564       ast_copy_string(cur->interface, interface, sizeof(cur->interface));
00565       if (!strchr(cur->interface, '/'))
00566          ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
00567       cur->status = ast_device_state(interface);
00568    }
00569 
00570    return cur;
00571 }

char* description ( void   ) 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 4020 of file app_queue.c.

References tdesc.

04021 {
04022    return tdesc;
04023 }

static void destroy_queue ( struct call_queue q  )  [static]

Definition at line 893 of file app_queue.c.

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

Referenced by leave_queue(), and reload_queues().

00894 {
00895    free_members(q, 1);
00896    ast_mutex_destroy(&q->lock);
00897    free(q);
00898 }

static void dump_queue_members ( struct call_queue pm_queue  )  [static]

Definition at line 2469 of file app_queue.c.

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

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

02470 {
02471    struct member *cur_member;
02472    char value[PM_MAX_LEN];
02473    int value_len = 0;
02474    int res;
02475 
02476    memset(value, 0, sizeof(value));
02477 
02478    if (!pm_queue)
02479       return;
02480 
02481    for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
02482       if (!cur_member->dynamic)
02483          continue;
02484 
02485       res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
02486                 cur_member->interface, cur_member->penalty, cur_member->paused,
02487                 cur_member->next ? "|" : "");
02488       if (res != strlen(value + value_len)) {
02489          ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
02490          break;
02491       }
02492       value_len += res;
02493    }
02494    
02495    if (value_len && !cur_member) {
02496       if (ast_db_put(pm_family, pm_queue->name, value))
02497          ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
02498    } else
02499       /* Delete the entry if the queue is empty or there is an error */
02500       ast_db_del(pm_family, pm_queue->name);
02501 }

static struct 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 921 of file app_queue.c.

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

00922 {
00923    struct ast_variable *v;
00924    struct call_queue *q, *prev_q = NULL;
00925    struct member *m, *prev_m, *next_m;
00926    char *interface;
00927    char *tmp, *tmp_name;
00928    char tmpbuf[64];  /* Must be longer than the longest queue param name. */
00929 
00930    /* Find the queue in the in-core list (we will create a new one if not found). */
00931    for (q = queues; q; q = q->next) {
00932       if (!strcasecmp(q->name, queuename)) {
00933          break;
00934       }
00935       prev_q = q;
00936    }
00937 
00938    /* Static queues override realtime. */
00939    if (q) {
00940       ast_mutex_lock(&q->lock);
00941       if (!q->realtime) {
00942          if (q->dead) {
00943             ast_mutex_unlock(&q->lock);
00944             return NULL;
00945          } else {
00946             ast_mutex_unlock(&q->lock);
00947             return q;
00948          }
00949       }
00950    } else if (!member_config)
00951       /* Not found in the list, and it's not realtime ... */
00952       return NULL;
00953 
00954    /* Check if queue is defined in realtime. */
00955    if (!queue_vars) {
00956       /* Delete queue from in-core list if it has been deleted in realtime. */
00957       if (q) {
00958          /*! \note Hmm, can't seem to distinguish a DB failure from a not
00959             found condition... So we might delete an in-core queue
00960             in case of DB failure. */
00961          ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
00962 
00963          q->dead = 1;
00964          /* Delete if unused (else will be deleted when last caller leaves). */
00965          if (!q->count) {
00966             /* Delete. */
00967             if (!prev_q) {
00968                queues = q->next;
00969             } else {
00970                prev_q->next = q->next;
00971             }
00972             ast_mutex_unlock(&q->lock);
00973             destroy_queue(q);
00974          } else
00975             ast_mutex_unlock(&q->lock);
00976       }
00977       return NULL;
00978    }
00979 
00980    /* Create a new queue if an in-core entry does not exist yet. */
00981    if (!q) {
00982       q = alloc_queue(queuename);
00983       if (!q)
00984          return NULL;
00985       ast_mutex_lock(&q->lock);
00986       clear_queue(q);
00987       q->realtime = 1;
00988       q->next = queues;
00989       queues = q;
00990    }
00991    init_queue(q);    /* Ensure defaults for all parameters not set explicitly. */
00992 
00993    v = queue_vars;
00994    memset(tmpbuf, 0, sizeof(tmpbuf));
00995    while(v) {
00996       /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
00997       if((tmp = strchr(v->name, '_')) != NULL) {
00998          ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
00999          tmp_name = tmpbuf;
01000          tmp = tmp_name;
01001          while((tmp = strchr(tmp, '_')) != NULL)
01002             *tmp++ = '-';
01003       } else
01004          tmp_name = v->name;
01005       queue_set_param(q, tmp_name, v->value, -1, 0);
01006       v = v->next;
01007    }
01008 
01009    /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
01010    m = q->members;
01011    while (m) {
01012       if (!m->dynamic)
01013          m->dead = 1;
01014       m = m->next;
01015    }
01016 
01017    interface = ast_category_browse(member_config, NULL);
01018    while (interface) {
01019       rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty"));
01020       interface = ast_category_browse(member_config, interface);
01021    }
01022 
01023    /* Delete all realtime members that have been deleted in DB. */
01024    m = q->members;
01025    prev_m = NULL;
01026    while (m) {
01027       next_m = m->next;
01028       if (m->dead) {
01029          if (prev_m) {
01030             prev_m->next = next_m;
01031          } else {
01032             q->members = next_m;
01033          }
01034          remove_from_interfaces(m->interface);
01035          free(m);
01036       } else {
01037          prev_m = m;
01038       }
01039       m = next_m;
01040    }
01041 
01042    ast_mutex_unlock(&q->lock);
01043 
01044    return q;
01045 }

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

Definition at line 874 of file app_queue.c.

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

Referenced by destroy_queue().

00875 {
00876    /* Free non-dynamic members */
00877    struct member *curm, *next, *prev = NULL;
00878 
00879    for (curm = q->members; curm; curm = next) {
00880       next = curm->next;
00881       if (all || !curm->dynamic) {
00882          if (prev)
00883             prev->next = next;
00884          else
00885             q->members = next;
00886          remove_from_interfaces(curm->interface);
00887          free(curm);
00888       } else 
00889          prev = curm;
00890    }
00891 }

static enum queue_member_status get_member_status ( const struct call_queue q  )  [static]

Definition at line 435 of file app_queue.c.

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

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

00436 {
00437    struct member *member;
00438    enum queue_member_status result = QUEUE_NO_MEMBERS;
00439 
00440    for (member = q->members; member; member = member->next) {
00441       if (member->paused) continue;
00442 
00443       switch (member->status) {
00444       case AST_DEVICE_INVALID:
00445          /* nothing to do */
00446          break;
00447       case AST_DEVICE_UNAVAILABLE:
00448          result = QUEUE_NO_REACHABLE_MEMBERS;
00449          break;
00450       default:
00451          return QUEUE_NORMAL;
00452       }
00453    }
00454    
00455    return result;
00456 }

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

Definition at line 3773 of file app_queue.c.

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

03774 {
03775    char *queuename, *interface;
03776    int penalty;
03777 
03778    if ((argc != 6) && (argc != 8)) {
03779       return RESULT_SHOWUSAGE;
03780    } else if (strcmp(argv[4], "to")) {
03781       return RESULT_SHOWUSAGE;
03782    } else if ((argc == 8) && strcmp(argv[6], "penalty")) {
03783       return RESULT_SHOWUSAGE;
03784    }
03785 
03786    queuename = argv[5];
03787    interface = argv[3];
03788    if (argc == 8) {
03789       if (sscanf(argv[7], "%d", &penalty) == 1) {
03790          if (penalty < 0) {
03791             ast_cli(fd, "Penalty must be >= 0\n");
03792             penalty = 0;
03793          }
03794       } else {
03795          ast_cli(fd, "Penalty must be an integer >= 0\n");
03796          penalty = 0;
03797       }
03798    } else {
03799       penalty = 0;
03800    }
03801 
03802    switch (add_to_queue(queuename, interface, penalty, 0, queue_persistent_members)) {
03803    case RES_OKAY:
03804       ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
03805       return RESULT_SUCCESS;
03806    case RES_EXISTS:
03807       ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
03808       return RESULT_FAILURE;
03809    case RES_NOSUCHQUEUE:
03810       ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
03811       return RESULT_FAILURE;
03812    case RES_OUTOFMEMORY:
03813       ast_cli(fd, "Out of memory\n");
03814       return RESULT_FAILURE;
03815    default:
03816       return RESULT_FAILURE;
03817    }
03818 }

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

Definition at line 3857 of file app_queue.c.

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

03858 {
03859    char *queuename, *interface;
03860 
03861    if (argc != 6) {
03862       return RESULT_SHOWUSAGE;
03863    } else if (strcmp(argv[4], "from")) {
03864       return RESULT_SHOWUSAGE;
03865    }
03866 
03867    queuename = argv[5];
03868    interface = argv[3];
03869 
03870    switch (remove_from_queue(queuename, interface)) {
03871    case RES_OKAY:
03872       ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
03873       return RESULT_SUCCESS;
03874    case RES_EXISTS:
03875       ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
03876       return RESULT_FAILURE;
03877    case RES_NOSUCHQUEUE:
03878       ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
03879       return RESULT_FAILURE;
03880    case RES_OUTOFMEMORY:
03881       ast_cli(fd, "Out of memory\n");
03882       return RESULT_FAILURE;
03883    default:
03884       return RESULT_FAILURE;
03885    }
03886 }

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

Definition at line 1378 of file app_queue.c.

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

Referenced by try_calling().

01379 {
01380    struct localuser *oo;
01381 
01382    while(outgoing) {
01383       /* Hangup any existing lines we have open */
01384       if (outgoing->chan && (outgoing->chan != exception))
01385          ast_hangup(outgoing->chan);
01386       oo = outgoing;
01387       outgoing=outgoing->next;
01388       free(oo);
01389    }
01390 }

static void init_queue ( struct call_queue q  )  [static]

Definition at line 586 of file app_queue.c.

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

Referenced by reload_queues().

00587 {
00588    q->dead = 0;
00589    q->retry = DEFAULT_RETRY;
00590    q->timeout = -1;
00591    q->maxlen = 0;
00592    q->announcefrequency = 0;
00593    q->announceholdtime = 0;
00594    q->roundingseconds = 0; /* Default - don't announce seconds */
00595    q->servicelevel = 0;
00596    q->moh[0] = '\0';
00597    q->announce[0] = '\0';
00598    q->context[0] = '\0';
00599    q->monfmt[0] = '\0';
00600    q->periodicannouncefrequency = 0;
00601    ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
00602    ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
00603    ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
00604    ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
00605    ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
00606    ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
00607    ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
00608    ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
00609    ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
00610    ast_copy_string(q->sound_periodicannounce, "queue-periodic-announce", sizeof(q->sound_periodicannounce));
00611 }

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

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

Definition at line 410 of file app_queue.c.

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

Referenced by join_queue().

00411 {
00412    struct queue_ent *cur;
00413 
00414    if (!q || !new)
00415       return;
00416    if (prev) {
00417       cur = prev->next;
00418       prev->next = new;
00419    } else {
00420       cur = q->head;
00421       q->head = new;
00422    }
00423    new->next = cur;
00424    new->parent = q;
00425    new->pos = ++(*pos);
00426    new->opos = *pos;
00427 }

static char* int2strat ( int  strategy  )  [static]

Definition at line 389 of file app_queue.c.

References name, and strategies.

Referenced by __queues_show().

00390 {
00391    int x;
00392    for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
00393       if (strategy == strategies[x].strategy)
00394          return strategies[x].name;
00395    }
00396    return "<unknown>";
00397 }

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

Definition at line 2451 of file app_queue.c.

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

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

02452 {
02453    struct member *mem;
02454 
02455    if (q)
02456       for (mem = q->members; mem; mem = mem->next)
02457          if (!strcasecmp(interface, mem->interface))
02458             return mem;
02459 
02460    return NULL;
02461 }

static int interface_exists_global ( char *  interface  )  [static]

Definition at line 653 of file app_queue.c.

References ast_mutex_lock(), ast_mutex_unlock(), member::interface, call_queue::lock, call_queue::members, member::next, call_queue::next, and queues.

Referenced by remove_from_interfaces().

00654 {
00655    struct call_queue *q;
00656    struct member *mem;
00657    int ret = 0;
00658 
00659    if (!interface)
00660       return ret;
00661 
00662    ast_mutex_lock(&qlock);
00663    for (q = queues; q && !ret; q = q->next) {
00664       ast_mutex_lock(&q->lock);
00665       for (mem = q->members; mem && !ret; mem = mem->next) {
00666          if (!strcasecmp(interface, mem->interface))
00667             ret = 1;
00668       }
00669       ast_mutex_unlock(&q->lock);
00670    }
00671    ast_mutex_unlock(&qlock);
00672 
00673    return ret;
00674 }

static int is_our_turn ( struct queue_ent qe  )  [static]

Definition at line 1993 of file app_queue.c.

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

Referenced by queue_exec(), and wait_our_turn().

01994 {
01995    struct queue_ent *ch;
01996    int res;
01997 
01998    /* Atomically read the parent head -- does not need a lock */
01999    ch = qe->parent->head;
02000    /* If we are now at the top of the head, break out */
02001    if (ch == qe) {
02002       if (option_debug)
02003          ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
02004       res = 1;
02005    } else {
02006       if (option_debug)
02007          ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
02008       res = 0;
02009    }
02010    return res;
02011 }

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

Definition at line 1094 of file app_queue.c.

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

Referenced by queue_exec().

01095 {
01096    struct call_queue *q;
01097    struct queue_ent *cur, *prev = NULL;
01098    int res = -1;
01099    int pos = 0;
01100    int inserted = 0;
01101    enum queue_member_status stat;
01102 
01103    q = load_realtime_queue(queuename);
01104    if (!q)
01105       return res;
01106 
01107    ast_mutex_lock(&qlock);
01108    ast_mutex_lock(&q->lock);
01109 
01110    /* This is our one */
01111    stat = get_member_status(q);
01112    if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
01113       *reason = QUEUE_JOINEMPTY;
01114    else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
01115       *reason = QUEUE_JOINUNAVAIL;
01116    else if (q->maxlen && (q->count >= q->maxlen))
01117       *reason = QUEUE_FULL;
01118    else {
01119       /* There's space for us, put us at the right position inside
01120        * the queue. 
01121        * Take into account the priority of the calling user */
01122       inserted = 0;
01123       prev = NULL;
01124       cur = q->head;
01125       while(cur) {
01126          /* We have higher priority than the current user, enter
01127           * before him, after all the other users with priority
01128           * higher or equal to our priority. */
01129          if ((!inserted) && (qe->prio > cur->prio)) {
01130             insert_entry(q, prev, qe, &pos);
01131             inserted = 1;
01132          }
01133          cur->pos = ++pos;
01134          prev = cur;
01135          cur = cur->next;
01136       }
01137       /* No luck, join at the end of the queue */
01138       if (!inserted)
01139          insert_entry(q, prev, qe, &pos);
01140       ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
01141       ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
01142       ast_copy_string(qe->context, q->context, sizeof(qe->context));
01143       q->count++;
01144       res = 0;
01145       manager_event(EVENT_FLAG_CALL, "Join", 
01146                "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
01147                qe->chan->name, 
01148                qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
01149                qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
01150                q->name, qe->pos, q->count );
01151 
01152       if (option_debug)
01153          ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
01154    }
01155    ast_mutex_unlock(&q->lock);
01156    ast_mutex_unlock(&qlock);
01157    return res;
01158 }

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

References ASTERISK_GPL_KEY.

04033 {
04034    return ASTERISK_GPL_KEY;
04035 }

static void leave_queue ( struct queue_ent qe  )  [static]

Definition at line 1333 of file app_queue.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), queue_ent::chan, call_queue::count, call_queue::dead, destroy_queue(), EVENT_FLAG_CALL, call_queue::head, call_queue::lock, LOG_NOTICE, manager_event(), 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().

01334 {
01335    struct call_queue *q;
01336    struct queue_ent *cur, *prev = NULL;
01337    int pos = 0;
01338 
01339    q = qe->parent;
01340    if (!q)
01341       return;
01342    ast_mutex_lock(&q->lock);
01343 
01344    prev = NULL;
01345    cur = q->head;
01346    while(cur) {
01347       if (cur == qe) {
01348          q->count--;
01349 
01350          /* Take us out of the queue */
01351          manager_event(EVENT_FLAG_CALL, "Leave",
01352             "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
01353             qe->chan->name, q->name,  q->count);
01354 #if 0
01355 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
01356 #endif
01357          /* Take us out of the queue */
01358          if (prev)
01359             prev->next = cur->next;
01360          else
01361             q->head = cur->next;
01362       } else {
01363          /* Renumber the people after us in the queue based on a new count */
01364          cur->pos = ++pos;
01365          prev = cur;
01366       }
01367       cur = cur->next;
01368    }
01369    ast_mutex_unlock(&q->lock);
01370    if (q->dead && !q->count) {   
01371       /* It's dead and nobody is in it, so kill it */
01372       remove_queue(q);
01373       destroy_queue(q);
01374    }
01375 }

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

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

03984 {
03985    int res;
03986    
03987    res = ast_register_application(app, queue_exec, synopsis, descrip);
03988    res |= ast_cli_register(&cli_show_queue);
03989    res |= ast_cli_register(&cli_show_queues);
03990    res |= ast_cli_register(&cli_add_queue_member);
03991    res |= ast_cli_register(&cli_remove_queue_member);
03992    res |= ast_devstate_add(statechange_queue, NULL);
03993    res |= ast_manager_register( "Queues", 0, manager_queues_show, "Queues" );
03994    res |= ast_manager_register( "QueueStatus", 0, manager_queues_status, "Queue Status" );
03995    res |= ast_manager_register( "QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue." );
03996    res |= ast_manager_register( "QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue." );
03997    res |= ast_manager_register( "QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable" );
03998    res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip) ;
03999    res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip) ;
04000    res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip) ;
04001    res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip) ;
04002    res |= ast_custom_function_register(&queueagentcount_function);
04003 
04004    if (!res) { 
04005       reload_queues();
04006       if (queue_persistent_members)
04007          reload_queue_members();
04008    }
04009 
04010    return res;
04011 }

static struct call_queue* load_realtime_queue ( char *  queuename  )  [static]

Definition at line 1047 of file app_queue.c.

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

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

01048 {
01049    struct ast_variable *queue_vars = NULL;
01050    struct ast_config *member_config = NULL;
01051    struct call_queue *q;
01052 
01053    /* Find the queue in the in-core list first. */
01054    ast_mutex_lock(&qlock);
01055    for (q = queues; q; q = q->next) {
01056       if (!strcasecmp(q->name, queuename)) {
01057          break;
01058       }
01059    }
01060    ast_mutex_unlock(&qlock);
01061 
01062    if (!q || q->realtime) {
01063       /*! \note Load from realtime before taking the global qlock, to avoid blocking all
01064          queue operations while waiting for the DB.
01065 
01066          This will be two separate database transactions, so we might
01067          see queue parameters as they were before another process
01068          changed the queue and member list as it was after the change.
01069          Thus we might see an empty member list when a queue is
01070          deleted. In practise, this is unlikely to cause a problem. */
01071 
01072       queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
01073       if (queue_vars) {
01074          member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
01075          if (!member_config) {
01076             ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
01077             return NULL;
01078          }
01079       }
01080 
01081       ast_mutex_lock(&qlock);
01082 
01083       q = find_queue_by_name_rt(queuename, queue_vars, member_config);
01084       if (member_config)
01085          ast_config_destroy(member_config);
01086       if (queue_vars)
01087          ast_variables_destroy(queue_vars);
01088 
01089       ast_mutex_unlock(&qlock);
01090    }
01091    return q;
01092 }

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

Definition at line 3669 of file app_queue.c.

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

Referenced by load_module().

03670 {
03671    char *queuename, *interface, *penalty_s, *paused_s;
03672    int paused, penalty = 0;
03673 
03674    queuename = astman_get_header(m, "Queue");
03675    interface = astman_get_header(m, "Interface");
03676    penalty_s = astman_get_header(m, "Penalty");
03677    paused_s = astman_get_header(m, "Paused");
03678 
03679    if (ast_strlen_zero(queuename)) {
03680       astman_send_error(s, m, "'Queue' not specified.");
03681       return 0;
03682    }
03683 
03684    if (ast_strlen_zero(interface)) {
03685       astman_send_error(s, m, "'Interface' not specified.");
03686       return 0;
03687    }
03688 
03689    if (ast_strlen_zero(penalty_s))
03690       penalty = 0;
03691    else if (sscanf(penalty_s, "%d", &penalty) != 1) {
03692       penalty = 0;
03693    }
03694 
03695    if (ast_strlen_zero(paused_s))
03696       paused = 0;
03697    else
03698       paused = abs(ast_true(paused_s));
03699 
03700    switch (add_to_queue(queuename, interface, penalty, paused, queue_persistent_members)) {
03701    case RES_OKAY:
03702       astman_send_ack(s, m, "Added interface to queue");
03703       break;
03704    case RES_EXISTS:
03705       astman_send_error(s, m, "Unable to add interface: Already there");
03706       break;
03707    case RES_NOSUCHQUEUE:
03708       astman_send_error(s, m, "Unable to add interface to queue: No such queue");
03709       break;
03710    case RES_OUTOFMEMORY:
03711       astman_send_error(s, m, "Out of memory");
03712       break;
03713    }
03714    return 0;
03715 }

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

Definition at line 3746 of file app_queue.c.

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

Referenced by load_module().

03747 {
03748    char *queuename, *interface, *paused_s;
03749    int paused;
03750 
03751    interface = astman_get_header(m, "Interface");
03752    paused_s = astman_get_header(m, "Paused");
03753    queuename = astman_get_header(m, "Queue");   /* Optional - if not supplied, pause the given Interface in all queues */
03754 
03755    if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
03756       astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
03757       return 0;
03758    }
03759 
03760    paused = abs(ast_true(paused_s));
03761 
03762    if (set_member_paused(queuename, interface, paused))
03763       astman_send_error(s, m, "Interface not found");
03764    else
03765       if (paused)
03766          astman_send_ack(s, m, "Interface paused successfully");
03767       else
03768          astman_send_ack(s, m, "Interface unpaused successfully");
03769 
03770    return 0;
03771 }

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

Definition at line 3570 of file app_queue.c.

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

Referenced by load_module().

03571 {
03572    char *a[] = { "show", "queues" };
03573    __queues_show(1, s->fd, 2, a, 0);
03574    ast_cli(s->fd, "\r\n\r\n");   /* Properly terminate Manager output */
03575 
03576    return RESULT_SUCCESS;
03577 } 

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

Definition at line 3580 of file app_queue.c.

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

Referenced by load_module().

03581 {
03582    time_t now;
03583    int pos;
03584    char *id = astman_get_header(m,"ActionID");
03585    char *queuefilter = astman_get_header(m,"Queue");
03586    char *memberfilter = astman_get_header(m,"Member");
03587    char idText[256] = "";
03588    struct call_queue *q;
03589    struct queue_ent *qe;
03590    float sl = 0;
03591    struct member *mem;
03592 
03593    astman_send_ack(s, m, "Queue status will follow");
03594    time(&now);
03595    ast_mutex_lock(&qlock);
03596    if (!ast_strlen_zero(id)) {
03597       snprintf(idText,256,"ActionID: %s\r\n",id);
03598    }
03599    for (q = queues; q; q = q->next) {
03600       ast_mutex_lock(&q->lock);
03601 
03602       /* List queue properties */
03603       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
03604          if(q->callscompleted > 0)
03605             sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
03606          ast_cli(s->fd, "Event: QueueParams\r\n"
03607                   "Queue: %s\r\n"
03608                   "Max: %d\r\n"
03609                   "Calls: %d\r\n"
03610                   "Holdtime: %d\r\n"
03611                   "Completed: %d\r\n"
03612                   "Abandoned: %d\r\n"
03613                   "ServiceLevel: %d\r\n"
03614                   "ServicelevelPerf: %2.1f\r\n"
03615                   "Weight: %d\r\n"
03616                   "%s"
03617                   "\r\n",
03618                      q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
03619                      q->callsabandoned, q->servicelevel, sl, q->weight, idText);
03620          /* List Queue Members */
03621          for (mem = q->members; mem; mem = mem->next) {
03622             if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
03623                ast_cli(s->fd, "Event: QueueMember\r\n"
03624                   "Queue: %s\r\n"
03625                   "Location: %s\r\n"
03626                   "Membership: %s\r\n"
03627                   "Penalty: %d\r\n"
03628                   "CallsTaken: %d\r\n"
03629                   "LastCall: %d\r\n"
03630                   "Status: %d\r\n"
03631                   "Paused: %d\r\n"
03632                   "%s"
03633                   "\r\n",
03634                      q->name, mem->interface, mem->dynamic ? "dynamic" : "static",
03635                      mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
03636             }
03637          }
03638          /* List Queue Entries */
03639          pos = 1;
03640          for (qe = q->head; qe; qe = qe->next) {
03641             ast_cli(s->fd, "Event: QueueEntry\r\n"
03642                "Queue: %s\r\n"
03643                "Position: %d\r\n"
03644                "Channel: %s\r\n"
03645                "CallerID: %s\r\n"
03646                "CallerIDName: %s\r\n"
03647                "Wait: %ld\r\n"
03648                "%s"
03649                "\r\n", 
03650                   q->name, pos++, qe->chan->name, 
03651                   qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
03652                   qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
03653                   (long)(now - qe->start), idText);
03654          }
03655       }
03656       ast_mutex_unlock(&q->lock);
03657    }
03658 
03659    ast_cli(s->fd,
03660       "Event: QueueStatusComplete\r\n"
03661       "%s"
03662       "\r\n",idText);
03663 
03664    ast_mutex_unlock(&qlock);
03665 
03666    return RESULT_SUCCESS;
03667 }

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

Definition at line 3717 of file app_queue.c.

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

Referenced by load_module().

03718 {
03719    char *queuename, *interface;
03720 
03721    queuename = astman_get_header(m, "Queue");
03722    interface = astman_get_header(m, "Interface");
03723 
03724    if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
03725       astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
03726       return 0;
03727    }
03728 
03729    switch (remove_from_queue(queuename, interface)) {
03730    case RES_OKAY:
03731       astman_send_ack(s, m, "Removed interface from queue");
03732       break;
03733    case RES_EXISTS:
03734       astman_send_error(s, m, "Unable to remove interface: Not there");
03735       break;
03736    case RES_NOSUCHQUEUE:
03737       astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
03738       break;
03739    case RES_OUTOFMEMORY:
03740       astman_send_error(s, m, "Out of memory");
03741       break;
03742    }
03743    return 0;
03744 }

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

Definition at line 1160 of file app_queue.c.

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

Referenced by say_position(), and try_calling().

01161 {
01162    int res;
01163 
01164    ast_stopstream(chan);
01165    res = ast_streamfile(chan, filename, chan->language);
01166 
01167    if (!res)
01168       res = ast_waitstream(chan, AST_DIGIT_ANY);
01169    else
01170       res = 0;
01171 
01172    ast_stopstream(chan);
01173 
01174    return res;
01175 }

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

Definition at line 2735 of file app_queue.c.

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

Referenced by load_module().

02736 {
02737    struct localuser *u;
02738    char *parse;
02739    int priority_jump = 0;
02740    AST_DECLARE_APP_ARGS(args,
02741       AST_APP_ARG(queuename);
02742       AST_APP_ARG(interface);
02743       AST_APP_ARG(options);
02744    );
02745 
02746    if (ast_strlen_zero(data)) {
02747       ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
02748       return -1;
02749    }
02750 
02751    LOCAL_USER_ADD(u);
02752 
02753    if (!(parse = ast_strdupa(data))) {
02754       ast_log(LOG_WARNING, "Memory Error!\n");
02755       LOCAL_USER_REMOVE(u);
02756       return -1;
02757    }
02758 
02759    AST_STANDARD_APP_ARGS(args, parse);
02760 
02761    if (args.options) {
02762       if (strchr(args.options, 'j'))
02763          priority_jump = 1;
02764    }
02765 
02766    if (ast_strlen_zero(args.interface)) {
02767       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
02768       LOCAL_USER_REMOVE(u);
02769       return -1;
02770    }
02771 
02772    if (set_member_paused(args.queuename, args.interface, 1)) {
02773       ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
02774       if (priority_jump || option_priority_jumping) {
02775          if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
02776             pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
02777             LOCAL_USER_REMOVE(u);
02778             return 0;
02779          }
02780       }
02781       LOCAL_USER_REMOVE(u);
02782       pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
02783       return -1;
02784    }
02785 
02786    LOCAL_USER_REMOVE(u);
02787    pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
02788    return 0;
02789 }

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

Definition at line 2990 of file app_queue.c.

References AST_CONTROL_RINGING, ast_indicate(), ast_log(), ast_moh_start(), ast_moh_stop(), AST_PBX_KEEPALIVE, ast_queue_log(), ast_stopstream(), ast_strlen_zero(), ast_verbose(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, get_member_status(), is_our_turn(), join_queue(), leave_queue(), LOCAL_USER_ADD, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_debug, option_verbose, pbx_builtin_getvar_helper(), QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), say_periodic_announcement(), say_position(), set_queue_result(), strsep(), try_calling(), ast_channel::uniqueid, valid_exit(), VERBOSE_PREFIX_3, wait_a_bit(), and wait_our_turn().

Referenced by load_module().

02991 {
02992    int res=-1;
02993    int ringing=0;
02994    struct localuser *u;
02995    char *queuename;
02996    char info[512];
02997    char *info_ptr = info;
02998    char *options = NULL;
02999    char *url = NULL;
03000    char *announceoverride = NULL;
03001    char *user_priority;
03002    int prio;
03003    char *queuetimeoutstr = NULL;
03004    enum queue_result reason = QUEUE_UNKNOWN;
03005 
03006    /* whether to exit Queue application after the timeout hits */
03007    int go_on = 0;
03008 
03009    /* Our queue entry */
03010    struct queue_ent qe;
03011    
03012    if (ast_strlen_zero(data)) {
03013       ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
03014       return -1;
03015    }
03016 
03017    LOCAL_USER_ADD(u);
03018 
03019    /* Setup our queue entry */
03020    memset(&qe, 0, sizeof(qe));
03021    qe.start = time(NULL);
03022    
03023    /* Parse our arguments XXX Check for failure XXX */
03024    ast_copy_string(info, (char *) data, sizeof(info));
03025    queuename = strsep(&info_ptr, "|");
03026    options = strsep(&info_ptr, "|");
03027    url = strsep(&info_ptr, "|");
03028    announceoverride = strsep(&info_ptr, "|");
03029    queuetimeoutstr = info_ptr;
03030 
03031    /* set the expire time based on the supplied timeout; */
03032    if (!ast_strlen_zero(queuetimeoutstr))
03033       qe.expire = qe.start + atoi(queuetimeoutstr);
03034    else
03035       qe.expire = 0;
03036 
03037    /* Get the priority from the variable ${QUEUE_PRIO} */
03038    user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
03039    if (user_priority) {
03040       if (sscanf(user_priority, "%d", &prio) == 1) {
03041          if (option_debug)
03042             ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
03043                chan->name, prio);
03044       } else {
03045          ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
03046             user_priority, chan->name);
03047          prio = 0;
03048       }
03049    } else {
03050       if (option_debug > 2)
03051          ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
03052       prio = 0;
03053    }
03054 
03055    if (options && (strchr(options, 'r')))
03056       ringing = 1;
03057 
03058    if (option_debug)  
03059       ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
03060          queuename, options, url, announceoverride, (long)qe.expire, (int)prio);
03061 
03062    qe.chan = chan;
03063    qe.prio = (int)prio;
03064    qe.last_pos_said = 0;
03065    qe.last_pos = 0;
03066    qe.last_periodic_announce_time = time(NULL);
03067    if (!join_queue(queuename, &qe, &reason)) {
03068       ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "",
03069                chan->cid.cid_num ? chan->cid.cid_num : "");
03070 check_turns:
03071       if (ringing) {
03072          ast_indicate(chan, AST_CONTROL_RINGING);
03073       } else {
03074          ast_moh_start(chan, qe.moh);
03075       }
03076       for (;;) {
03077          /* This is the wait loop for callers 2 through maxlen */
03078 
03079          res = wait_our_turn(&qe, ringing, &reason);
03080          /* If they hungup, return immediately */
03081          if (res < 0) {
03082             /* Record this abandoned call */
03083             record_abandoned(&qe);
03084             ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
03085             if (option_verbose > 2) {
03086                ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
03087             }
03088             res = -1;
03089             break;
03090          }
03091          if (!res) 
03092             break;
03093          if (valid_exit(&qe, res)) {
03094             ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
03095             break;
03096          }
03097       }
03098       if (!res) {
03099          int makeannouncement = 0;
03100          for (;;) {
03101             /* This is the wait loop for the head caller*/
03102             /* To exit, they may get their call answered; */
03103             /* they may dial a digit from the queue context; */
03104             /* or, they may timeout. */
03105 
03106             enum queue_member_status stat;
03107 
03108             /* Leave if we have exceeded our queuetimeout */
03109             if (qe.expire && (time(NULL) > qe.expire)) {
03110                record_abandoned(&qe);
03111                reason = QUEUE_TIMEOUT;
03112                res = 0;
03113                ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
03114                break;
03115             }
03116 
03117             if (makeannouncement) {
03118                /* Make a position announcement, if enabled */
03119                if (qe.parent->announcefrequency && !ringing &&
03120                    (res = say_position(&qe))) {
03121                   ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
03122                   break;
03123                }
03124 
03125             }
03126             makeannouncement = 1;
03127 
03128             /* Make a periodic announcement, if enabled */
03129             if (qe.parent->periodicannouncefrequency && !ringing &&
03130                 (res = say_periodic_announcement(&qe))) {
03131                ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
03132                break;
03133             }
03134 
03135             /* Try calling all queue members for 'timeout' seconds */
03136             res = try_calling(&qe, options, announceoverride, url, &go_on);
03137             if (res) {
03138                if (res < 0) {
03139                   if (!qe.handled) {
03140                      record_abandoned(&qe);
03141                      ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
03142                   }
03143                } else if (valid_exit(&qe, res)) {
03144                   ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
03145                }
03146                break;
03147             }
03148 
03149             stat = get_member_status(qe.parent);
03150 
03151             /* leave the queue if no agents, if enabled */
03152             if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
03153                record_abandoned(&qe);
03154                reason = QUEUE_LEAVEEMPTY;
03155                res = 0;
03156                break;
03157             }
03158 
03159             /* leave the queue if no reachable agents, if enabled */
03160             if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
03161                record_abandoned(&qe);
03162                reason = QUEUE_LEAVEUNAVAIL;
03163                res = 0;
03164                break;
03165             }
03166 
03167             /* Leave if we have exceeded our queuetimeout */
03168             if (qe.expire && (time(NULL) > qe.expire)) {
03169                record_abandoned(&qe);
03170                reason = QUEUE_TIMEOUT;
03171                res = 0;
03172                ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);   
03173                break;
03174             }
03175 
03176             /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
03177             res = wait_a_bit(&qe);
03178             if (res < 0) {
03179                record_abandoned(&qe);
03180                ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
03181                if (option_verbose > 2) {
03182                   ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
03183                }
03184                res = -1;
03185                break;
03186             }
03187             if (res && valid_exit(&qe, res)) {
03188                ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
03189                break;
03190             }
03191             /* exit after 'timeout' cycle if 'n' option enabled */
03192             if (go_on) {
03193                if (option_verbose > 2)
03194                   ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
03195                ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
03196                record_abandoned(&qe);
03197                reason = QUEUE_TIMEOUT;
03198                res = 0;
03199                break;
03200             }
03201             /* Since this is a priority queue and 
03202              * it is not sure that we are still at the head
03203              * of the queue, go and check for our turn again.
03204              */
03205             if (!is_our_turn(&qe)) {
03206                if (option_debug)
03207                   ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
03208                      qe.chan->name);
03209                goto check_turns;
03210             }
03211          }
03212       }
03213       /* Don't allow return code > 0 */
03214       if (res >= 0 && res != AST_PBX_KEEPALIVE) {
03215          res = 0; 
03216          if (ringing) {
03217             ast_indicate(chan, -1);
03218          } else {
03219             ast_moh_stop(chan);
03220          }        
03221          ast_stopstream(chan);
03222       }
03223       leave_queue(&qe);
03224       if (reason != QUEUE_UNKNOWN)
03225          set_queue_result(chan, reason);
03226    } else {
03227       ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
03228       set_queue_result(chan, reason);
03229       res = 0;
03230    }
03231    LOCAL_USER_REMOVE(u);
03232    return res;
03233 }

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

Definition at line 3235 of file app_queue.c.

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

03236 {
03237    int count = 0;
03238    struct call_queue *q;
03239    struct localuser *u;
03240    struct member *m;
03241 
03242    LOCAL_USER_ACF_ADD(u);
03243 
03244    ast_copy_string(buf, "0", len);
03245    
03246    if (ast_strlen_zero(data)) {
03247       ast_log(LOG_ERROR, "QUEUEAGENTCOUNT requires an argument: queuename\n");
03248       LOCAL_USER_REMOVE(u);
03249       return buf;
03250    }
03251 
03252    ast_mutex_lock(&qlock);
03253 
03254    /* Find the right queue */
03255    for (q = queues; q; q = q->next) {
03256       if (!strcasecmp(q->name, data)) {
03257          ast_mutex_lock(&q->lock);
03258          break;
03259       }
03260    }
03261 
03262    ast_mutex_unlock(&qlock);
03263 
03264    if (q) {
03265       for (m = q->members; m; m = m->next) {
03266          /* Count the agents who are logged in and presently answering calls */
03267          if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
03268             count++;
03269          }
03270       }
03271       ast_mutex_unlock(&q->lock);
03272    }
03273 
03274    snprintf(buf, len, "%d", count);
03275    LOCAL_USER_REMOVE(u);
03276    return buf;
03277 }

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

Configure a queue parameter.

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

Definition at line 718 of file app_queue.c.

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

Referenced by reload_queues().

00719 {
00720    if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
00721       ast_copy_string(q->moh, val, sizeof(q->moh));
00722    } else if (!strcasecmp(param, "announce")) {
00723       ast_copy_string(q->announce, val, sizeof(q->announce));
00724    } else if (!strcasecmp(param, "context")) {
00725       ast_copy_string(q->context, val, sizeof(q->context));
00726    } else if (!strcasecmp(param, "timeout")) {
00727       q->timeout = atoi(val);
00728       if (q->timeout < 0)
00729          q->timeout = DEFAULT_TIMEOUT;
00730    } else if (!strcasecmp(param, "monitor-join")) {
00731       q->monjoin = ast_true(val);
00732    } else if (!strcasecmp(param, "monitor-format")) {
00733       ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
00734    } else if (!strcasecmp(param, "queue-youarenext")) {
00735       ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
00736    } else if (!strcasecmp(param, "queue-thereare")) {
00737       ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
00738    } else if (!strcasecmp(param, "queue-callswaiting")) {
00739       ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
00740    } else if (!strcasecmp(param, "queue-holdtime")) {
00741       ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
00742    } else if (!strcasecmp(param, "queue-minutes")) {
00743       ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
00744    } else if (!strcasecmp(param, "queue-seconds")) {
00745       ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
00746    } else if (!strcasecmp(param, "queue-lessthan")) {
00747       ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
00748    } else if (!strcasecmp(param, "queue-thankyou")) {
00749       ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
00750    } else if (!strcasecmp(param, "queue-reporthold")) {
00751       ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
00752    } else if (!strcasecmp(param, "announce-frequency")) {
00753       q->announcefrequency = atoi(val);
00754    } else if (!strcasecmp(param, "announce-round-seconds")) {
00755       q->roundingseconds = atoi(val);
00756       if (q->roundingseconds>60 || q->roundingseconds<0) {
00757          if (linenum >= 0) {
00758             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
00759                "using 0 instead for queue '%s' at line %d of queues.conf\n",
00760                val, param, q->name, linenum);
00761          } else {
00762             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
00763                "using 0 instead for queue '%s'\n", val, param, q->name);
00764          }
00765          q->roundingseconds=0;
00766       }
00767    } else if (!strcasecmp(param, "announce-holdtime")) {
00768       if (!strcasecmp(val, "once"))
00769          q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
00770       else if (ast_true(val))
00771          q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
00772       else
00773          q->announceholdtime = 0;
00774     } else if (!strcasecmp(param, "periodic-announce")) {
00775       ast_copy_string(q->sound_periodicannounce, val, sizeof(q->sound_periodicannounce));
00776    } else if (!strcasecmp(param, "periodic-announce-frequency")) {
00777       q->periodicannouncefrequency = atoi(val);
00778    } else if (!strcasecmp(param, "retry")) {
00779       q->retry = atoi(val);
00780       if (q->retry <= 0)
00781          q->retry = DEFAULT_RETRY;
00782    } else if (!strcasecmp(param, "wrapuptime")) {
00783       q->wrapuptime = atoi(val);
00784    } else if (!strcasecmp(param, "maxlen")) {
00785       q->maxlen = atoi(val);
00786       if (q->maxlen < 0)
00787          q->maxlen = 0;
00788    } else if (!strcasecmp(param, "servicelevel")) {
00789       q->servicelevel= atoi(val);
00790    } else if (!strcasecmp(param, "strategy")) {
00791       q->strategy = strat2int(val);
00792       if (q->strategy < 0) {
00793          ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
00794             val, q->name);
00795          q->strategy = 0;
00796       }
00797    } else if (!strcasecmp(param, "joinempty")) {
00798       if (!strcasecmp(val, "strict"))
00799          q->joinempty = QUEUE_EMPTY_STRICT;
00800       else if (ast_true(val))
00801          q->joinempty = QUEUE_EMPTY_NORMAL;
00802       else
00803          q->joinempty = 0;
00804    } else if (!strcasecmp(param, "leavewhenempty")) {
00805       if (!strcasecmp(val, "strict"))
00806          q->leavewhenempty = QUEUE_EMPTY_STRICT;
00807       else if (ast_true(val))
00808          q->leavewhenempty = QUEUE_EMPTY_NORMAL;
00809       else
00810          q->leavewhenempty = 0;
00811    } else if (!strcasecmp(param, "eventmemberstatus")) {
00812       q->maskmemberstatus = !ast_true(val);
00813    } else if (!strcasecmp(param, "eventwhencalled")) {
00814       q->eventwhencalled = ast_true(val);
00815    } else if (!strcasecmp(param, "reportholdtime")) {
00816       q->reportholdtime = ast_true(val);
00817    } else if (!strcasecmp(param, "memberdelay")) {
00818       q->memberdelay = atoi(val);
00819    } else if (!strcasecmp(param, "weight")) {
00820       q->weight = atoi(val);
00821       if (q->weight)
00822          use_weight++;
00823       /* With Realtime queues, if the last queue using weights is deleted in realtime,
00824          we will not see any effect on use_weight until next reload. */
00825    } else if (!strcasecmp(param, "timeoutrestart")) {
00826       q->timeoutrestart = ast_true(val);
00827    } else if(failunknown) {
00828       if (linenum >= 0) {
00829          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
00830             q->name, param, linenum);
00831       } else {
00832          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
00833       }
00834    }
00835 }

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

Definition at line 3546 of file app_queue.c.

References __queues_show().

03547 {
03548    return __queues_show(0, fd, argc, argv, 1);
03549 }

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

Definition at line 3541 of file app_queue.c.

References __queues_show().

03542 {
03543    return __queues_show(0, fd, argc, argv, 0);
03544 }

static void recalc_holdtime ( struct queue_ent qe  )  [static]

Definition at line 1314 of file app_queue.c.

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

Referenced by try_calling().

01315 {
01316    int oldvalue, newvalue;
01317 
01318    /* Calculate holdtime using a recursive boxcar filter */
01319    /* Thanks to SRT for this contribution */
01320    /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
01321 
01322    newvalue = time(NULL) - qe->start;
01323 
01324    ast_mutex_lock(&qe->parent->lock);
01325    if (newvalue <= qe->parent->servicelevel)
01326       qe->parent->callscompletedinsl++;
01327    oldvalue = qe->parent->holdtime;
01328    qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
01329    ast_mutex_unlock(&qe->parent->lock);
01330 }

static void record_abandoned ( struct queue_ent qe  )  [static]

Definition at line 1730 of file app_queue.c.

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

Referenced by queue_exec(), and try_calling().

01731 {
01732    ast_mutex_lock(&qe->parent->lock);
01733    qe->parent->callsabandoned++;
01734    ast_mutex_unlock(&qe->parent->lock);
01735 }

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

References reload_queues().

04015 {
04016    reload_queues();
04017    return 0;
04018 }

static void reload_queue_members ( void   )  [static]

Definition at line 2646 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(), member::interface, ast_db_entry::key, call_queue::lock, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, call_queue::name, call_queue::next, ast_db_entry::next, option_debug, member::paused, member::penalty, pm_family, PM_MAX_LEN, queues, RES_OUTOFMEMORY, and strsep().

Referenced by load_module().

02647 {
02648    char *cur_ptr; 
02649    char *queue_name;
02650    char *member;
02651    char *interface;
02652    char *penalty_tok;
02653    int penalty = 0;
02654    char *paused_tok;
02655    int paused = 0;
02656    struct ast_db_entry *db_tree;
02657    struct ast_db_entry *entry;
02658    struct call_queue *cur_queue;
02659    char queue_data[PM_MAX_LEN];
02660 
02661    ast_mutex_lock(&qlock);
02662 
02663    /* Each key in 'pm_family' is the name of a queue */
02664    db_tree = ast_db_gettree(pm_family, NULL);
02665    for (entry = db_tree; entry; entry = entry->next) {
02666 
02667       queue_name = entry->key + strlen(pm_family) + 2;
02668 
02669       cur_queue = queues;
02670       while (cur_queue) {
02671          ast_mutex_lock(&cur_queue->lock);
02672          if (!strcmp(queue_name, cur_queue->name))
02673             break;
02674          ast_mutex_unlock(&cur_queue->lock);
02675          cur_queue = cur_queue->next;
02676       }
02677 
02678       if (!cur_queue) {
02679          /* If the queue no longer exists, remove it from the
02680           * database */
02681          ast_db_del(pm_family, queue_name);
02682          continue;
02683       } else
02684          ast_mutex_unlock(&cur_queue->lock);
02685 
02686       if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
02687          continue;
02688 
02689       cur_ptr = queue_data;
02690       while ((member = strsep(&cur_ptr, "|"))) {
02691          if (ast_strlen_zero(member))
02692             continue;
02693 
02694          interface = strsep(&member, ";");
02695          penalty_tok = strsep(&member, ";");
02696          paused_tok = strsep(&member, ";");
02697 
02698          if (!penalty_tok) {
02699             ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
02700             break;
02701          }
02702          penalty = strtol(penalty_tok, NULL, 10);
02703          if (errno == ERANGE) {
02704             ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
02705             break;
02706          }
02707          
02708          if (!paused_tok) {
02709             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
02710             break;
02711          }
02712          paused = strtol(paused_tok, NULL, 10);
02713          if ((errno == ERANGE) || paused < 0 || paused > 1) {
02714             ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
02715             break;
02716          }
02717 
02718          if (option_debug)
02719             ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Penalty: %d  Paused: %d\n", queue_name, interface, penalty, paused);
02720          
02721          if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
02722             ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
02723             break;
02724          }
02725       }
02726    }
02727 
02728    ast_mutex_unlock(&qlock);
02729    if (db_tree) {
02730       ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
02731       ast_db_freetree(db_tree);
02732    }
02733 }

static void reload_queues ( void   )  [static]

Definition at line 3286 of file app_queue.c.

References add_to_interfaces(), 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(), call_queue::count, create_queue_member(), call_queue::dead, member::delme, destroy_queue(), member::dynamic, free, init_queue(), member::interface, call_queue::lock, LOG_NOTICE, LOG_WARNING, call_queue::members, call_queue::name, member::next, call_queue::next, member::paused, member::penalty, queue_persistent_members, queue_set_param(), queues, remove_from_interfaces(), member::status, use_weight, and var.

Referenced by load_module(), and reload().

03287 {
03288    struct call_queue *q, *ql, *qn;
03289    struct ast_config *cfg;
03290    char *cat, *tmp;
03291    struct ast_variable *var;
03292    struct member *prev, *cur, *newm;
03293    int new;
03294    char *general_val = NULL;
03295    char interface[80];
03296    int penalty;
03297    
03298    cfg = ast_config_load("queues.conf");
03299    if (!cfg) {
03300       ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
03301       return;
03302    }
03303    memset(interface, 0, sizeof(interface));
03304    ast_mutex_lock(&qlock);
03305    use_weight=0;
03306    /* Mark all queues as dead for the moment */
03307    q = queues;
03308    while(q) {
03309       q->dead = 1;
03310       q = q->next;
03311    }
03312    /* Chug through config file */
03313    cat = ast_category_browse(cfg, NULL);
03314    while(cat) {
03315       if (!strcasecmp(cat, "general")) {  
03316          /* Initialize global settings */
03317          queue_persistent_members = 0;
03318          if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
03319             queue_persistent_members = ast_true(general_val);
03320       } else { /* Define queue */
03321          /* Look for an existing one */
03322          q = queues;
03323          while(q) {
03324             if (!strcmp(q->name, cat))
03325                break;
03326             q = q->next;
03327          }
03328          if (!q) {
03329             /* Make one then */
03330             q = alloc_queue(cat);
03331             new = 1;
03332          } else
03333             new = 0;
03334          if (q) {
03335             if (!new)
03336                ast_mutex_lock(&q->lock);
03337             /* Re-initialize the queue, and clear statistics */
03338             init_queue(q);
03339             clear_queue(q);
03340             for (cur = q->members; cur; cur = cur->next) {
03341                if (!cur->dynamic) {
03342                   cur->delme = 1;
03343                }
03344             }
03345             var = ast_variable_browse(cfg, cat);
03346             while (var) {
03347                if (!strcasecmp(var->name, "member")) {
03348                   /* Add a new member */
03349                   ast_copy_string(interface, var->value, sizeof(interface));
03350                   if ((tmp = strchr(interface, ','))) {
03351                      *tmp = '\0';
03352                      tmp++;
03353                      penalty = atoi(tmp);
03354                      if (penalty < 0) {
03355                         penalty = 0;
03356                      }
03357                   } else
03358                      penalty = 0;
03359 
03360                   /* Find the old position in the list */
03361                   for (prev = NULL, cur = q->members; cur; prev = cur, cur = cur->next) {
03362                      if (!strcmp(cur->interface, interface)) {
03363                         break;
03364                      }
03365                   }
03366 
03367                   newm = create_queue_member(interface, penalty, cur ? cur->paused : 0);
03368 
03369                   if (cur) {
03370                      /* Delete it now */
03371                      newm->next = cur->next;
03372                      if (prev) {
03373                         prev->next = newm;
03374                      } else {
03375                         q->members = newm;
03376                      }
03377                      free(cur);
03378                   } else {
03379                      /* Add them to the master int list if necessary */
03380                      add_to_interfaces(interface);
03381                      newm->next = q->members;
03382                      q->members = newm;
03383                   }
03384                } else {
03385                   queue_set_param(q, var->name, var->value, var->lineno, 1);
03386                }
03387                var = var->next;
03388             }
03389 
03390             /* Free remaining members marked as delme */
03391             for (prev = NULL, newm = NULL, cur = q->members; cur; prev = cur, cur = cur->next) {
03392                if (newm) {
03393                   free(newm);
03394                   newm = NULL;
03395                }
03396 
03397                if (cur->delme) {
03398                   if (prev) {
03399                      prev->next = cur->next;
03400                      newm = cur;
03401                   } else {
03402                      q->members = cur->next;
03403                      newm = cur;
03404                   }
03405                   remove_from_interfaces(cur->interface);
03406                }
03407             }
03408             if (!new) 
03409                ast_mutex_unlock(&q->lock);
03410             if (new) {
03411                q->next = queues;
03412                queues = q;
03413             }
03414          }
03415       }
03416       cat = ast_category_browse(cfg, cat);
03417    }
03418    ast_config_destroy(cfg);
03419    q = queues;
03420    ql = NULL;
03421    while(q) {
03422       qn = q->next;
03423       if (q->dead) {
03424          if (ql)
03425             ql->next = q->next;
03426          else
03427             queues = q->next;
03428          if (!q->count) {
03429             destroy_queue(q);
03430          } else
03431             ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
03432       } else {
03433          ast_mutex_lock(&q->lock);
03434          for (cur = q->members; cur; cur = cur->next)
03435             cur->status = ast_device_state(cur->interface);
03436          ql = q;
03437          ast_mutex_unlock(&q->lock);
03438       }
03439       q = qn;
03440    }
03441    ast_mutex_unlock(&qlock);
03442 }

static int remove_from_interfaces ( char *  interface  )  [static]

Definition at line 676 of file app_queue.c.

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

Referenced by free_members(), and reload_queues().

00677 {
00678    struct member_interface *curint;
00679 
00680    if (!interface)
00681       return 0;
00682 
00683    AST_LIST_LOCK(&interfaces);
00684    AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
00685       if (!strcasecmp(curint->interface, interface)) {
00686          if (!interface_exists_global(interface)) {
00687             if (option_debug)
00688                ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
00689             AST_LIST_REMOVE_CURRENT(&interfaces, list);
00690             free(curint);
00691          }
00692          break;
00693       }
00694    }
00695    AST_LIST_TRAVERSE_SAFE_END;
00696    AST_LIST_UNLOCK(&interfaces);
00697 
00698    return 0;
00699 }

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

Definition at line 2503 of file app_queue.c.

References ast_mutex_lock(), dump_queue_members(), EVENT_FLAG_AGENT, free, member::interface, interface_exists(), call_queue::lock, manager_event(), call_queue::members, call_queue::name, member::next, call_queue::next, queue_persistent_members, queues, RES_NOSUCHQUEUE, and RES_OKAY.

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

02504 {
02505    struct call_queue *q;
02506    struct member *last_member, *look;
02507    int res = RES_NOSUCHQUEUE;
02508 
02509    ast_mutex_lock(&qlock);
02510    for (q = queues ; q ; q = q->next) {
02511       ast_mutex_lock(&q->lock);
02512       if (!strcmp(q->name, queuename)) {
02513          if ((last_member = interface_exists(q, interface))) {
02514             if ((look = q->members) == last_member) {
02515                q->members = last_member->next;
02516             } else {
02517                while (look != NULL) {
02518                   if (look->next == last_member) {
02519                      look->next = last_member->next;
02520                      break;
02521                   } else {
02522                       look = look->next;
02523                   }
02524                }
02525             }
02526             manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
02527                   "Queue: %s\r\n"
02528                   "Location: %s\r\n",
02529                q->name, last_member->interface);
02530             free(last_member);
02531 
02532             if (queue_persistent_members)
02533                dump_queue_members(q);
02534 
02535             res = RES_OKAY;
02536          } else {
02537             res = RES_EXISTS;
02538          }
02539          ast_mutex_unlock(&q->lock);
02540          break;
02541       }
02542       ast_mutex_unlock(&q->lock);
02543    }
02544    if (res == RES_OKAY)
02545       remove_from_interfaces(interface);
02546    ast_mutex_unlock(&qlock);
02547    return res;
02548 }

static void remove_queue ( struct call_queue q  )  [static]

Definition at line 900 of file app_queue.c.

References ast_mutex_lock(), ast_mutex_unlock(), call_queue::next, and queues.

Referenced by leave_queue().

00901 {
00902    struct call_queue *cur, *prev = NULL;
00903 
00904    ast_mutex_lock(&qlock);
00905    for (cur = queues; cur; cur = cur->next) {
00906       if (cur == q) {
00907          if (prev)
00908             prev->next = cur->next;
00909          else
00910             queues = cur->next;
00911       } else {
00912          prev = cur;
00913       }
00914    }
00915    ast_mutex_unlock(&qlock);
00916 }

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

Definition at line 1471 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_mutex_lock(), ast_mutex_unlock(), 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, call_queue::eventwhencalled, ast_channel::exten, free, localuser::interface, localuser::lastcall, call_queue::lock, LOG_DEBUG, LOG_NOTICE, manager_event(), localuser::member, ast_channel::name, call_queue::name, ast_channel::nativeformats, localuser::oldstatus, option_debug, option_verbose, queue_ent::parent, member::paused, ast_channel::priority, call_queue::rrpos, member::status, localuser::stillgoing, strdup, update_dial_status(), use_weight, VERBOSE_PREFIX_3, ast_channel::whentohangup, and call_queue::wrapuptime.

Referenced by ring_one().

01472 {
01473    int res;
01474    int status;
01475    char tech[256];
01476    char *location;
01477 
01478    if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
01479       if (option_debug)
01480          ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
01481       if (qe->chan->cdr)
01482          ast_cdr_busy(qe->chan->cdr);
01483       tmp->stillgoing = 0;
01484       (*busies)++;
01485       return 0;
01486    }
01487    
01488    if (tmp->member->paused) {
01489       if (option_debug)
01490          ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
01491       if (qe->chan->cdr)
01492          ast_cdr_busy(qe->chan->cdr);
01493       tmp->stillgoing = 0;
01494       return 0;
01495    }
01496    if (use_weight && compare_weight(qe->parent,tmp->member)) {
01497       ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
01498       if (qe->chan->cdr)
01499          ast_cdr_busy(qe->chan->cdr);
01500       tmp->stillgoing = 0;
01501       (*busies)++;
01502       return 0;
01503    }
01504 
01505    ast_copy_string(tech, tmp->interface, sizeof(tech));
01506    if ((location = strchr(tech, '/')))
01507       *location++ = '\0';
01508    else
01509       location = "";
01510 
01511    /* Request the peer */
01512    tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
01513    if (!tmp->chan) {       /* If we can't, just go on to the next call */
01514 #if 0
01515       ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
01516 #endif         
01517       if (qe->chan->cdr)
01518          ast_cdr_busy(qe->chan->cdr);
01519       tmp->stillgoing = 0;
01520       update_dial_status(qe->parent, tmp->member, status);
01521 
01522       ast_mutex_lock(&qe->parent->lock);
01523       qe->parent->rrpos++;
01524       ast_mutex_unlock(&qe->parent->lock);
01525 
01526       (*busies)++;
01527       return 0;
01528    } else if (status != tmp->oldstatus) 
01529       update_dial_status(qe->parent, tmp->member, status);
01530    
01531    tmp->chan->appl = "AppQueue";
01532    tmp->chan->data = "(Outgoing Line)";
01533    tmp->chan->whentohangup = 0;
01534    if (tmp->chan->cid.cid_num)
01535       free(tmp->chan->cid.cid_num);
01536    tmp->chan->cid.cid_num = NULL;
01537    if (tmp->chan->cid.cid_name)
01538       free(tmp->chan->cid.cid_name);
01539    tmp->chan->cid.cid_name = NULL;
01540    if (tmp->chan->cid.cid_ani)
01541       free(tmp->chan->cid.cid_ani);
01542    tmp->chan->cid.cid_ani = NULL;
01543    if (qe->chan->cid.cid_num)
01544       tmp->chan->cid.cid_num = strdup(qe->chan->cid.cid_num);
01545    if (qe->chan->cid.cid_name)
01546       tmp->chan->cid.cid_name = strdup(qe->chan->cid.cid_name);
01547    if (qe->chan->cid.cid_ani)
01548       tmp->chan->cid.cid_ani = strdup(qe->chan->cid.cid_ani);
01549 
01550    /* Inherit specially named variables from parent channel */
01551    ast_channel_inherit_variables(qe->chan, tmp->chan);
01552 
01553    /* Presense of ADSI CPE on outgoing channel follows ours */
01554    tmp->chan->adsicpe = qe->chan->adsicpe;
01555 
01556    /* Place the call, but don't wait on the answer */
01557    res = ast_call(tmp->chan, location, 0);
01558    if (res) {
01559       /* Again, keep going even if there's an error */
01560       if (option_debug)
01561          ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
01562       else if (option_verbose > 2)
01563          ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
01564       ast_hangup(tmp->chan);
01565       tmp->chan = NULL;
01566       tmp->stillgoing = 0;
01567       (*busies)++;
01568       return 0;
01569    } else {
01570       if (qe->parent->eventwhencalled) {
01571          manager_event(EVENT_FLAG_AGENT, "AgentCalled",
01572                   "AgentCalled: %s\r\n"
01573                   "ChannelCalling: %s\r\n"
01574                   "CallerID: %s\r\n"
01575                   "CallerIDName: %s\r\n"
01576                   "Context: %s\r\n"
01577                   "Extension: %s\r\n"
01578                   "Priority: %d\r\n",
01579                   tmp->interface, qe->chan->name,
01580                   tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
01581                   tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
01582                   qe->chan->context, qe->chan->exten, qe->chan->priority);
01583       }
01584       if (option_verbose > 2)
01585          ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
01586    }
01587    return 1;
01588 }

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

Definition at line 1590 of file app_queue.c.

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

Referenced by try_calling(), and wait_for_answer().

01591 {
01592    struct localuser *cur;
01593    struct localuser *best;
01594    int bestmetric=0;
01595 
01596    do {
01597       best = NULL;
01598       cur = outgoing;
01599       while(cur) {
01600          if (cur->stillgoing &&              /* Not already done */
01601             !cur->chan &&              /* Isn't already going */
01602             (!best || (cur->metric < bestmetric))) {  /* We haven't found one yet, or it's better */
01603                bestmetric = cur->metric;
01604                best = cur;
01605          }
01606          cur = cur->next;
01607       }
01608       if (best) {
01609          if (!qe->parent->strategy) {
01610             /* Ring everyone who shares this best metric (for ringall) */
01611             cur = outgoing;
01612             while(cur) {
01613                if (cur->stillgoing && !cur->chan && (cur->metric <= bestmetric)) {
01614                   if (option_debug)
01615                      ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
01616                   ring_entry(qe, cur, busies);
01617                }
01618                cur = cur->next;
01619             }
01620          } else {
01621             /* Ring just the best channel */
01622             if (option_debug)
01623                ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
01624             ring_entry(qe, best, busies);
01625          }
01626       }
01627    } while (best && !best->chan);
01628    if (!best) {
01629       if (option_debug)
01630          ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
01631       return 0;
01632    }
01633    return 1;
01634 }

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

Definition at line 2847 of file app_queue.c.

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

Referenced by load_module().

02848 {
02849    int res=-1;
02850    struct localuser *u;
02851    char *parse, *temppos = NULL;
02852    int priority_jump = 0;
02853    AST_DECLARE_APP_ARGS(args,
02854       AST_APP_ARG(queuename);
02855       AST_APP_ARG(interface);
02856       AST_APP_ARG(options);
02857    );
02858 
02859 
02860    if (ast_strlen_zero(data)) {
02861       ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
02862       return -1;
02863    }
02864 
02865    LOCAL_USER_ADD(u);
02866 
02867    if (!(parse = ast_strdupa(data))) {
02868       ast_log(LOG_WARNING, "Memory Error!\n");
02869       LOCAL_USER_REMOVE(u);
02870       return -1;
02871    }
02872 
02873    AST_STANDARD_APP_ARGS(args, parse);
02874 
02875    if (ast_strlen_zero(args.interface)) {
02876       args.interface = ast_strdupa(chan->name);
02877       temppos = strrchr(args.interface, '-');
02878       if (temppos)
02879          *temppos = '\0';
02880    }
02881 
02882    if (args.options) {
02883       if (strchr(args.options, 'j'))
02884          priority_jump = 1;
02885    }
02886 
02887    switch (remove_from_queue(args.queuename, args.interface)) {
02888    case RES_OKAY:
02889       ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
02890       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
02891       res = 0;
02892       break;
02893    case RES_EXISTS:
02894       ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
02895       if (priority_jump || option_priority_jumping) 
02896          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
02897       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
02898       res = 0;
02899       break;
02900    case RES_NOSUCHQUEUE:
02901       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
02902       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
02903       res = 0;
02904       break;
02905    case RES_OUTOFMEMORY:
02906       ast_log(LOG_ERROR, "Out of memory\n");
02907       break;
02908    }
02909 
02910    LOCAL_USER_REMOVE(u);
02911    return res;
02912 }

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

Definition at line 837 of file app_queue.c.

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

00838 {
00839    struct member *m, *prev_m;
00840    int penalty = 0;
00841 
00842    if(penalty_str) {
00843       penalty = atoi(penalty_str);
00844       if(penalty < 0)
00845          penalty = 0;
00846    }
00847 
00848    /* Find the member, or the place to put a new one. */
00849    prev_m = NULL;
00850    m = q->members;
00851    while (m && strcmp(m->interface, interface)) {
00852       prev_m = m;
00853       m = m->next;
00854    }
00855 
00856    /* Create a new one if not found, else update penalty */
00857    if (!m) {
00858       m = create_queue_member(interface, penalty, 0);
00859       if (m) {
00860          m->dead = 0;
00861          add_to_interfaces(interface);
00862          if (prev_m) {
00863             prev_m->next = m;
00864          } else {
00865             q->members = m;
00866          }
00867       }
00868    } else {
00869       m->dead = 0;   /* Do not delete this one. */
00870       m->penalty = penalty;
00871    }
00872 }

static int say_periodic_announcement ( struct queue_ent qe  )  [static]

Definition at line 1699 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, call_queue::periodicannouncefrequency, call_queue::sound_periodicannounce, and VERBOSE_PREFIX_3.

Referenced by queue_exec(), and wait_our_turn().

01700 {
01701    int res = 0;
01702    time_t now;
01703 
01704    /* Get the current time */
01705    time(&now);
01706 
01707    /* Check to see if it is time to announce */
01708    if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
01709       return 0;
01710 
01711    /* Stop the music on hold so we can play our own file */
01712    ast_moh_stop(qe->chan);
01713 
01714    if (option_verbose > 2)
01715       ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
01716 
01717    /* play the announcement */
01718    res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce);
01719 
01720    /* Resume Music on Hold if the caller is going to stay in the queue */
01721    if (!res)
01722       ast_moh_start(qe->chan, qe->moh);
01723 
01724    /* update last_periodic_announce_time */
01725    qe->last_periodic_announce_time = now;
01726 
01727    return res;
01728 }

static int say_position ( struct queue_ent qe  )  [static]

Definition at line 1208 of file app_queue.c.

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

Referenced by queue_exec(), and wait_our_turn().

01209 {
01210    int res = 0, avgholdmins, avgholdsecs;
01211    time_t now;
01212 
01213    /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
01214    time(&now);
01215    if ( (now - qe->last_pos) < 15 )
01216       return 0;
01217 
01218    /* If either our position has changed, or we are over the freq timer, say position */
01219    if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
01220       return 0;
01221 
01222    ast_moh_stop(qe->chan);
01223    /* Say we're next, if we are */
01224    if (qe->pos == 1) {
01225       res = play_file(qe->chan, qe->parent->sound_next);
01226       if (res && valid_exit(qe, res))
01227          goto playout;
01228       else
01229          goto posout;
01230    } else {
01231       res = play_file(qe->chan, qe->parent->sound_thereare);
01232       if (res && valid_exit(qe, res))
01233          goto playout;
01234       res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
01235       if (res && valid_exit(qe, res))
01236          goto playout;
01237       res = play_file(qe->chan, qe->parent->sound_calls);
01238       if (res && valid_exit(qe, res))
01239          goto playout;
01240    }
01241    /* Round hold time to nearest minute */
01242    avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
01243 
01244    /* If they have specified a rounding then round the seconds as well */
01245    if(qe->parent->roundingseconds) {
01246       avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
01247       avgholdsecs*= qe->parent->roundingseconds;
01248    } else {
01249       avgholdsecs=0;
01250    }
01251 
01252    if (option_verbose > 2)
01253       ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
01254 
01255    /* If the hold time is >1 min, if it's enabled, and if it's not
01256       supposed to be only once and we have already said it, say it */
01257    if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
01258        (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
01259       res = play_file(qe->chan, qe->parent->sound_holdtime);
01260       if (res && valid_exit(qe, res))
01261          goto playout;
01262 
01263       if (avgholdmins>0) {
01264          if (avgholdmins < 2) {
01265             res = play_file(qe->chan, qe->parent->sound_lessthan);
01266             if (res && valid_exit(qe, res))
01267                goto playout;
01268 
01269             res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
01270             if (res && valid_exit(qe, res))
01271                goto playout;
01272          } else {
01273             res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
01274             if (res && valid_exit(qe, res))
01275                goto playout;
01276          }
01277          
01278          res = play_file(qe->chan, qe->parent->sound_minutes);
01279          if (res && valid_exit(qe, res))
01280             goto playout;
01281       }
01282       if (avgholdsecs>0) {
01283          res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
01284          if (res && valid_exit(qe, res))
01285             goto playout;
01286 
01287          res = play_file(qe->chan, qe->parent->sound_seconds);
01288          if (res && valid_exit(qe, res))
01289             goto playout;
01290       }
01291 
01292    }
01293 
01294  posout:
01295    if (option_verbose > 2)
01296       ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
01297              qe->chan->name, qe->parent->name, qe->pos);
01298    res = play_file(qe->chan, qe->parent->sound_thanks);
01299    if (res && !valid_exit(qe, res))
01300       res = 0;
01301 
01302  playout:
01303    /* Set our last_pos indicators */
01304    qe->last_pos = now;
01305    qe->last_pos_said = qe->pos;
01306 
01307    /* Don't restart music on hold if we're about to exit the caller from the queue */
01308    if (!res)
01309       ast_moh_start(qe->chan, qe->moh);
01310 
01311    return res;
01312 }

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

Definition at line 2602 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(), call_queue::lock, LOG_DEBUG, manager_event(), call_queue::name, call_queue::next, member::paused, queue_persistent_members, and queues.

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

02603 {
02604    int found = 0;
02605    struct call_queue *q;
02606    struct member *mem;
02607 
02608    /* Special event for when all queues are paused - individual events still generated */
02609 
02610    if (ast_strlen_zero(queuename))
02611       ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
02612 
02613    ast_mutex_lock(&qlock);
02614    for (q = queues ; q ; q = q->next) {
02615       ast_mutex_lock(&q->lock);
02616       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
02617          if ((mem = interface_exists(q, interface))) {
02618             found++;
02619             if (mem->paused == paused)
02620                ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
02621             mem->paused = paused;
02622 
02623             if (queue_persistent_members)
02624                dump_queue_members(q);
02625 
02626             ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
02627 
02628             manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
02629                "Queue: %s\r\n"
02630                "Location: %s\r\n"
02631                "Paused: %d\r\n",
02632                   q->name, mem->interface, paused);
02633          }
02634       }
02635       ast_mutex_unlock(&q->lock);
02636    }
02637    ast_mutex_unlock(&qlock);
02638 
02639    if (found)
02640       return RESULT_SUCCESS;
02641    else
02642       return RESULT_FAILURE;
02643 }

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

Definition at line 377 of file app_queue.c.

References pbx_builtin_setvar_helper(), queue_results, and text.

Referenced by queue_exec().

00378 {
00379    int i;
00380 
00381    for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
00382       if (queue_results[i].id == res) {
00383          pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
00384          return;
00385       }
00386    }
00387 }

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

Definition at line 529 of file app_queue.c.

References ast_log(), ast_pthread_create, changethread(), free, LOG_WARNING, malloc, and t.

Referenced by load_module(), and unload_module().

00530 {
00531    /* Avoid potential for deadlocks by spawning a new thread to handle
00532       the event */
00533    struct statechange *sc;
00534    pthread_t t;
00535    pthread_attr_t attr;
00536 
00537    if (!(sc = malloc(sizeof(*sc) + strlen(dev) + 1)))
00538       return 0;
00539 
00540    sc->state = state;
00541    strcpy(sc->dev, dev);
00542    pthread_attr_init(&attr);
00543    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00544    if (ast_pthread_create(&t, &attr, changethread, sc)) {
00545       ast_log(LOG_WARNING, "Failed to create update thread!\n");
00546       free(sc);
00547    }
00548 
00549    return 0;
00550 }

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

Definition at line 1636 of file app_queue.c.

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

Referenced by try_calling().

01637 {
01638    struct localuser *cur;
01639    struct localuser *best;
01640    int bestmetric=0;
01641 
01642    best = NULL;
01643    cur = outgoing;
01644    while(cur) {
01645       if (cur->stillgoing &&              /* Not already done */
01646          !cur->chan &&              /* Isn't already going */
01647          (!best || (cur->metric < bestmetric))) {  /* We haven't found one yet, or it's better */
01648             bestmetric = cur->metric;
01649             best = cur;
01650       }
01651       cur = cur->next;
01652    }
01653    if (best) {
01654       /* Ring just the best channel */
01655       if (option_debug)
01656          ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
01657       qe->parent->rrpos = best->metric % 1000;
01658    } else {
01659       /* Just increment rrpos */
01660       if (qe->parent->wrapped) {
01661          /* No more channels, start over */
01662          qe->parent->rrpos = 0;
01663       } else {
01664          /* Prioritize next entry */
01665          qe->parent->rrpos++;
01666       }
01667    }
01668    qe->parent->wrapped = 0;
01669    return 0;
01670 }

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

Definition at line 399 of file app_queue.c.

References name, and strategies.

Referenced by queue_set_param().

00400 {
00401    int x;
00402    for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
00403       if (!strcasecmp(strategy, strategies[x].name))
00404          return strategies[x].strategy;
00405    }
00406    return -1;
00407 }

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

Definition at line 2136 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_MAX_CONTEXT, AST_MAX_EXTENSION, ast_moh_stop(), ast_monitor_setjoinfiles(), ast_monitor_start(), ast_mutex_lock(), ast_mutex_unlock(), AST_OPTION_TONE_VERIFY, AST_PBX_NO_HANGUP_PEER, ast_queue_log(), ast_safe_sleep(), ast_say_number(), ast_set_flag, AST_STATE_UP, ast_strlen_zero(), ast_test_flag, calc_metric(), ast_channel::cdr, localuser::chan, queue_ent::chan, ast_channel::context, EVENT_FLAG_AGENT, call_queue::eventwhencalled, queue_ent::expire, ast_channel::exten, queue_ent::handled, hangupcalls(), member::interface, ast_channel::language, member::lastcall, leave_queue(), call_queue::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, malloc, manager_event(), localuser::member, call_queue::memberdelay, call_queue::members, call_queue::monfmt, call_queue::monjoin, call_queue::name, ast_channel::name, member::next, queue_ent::opos, option_debug, queue_ent::parent, pbx_builtin_getvar_helper(), play_file(), queue_ent::pos, QUEUE_STRATEGY_RRMEMORY, recalc_holdtime(), record_abandoned(), call_queue::reportholdtime, ring_one(), call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_reporthold, queue_ent::start, member::status, store_next(), call_queue::strategy, call_queue::timeout, ast_channel::type, ast_cdr::uniqueid, ast_channel::uniqueid, update_queue(), use_weight, and wait_for_answer().

Referenced by queue_exec().

02137 {
02138    struct member *cur;
02139    struct localuser *outgoing=NULL, *tmp = NULL;
02140    int to;
02141    char restofit[AST_MAX_EXTENSION];
02142    char oldexten[AST_MAX_EXTENSION]="";
02143    char oldcontext[AST_MAX_CONTEXT]="";
02144    char queuename[256]="";
02145    char *newnum;
02146    char *monitorfilename;
02147    struct ast_channel *peer;
02148    struct ast_channel *which;
02149    struct localuser *lpeer;
02150    struct member *member;
02151    int res = 0, bridge = 0;
02152    int numbusies = 0;
02153    int x=0;
02154    char *announce = NULL;
02155    char digit = 0;
02156    time_t callstart;
02157    time_t now = time(NULL);
02158    struct ast_bridge_config bridge_config;
02159    char nondataquality = 1;
02160 
02161    memset(&bridge_config, 0, sizeof(bridge_config));
02162    time(&now);
02163       
02164    for (; options && *options; options++)
02165       switch (*options) {
02166       case 't':
02167          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
02168          break;
02169       case 'T':
02170          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
02171          break;
02172       case 'w':
02173          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
02174          break;
02175       case 'W':
02176          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
02177          break;
02178       case 'd':
02179          nondataquality = 0;
02180          break;
02181       case 'h':
02182          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
02183          break;
02184       case 'H':
02185          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
02186          break;
02187       case 'n':
02188          if ((now - qe->start >= qe->parent->timeout))
02189             *go_on = 1;
02190          break;
02191       }
02192 
02193    /* Hold the lock while we setup the outgoing calls */
02194    if (use_weight) 
02195       ast_mutex_lock(&qlock);
02196    ast_mutex_lock(&qe->parent->lock);
02197    if (option_debug)
02198       ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 
02199                      qe->chan->name);
02200    ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
02201    cur = qe->parent->members;
02202    if (!ast_strlen_zero(qe->announce))
02203       announce = qe->announce;
02204    if (!ast_strlen_zero(announceoverride))
02205       announce = announceoverride;
02206 
02207    while(cur) {
02208       tmp = malloc(sizeof(*tmp));
02209       if (!tmp) {
02210          ast_mutex_unlock(&qe->parent->lock);
02211          if (use_weight) 
02212             ast_mutex_unlock(&qlock);
02213          ast_log(LOG_WARNING, "Out of memory\n");
02214          goto out;
02215       }
02216       memset(tmp, 0, sizeof(*tmp));
02217       tmp->stillgoing = -1;
02218       if (option_debug) {
02219          if (url)
02220             ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
02221          else 
02222             ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
02223       }
02224 
02225       tmp->member = cur;      /* Never directly dereference!  Could change on reload */
02226       tmp->oldstatus = cur->status;
02227       tmp->lastcall = cur->lastcall;
02228       ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
02229       /* If we're dialing by extension, look at the extension to know what to dial */
02230       if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) {
02231          newnum++;
02232          strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
02233          snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
02234          if (option_debug)
02235             ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
02236       }
02237       /* Special case: If we ring everyone, go ahead and ring them, otherwise
02238          just calculate their metric for the appropriate strategy */
02239       calc_metric(qe->parent, cur, x++, qe, tmp);
02240       /* Put them in the list of outgoing thingies...  We're ready now. 
02241          XXX If we're forcibly removed, these outgoing calls won't get
02242          hung up XXX */
02243       tmp->next = outgoing;
02244       outgoing = tmp;      
02245       /* If this line is up, don't try anybody else */
02246       if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
02247          break;
02248 
02249       cur = cur->next;
02250    }
02251    if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
02252       to = (qe->expire - now) * 1000;
02253    else
02254       to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
02255    ring_one(qe, outgoing, &numbusies);
02256    ast_mutex_unlock(&qe->parent->lock);
02257    if (use_weight) 
02258       ast_mutex_unlock(&qlock);
02259    lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT));
02260    ast_mutex_lock(&qe->parent->lock);
02261    if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
02262       store_next(qe, outgoing);
02263    }
02264    ast_mutex_unlock(&qe->parent->lock);
02265    if (lpeer)
02266       peer = lpeer->chan;
02267    else
02268       peer = NULL;
02269    if (!peer) {
02270       if (to) {
02271          /* Musta gotten hung up */
02272          res = -1;
02273       } else {
02274          res = digit;
02275       }
02276       if (option_debug)
02277          ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
02278       goto out;
02279    }
02280    if (peer) {
02281       /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
02282          we will always return with -1 so that it is hung up properly after the 
02283          conversation.  */
02284       qe->handled++;
02285       if (!strcmp(qe->chan->type,"Zap"))
02286          ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
02287       if (!strcmp(peer->type,"Zap"))
02288          ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
02289       /* Update parameters for the queue */
02290       recalc_holdtime(qe);
02291       member = lpeer->member;
02292       hangupcalls(outgoing, peer);
02293       outgoing = NULL;
02294       if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
02295          int res2;
02296          res2 = ast_autoservice_start(qe->chan);
02297          if (!res2) {
02298             if (qe->parent->memberdelay) {
02299                ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
02300                res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
02301             }
02302             if (!res2 && announce) {
02303                if (play_file(peer, announce))
02304                   ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
02305             }
02306             if (!res2 && qe->parent->reportholdtime) {
02307                if (!play_file(peer, qe->parent->sound_reporthold)) {
02308                   int holdtime;
02309 
02310                   time(&now);
02311                   holdtime = abs((now - qe->start) / 60);
02312                   if (holdtime < 2) {
02313                      play_file(peer, qe->parent->sound_lessthan);
02314                      ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
02315                   } else 
02316                      ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
02317                   play_file(peer, qe->parent->sound_minutes);
02318                }
02319             }
02320          }
02321          res2 |= ast_autoservice_stop(qe->chan);
02322          if (peer->_softhangup) {
02323             /* Agent must have hung up */
02324             ast_log(LOG_WARNING, "Agent on %s hungup on the customer.  They're going to be pissed.\n", peer->name);
02325             ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
02326             record_abandoned(qe);
02327             if (qe->parent->eventwhencalled) {
02328                manager_event(EVENT_FLAG_AGENT, "AgentDump",
02329                         "Queue: %s\r\n"
02330                         "Uniqueid: %s\r\n"
02331                         "Channel: %s\r\n"
02332                         "Member: %s\r\n",
02333                         queuename, qe->chan->uniqueid, peer->name, member->interface);
02334             }
02335             ast_hangup(peer);
02336             goto out;
02337          } else if (res2) {
02338             /* Caller must have hung up just before being connected*/
02339             ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
02340             ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02341             record_abandoned(qe);
02342             ast_hangup(peer);
02343             return -1;
02344          }
02345       }
02346       /* Stop music on hold */
02347       ast_moh_stop(qe->chan);
02348       /* If appropriate, log that we have a destination channel */
02349       if (qe->chan->cdr)
02350          ast_cdr_setdestchan(qe->chan->cdr, peer->name);
02351       /* Make sure channels are compatible */
02352       res = ast_channel_make_compatible(qe->chan, peer);
02353       if (res < 0) {
02354          ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
02355          ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
02356          record_abandoned(qe);
02357          ast_hangup(peer);
02358          return -1;
02359       }
02360       /* Begin Monitoring */
02361       if (qe->parent->monfmt && *qe->parent->monfmt) {
02362          monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
02363          if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
02364             which = qe->chan;
02365          else
02366             which = peer;
02367          if (monitorfilename)
02368             ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
02369          else if (qe->chan->cdr) 
02370             ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
02371          else {
02372             /* Last ditch effort -- no CDR, make up something */
02373             char tmpid[256];
02374             snprintf(tmpid, sizeof(tmpid), "chan-%x", rand());
02375             ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
02376          }
02377          if (qe->parent->monjoin)
02378             ast_monitor_setjoinfiles(which, 1);
02379       }
02380       /* Drop out of the queue at this point, to prepare for next caller */
02381       leave_queue(qe);        
02382       if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
02383          if (option_debug)
02384             ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
02385          ast_channel_sendurl(peer, url);
02386       }
02387       ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
02388       if (qe->parent->eventwhencalled)
02389          manager_event(EVENT_FLAG_AGENT, "AgentConnect",
02390                   "Queue: %s\r\n"
02391                   "Uniqueid: %s\r\n"
02392                   "Channel: %s\r\n"
02393                   "Member: %s\r\n"
02394                   "Holdtime: %ld\r\n",
02395                   queuename, qe->chan->uniqueid, peer->name, member->interface,
02396                   (long)time(NULL) - qe->start);
02397       ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
02398       ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
02399       time(&callstart);
02400 
02401       bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
02402 
02403       if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
02404          ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
02405       } else if (qe->chan->_softhangup) {
02406          ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
02407                   (long)(callstart - qe->start), (long)(time(NULL) - callstart));
02408          if (qe->parent->eventwhencalled)
02409             manager_event(EVENT_FLAG_AGENT, "AgentComplete",
02410                      "Queue: %s\r\n"
02411                      "Uniqueid: %s\r\n"
02412                      "Channel: %s\r\n"
02413                      "Member: %s\r\n"
02414                      "HoldTime: %ld\r\n"
02415                      "TalkTime: %ld\r\n"
02416                      "Reason: caller\r\n",
02417                      queuename, qe->chan->uniqueid, peer->name, member->interface,
02418                      (long)(callstart - qe->start), (long)(time(NULL) - callstart));
02419       } else {
02420          ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
02421          if (qe->parent->eventwhencalled)
02422             manager_event(EVENT_FLAG_AGENT, "AgentComplete",
02423                      "Queue: %s\r\n"
02424                      "Uniqueid: %s\r\n"
02425                      "Channel: %s\r\n"
02426                      "HoldTime: %ld\r\n"
02427                      "TalkTime: %ld\r\n"
02428                      "Reason: agent\r\n",
02429                      queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start),
02430                      (long)(time(NULL) - callstart));
02431       }
02432 
02433       if (bridge != AST_PBX_NO_HANGUP_PEER)
02434          ast_hangup(peer);
02435       update_queue(qe->parent, member);
02436       res = bridge ? bridge : 1;
02437    }  
02438 out:
02439    hangupcalls(outgoing, NULL);
02440    return res;
02441 }

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 3956 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(), clear_and_free_interfaces(), cli_add_queue_member, cli_remove_queue_member, cli_show_queue, cli_show_queues, queueagentcount_function, STANDARD_HANGUP_LOCALUSERS, and statechange_queue().

03957 {
03958    int res;
03959 
03960    clear_and_free_interfaces();
03961    res = ast_cli_unregister(&cli_show_queue);
03962    res |= ast_cli_unregister(&cli_show_queues);
03963    res |= ast_cli_unregister(&cli_add_queue_member);
03964    res |= ast_cli_unregister(&cli_remove_queue_member);
03965    res |= ast_manager_unregister("Queues");
03966    res |= ast_manager_unregister("QueueStatus");
03967    res |= ast_manager_unregister("QueueAdd");
03968    res |= ast_manager_unregister("QueueRemove");
03969    res |= ast_manager_unregister("QueuePause");
03970    ast_devstate_del(statechange_queue, NULL);
03971    res |= ast_unregister_application(app_aqm);
03972    res |= ast_unregister_application(app_rqm);
03973    res |= ast_unregister_application(app_pqm);
03974    res |= ast_unregister_application(app_upqm);
03975    res |= ast_custom_function_unregister(&queueagentcount_function);
03976    res |= ast_unregister_application(app);
03977 
03978    STANDARD_HANGUP_LOCALUSERS;
03979 
03980    return res;
03981 }

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

Definition at line 1424 of file app_queue.c.

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

Referenced by ring_entry(), and wait_for_answer().

01425 {
01426    if (status == AST_CAUSE_BUSY)
01427       status = AST_DEVICE_BUSY;
01428    else if (status == AST_CAUSE_UNREGISTERED)
01429       status = AST_DEVICE_UNAVAILABLE;
01430    else if (status == AST_CAUSE_NOSUCHDRIVER)
01431       status = AST_DEVICE_INVALID;
01432    else
01433       status = AST_DEVICE_UNKNOWN;
01434    return update_status(q, member, status);
01435 }

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

Definition at line 2063 of file app_queue.c.

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

Referenced by try_calling().

02064 {
02065    struct member *cur;
02066 
02067    /* Since a reload could have taken place, we have to traverse the list to
02068       be sure it's still valid */
02069    ast_mutex_lock(&q->lock);
02070    cur = q->members;
02071    while(cur) {
02072       if (member == cur) {
02073          time(&cur->lastcall);
02074          cur->calls++;
02075          break;
02076       }
02077       cur = cur->next;
02078    }
02079    q->callscompleted++;
02080    ast_mutex_unlock(&q->lock);
02081    return 0;
02082 }

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

Definition at line 1392 of file app_queue.c.

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

Referenced by update_dial_status().

01393 {
01394    struct member *cur;
01395 
01396    /* Since a reload could have taken place, we have to traverse the list to
01397       be sure it's still valid */
01398    ast_mutex_lock(&q->lock);
01399    cur = q->members;
01400    while(cur) {
01401       if (member == cur) {
01402          cur->status = status;
01403          if (!q->maskmemberstatus) {
01404             manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
01405                "Queue: %s\r\n"
01406                "Location: %s\r\n"
01407                "Membership: %s\r\n"
01408                "Penalty: %d\r\n"
01409                "CallsTaken: %d\r\n"
01410                "LastCall: %d\r\n"
01411                "Status: %d\r\n"
01412                "Paused: %d\r\n",
01413             q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
01414             cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
01415          }
01416          break;
01417       }
01418       cur = cur->next;
01419    }
01420    ast_mutex_unlock(&q->lock);
01421    return 0;
01422 }

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

Definition at line 2791 of file app_queue.c.

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

Referenced by load_module().

02792 {
02793    struct localuser *u;
02794    char *parse;
02795    int priority_jump = 0;
02796    AST_DECLARE_APP_ARGS(args,
02797       AST_APP_ARG(queuename);
02798       AST_APP_ARG(interface);
02799       AST_APP_ARG(options);
02800    );
02801 
02802    if (ast_strlen_zero(data)) {
02803       ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
02804       return -1;
02805    }
02806 
02807    LOCAL_USER_ADD(u);
02808 
02809    if (!(parse = ast_strdupa(data))) {
02810       ast_log(LOG_WARNING, "Memory Error!\n");
02811       LOCAL_USER_REMOVE(u);
02812       return -1;
02813    }
02814 
02815    AST_STANDARD_APP_ARGS(args, parse);
02816 
02817    if (args.options) {
02818       if (strchr(args.options, 'j'))
02819          priority_jump = 1;
02820    }
02821 
02822    if (ast_strlen_zero(args.interface)) {
02823       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
02824       LOCAL_USER_REMOVE(u);
02825       return -1;
02826    }
02827 
02828    if (set_member_paused(args.queuename, args.interface, 0)) {
02829       ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
02830       if (priority_jump || option_priority_jumping) {
02831          if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
02832             pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
02833             LOCAL_USER_REMOVE(u);
02834             return 0;
02835          }
02836       }
02837       LOCAL_USER_REMOVE(u);
02838       pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
02839       return -1;
02840    }
02841 
02842    LOCAL_USER_REMOVE(u);
02843    pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
02844    return 0;
02845 }

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

References STANDARD_USECOUNT.

04026 {
04027    int res;
04028    STANDARD_USECOUNT(res);
04029    return res;
04030 }

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

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

01178 {
01179    int digitlen = strlen(qe->digits);
01180 
01181    /* Prevent possible buffer overflow */
01182    if (digitlen < sizeof(qe->digits) - 2) {
01183       qe->digits[digitlen] = digit;
01184       qe->digits[digitlen + 1] = '\0';
01185    } else {
01186       qe->digits[0] = '\0';
01187       return 0;
01188    }
01189 
01190    /* If there's no context to goto, short-circuit */
01191    if (ast_strlen_zero(qe->context))
01192       return 0;
01193 
01194    /* If the extension is bad, then reset the digits to blank */
01195    if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
01196       qe->digits[0] = '\0';
01197       return 0;
01198    }
01199 
01200    /* We have an exact match */
01201    if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
01202       /* Return 1 on a successful goto */
01203       return 1;
01204    }
01205    return 0;
01206 }

static int wait_a_bit ( struct queue_ent qe  )  [static]

Definition at line 2443 of file app_queue.c.

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

Referenced by queue_exec().

02444 {
02445    /* Don't need to hold the lock while we setup the outgoing calls */
02446    int retrywait = qe->parent->retry * 1000;
02447 
02448    return ast_waitfordigit(qe->chan, retrywait);
02449 }

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

Definition at line 1760 of file app_queue.c.

References ast_channel::_state, ast_channel::accountcode, ast_call(), ast_cdr_busy(), ast_channel_inherit_variables(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_OFFHOOK, AST_CONTROL_RINGING, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_WATCHERS, ast_read(), ast_request(), AST_STATE_UP, ast_strlen_zero(), ast_verbose(), ast_waitfor_n(), BUILD_WATCHERS, ast_channel::call_forward, ast_channel::cdr, ast_channel::cdrflags, localuser::chan, queue_ent::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_channel::context, ast_channel::exten, ast_frame::frametype, free, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_channel::macroexten, malloc, localuser::member, ast_channel::name, call_queue::name, ast_channel::nativeformats, localuser::next, localuser::oldstatus, option_verbose, queue_ent::parent, ring_one(), localuser::stillgoing, call_queue::strategy, strdup, ast_frame::subclass, ast_channel::tech, call_queue::timeoutrestart, update_dial_status(), valid_exit(), and VERBOSE_PREFIX_3.

01761 {
01762    char *queue = qe->parent->name;
01763    struct localuser *o;
01764    int found;
01765    int numlines;
01766    int status;
01767    int sentringing = 0;
01768    int numbusies = prebusies;
01769    int numnochan = 0;
01770    int stillgoing = 0;
01771    int orig = *to;
01772    struct ast_frame *f;
01773    struct localuser *peer = NULL;
01774    struct ast_channel *watchers[AST_MAX_WATCHERS];
01775    int pos;
01776    struct ast_channel *winner;
01777    struct ast_channel *in = qe->chan;
01778    
01779    while(*to && !peer) {
01780       BUILD_WATCHERS;
01781       if ((found < 0) && stillgoing && !qe->parent->strategy) {
01782          /* On "ringall" strategy we only move to the next penalty level
01783             when *all* ringing phones are done in the current penalty level */
01784          ring_one(qe, outgoing, &numbusies);
01785          BUILD_WATCHERS;
01786       }
01787       if (found < 0) {
01788          if (numlines == (numbusies + numnochan)) {
01789             ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
01790          } else {
01791             ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
01792          }
01793          *to = 0;
01794          return NULL;
01795       }
01796       winner = ast_waitfor_n(watchers, pos, to);
01797       o = outgoing;
01798       while(o) {
01799          if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
01800             if (!peer) {
01801                if (option_verbose > 2)
01802                   ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
01803                peer = o;
01804             }
01805          } else if (o->chan && (o->chan == winner)) {
01806             if (!ast_strlen_zero(o->chan->call_forward)) {
01807                char tmpchan[256]="";
01808                char *stuff;
01809                char *tech;
01810                ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
01811                if ((stuff = strchr(tmpchan, '/'))) {
01812                   *stuff = '\0';
01813                   stuff++;
01814                   tech = tmpchan;
01815                } else {
01816                   snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
01817                   stuff = tmpchan;
01818                   tech = "Local";
01819                }
01820                /* Before processing channel, go ahead and check for forwarding */
01821                if (option_verbose > 2)
01822                   ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
01823                /* Setup parameters */
01824                o->chan = ast_request(tech, in->nativeformats, stuff, &status);
01825                if (status != o->oldstatus) 
01826                   update_dial_status(qe->parent, o->member, status);                
01827                if (!o->chan) {
01828                   ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
01829                   o->stillgoing = 0;
01830                   numnochan++;
01831                } else {
01832                   ast_channel_inherit_variables(in, o->chan);
01833                   if (o->chan->cid.cid_num)
01834                      free(o->chan->cid.cid_num);
01835                   o->chan->cid.cid_num = NULL;
01836                   if (o->chan->cid.cid_name)
01837                      free(o->chan->cid.cid_name);
01838                   o->chan->cid.cid_name = NULL;
01839 
01840                   if (in->cid.cid_num) {
01841                      o->chan->cid.cid_num = strdup(in->cid.cid_num);
01842                      if (!o->chan->cid.cid_num)
01843                         ast_log(LOG_WARNING, "Out of memory\n");  
01844                   }
01845                   if (in->cid.cid_name) {
01846                      o->chan->cid.cid_name = strdup(in->cid.cid_name);
01847                      if (!o->chan->cid.cid_name)
01848                         ast_log(LOG_WARNING, "Out of memory\n");  
01849                   }
01850                   ast_copy_string(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode));
01851                   o->chan->cdrflags = in->cdrflags;
01852 
01853                   if (in->cid.cid_ani) {
01854                      if (o->chan->cid.cid_ani)
01855                         free(o->chan->cid.cid_ani);
01856                      o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1);
01857                      if (o->chan->cid.cid_ani)
01858                         strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
01859                      else
01860                         ast_log(LOG_WARNING, "Out of memory\n");
01861                   }
01862                   if (o->chan->cid.cid_rdnis) 
01863                      free(o->chan->cid.cid_rdnis);
01864                   if (!ast_strlen_zero(in->macroexten))
01865                      o->chan->cid.cid_rdnis = strdup(in->macroexten);
01866                   else
01867                      o->chan->cid.cid_rdnis = strdup(in->exten);
01868                   if (ast_call(o->chan, tmpchan, 0)) {
01869                      ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
01870                      o->stillgoing = 0;
01871                      ast_hangup(o->chan);
01872                      o->chan = NULL;
01873                      numnochan++;
01874                   }
01875                }
01876                /* Hangup the original channel now, in case we needed it */
01877                ast_hangup(winner);
01878                continue;
01879             }
01880             f = ast_read(winner);
01881             if (f) {
01882                if (f->frametype == AST_FRAME_CONTROL) {
01883                   switch(f->subclass) {
01884                   case AST_CONTROL_ANSWER:
01885                      /* This is our guy if someone answered. */
01886                      if (!peer) {
01887                         if (option_verbose > 2)
01888                            ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
01889                         peer = o;
01890                      }
01891                      break;
01892                   case AST_CONTROL_BUSY:
01893                      if (option_verbose > 2)
01894                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
01895                      o->stillgoing = 0;
01896                      if (in->cdr)
01897                         ast_cdr_busy(in->cdr);
01898                      ast_hangup(o->chan);
01899                      o->chan = NULL;
01900                      if (qe->parent->strategy) {
01901                         if (qe->parent->timeoutrestart)
01902                            *to = orig;
01903                         ring_one(qe, outgoing, &numbusies);
01904                      }
01905                      numbusies++;
01906                      break;
01907                   case AST_CONTROL_CONGESTION:
01908                      if (option_verbose > 2)
01909                         ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
01910                      o->stillgoing = 0;
01911                      if (in->cdr)
01912                         ast_cdr_busy(in->cdr);
01913                      ast_hangup(o->chan);
01914                      o->chan = NULL;
01915                      if (qe->parent->strategy) {
01916                         if (qe->parent->timeoutrestart)
01917                            *to = orig;
01918                         ring_one(qe, outgoing, &numbusies);
01919                      }
01920                      numbusies++;
01921                      break;
01922                   case AST_CONTROL_RINGING:
01923                      if (option_verbose > 2)
01924                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
01925                      if (!sentringing) {
01926 #if 0
01927                         ast_indicate(in, AST_CONTROL_RINGING);
01928 #endif                        
01929                         sentringing++;
01930                      }
01931                      break;
01932                   case AST_CONTROL_OFFHOOK:
01933                      /* Ignore going off hook */
01934                      break;
01935                   default:
01936                      ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
01937                   }
01938                }
01939                ast_frfree(f);
01940             } else {
01941                o->stillgoing = 0;
01942                ast_hangup(o->chan);
01943                o->chan = NULL;
01944                if (qe->parent->strategy) {
01945                   if (qe->parent->timeoutrestart)
01946                      *to = orig;
01947                   ring_one(qe, outgoing, &numbusies);
01948                }
01949             }
01950          }
01951          o = o->next;
01952       }
01953       if (winner == in) {
01954          f = ast_read(in);
01955 #if 0
01956          if (f && (f->frametype != AST_FRAME_VOICE))
01957                printf("Frame type: %d, %d\n", f->frametype, f->subclass);
01958          else if (!f || (f->frametype != AST_FRAME_VOICE))
01959             printf("Hangup received on %s\n", in->name);
01960 #endif
01961          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
01962             /* Got hung up */
01963             *to=-1;
01964             if (f)
01965                ast_frfree(f);
01966             return NULL;
01967          }
01968          if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
01969             if (option_verbose > 3)
01970                ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
01971             *to=0;
01972             ast_frfree(f);
01973             return NULL;
01974          }
01975          if ((f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
01976             if (option_verbose > 3)
01977                ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
01978             *to=0;
01979             *digit=f->subclass;
01980             ast_frfree(f);
01981             return NULL;
01982          }
01983          ast_frfree(f);
01984       }
01985       if (!*to && (option_verbose > 2))
01986          ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
01987    }
01988 
01989    return peer;
01990    
01991 }

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

Definition at line 2013 of file app_queue.c.

References call_queue::announcefrequency, ast_waitfordigit(), queue_ent::chan, get_member_status(), is_our_turn(), leave_queue(), call_queue::leavewhenempty, queue_ent::parent, call_queue::periodicannouncefrequency, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, RECHECK, say_periodic_announcement(), and say_position().

Referenced by queue_exec().

02014 {
02015    int res = 0;
02016 
02017    /* This is the holding pen for callers 2 through maxlen */
02018    for (;;) {
02019       enum queue_member_status stat;
02020 
02021       if (is_our_turn(qe))
02022          break;
02023 
02024       /* If we have timed out, break out */
02025       if (qe->expire && (time(NULL) > qe->expire)) {
02026          *reason = QUEUE_TIMEOUT;
02027          break;
02028       }
02029 
02030       stat = get_member_status(qe->parent);
02031 
02032       /* leave the queue if no agents, if enabled */
02033       if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
02034          *reason = QUEUE_LEAVEEMPTY;
02035          leave_queue(qe);
02036          break;
02037       }
02038 
02039       /* leave the queue if no reachable agents, if enabled */
02040       if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
02041          *reason = QUEUE_LEAVEUNAVAIL;
02042          leave_queue(qe);
02043          break;
02044       }
02045 
02046       /* Make a position announcement, if enabled */
02047       if (qe->parent->announcefrequency && !ringing &&
02048           (res = say_position(qe)))
02049          break;
02050 
02051       /* Make a periodic announcement, if enabled */
02052       if (qe->parent->periodicannouncefrequency && !ringing &&
02053           (res = say_periodic_announcement(qe)))
02054          break;
02055 
02056       /* Wait a second before checking again */
02057       if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000)))
02058          break;
02059    }
02060    return res;
02061 }


Variable Documentation

char* app = "Queue" [static]

Definition at line 123 of file app_queue.c.

char* app_aqm = "AddQueueMember" [static]

Definition at line 153 of file app_queue.c.

Referenced by load_module(), and unload_module().

char* app_aqm_descrip [static]

Definition at line 155 of file app_queue.c.

Referenced by load_module().

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

Definition at line 154 of file app_queue.c.

Referenced by load_module().

char* app_pqm = "PauseQueueMember" [static]

Definition at line 185 of file app_queue.c.

Referenced by load_module(), and unload_module().

char* app_pqm_descrip [static]

Definition at line 187 of file app_queue.c.

Referenced by load_module().

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

Definition at line 186 of file app_queue.c.

Referenced by load_module().

char* app_rqm = "RemoveQueueMember" [static]

Definition at line 169 of file app_queue.c.

Referenced by load_module(), and unload_module().

char* app_rqm_descrip [static]

Definition at line 171 of file app_queue.c.

Referenced by load_module().

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

Definition at line 170 of file app_queue.c.

Referenced by load_module().

char* app_upqm = "UnpauseQueueMember" [static]

Definition at line 207 of file app_queue.c.

Referenced by load_module(), and unload_module().

char* app_upqm_descrip [static]

Definition at line 209 of file app_queue.c.

Referenced by load_module().

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

Definition at line 208 of file app_queue.c.

Referenced by load_module().

char aqm_cmd_usage[] [static]

Initial value:

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

Definition at line 3942 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 3945 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 3952 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 3938 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 3930 of file app_queue.c.

Referenced by load_module(), and unload_module().

char* descrip [static]

Definition at line 127 of file app_queue.c.

enum queue_result id

Definition at line 244 of file app_queue.c.

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

LOCAL_USER_DECL

Definition at line 271 of file app_queue.c.

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

Persistent Members astdb family.

Definition at line 223 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

int queue_persistent_members = 0 [static]

queues.conf [general] option

Definition at line 228 of file app_queue.c.

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

struct { ... } queue_results[]

Referenced by set_queue_result().

struct ast_custom_function queueagentcount_function [static]

Definition at line 3279 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct call_queue* queues = NULL [static]

Definition at line 374 of file app_queue.c.

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

char rqm_cmd_usage[] [static]

Initial value:

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

Definition at line 3949 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 3934 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 3926 of file app_queue.c.

struct strategy strategies[] [static]

Referenced by int2strat(), and strat2int().

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

Definition at line 125 of file app_queue.c.

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

Definition at line 121 of file app_queue.c.

char* text

Definition at line 245 of file app_queue.c.

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

int use_weight = 0 [static]

queues.conf per-queue weight option

Definition at line 231 of file app_queue.c.

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


Generated on Sat Mar 24 22:55:36 2007 for Asterisk - the Open Source PBX by  doxygen 1.4.7