Sun Aug 6 15:04:04 2006

Asterisk developer's documentation


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

app_queue.c File Reference

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

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

Include dependency graph for app_queue.c:

Go to the source code of this file.

Data Structures

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

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

#define BUILD_WATCHERS
 

Definition at line 1735 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(), remove_from_queue(), 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
 

Enumeration values:
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
 

Enumeration values:
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 

Definition at line 233 of file app_queue.c.

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

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

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

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

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 find_queue_by_name_rt(), and 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 2909 of file app_queue.c.

References add_to_queue(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_channel::context, localuser::interface, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_NOTICE, 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().

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

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

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

Referenced by say_periodic_announcement().

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

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

Definition at line 2079 of file app_queue.c.

References ast_log(), member::calls, member::lastcall, 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().

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

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_mutex_unlock(), 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 find_queue_by_name_rt(), and 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 3815 of file app_queue.c.

References complete_queue(), malloc, and strdup.

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

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

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

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

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

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

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

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

References tdesc.

04016 {
04017    return tdesc;
04018 }

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 find_queue_by_name_rt(), 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 2464 of file app_queue.c.

References ast_db_del(), ast_db_put(), ast_log(), member::dynamic, member::interface, 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().

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

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.

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 alloc_queue(), ast_category_browse(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_variable_retrieve(), clear_queue(), member::dead, destroy_queue(), member::dynamic, free, init_queue(), member::interface, member_interface::interface, LOG_DEBUG, ast_variable::name, call_queue::name, member::next, ast_variable::next, call_queue::next, queue_set_param(), queues, remove_from_interfaces(), rt_handle_member_record(), and ast_variable::value.

Referenced by load_realtime_queue().

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

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

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

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

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

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

02447 {
02448    struct member *mem;
02449 
02450    if (q)
02451       for (mem = q->members; mem; mem = mem->next)
02452          if (!strcasecmp(interface, mem->interface))
02453             return mem;
02454 
02455    return NULL;
02456 }

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

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

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

References ASTERISK_GPL_KEY.

04028 {
04029    return ASTERISK_GPL_KEY;
04030 }

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

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

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

Note:
Load from realtime before taking the global qlock, to avoid blocking all queue operations while waiting for the DB.
This will be two separate database transactions, so we might see queue parameters as they were before another process changed the queue and member list as it was after the change. Thus we might see an empty member list when a queue is deleted. In practise, this is unlikely to cause a problem.

Definition at line 1047 of file app_queue.c.

References ast_config_destroy(), ast_load_realtime(), ast_load_realtime_multientry(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_variables_destroy(), find_queue_by_name_rt(), LOG_ERROR, call_queue::name, call_queue::next, queues, and call_queue::realtime.

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 3664 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, and RES_OUTOFMEMORY.

Referenced by load_module().

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

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

Definition at line 3741 of file app_queue.c.

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

Referenced by load_module().

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

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

Definition at line 3565 of file app_queue.c.

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

Referenced by load_module().

03566 {
03567    char *a[] = { "show", "queues" };
03568    __queues_show(1, s->fd, 2, a, 0);
03569    ast_cli(s->fd, "\r\n\r\n");   /* Properly terminate Manager output */
03570 
03571    return RESULT_SUCCESS;
03572 } 

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

Definition at line 3575 of file app_queue.c.

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

Referenced by load_module().

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

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

Definition at line 3712 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, and RES_OUTOFMEMORY.

Referenced by load_module().

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

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(), 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 2730 of file app_queue.c.

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

Referenced by load_module().

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

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

Definition at line 2985 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(), ast_channel::cid, ast_callerid::cid_num, get_member_status(), is_our_turn(), join_queue(), leave_queue(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_DEBUG, 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().

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

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

Definition at line 3230 of file app_queue.c.

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

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

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 find_queue_by_name_rt(), and 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 3541 of file app_queue.c.

References __queues_show().

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

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

Definition at line 3536 of file app_queue.c.

References __queues_show().

03537 {
03538    return __queues_show(0, fd, argc, argv, 0);
03539 }

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

01726 {
01727    ast_mutex_lock(&qe->parent->lock);
01728    qe->parent->callsabandoned++;
01729    ast_mutex_unlock(&qe->parent->lock);
01730 }

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

References reload_queues().

04010 {
04011    reload_queues();
04012    return 0;
04013 }

static void reload_queue_members void   )  [static]
 

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

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

static void reload_queues void   )  [static]
 

Definition at line 3281 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, ast_variable::lineno, call_queue::lock, LOG_NOTICE, call_queue::members, ast_variable::name, call_queue::name, ast_variable::next, member::next, call_queue::next, member::paused, member::penalty, queue_persistent_members, queue_set_param(), queues, remove_from_interfaces(), member::status, use_weight, ast_variable::value, and var.

Referenced by load_module(), and reload().

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

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

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

References ast_mutex_lock(), ast_mutex_unlock(), 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, remove_from_interfaces(), RES_EXISTS, RES_NOSUCHQUEUE, and RES_OKAY.

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

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

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_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, 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, 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       (*busies)++;
01522       return 0;
01523    } else if (status != tmp->oldstatus) 
01524       update_dial_status(qe->parent, tmp->member, status);
01525    
01526    tmp->chan->appl = "AppQueue";
01527    tmp->chan->data = "(Outgoing Line)";
01528    tmp->chan->whentohangup = 0;
01529    if (tmp->chan->cid.cid_num)
01530       free(tmp->chan->cid.cid_num);
01531    tmp->chan->cid.cid_num = NULL;
01532    if (tmp->chan->cid.cid_name)
01533       free(tmp->chan->cid.cid_name);
01534    tmp->chan->cid.cid_name = NULL;
01535    if (tmp->chan->cid.cid_ani)
01536       free(tmp->chan->cid.cid_ani);
01537    tmp->chan->cid.cid_ani = NULL;
01538    if (qe->chan->cid.cid_num)
01539       tmp->chan->cid.cid_num = strdup(qe->chan->cid.cid_num);
01540    if (qe->chan->cid.cid_name)
01541       tmp->chan->cid.cid_name = strdup(qe->chan->cid.cid_name);
01542    if (qe->chan->cid.cid_ani)
01543       tmp->chan->cid.cid_ani = strdup(qe->chan->cid.cid_ani);
01544 
01545    /* Inherit specially named variables from parent channel */
01546    ast_channel_inherit_variables(qe->chan, tmp->chan);
01547 
01548    /* Presense of ADSI CPE on outgoing channel follows ours */
01549    tmp->chan->adsicpe = qe->chan->adsicpe;
01550 
01551    /* Place the call, but don't wait on the answer */
01552    res = ast_call(tmp->chan, location, 0);
01553    if (res) {
01554       /* Again, keep going even if there's an error */
01555       if (option_debug)
01556          ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
01557       else if (option_verbose > 2)
01558          ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
01559       ast_hangup(tmp->chan);
01560       tmp->chan = NULL;
01561       tmp->stillgoing = 0;
01562       (*busies)++;
01563       return 0;
01564    } else {
01565       if (qe->parent->eventwhencalled) {
01566          manager_event(EVENT_FLAG_AGENT, "AgentCalled",
01567                   "AgentCalled: %s\r\n"
01568                   "ChannelCalling: %s\r\n"
01569                   "CallerID: %s\r\n"
01570                   "CallerIDName: %s\r\n"
01571                   "Context: %s\r\n"
01572                   "Extension: %s\r\n"
01573                   "Priority: %d\r\n",
01574                   tmp->interface, qe->chan->name,
01575                   tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
01576                   tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
01577                   qe->chan->context, qe->chan->exten, qe->chan->priority);
01578       }
01579       if (option_verbose > 2)
01580          ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
01581    }
01582    return 1;
01583 }

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

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

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

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

Definition at line 2842 of file app_queue.c.

References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_channel::context, localuser::interface, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_NOTICE, 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().

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

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.

Referenced by find_queue_by_name_rt().

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

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

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 2597 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, queues, RESULT_FAILURE, and RESULT_SUCCESS.

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

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

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

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

Referenced by try_calling().

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

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

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

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

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

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

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

References ast_mutex_lock(), ast_mutex_unlock(), member::calls, member::lastcall, and member::next.

Referenced by try_calling().

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

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

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

Referenced by load_module().

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

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

References STANDARD_USECOUNT.

04021 {
04022    int res;
04023    STANDARD_USECOUNT(res);
04024    return res;
04025 }

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

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

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

Referenced by queue_exec().

02439 {
02440    /* Don't need to hold the lock while we setup the outgoing calls */
02441    int retrywait = qe->parent->retry * 1000;
02442 
02443    return ast_waitfordigit(qe->chan, retrywait);
02444 }

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

References ast_log(), AST_MAX_WATCHERS, AST_STATE_UP, ast_verbose(), ast_waitfor_n(), BUILD_WATCHERS, queue_ent::chan, LOG_DEBUG, LOG_NOTICE, ast_channel::name, call_queue::name, option_verbose, queue_ent::parent, ring_one(), localuser::stillgoing, and VERBOSE_PREFIX_3.

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

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

Definition at line 2007 of file app_queue.c.

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

Referenced by queue_exec().

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


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

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

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

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

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

const { ... } queue_results[]
 

Referenced by set_queue_result().

struct ast_custom_function queueagentcount_function [static]
 

Definition at line 3274 of file app_queue.c.

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 3944 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 3929 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 3921 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 Sun Aug 6 15:04:06 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2