Thu Dec 17 17:40:17 2009

Asterisk developer's documentation


app_queue.c File Reference

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

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

Go to the source code of this file.

Data Structures

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

Defines

#define ANNOUNCEHOLDTIME_ALWAYS   1
#define ANNOUNCEHOLDTIME_ONCE   2
#define AST_MAX_WATCHERS   256
#define DEFAULT_RETRY   5
#define DEFAULT_TIMEOUT   15
#define MAX_PERIODIC_ANNOUNCEMENTS   10
#define PM_MAX_LEN   8192
#define QUEUE_EMPTY_NORMAL   1
#define QUEUE_EMPTY_STRICT   2
#define QUEUE_EVENT_VARIABLES   3
#define RECHECK   1
#define RES_EXISTS   (-1)
#define RES_NOSUCHQUEUE   (-3)
#define RES_NOT_DYNAMIC   (-4)
#define RES_OKAY   0
#define RES_OUTOFMEMORY   (-2)

Enumerations

enum  {
  QUEUE_STRATEGY_RINGALL = 0, QUEUE_STRATEGY_ROUNDROBIN, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_FEWESTCALLS,
  QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RRMEMORY
}
enum  qmc_status {
  QMC_VALID = 0, QMC_PAUSED, QMC_ACTIVE, QMC_FREE,
  QMC_ALL
}
enum  queue_member_status { QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NORMAL }
enum  queue_result {
  QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, QUEUE_JOINEMPTY = 2, QUEUE_LEAVEEMPTY = 3,
  QUEUE_JOINUNAVAIL = 4, QUEUE_LEAVEUNAVAIL = 5, QUEUE_FULL = 6
}

Functions

static int __queues_show (struct mansession *s, int manager, int fd, int argc, char **argv)
static void __reg_module (void)
static void __unreg_module (void)
static int add_to_interfaces (const char *interface)
static int add_to_queue (const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
static struct call_queuealloc_queue (const char *queuename)
static int aqm_exec (struct ast_channel *chan, void *data)
static int attended_transfer_occurred (struct ast_channel *chan)
 mechanism to tell if a queue caller was atxferred by a queue member.
static int calc_metric (struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
 Calculate the metric of each member in the outgoing callattempts.
static void clear_and_free_interfaces (void)
static void clear_queue (struct call_queue *q)
static int cli_queue_member_count (int fd, int argc, char **argv)
static int compare_weight (struct call_queue *rq, struct member *member)
static char * complete_queue (const char *line, const char *word, int pos, int state)
static char * complete_queue_add_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_member_count (const char *line, const char *word, int pos, int state)
static char * complete_queue_remove_member (const char *line, const char *word, int pos, int state)
static char * complete_queue_show (const char *line, const char *word, int pos, int state)
static int compress_char (const char c)
static struct membercreate_queue_member (const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
 allocate space for new queue member and set fields based on parameters passed
static void destroy_queue (struct call_queue *q)
static void * device_state_thread (void *data)
 Consumer of the statechange queue.
static void do_hang (struct callattempt *o)
 common hangup actions
static void dump_queue_members (struct call_queue *pm_queue)
static struct callattemptfind_best (struct callattempt *outgoing)
 find the entry with the best metric, or NULL
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 (struct call_queue *q, int max_penalty)
 Check if members are available.
static int handle_queue_add_member (int fd, int argc, char *argv[])
static int handle_queue_remove_member (int fd, int argc, char *argv[])
static void * handle_statechange (struct statechange *sc)
 set a member's status based on device state of that member's interface
static void hangupcalls (struct callattempt *outgoing, struct ast_channel *exception)
static void init_queue (struct call_queue *q)
static void insert_entry (struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
 Insert the 'new' entry after the 'prev' entry of queue 'q'.
static char * int2strat (int strategy)
static struct memberinterface_exists (struct call_queue *q, const char *interface)
static int interface_exists_global (const char *interface)
static int is_our_turn (struct queue_ent *qe)
 Check if we should start attempting to call queue members.
static int join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason)
static void leave_queue (struct queue_ent *qe)
static int load_module (void)
static struct call_queueload_realtime_queue (const char *queuename)
static int manager_add_queue_member (struct mansession *s, const struct message *m)
static int manager_pause_queue_member (struct mansession *s, const struct message *m)
static int manager_queue_member_count (struct mansession *s, const struct message *m)
static int manager_queues_show (struct mansession *s, const struct message *m)
static int manager_queues_status (struct mansession *s, const struct message *m)
static int manager_remove_queue_member (struct mansession *s, const struct message *m)
static int member_cmp_fn (void *obj1, void *obj2, int flags)
static int member_hash_fn (const void *obj, const int flags)
static void monjoin_dep_warning (void)
static int num_available_members (struct call_queue *q)
 Get the number of members available to accept a call.
static int play_file (struct ast_channel *chan, char *filename)
static int pqm_exec (struct ast_channel *chan, void *data)
static int ql_exec (struct ast_channel *chan, void *data)
static int qmc_handler (const char *queuename, char *buffer, int len)
static int queue_exec (struct ast_channel *chan, void *data)
 The starting point for all queue calls.
static int queue_function_queuemembercount (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
static int queue_function_queuememberlist (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
static int queue_function_queuewaitingcount (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
static int queue_member_count (const char *qname, struct member_count *qmc)
static void queue_set_param (struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
 Configure a queue parameter.
static int queue_show (int fd, int argc, char **argv)
static void queue_transfer_destroy (void *data)
static void queue_transfer_fixup (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
 Log an attended transfer when a queue caller channel is masqueraded.
static void recalc_holdtime (struct queue_ent *qe, int newholdtime)
static void record_abandoned (struct queue_ent *qe)
static int reload (void)
static void reload_queue_members (void)
static int reload_queues (void)
static int remove_from_interfaces (const char *interface)
static int remove_from_queue (const char *queuename, const char *interface)
static int ring_entry (struct queue_ent *qe, struct callattempt *tmp, int *busies)
 Part 2 of ring_one.
static int ring_one (struct queue_ent *qe, struct callattempt *outgoing, int *busies)
 Place a call to a queue member.
static void rna (int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause)
 RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.
static int rqm_exec (struct ast_channel *chan, void *data)
static void rr_dep_warning (void)
static void rt_handle_member_record (struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface)
static int say_periodic_announcement (struct queue_ent *qe)
static int say_position (struct queue_ent *qe)
static int set_member_paused (const char *queuename, const char *interface, int paused)
static void set_queue_result (struct ast_channel *chan, enum queue_result res)
 sets the QUEUESTATUS channel variable
static struct ast_datastoresetup_transfer_datastore (struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl)
 create a datastore for storing relevant info to log attended transfers in the queue_log
static int statechange_queue (const char *dev, int state, void *ign)
 Producer of the statechange queue.
static int store_next (struct queue_ent *qe, struct callattempt *outgoing)
static int strat2int (const char *strategy)
static int try_calling (struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi)
 A large function which calls members, updates statistics, and bridges the caller and a member.
static int unload_module (void)
static int update_queue (struct call_queue *q, struct member *member, int callcompletedinsl)
static int update_realtime_member_field (struct member *mem, const char *queue_name, const char *field, const char *value)
static void update_realtime_members (struct call_queue *q)
static int update_status (const char *interface, const int status)
static int upqm_exec (struct ast_channel *chan, void *data)
static int valid_exit (struct queue_ent *qe, char digit)
static char * vars2manager (struct ast_channel *chan, char *vars, size_t len)
static int wait_a_bit (struct queue_ent *qe)
static struct callattemptwait_for_answer (struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
 Wait for a member to answer the call.
static int wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason)
 The waiting areas for callers who are not actively calling members.

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, }
static char * app = "Queue"
static char * app_aqm = "AddQueueMember"
static char * app_aqm_descrip
static char * app_aqm_synopsis = "Dynamically adds queue members"
static char * app_pqm = "PauseQueueMember"
static char * app_pqm_descrip
static char * app_pqm_synopsis = "Pauses a queue member"
static char * app_ql = "QueueLog"
static char * app_ql_descrip
static char * app_ql_synopsis = "Writes to the queue_log"
static char * app_rqm = "RemoveQueueMember"
static char * app_rqm_descrip
static char * app_rqm_synopsis = "Dynamically removes queue members"
static char * app_upqm = "UnpauseQueueMember"
static char * app_upqm_descrip
static char * app_upqm_synopsis = "Unpauses a queue member"
static const struct ast_module_infoast_module_info = &__mod_info
static int autofill_default = 0
 queues.conf [general] option
static struct ast_cli_entry cli_add_queue_member_deprecated
static struct ast_cli_entry cli_queue []
static struct ast_cli_entry cli_remove_queue_member_deprecated
static struct ast_cli_entry cli_show_queue_deprecated
static char * descrip
struct {
   ast_cond_t   cond
   ast_mutex_t   lock
   struct {
      statechange *   first
      statechange *   last
   }   state_change_q
   unsigned int   stop:1
   pthread_t   thread
device_state
 Data used by the device state thread.
static int montype_default = 0
 queues.conf [general] option
static const char * pm_family = "Queue/PersistentMembers"
 Persistent Members astdb family.
static char qam_cmd_usage []
static char qmc_cmd_usage []
static char qrm_cmd_usage []
static int queue_debug = 0
 queues.conf [general] extra debug option
static int queue_persistent_members = 0
 queues.conf [general] option
struct {
   enum queue_result   id
   char *   text
queue_results []
static char queue_show_usage []
static struct ast_datastore_info queue_transfer_info
 a datastore used to help correctly log attended transfers of queue callers
static struct ast_custom_function queueagentcount_function
static struct ast_custom_function queuemembercount_function
static struct ast_custom_function queuememberlist_function
static struct ast_custom_function queuewaitingcount_function
static struct strategy strategies []
static char * synopsis = "Queue a call for a call queue"
static int use_weight = 0
 queues.conf per-queue weight option


Detailed Description

True call queues with optional send URL on answer.

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

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

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

Patch Version 1.07 2003-12-24 01

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

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

Definition in file app_queue.c.


Define Documentation

#define ANNOUNCEHOLDTIME_ALWAYS   1

Definition at line 390 of file app_queue.c.

Referenced by queue_set_param().

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 391 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

#define AST_MAX_WATCHERS   256

Definition at line 2203 of file app_queue.c.

#define DEFAULT_RETRY   5

Definition at line 137 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

#define DEFAULT_TIMEOUT   15

Definition at line 138 of file app_queue.c.

Referenced by queue_set_param().

#define MAX_PERIODIC_ANNOUNCEMENTS   10

Definition at line 140 of file app_queue.c.

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

#define PM_MAX_LEN   8192

Definition at line 276 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

#define QUEUE_EMPTY_NORMAL   1

Definition at line 388 of file app_queue.c.

Referenced by queue_set_param().

#define QUEUE_EMPTY_STRICT   2

Definition at line 389 of file app_queue.c.

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

#define QUEUE_EVENT_VARIABLES   3

Definition at line 392 of file app_queue.c.

Referenced by queue_set_param(), and ring_entry().

#define RECHECK   1

Definition at line 139 of file app_queue.c.

Referenced by wait_our_turn().

#define RES_EXISTS   (-1)

Definition at line 143 of file app_queue.c.

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

#define RES_NOSUCHQUEUE   (-3)

Definition at line 145 of file app_queue.c.

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

#define RES_NOT_DYNAMIC   (-4)

Definition at line 146 of file app_queue.c.

Referenced by handle_queue_remove_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec().

#define RES_OKAY   0

Definition at line 142 of file app_queue.c.

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

#define RES_OUTOFMEMORY   (-2)

Definition at line 144 of file app_queue.c.

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


Enumeration Type Documentation

anonymous enum

Enumerator:
QUEUE_STRATEGY_RINGALL 
QUEUE_STRATEGY_ROUNDROBIN 
QUEUE_STRATEGY_LEASTRECENT 
QUEUE_STRATEGY_FEWESTCALLS 
QUEUE_STRATEGY_RANDOM 
QUEUE_STRATEGY_RRMEMORY 

Definition at line 116 of file app_queue.c.

enum qmc_status

Enumerator:
QMC_VALID 
QMC_PAUSED 
QMC_ACTIVE 
QMC_FREE 
QMC_ALL 

Definition at line 4279 of file app_queue.c.

04279                 {
04280    QMC_VALID = 0, /* Count valid members */
04281    QMC_PAUSED,    /* Count paused members */
04282    QMC_ACTIVE,    /* Count active members */
04283    QMC_FREE,      /* Count free members */
04284    QMC_ALL        /* Count all queue members */
04285 };

enum queue_member_status

Enumerator:
QUEUE_NO_MEMBERS 
QUEUE_NO_REACHABLE_MEMBERS 
QUEUE_NORMAL 

Definition at line 543 of file app_queue.c.

00543                          {
00544    QUEUE_NO_MEMBERS,
00545    QUEUE_NO_REACHABLE_MEMBERS,
00546    QUEUE_NORMAL
00547 };

enum queue_result

Enumerator:
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 

Definition at line 293 of file app_queue.c.

00293                   {
00294    QUEUE_UNKNOWN = 0,
00295    QUEUE_TIMEOUT = 1,
00296    QUEUE_JOINEMPTY = 2,
00297    QUEUE_LEAVEEMPTY = 3,
00298    QUEUE_JOINUNAVAIL = 4,
00299    QUEUE_LEAVEUNAVAIL = 5,
00300    QUEUE_FULL = 6,
00301 };


Function Documentation

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

Definition at line 4720 of file app_queue.c.

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ast_build_string(), ast_category_browse(), ast_check_realtime(), ast_cli(), ast_config_destroy(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime_multientry(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_append(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, call_queue::count, devstate2str(), member::dynamic, call_queue::head, call_queue::holdtime, int2strat(), member::interface, member::lastcall, load_realtime_queue(), call_queue::lock, call_queue::maxlen, member::membername, call_queue::members, ast_channel::name, call_queue::name, queue_ent::next, member::paused, member::penalty, queue_ent::prio, queue_show(), member::realtime, RESULT_SHOWUSAGE, RESULT_SUCCESS, call_queue::ringlimit, s, call_queue::servicelevel, queue_ent::start, member::status, call_queue::strategy, and call_queue::weight.

Referenced by manager_queues_show(), and queue_show().

04721 {
04722    struct call_queue *q;
04723    struct queue_ent *qe;
04724    struct member *mem;
04725    int pos, queue_show;
04726    time_t now;
04727    char max_buf[150];
04728    char *max;
04729    size_t max_left;
04730    float sl = 0;
04731    char *term = manager ? "\r\n" : "\n";
04732    struct ao2_iterator mem_iter;
04733 
04734    time(&now);
04735    if (argc == 2)
04736       queue_show = 0;
04737    else if (argc == 3)
04738       queue_show = 1;
04739    else
04740       return RESULT_SHOWUSAGE;
04741 
04742    /* We only want to load realtime queues when a specific queue is asked for. */
04743    if (queue_show) {
04744       load_realtime_queue(argv[2]);
04745    } else if (ast_check_realtime("queues")) {
04746       struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", (char *) NULL);
04747       char *queuename;
04748       if (cfg) {
04749          for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
04750             load_realtime_queue(queuename);
04751          }
04752          ast_config_destroy(cfg);
04753       }
04754    }
04755 
04756    AST_LIST_LOCK(&queues);
04757    if (AST_LIST_EMPTY(&queues)) {
04758       AST_LIST_UNLOCK(&queues);
04759       if (queue_show) {
04760          if (s)
04761             astman_append(s, "No such queue: %s.%s",argv[2], term);
04762          else
04763             ast_cli(fd, "No such queue: %s.%s",argv[2], term);
04764       } else {
04765          if (s)
04766             astman_append(s, "No queues.%s", term);
04767          else
04768             ast_cli(fd, "No queues.%s", term);
04769       }
04770       return RESULT_SUCCESS;
04771    }
04772    AST_LIST_TRAVERSE(&queues, q, list) {
04773       ast_mutex_lock(&q->lock);
04774       if (queue_show) {
04775          if (strcasecmp(q->name, argv[2]) != 0) {
04776             ast_mutex_unlock(&q->lock);
04777             if (!AST_LIST_NEXT(q, list)) {
04778                ast_cli(fd, "No such queue: %s.%s",argv[2], term);
04779                break;
04780             }
04781             continue;
04782          }
04783       }
04784       max_buf[0] = '\0';
04785       max = max_buf;
04786       max_left = sizeof(max_buf);
04787       if (q->maxlen)
04788          ast_build_string(&max, &max_left, "%d", q->maxlen);
04789       else
04790          ast_build_string(&max, &max_left, "unlimited");
04791       sl = 0;
04792       if (q->callscompleted > 0)
04793          sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
04794       if (s)
04795          astman_append(s, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), R:%d, W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
04796                               q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit,
04797                               q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term);
04798       else
04799          ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), R:%d, W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
04800                      q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit,
04801                      q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term);
04802       if (ao2_container_count(q->members)) {
04803          if (s)
04804             astman_append(s, "   Members: %s", term);
04805          else
04806             ast_cli(fd, "   Members: %s", term);
04807          mem_iter = ao2_iterator_init(q->members, 0);
04808          while ((mem = ao2_iterator_next(&mem_iter))) {
04809             max_buf[0] = '\0';
04810             max = max_buf;
04811             max_left = sizeof(max_buf);
04812             if (strcasecmp(mem->membername, mem->interface)) {
04813                ast_build_string(&max, &max_left, " (%s)", mem->interface);
04814             }
04815             if (mem->penalty)
04816                ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
04817             if (mem->dynamic)
04818                ast_build_string(&max, &max_left, " (dynamic)");
04819             if (mem->realtime)
04820                ast_build_string(&max, &max_left, " (realtime)");
04821             if (mem->paused)
04822                ast_build_string(&max, &max_left, " (paused)");
04823             ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
04824             if (mem->calls) {
04825                ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
04826                   mem->calls, (long) (time(NULL) - mem->lastcall));
04827             } else
04828                ast_build_string(&max, &max_left, " has taken no calls yet");
04829             if (s)
04830                astman_append(s, "      %s%s%s", mem->membername, max_buf, term);
04831             else
04832                ast_cli(fd, "      %s%s%s", mem->membername, max_buf, term);
04833             ao2_ref(mem, -1);
04834          }
04835          ao2_iterator_destroy(&mem_iter);
04836       } else if (s)
04837          astman_append(s, "   No Members%s", term);
04838       else  
04839          ast_cli(fd, "   No Members%s", term);
04840       if (q->head) {
04841          pos = 1;
04842          if (s)
04843             astman_append(s, "   Callers: %s", term);
04844          else
04845             ast_cli(fd, "   Callers: %s", term);
04846          for (qe = q->head; qe; qe = qe->next) {
04847             if (s)
04848                astman_append(s, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
04849                   pos++, qe->chan->name, (long) (now - qe->start) / 60,
04850                   (long) (now - qe->start) % 60, qe->prio, term);
04851             else
04852                ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
04853                   qe->chan->name, (long) (now - qe->start) / 60,
04854                   (long) (now - qe->start) % 60, qe->prio, term);
04855          }
04856       } else if (s)
04857          astman_append(s, "   No Callers%s", term);
04858       else
04859          ast_cli(fd, "   No Callers%s", term);
04860       if (s)
04861          astman_append(s, "%s", term);
04862       else
04863          ast_cli(fd, "%s", term);
04864       ast_mutex_unlock(&q->lock);
04865       if (queue_show)
04866          break;
04867    }
04868    AST_LIST_UNLOCK(&queues);
04869    return RESULT_SUCCESS;
04870 }

static void __reg_module ( void   )  [static]

Definition at line 5548 of file app_queue.c.

static void __unreg_module ( void   )  [static]

Definition at line 5548 of file app_queue.c.

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

Definition at line 891 of file app_queue.c.

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

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

00892 {
00893    struct member_interface *curint;
00894 
00895    AST_LIST_LOCK(&interfaces);
00896    AST_LIST_TRAVERSE(&interfaces, curint, list) {
00897       if (!strcasecmp(curint->interface, interface))
00898          break;
00899    }
00900 
00901    if (curint) {
00902       AST_LIST_UNLOCK(&interfaces);
00903       return 0;
00904    }
00905 
00906    if (option_debug)
00907       ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
00908    
00909    if ((curint = ast_calloc(1, sizeof(*curint)))) {
00910       ast_copy_string(curint->interface, interface, sizeof(curint->interface));
00911       AST_LIST_INSERT_HEAD(&interfaces, curint, list);
00912    }
00913    AST_LIST_UNLOCK(&interfaces);
00914 
00915    return 0;
00916 }

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

Definition at line 3503 of file app_queue.c.

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

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

03504 {
03505    struct call_queue *q;
03506    struct member *new_member, *old_member;
03507    int res = RES_NOSUCHQUEUE;
03508 
03509    /* \note Ensure the appropriate realtime queue is loaded.  Note that this
03510     * short-circuits if the queue is already in memory. */
03511    if (!(q = load_realtime_queue(queuename)))
03512       return res;
03513 
03514    AST_LIST_LOCK(&queues);
03515 
03516    ast_mutex_lock(&q->lock);
03517    if ((old_member = interface_exists(q, interface)) == NULL) {
03518       if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
03519          add_to_interfaces(new_member->state_interface);
03520          new_member->dynamic = 1;
03521          ao2_link(q->members, new_member);
03522          q->membercount++;
03523          manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
03524             "Queue: %s\r\n"
03525             "Location: %s\r\n"
03526             "MemberName: %s\r\n"
03527             "Membership: %s\r\n"
03528             "Penalty: %d\r\n"
03529             "CallsTaken: %d\r\n"
03530             "LastCall: %d\r\n"
03531             "Status: %d\r\n"
03532             "Paused: %d\r\n",
03533             q->name, new_member->interface, new_member->membername,
03534             "dynamic",
03535             new_member->penalty, new_member->calls, (int) new_member->lastcall,
03536             new_member->status, new_member->paused);
03537          
03538          ao2_ref(new_member, -1);
03539          new_member = NULL;
03540 
03541          if (dump)
03542             dump_queue_members(q);
03543          
03544          res = RES_OKAY;
03545       } else {
03546          res = RES_OUTOFMEMORY;
03547       }
03548    } else {
03549       ao2_ref(old_member, -1);
03550       res = RES_EXISTS;
03551    }
03552    ast_mutex_unlock(&q->lock);
03553    AST_LIST_UNLOCK(&queues);
03554 
03555    return res;
03556 }

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

Definition at line 792 of file app_queue.c.

References ast_calloc, ast_copy_string(), and ast_mutex_init().

Referenced by find_queue_by_name_rt(), and reload_queues().

00793 {
00794    struct call_queue *q;
00795 
00796    if ((q = ast_calloc(1, sizeof(*q)))) {
00797       ast_mutex_init(&q->lock);
00798       ast_copy_string(q->name, queuename, sizeof(q->name));
00799    }
00800    return q;
00801 }

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

Definition at line 3884 of file app_queue.c.

References add_to_queue(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::name, parse(), pbx_builtin_setvar_helper(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and ast_channel::uniqueid.

Referenced by load_module().

03885 {
03886    int res=-1;
03887    struct ast_module_user *lu;
03888    char *parse, *temppos = NULL;
03889    int priority_jump = 0;
03890    AST_DECLARE_APP_ARGS(args,
03891       AST_APP_ARG(queuename);
03892       AST_APP_ARG(interface);
03893       AST_APP_ARG(penalty);
03894       AST_APP_ARG(options);
03895       AST_APP_ARG(membername);
03896       AST_APP_ARG(state_interface);
03897    );
03898    int penalty = 0;
03899 
03900    if (ast_strlen_zero(data)) {
03901       ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|interface[|penalty[|options[|membername[|state_interface]]]]])\n");
03902       return -1;
03903    }
03904 
03905    parse = ast_strdupa(data);
03906 
03907    AST_STANDARD_APP_ARGS(args, parse);
03908 
03909    lu = ast_module_user_add(chan);
03910 
03911    if (ast_strlen_zero(args.interface)) {
03912       args.interface = ast_strdupa(chan->name);
03913       temppos = strrchr(args.interface, '-');
03914       if (temppos)
03915          *temppos = '\0';
03916    }
03917 
03918    if (!ast_strlen_zero(args.penalty)) {
03919       if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
03920          ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
03921          penalty = 0;
03922       }
03923    }
03924    
03925    if (args.options) {
03926       if (strchr(args.options, 'j'))
03927          priority_jump = 1;
03928    }
03929 
03930    switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
03931    case RES_OKAY:
03932       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
03933       ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
03934       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
03935       res = 0;
03936       break;
03937    case RES_EXISTS:
03938       ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
03939       if (priority_jump || ast_opt_priority_jumping)
03940          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
03941       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
03942       res = 0;
03943       break;
03944    case RES_NOSUCHQUEUE:
03945       ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
03946       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
03947       res = 0;
03948       break;
03949    case RES_OUTOFMEMORY:
03950       ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
03951       break;
03952    }
03953 
03954    ast_module_user_remove(lu);
03955 
03956    return res;
03957 }

static int attended_transfer_occurred ( struct ast_channel chan  )  [static]

mechanism to tell if a queue caller was atxferred by a queue member.

When a caller is atxferred, then the queue_transfer_info datastore is removed from the channel. If it's still there after the bridge is broken, then the caller was not atxferred.

Note:
Only call this with chan locked

Definition at line 2742 of file app_queue.c.

References ast_channel_datastore_find(), and queue_transfer_info.

02743 {
02744    return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
02745 }

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

Calculate the metric of each member in the outgoing callattempts.

A numeric metric is given to each member depending on the ring strategy used by the queue. Members with lower metrics will be called before members with higher metrics

Definition at line 2620 of file app_queue.c.

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

Referenced by try_calling().

02621 {
02622    if (qe->max_penalty && (mem->penalty > qe->max_penalty))
02623       return -1;
02624 
02625    switch (q->strategy) {
02626    case QUEUE_STRATEGY_RINGALL:
02627       /* Everyone equal, except for penalty */
02628       tmp->metric = mem->penalty * 1000000;
02629       break;
02630    case QUEUE_STRATEGY_ROUNDROBIN:
02631       if (!pos) {
02632          if (!q->wrapped) {
02633             /* No more channels, start over */
02634             q->rrpos = 0;
02635          } else {
02636             /* Prioritize next entry */
02637             q->rrpos++;
02638          }
02639          q->wrapped = 0;
02640       }
02641       /* Fall through */
02642    case QUEUE_STRATEGY_RRMEMORY:
02643       if (pos < q->rrpos) {
02644          tmp->metric = 1000 + pos;
02645       } else {
02646          if (pos > q->rrpos)
02647             /* Indicate there is another priority */
02648             q->wrapped = 1;
02649          tmp->metric = pos;
02650       }
02651       tmp->metric += mem->penalty * 1000000;
02652       break;
02653    case QUEUE_STRATEGY_RANDOM:
02654       tmp->metric = ast_random() % 1000;
02655       tmp->metric += mem->penalty * 1000000;
02656       break;
02657    case QUEUE_STRATEGY_FEWESTCALLS:
02658       tmp->metric = mem->calls;
02659       tmp->metric += mem->penalty * 1000000;
02660       break;
02661    case QUEUE_STRATEGY_LEASTRECENT:
02662       if (!mem->lastcall)
02663          tmp->metric = 0;
02664       else
02665          tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
02666       tmp->metric += mem->penalty * 1000000;
02667       break;
02668    default:
02669       ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
02670       break;
02671    }
02672    if (q->ringlimit && (mem->ringcount >= q->ringlimit)) {
02673       tmp->metric += (mem->ringcount / q->ringlimit) * 10000000;
02674    }
02675    if (option_debug)
02676       ast_log(LOG_DEBUG, "New metric %d for member %s with %d rings (limit %d)\n", 
02677                   tmp->metric, mem->interface, mem->ringcount, q->ringlimit);
02678    return 0;
02679 }

static void clear_and_free_interfaces ( void   )  [static]

Definition at line 970 of file app_queue.c.

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

Referenced by unload_module().

00971 {
00972    struct member_interface *curint;
00973 
00974    AST_LIST_LOCK(&interfaces);
00975    while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
00976       free(curint);
00977    AST_LIST_UNLOCK(&interfaces);
00978 }

static void clear_queue ( struct call_queue q  )  [static]

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

00883 {
00884    q->holdtime = 0;
00885    q->callscompleted = 0;
00886    q->callsabandoned = 0;
00887    q->callscompletedinsl = 0;
00888    q->wrapuptime = 0;
00889 }

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

Definition at line 5375 of file app_queue.c.

References ast_cli(), qmc_handler(), RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

05376 {
05377    char buffer[256] = "";
05378    char *queuename;
05379    
05380    if (argc != 4) {
05381       return RESULT_SHOWUSAGE;
05382    }
05383    queuename = argv[3];
05384 
05385    if (qmc_handler(queuename, buffer, sizeof(buffer)) == RESULT_SUCCESS) {
05386          ast_cli(fd, 
05387                      "Member count for queue '%s'\n"
05388                      "%s\n",
05389                      queuename, buffer); 
05390          return RESULT_SUCCESS;
05391    } else {
05392          ast_cli(fd, "No such queue: '%s'\n", queuename);
05393          return RESULT_FAILURE;
05394    }
05395 }

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

Definition at line 1812 of file app_queue.c.

References ao2_find(), ao2_ref(), AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), call_queue::count, member::interface, member_interface::list, call_queue::lock, LOG_DEBUG, call_queue::members, call_queue::name, num_available_members(), and call_queue::weight.

Referenced by ring_entry().

01813 {
01814    struct call_queue *q;
01815    struct member *mem;
01816    int found = 0;
01817    
01818    /* &qlock and &rq->lock already set by try_calling()
01819     * to solve deadlock */
01820    AST_LIST_TRAVERSE(&queues, q, list) {
01821       if (q == rq) /* don't check myself, could deadlock */
01822          continue;
01823       ast_mutex_lock(&q->lock);
01824       if (q->count && q->members) {
01825          if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
01826             ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
01827             if (q->weight > rq->weight && q->count >= num_available_members(q)) {
01828                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);
01829                found = 1;
01830             }
01831             ao2_ref(mem, -1);
01832          }
01833       }
01834       ast_mutex_unlock(&q->lock);
01835       if (found)
01836          break;
01837    }
01838    return found;
01839 }

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

Definition at line 4877 of file app_queue.c.

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

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

04878 {
04879    struct call_queue *q;
04880    char *ret = NULL;
04881    int which = 0;
04882    int wordlen = strlen(word);
04883    
04884    AST_LIST_LOCK(&queues);
04885    AST_LIST_TRAVERSE(&queues, q, list) {
04886       if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
04887          ret = ast_strdup(q->name); 
04888          break;
04889       }
04890    }
04891    AST_LIST_UNLOCK(&queues);
04892 
04893    return ret;
04894 }

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

Definition at line 5180 of file app_queue.c.

References ast_malloc, ast_strdup, and complete_queue().

05181 {
05182    /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
05183    switch (pos) {
05184    case 3:  /* Don't attempt to complete name of interface (infinite possibilities) */
05185       return NULL;
05186    case 4:  /* only one possible match, "to" */
05187       return state == 0 ? ast_strdup("to") : NULL;
05188    case 5:  /* <queue> */
05189       return complete_queue(line, word, pos, state);
05190    case 6: /* only one possible match, "penalty" */
05191       return state == 0 ? ast_strdup("penalty") : NULL;
05192    case 7:
05193       if (state < 100) {   /* 0-99 */
05194          char *num;
05195          if ((num = ast_malloc(3))) {
05196             sprintf(num, "%d", state);
05197          }
05198          return num;
05199       } else {
05200          return NULL;
05201       }
05202    case 8: /* only one possible match, "as" */
05203       return state == 0 ? ast_strdup("as") : NULL;
05204    case 9:  /* Don't attempt to complete name of member (infinite possibilities) */
05205       return NULL;
05206    case 10:
05207       return state == 0 ? ast_strdup("state_interface") : NULL;
05208    default:
05209       return NULL;
05210    }
05211 }

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

Definition at line 5402 of file app_queue.c.

References complete_queue().

05403 {
05404       /* 0 - queue; 1 - member; 2 - count; 3 - <queue> */
05405       switch (pos) {
05406       case 3:  /* <queue> */
05407             return complete_queue(line, word, pos, state);
05408       default:
05409          return NULL;
05410       }
05411 }

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

Definition at line 5248 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_LIST_EMPTY, AST_LIST_TRAVERSE, ast_mutex_lock(), ast_mutex_unlock(), ast_strdup, complete_queue(), member::interface, call_queue::lock, and call_queue::members.

05249 {
05250    int which = 0;
05251    struct call_queue *q;
05252    struct member *m;
05253    struct ao2_iterator mem_iter;
05254 
05255    /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
05256    if (pos > 5 || pos < 3)
05257       return NULL;
05258    if (pos == 4)  /* only one possible match, 'from' */
05259       return state == 0 ? ast_strdup("from") : NULL;
05260 
05261    if (pos == 5)  /* No need to duplicate code */
05262       return complete_queue(line, word, pos, state);
05263 
05264    /* here is the case for 3, <member> */
05265    if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */
05266       AST_LIST_TRAVERSE(&queues, q, list) {
05267          ast_mutex_lock(&q->lock);
05268          mem_iter = ao2_iterator_init(q->members, 0);
05269          while ((m = ao2_iterator_next(&mem_iter))) {
05270             if (++which > state) {
05271                char *tmp;
05272                ao2_iterator_destroy(&mem_iter);
05273                ast_mutex_unlock(&q->lock);
05274                tmp = ast_strdup(m->interface);
05275                ao2_ref(m, -1);
05276                return tmp;
05277             }
05278             ao2_ref(m, -1);
05279          }
05280          ao2_iterator_destroy(&mem_iter);
05281          ast_mutex_unlock(&q->lock);
05282       }
05283    }
05284 
05285    return NULL;
05286 }

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

Definition at line 4896 of file app_queue.c.

References complete_queue().

04897 {
04898    if (pos == 2)
04899       return complete_queue(line, word, pos, state);
04900    return NULL;
04901 }

static int compress_char ( const char  c  )  [static]

Definition at line 803 of file app_queue.c.

00804 {
00805    if (c < 32)
00806       return 0;
00807    else if (c > 96)
00808       return c - 64;
00809    else
00810       return c - 32;
00811 }

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

allocate space for new queue member and set fields based on parameters passed

Definition at line 767 of file app_queue.c.

References ao2_alloc(), ast_copy_string(), ast_device_state(), ast_log(), ast_strlen_zero(), LOG_WARNING, and member::penalty.

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

00768 {
00769    struct member *cur;
00770    
00771    if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
00772       cur->penalty = penalty;
00773       cur->paused = paused;
00774       ast_copy_string(cur->interface, interface, sizeof(cur->interface));
00775       if (!ast_strlen_zero(state_interface)) {
00776          ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
00777       } else {
00778          ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
00779       }
00780       if (!ast_strlen_zero(membername))
00781          ast_copy_string(cur->membername, membername, sizeof(cur->membername));
00782       else
00783          ast_copy_string(cur->membername, interface, sizeof(cur->membername));
00784       if (!strchr(cur->interface, '/'))
00785          ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
00786       cur->status = ast_device_state(cur->state_interface);
00787    }
00788 
00789    return cur;
00790 }

static void destroy_queue ( struct call_queue q  )  [static]

Definition at line 1203 of file app_queue.c.

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

Referenced by find_queue_by_name_rt(), and leave_queue().

01204 {
01205    free_members(q, 1);
01206    ast_mutex_destroy(&q->lock);
01207    ao2_ref(q->members, -1);
01208    free(q);
01209 }

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

Consumer of the statechange queue.

Definition at line 715 of file app_queue.c.

References ast_cond_wait(), AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), device_state, statechange::entry, free, and handle_statechange().

Referenced by load_module().

00716 {
00717    struct statechange *sc = NULL;
00718 
00719    while (!device_state.stop) {
00720       ast_mutex_lock(&device_state.lock);
00721       if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
00722          ast_cond_wait(&device_state.cond, &device_state.lock);
00723          sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry);
00724       }
00725       ast_mutex_unlock(&device_state.lock);
00726 
00727       /* Check to see if we were woken up to see the request to stop */
00728       if (device_state.stop)
00729          break;
00730 
00731       if (!sc)
00732          continue;
00733 
00734       handle_statechange(sc);
00735 
00736       free(sc);
00737       sc = NULL;
00738    }
00739 
00740    if (sc)
00741       free(sc);
00742 
00743    while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry)))
00744       free(sc);
00745 
00746    return NULL;
00747 }

static void do_hang ( struct callattempt o  )  [static]

common hangup actions

Definition at line 1842 of file app_queue.c.

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

Referenced by ring_entry().

01843 {
01844    o->stillgoing = 0;
01845    ast_hangup(o->chan);
01846    o->chan = NULL;
01847 }

static void dump_queue_members ( struct call_queue pm_queue  )  [static]

Definition at line 3411 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ast_db_del(), ast_db_put(), ast_log(), member::dynamic, member::interface, LOG_WARNING, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, PM_MAX_LEN, and member::state_interface.

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

03412 {
03413    struct member *cur_member;
03414    char value[PM_MAX_LEN];
03415    int value_len = 0;
03416    int res;
03417    struct ao2_iterator mem_iter;
03418 
03419    memset(value, 0, sizeof(value));
03420 
03421    if (!pm_queue)
03422       return;
03423 
03424    mem_iter = ao2_iterator_init(pm_queue->members, 0);
03425    while ((cur_member = ao2_iterator_next(&mem_iter))) {
03426       if (!cur_member->dynamic) {
03427          ao2_ref(cur_member, -1);
03428          continue;
03429       }
03430 
03431       res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s",
03432          value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface);
03433 
03434       ao2_ref(cur_member, -1);
03435 
03436       if (res != strlen(value + value_len)) {
03437          ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
03438          break;
03439       }
03440       value_len += res;
03441    }
03442    ao2_iterator_destroy(&mem_iter);
03443    
03444    if (value_len && !cur_member) {
03445       if (ast_db_put(pm_family, pm_queue->name, value))
03446          ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
03447    } else
03448       /* Delete the entry if the queue is empty or there is an error */
03449       ast_db_del(pm_family, pm_queue->name);
03450 }

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

find the entry with the best metric, or NULL

Definition at line 2049 of file app_queue.c.

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

02050 {
02051    struct callattempt *best = NULL, *cur;
02052 
02053    for (cur = outgoing; cur; cur = cur->q_next) {
02054       if (cur->stillgoing &&              /* Not already done */
02055          !cur->chan &&              /* Isn't already going */
02056          (!best || cur->metric < best->metric)) {     /* We haven't found one yet, or it's better */
02057          best = cur;
02058       }
02059    }
02060 
02061    return best;
02062 }

static struct call_queue* find_queue_by_name_rt ( const char *  queuename,
struct ast_variable queue_vars,
struct ast_config member_config 
) [static]

Reload a single queue via realtime.

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

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

Definition at line 1214 of file app_queue.c.

References alloc_queue(), ast_copy_string(), AST_LIST_INSERT_HEAD, AST_LIST_REMOVE, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), clear_queue(), call_queue::dead, destroy_queue(), init_queue(), member_interface::interface, member_interface::list, call_queue::lock, LOG_DEBUG, LOG_WARNING, ast_variable::name, call_queue::name, ast_variable::next, queue_set_param(), call_queue::realtime, and ast_variable::value.

Referenced by load_realtime_queue().

01215 {
01216    struct ast_variable *v;
01217    struct call_queue *q;
01218    struct member *m;
01219    struct ao2_iterator mem_iter;
01220    char *interface = NULL;
01221    char *tmp, *tmp_name;
01222    char tmpbuf[64];  /* Must be longer than the longest queue param name. */
01223 
01224    /* Find the queue in the in-core list (we will create a new one if not found). */
01225    AST_LIST_TRAVERSE(&queues, q, list) {
01226       if (!strcasecmp(q->name, queuename))
01227          break;
01228    }
01229 
01230    /* Static queues override realtime. */
01231    if (q) {
01232       ast_mutex_lock(&q->lock);
01233       if (!q->realtime) {
01234          if (q->dead) {
01235             ast_mutex_unlock(&q->lock);
01236             return NULL;
01237          } else {
01238             ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
01239             ast_mutex_unlock(&q->lock);
01240             return q;
01241          }
01242       }
01243    } else if (!member_config)
01244       /* Not found in the list, and it's not realtime ... */
01245       return NULL;
01246 
01247    /* Check if queue is defined in realtime. */
01248    if (!queue_vars) {
01249       /* Delete queue from in-core list if it has been deleted in realtime. */
01250       if (q) {
01251          /*! \note Hmm, can't seem to distinguish a DB failure from a not
01252             found condition... So we might delete an in-core queue
01253             in case of DB failure. */
01254          ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
01255 
01256          q->dead = 1;
01257          /* Delete if unused (else will be deleted when last caller leaves). */
01258          if (!q->count) {
01259             /* Delete. */
01260             AST_LIST_REMOVE(&queues, q, list);
01261             ast_mutex_unlock(&q->lock);
01262             destroy_queue(q);
01263          } else
01264             ast_mutex_unlock(&q->lock);
01265       }
01266       return NULL;
01267    }
01268 
01269    /* Create a new queue if an in-core entry does not exist yet. */
01270    if (!q) {
01271       if (!(q = alloc_queue(queuename)))
01272          return NULL;
01273       ast_mutex_lock(&q->lock);
01274       clear_queue(q);
01275       q->realtime = 1;
01276       AST_LIST_INSERT_HEAD(&queues, q, list);
01277    }
01278    init_queue(q);    /* Ensure defaults for all parameters not set explicitly. */
01279 
01280    memset(tmpbuf, 0, sizeof(tmpbuf));
01281    for (v = queue_vars; v; v = v->next) {
01282       /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
01283       if ((tmp = strchr(v->name, '_'))) {
01284          ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
01285          tmp_name = tmpbuf;
01286          tmp = tmp_name;
01287          while ((tmp = strchr(tmp, '_')))
01288             *tmp++ = '-';
01289       } else
01290          tmp_name = v->name;
01291 
01292       if (!ast_strlen_zero(v->value)) {
01293          /* Don't want to try to set the option if the value is empty */
01294          queue_set_param(q, tmp_name, v->value, -1, 0);
01295       }
01296    }
01297 
01298    if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
01299       rr_dep_warning();
01300 
01301    /* Temporarily set realtime members dead so we can detect deleted ones. 
01302     * Also set the membercount correctly for realtime*/
01303    mem_iter = ao2_iterator_init(q->members, 0);
01304    while ((m = ao2_iterator_next(&mem_iter))) {
01305       q->membercount++;
01306       if (m->realtime)
01307          m->dead = 1;
01308       ao2_ref(m, -1);
01309    }
01310    ao2_iterator_destroy(&mem_iter);
01311 
01312    while ((interface = ast_category_browse(member_config, interface))) {
01313       rt_handle_member_record(q, interface,
01314          ast_variable_retrieve(member_config, interface, "membername"),
01315          ast_variable_retrieve(member_config, interface, "penalty"),
01316          ast_variable_retrieve(member_config, interface, "paused"),
01317          S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
01318    }
01319 
01320    /* Delete all realtime members that have been deleted in DB. */
01321    mem_iter = ao2_iterator_init(q->members, 0);
01322    while ((m = ao2_iterator_next(&mem_iter))) {
01323       if (m->dead) {
01324          ao2_unlink(q->members, m);
01325          ast_mutex_unlock(&q->lock);
01326          remove_from_interfaces(m->state_interface);
01327          ast_mutex_lock(&q->lock);
01328          q->membercount--;
01329       }
01330       ao2_ref(m, -1);
01331    }
01332    ao2_iterator_destroy(&mem_iter);
01333 
01334    ast_mutex_unlock(&q->lock);
01335 
01336    return q;
01337 }

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

Definition at line 1186 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ao2_unlink(), member::dynamic, call_queue::membercount, call_queue::members, remove_from_interfaces(), and member::state_interface.

Referenced by destroy_queue().

01187 {
01188    /* Free non-dynamic members */
01189    struct member *cur;
01190    struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
01191 
01192    while ((cur = ao2_iterator_next(&mem_iter))) {
01193       if (all || !cur->dynamic) {
01194          ao2_unlink(q->members, cur);
01195          remove_from_interfaces(cur->state_interface);
01196          q->membercount--;
01197       }
01198       ao2_ref(cur, -1);
01199    }
01200    ao2_iterator_destroy(&mem_iter);
01201 }

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

Check if members are available.

This function checks to see if members are available to be called. If any member is available, the function immediately returns QUEUE_NORMAL. If no members are available, the appropriate reason why is returned

Definition at line 555 of file app_queue.c.

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

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

00556 {
00557    struct member *member;
00558    struct ao2_iterator mem_iter;
00559    enum queue_member_status result = QUEUE_NO_MEMBERS;
00560 
00561    ast_mutex_lock(&q->lock);
00562    mem_iter = ao2_iterator_init(q->members, 0);
00563    while ((member = ao2_iterator_next(&mem_iter))) {
00564       if (max_penalty && (member->penalty > max_penalty)) {
00565          ao2_ref(member, -1);
00566          continue;
00567       }
00568 
00569       if (member->paused) {
00570          ao2_ref(member, -1);
00571          continue;
00572       }
00573 
00574       switch (member->status) {
00575       case AST_DEVICE_INVALID:
00576          /* nothing to do */
00577          ao2_ref(member, -1);
00578          break;
00579       case AST_DEVICE_UNAVAILABLE:
00580          result = QUEUE_NO_REACHABLE_MEMBERS;
00581          ao2_ref(member, -1);
00582          break;
00583       default:
00584          ast_mutex_unlock(&q->lock);
00585          ao2_ref(member, -1);
00586          return QUEUE_NORMAL;
00587       }
00588    }
00589    ao2_iterator_destroy(&mem_iter);
00590    ast_mutex_unlock(&q->lock);
00591    return result;
00592 }

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

Definition at line 5120 of file app_queue.c.

References add_to_queue(), ast_cli(), ast_queue_log(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

05121 {
05122    char *queuename, *interface, *membername = NULL, *state_interface = NULL;
05123    int penalty;
05124 
05125    if ((argc != 6) && (argc != 8) && (argc != 10) && (argc != 12)) {
05126       return RESULT_SHOWUSAGE;
05127    } else if (strcmp(argv[4], "to")) {
05128       return RESULT_SHOWUSAGE;
05129    } else if ((argc == 8) && strcmp(argv[6], "penalty")) {
05130       return RESULT_SHOWUSAGE;
05131    } else if ((argc == 10) && strcmp(argv[8], "as")) {
05132       return RESULT_SHOWUSAGE;
05133    } else if ((argc == 12) && strcmp(argv[10], "state_interface")) {
05134       return RESULT_SHOWUSAGE;
05135    }
05136 
05137    queuename = argv[5];
05138    interface = argv[3];
05139    if (argc >= 8) {
05140       if (sscanf(argv[7], "%30d", &penalty) == 1) {
05141          if (penalty < 0) {
05142             ast_cli(fd, "Penalty must be >= 0\n");
05143             penalty = 0;
05144          }
05145       } else {
05146          ast_cli(fd, "Penalty must be an integer >= 0\n");
05147          penalty = 0;
05148       }
05149    } else {
05150       penalty = 0;
05151    }
05152 
05153    if (argc >= 10) {
05154       membername = argv[9];
05155    }
05156 
05157    if (argc >= 12) {
05158       state_interface = argv[11];
05159    }
05160 
05161    switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
05162    case RES_OKAY:
05163       ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
05164       ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
05165       return RESULT_SUCCESS;
05166    case RES_EXISTS:
05167       ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
05168       return RESULT_FAILURE;
05169    case RES_NOSUCHQUEUE:
05170       ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
05171       return RESULT_FAILURE;
05172    case RES_OUTOFMEMORY:
05173       ast_cli(fd, "Out of memory\n");
05174       return RESULT_FAILURE;
05175    default:
05176       return RESULT_FAILURE;
05177    }
05178 }

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

Definition at line 5213 of file app_queue.c.

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

05214 {
05215    char *queuename, *interface;
05216 
05217    if (argc != 6) {
05218       return RESULT_SHOWUSAGE;
05219    } else if (strcmp(argv[4], "from")) {
05220       return RESULT_SHOWUSAGE;
05221    }
05222 
05223    queuename = argv[5];
05224    interface = argv[3];
05225 
05226    switch (remove_from_queue(queuename, interface)) {
05227    case RES_OKAY:
05228       ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
05229       ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
05230       return RESULT_SUCCESS;
05231    case RES_EXISTS:
05232       ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
05233       return RESULT_FAILURE;
05234    case RES_NOSUCHQUEUE:
05235       ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
05236       return RESULT_FAILURE;
05237    case RES_OUTOFMEMORY:
05238       ast_cli(fd, "Out of memory\n");
05239       return RESULT_FAILURE;
05240    case RES_NOT_DYNAMIC:
05241       ast_cli(fd, "Member not dynamic\n");
05242       return RESULT_FAILURE;
05243    default:
05244       return RESULT_FAILURE;
05245    }
05246 }

static void* handle_statechange ( struct statechange sc  )  [static]

set a member's status based on device state of that member's interface

Definition at line 654 of file app_queue.c.

References ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strdupa, statechange::dev, devstate2str(), member_interface::interface, member_interface::list, LOG_DEBUG, option_debug, statechange::state, and update_status().

Referenced by device_state_thread().

00655 {
00656    struct member_interface *curint;
00657    char *loc;
00658    char *technology;
00659    char interface[80];
00660 
00661    technology = ast_strdupa(sc->dev);
00662    loc = strchr(technology, '/');
00663    if (loc) {
00664       *loc++ = '\0';
00665    } else {
00666       return NULL;
00667    }
00668 
00669    AST_LIST_LOCK(&interfaces);
00670    AST_LIST_TRAVERSE(&interfaces, curint, list) {
00671       char *slash_pos;
00672       ast_copy_string(interface, curint->interface, sizeof(interface));
00673       if ((slash_pos = strchr(interface, '/')))
00674          if ((slash_pos = strchr(slash_pos + 1, '/')))
00675             *slash_pos = '\0';
00676 
00677       if (!strcasecmp(interface, sc->dev))
00678          break;
00679    }
00680    AST_LIST_UNLOCK(&interfaces);
00681 
00682    if (!curint) {
00683       if (option_debug > 2)
00684          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));
00685       return NULL;
00686    }
00687 
00688    if (option_debug)
00689       ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
00690 
00691    update_status(sc->dev, sc->state);
00692 
00693    return NULL;
00694 }

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

Definition at line 1745 of file app_queue.c.

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

01746 {
01747    struct callattempt *oo;
01748 
01749    while (outgoing) {
01750       /* Hangup any existing lines we have open */
01751       if (outgoing->chan && (outgoing->chan != exception))
01752          ast_hangup(outgoing->chan);
01753       oo = outgoing;
01754       outgoing = outgoing->q_next;
01755       if (oo->member)
01756          ao2_ref(oo->member, -1);
01757       free(oo);
01758    }
01759 }

static void init_queue ( struct call_queue q  )  [static]

Definition at line 831 of file app_queue.c.

References call_queue::announce, call_queue::announcefrequency, call_queue::announceholdtime, ao2_container_alloc(), ast_copy_string(), call_queue::autofill, call_queue::context, call_queue::dead, DEFAULT_RETRY, call_queue::eventwhencalled, call_queue::found, call_queue::joinempty, call_queue::leavewhenempty, call_queue::maskmemberstatus, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, member_cmp_fn(), member_hash_fn(), call_queue::membercount, call_queue::memberdelay, call_queue::members, call_queue::moh, call_queue::monfmt, call_queue::monjoin, call_queue::montype, call_queue::periodicannouncefrequency, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::ringlimit, call_queue::roundingseconds, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_periodicannounce, call_queue::sound_reporthold, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, call_queue::timeout, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.

Referenced by find_queue_by_name_rt(), and reload_queues().

00832 {
00833    int i;
00834 
00835    q->dead = 0;
00836    q->retry = DEFAULT_RETRY;
00837    q->timeout = -1;
00838    q->maxlen = 0;
00839    q->ringlimit = 0;
00840    q->announcefrequency = 0;
00841    q->announceholdtime = 0;
00842    q->roundingseconds = 0; /* Default - don't announce seconds */
00843    q->servicelevel = 0;
00844    q->ringinuse = 1;
00845    q->setinterfacevar = 0;
00846    q->autofill = autofill_default;
00847    q->montype = montype_default;
00848    q->moh[0] = '\0';
00849    q->announce[0] = '\0';
00850    q->context[0] = '\0';
00851    q->monfmt[0] = '\0';
00852    q->periodicannouncefrequency = 0;
00853    q->reportholdtime = 0;
00854    q->monjoin = 0;
00855    q->wrapuptime = 0;
00856    q->joinempty = 0;
00857    q->leavewhenempty = 0;
00858    q->memberdelay = 0;
00859    q->maskmemberstatus = 0;
00860    q->eventwhencalled = 0;
00861    q->weight = 0;
00862    q->timeoutrestart = 0;
00863    if (!q->members)
00864       q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
00865    q->membercount = 0;
00866    q->found = 1;
00867    ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
00868    ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
00869    ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
00870    ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
00871    ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
00872    ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
00873    ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
00874    ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
00875    ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
00876    ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
00877    for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
00878       q->sound_periodicannounce[i][0]='\0';
00879    }
00880 }

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

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

Referenced by join_queue().

00525 {
00526    struct queue_ent *cur;
00527 
00528    if (!q || !new)
00529       return;
00530    if (prev) {
00531       cur = prev->next;
00532       prev->next = new;
00533    } else {
00534       cur = q->head;
00535       q->head = new;
00536    }
00537    new->next = cur;
00538    new->parent = q;
00539    new->pos = ++(*pos);
00540    new->opos = *pos;
00541 }

static char* int2strat ( int  strategy  )  [static]

Definition at line 499 of file app_queue.c.

References name, and strategies.

Referenced by __queues_show().

00500 {
00501    int x;
00502 
00503    for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
00504       if (strategy == strategies[x].strategy)
00505          return strategies[x].name;
00506    }
00507 
00508    return "<unknown>";
00509 }

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

Definition at line 3384 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), member::interface, and call_queue::members.

Referenced by add_to_queue(), and set_member_paused().

03385 {
03386    struct member *mem;
03387    struct ao2_iterator mem_iter;
03388 
03389    if (!q)
03390       return NULL;
03391 
03392    mem_iter = ao2_iterator_init(q->members, 0);
03393    while ((mem = ao2_iterator_next(&mem_iter))) {
03394       if (!strcasecmp(interface, mem->interface)) {
03395          ao2_iterator_destroy(&mem_iter);
03396          return mem;
03397       }
03398       ao2_ref(mem, -1);
03399    }
03400    ao2_iterator_destroy(&mem_iter);
03401 
03402    return NULL;
03403 }

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

Definition at line 918 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), member_interface::list, call_queue::lock, call_queue::members, and member::state_interface.

Referenced by remove_from_interfaces().

00919 {
00920    struct call_queue *q;
00921    struct member *mem;
00922    struct ao2_iterator mem_iter;
00923    int ret = 0;
00924 
00925    AST_LIST_LOCK(&queues);
00926    AST_LIST_TRAVERSE(&queues, q, list) {
00927       ast_mutex_lock(&q->lock);
00928       mem_iter = ao2_iterator_init(q->members, 0);
00929       while ((mem = ao2_iterator_next(&mem_iter))) {
00930          if (!strcasecmp(mem->state_interface, interface)) {
00931             ao2_ref(mem, -1);
00932             ret = 1;
00933             break;
00934          }
00935          ao2_ref(mem, -1);
00936       }
00937       ao2_iterator_destroy(&mem_iter);
00938       ast_mutex_unlock(&q->lock);
00939       if (ret)
00940          break;
00941    }
00942    AST_LIST_UNLOCK(&queues);
00943 
00944    return ret;
00945 }

static int is_our_turn ( struct queue_ent qe  )  [static]

Check if we should start attempting to call queue members.

A simple process, really. Count the number of members who are available to take our call and then see if we are in a position in the queue at which a member could accept our call.

Parameters:
[in] qe The caller who wants to know if it is his turn
Return values:
0 It is not our turn
1 It is our turn

Definition at line 2479 of file app_queue.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), queue_ent::chan, call_queue::head, call_queue::lock, LOG_DEBUG, ast_channel::name, queue_ent::next, num_available_members(), option_debug, queue_ent::parent, and queue_ent::pending.

Referenced by queue_exec(), and wait_our_turn().

02480 {
02481    struct queue_ent *ch;
02482    int res;
02483    int avl;
02484    int idx = 0;
02485    /* This needs a lock. How many members are available to be served? */
02486    ast_mutex_lock(&qe->parent->lock);
02487 
02488    avl = num_available_members(qe->parent);
02489 
02490    ch = qe->parent->head;
02491 
02492    if (option_debug) {
02493       ast_log(LOG_DEBUG, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
02494    }
02495 
02496    while ((idx < avl) && (ch) && (ch != qe)) {
02497       if (!ch->pending)
02498          idx++;
02499       ch = ch->next;       
02500    }
02501 
02502    ast_mutex_unlock(&qe->parent->lock);
02503 
02504    /* If the queue entry is within avl [the number of available members] calls from the top ... */
02505    if (ch && idx < avl) {
02506       if (option_debug)
02507          ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
02508       res = 1;
02509    } else {
02510       if (option_debug)
02511          ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
02512       res = 0;
02513    }
02514 
02515    return res;
02516 }

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

Definition at line 1460 of file app_queue.c.

References queue_ent::announce, ast_copy_string(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, queue_ent::context, call_queue::count, EVENT_FLAG_CALL, get_member_status(), call_queue::head, insert_entry(), call_queue::joinempty, load_realtime_queue(), call_queue::lock, LOG_DEBUG, manager_event(), queue_ent::max_penalty, call_queue::maxlen, 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, QUEUE_NO_REACHABLE_MEMBERS, S_OR, and ast_channel::uniqueid.

Referenced by queue_exec().

01461 {
01462    struct call_queue *q;
01463    struct queue_ent *cur, *prev = NULL;
01464    int res = -1;
01465    int pos = 0;
01466    int inserted = 0;
01467    enum queue_member_status stat;
01468 
01469    if (!(q = load_realtime_queue(queuename)))
01470       return res;
01471 
01472    AST_LIST_LOCK(&queues);
01473    ast_mutex_lock(&q->lock);
01474 
01475    /* This is our one */
01476    stat = get_member_status(q, qe->max_penalty);
01477    if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
01478       *reason = QUEUE_JOINEMPTY;
01479    else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS))
01480       *reason = QUEUE_JOINUNAVAIL;
01481    else if (q->maxlen && (q->count >= q->maxlen))
01482       *reason = QUEUE_FULL;
01483    else {
01484       /* There's space for us, put us at the right position inside
01485        * the queue.
01486        * Take into account the priority of the calling user */
01487       inserted = 0;
01488       prev = NULL;
01489       cur = q->head;
01490       while (cur) {
01491          /* We have higher priority than the current user, enter
01492           * before him, after all the other users with priority
01493           * higher or equal to our priority. */
01494          if ((!inserted) && (qe->prio > cur->prio)) {
01495             insert_entry(q, prev, qe, &pos);
01496             inserted = 1;
01497          }
01498          cur->pos = ++pos;
01499          prev = cur;
01500          cur = cur->next;
01501       }
01502       /* No luck, join at the end of the queue */
01503       if (!inserted)
01504          insert_entry(q, prev, qe, &pos);
01505       ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
01506       ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
01507       ast_copy_string(qe->context, q->context, sizeof(qe->context));
01508       q->count++;
01509       res = 0;
01510       manager_event(EVENT_FLAG_CALL, "Join",
01511          "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
01512          qe->chan->name,
01513          S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
01514          S_OR(qe->chan->cid.cid_name, "unknown"),
01515          q->name, qe->pos, q->count, qe->chan->uniqueid );
01516       if (option_debug)
01517          ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
01518    }
01519    ast_mutex_unlock(&q->lock);
01520    AST_LIST_UNLOCK(&queues);
01521 
01522    return res;
01523 }

static void leave_queue ( struct queue_ent qe  )  [static]

Definition at line 1701 of file app_queue.c.

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

Referenced by queue_exec(), and wait_our_turn().

01702 {
01703    struct call_queue *q;
01704    struct queue_ent *cur, *prev = NULL;
01705    int pos = 0;
01706 
01707    if (!(q = qe->parent))
01708       return;
01709    ast_mutex_lock(&q->lock);
01710 
01711    prev = NULL;
01712    for (cur = q->head; cur; cur = cur->next) {
01713       if (cur == qe) {
01714          q->count--;
01715 
01716          /* Take us out of the queue */
01717          manager_event(EVENT_FLAG_CALL, "Leave",
01718             "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
01719             qe->chan->name, q->name,  q->count, qe->chan->uniqueid);
01720          if (option_debug)
01721             ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
01722          /* Take us out of the queue */
01723          if (prev)
01724             prev->next = cur->next;
01725          else
01726             q->head = cur->next;
01727       } else {
01728          /* Renumber the people after us in the queue based on a new count */
01729          cur->pos = ++pos;
01730          prev = cur;
01731       }
01732    }
01733    ast_mutex_unlock(&q->lock);
01734 
01735    if (q->dead && !q->count) {   
01736       /* It's dead and nobody is in it, so kill it */
01737       AST_LIST_LOCK(&queues);
01738       AST_LIST_REMOVE(&queues, q, list);
01739       AST_LIST_UNLOCK(&queues);
01740       destroy_queue(q);
01741    }
01742 }

static int load_module ( void   )  [static]

Definition at line 5502 of file app_queue.c.

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

05503 {
05504    int res;
05505 
05506    if (!reload_queues())
05507       return AST_MODULE_LOAD_DECLINE;
05508 
05509    if (queue_persistent_members)
05510       reload_queue_members();
05511 
05512    ast_mutex_init(&device_state.lock);
05513    ast_cond_init(&device_state.cond, NULL);
05514    ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL);
05515 
05516    ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
05517    res = ast_register_application(app, queue_exec, synopsis, descrip);
05518    res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip);
05519    res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip);
05520    res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip);
05521    res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip);
05522    res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip);
05523    res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues");
05524    res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status");
05525    res |= ast_manager_register("QueueMemberCount", 0, manager_queue_member_count, "Queue Member Count");
05526    res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue.");
05527    res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
05528    res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
05529    res |= ast_custom_function_register(&queueagentcount_function);
05530    res |= ast_custom_function_register(&queuemembercount_function);
05531    res |= ast_custom_function_register(&queuememberlist_function);
05532    res |= ast_custom_function_register(&queuewaitingcount_function);
05533    res |= ast_devstate_add(statechange_queue, NULL);
05534 
05535    return res;
05536 }

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

Definition at line 1410 of file app_queue.c.

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

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

01411 {
01412    struct ast_variable *queue_vars;
01413    struct ast_config *member_config = NULL;
01414    struct call_queue *q;
01415 
01416    /* Find the queue in the in-core list first. */
01417    AST_LIST_LOCK(&queues);
01418    AST_LIST_TRAVERSE(&queues, q, list) {
01419       if (!strcasecmp(q->name, queuename)) {
01420          break;
01421       }
01422    }
01423    AST_LIST_UNLOCK(&queues);
01424 
01425    if (!q || q->realtime) {
01426       /*! \note Load from realtime before taking the global qlock, to avoid blocking all
01427          queue operations while waiting for the DB.
01428 
01429          This will be two separate database transactions, so we might
01430          see queue parameters as they were before another process
01431          changed the queue and member list as it was after the change.
01432          Thus we might see an empty member list when a queue is
01433          deleted. In practise, this is unlikely to cause a problem. */
01434 
01435       queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
01436       if (queue_vars) {
01437          member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
01438          if (!member_config) {
01439             ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
01440             ast_variables_destroy(queue_vars);
01441             return NULL;
01442          }
01443       }
01444 
01445       AST_LIST_LOCK(&queues);
01446 
01447       q = find_queue_by_name_rt(queuename, queue_vars, member_config);
01448       if (member_config)
01449          ast_config_destroy(member_config);
01450       if (queue_vars)
01451          ast_variables_destroy(queue_vars);
01452 
01453       AST_LIST_UNLOCK(&queues);
01454    } else { 
01455       update_realtime_members(q);
01456    }
01457    return q;
01458 }

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

Definition at line 5012 of file app_queue.c.

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

Referenced by load_module().

05013 {
05014    const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
05015    int paused, penalty = 0;
05016 
05017    queuename = astman_get_header(m, "Queue");
05018    interface = astman_get_header(m, "Interface");
05019    penalty_s = astman_get_header(m, "Penalty");
05020    paused_s = astman_get_header(m, "Paused");
05021    membername = astman_get_header(m, "MemberName");
05022    state_interface = astman_get_header(m, "StateInterface");
05023 
05024    if (ast_strlen_zero(queuename)) {
05025       astman_send_error(s, m, "'Queue' not specified.");
05026       return 0;
05027    }
05028 
05029    if (ast_strlen_zero(interface)) {
05030       astman_send_error(s, m, "'Interface' not specified.");
05031       return 0;
05032    }
05033 
05034    if (ast_strlen_zero(penalty_s))
05035       penalty = 0;
05036    else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0)
05037       penalty = 0;
05038 
05039    if (ast_strlen_zero(paused_s))
05040       paused = 0;
05041    else
05042       paused = abs(ast_true(paused_s));
05043 
05044    switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
05045    case RES_OKAY:
05046       ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
05047       astman_send_ack(s, m, "Added interface to queue");
05048       break;
05049    case RES_EXISTS:
05050       astman_send_error(s, m, "Unable to add interface: Already there");
05051       break;
05052    case RES_NOSUCHQUEUE:
05053       astman_send_error(s, m, "Unable to add interface to queue: No such queue");
05054       break;
05055    case RES_OUTOFMEMORY:
05056       astman_send_error(s, m, "Out of memory");
05057       break;
05058    }
05059 
05060    return 0;
05061 }

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

Definition at line 5097 of file app_queue.c.

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

Referenced by load_module().

05098 {
05099    const char *queuename, *interface, *paused_s;
05100    int paused;
05101 
05102    interface = astman_get_header(m, "Interface");
05103    paused_s = astman_get_header(m, "Paused");
05104    queuename = astman_get_header(m, "Queue");   /* Optional - if not supplied, pause the given Interface in all queues */
05105 
05106    if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
05107       astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
05108       return 0;
05109    }
05110 
05111    paused = abs(ast_true(paused_s));
05112 
05113    if (set_member_paused(queuename, interface, paused))
05114       astman_send_error(s, m, "Interface not found");
05115    else
05116       astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
05117    return 0;
05118 }

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

Definition at line 5357 of file app_queue.c.

References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), qmc_handler(), RESULT_SUCCESS, and s.

Referenced by load_module().

05358 {
05359    char buffer[256] = "";
05360    const char *queuename = astman_get_header(m,"Queue");
05361 
05362    if (ast_strlen_zero(queuename)) {
05363          astman_send_error(s, m, "'Queue' not specified.");
05364          return 0;
05365    }
05366    if (qmc_handler(queuename, buffer, sizeof(buffer)) == RESULT_SUCCESS) {
05367          astman_send_ack(s, m, buffer);
05368          return RESULT_SUCCESS;
05369    } else {
05370          astman_send_error(s, m, "Queue not found.");
05371          return 0;
05372    }
05373 }

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

Definition at line 4906 of file app_queue.c.

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

Referenced by load_module().

04907 {
04908    char *a[] = { "queue", "show" };
04909 
04910    __queues_show(s, 1, -1, 2, a);
04911    astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
04912 
04913    return RESULT_SUCCESS;
04914 }

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

Definition at line 4917 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), member::calls, call_queue::callsabandoned, call_queue::callscompleted, call_queue::callscompletedinsl, queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, call_queue::count, member::dynamic, call_queue::head, call_queue::holdtime, member::interface, member::lastcall, call_queue::lock, call_queue::maxlen, member::membername, call_queue::members, ast_channel::name, call_queue::name, queue_ent::next, member::paused, member::penalty, RESULT_SUCCESS, call_queue::ringlimit, s, S_OR, call_queue::servicelevel, queue_ent::start, member::status, and call_queue::weight.

Referenced by load_module().

04918 {
04919    time_t now;
04920    int pos;
04921    const char *id = astman_get_header(m,"ActionID");
04922    const char *queuefilter = astman_get_header(m,"Queue");
04923    const char *memberfilter = astman_get_header(m,"Member");
04924    char idText[256] = "";
04925    struct call_queue *q;
04926    struct queue_ent *qe;
04927    float sl = 0;
04928    struct member *mem;
04929    struct ao2_iterator mem_iter;
04930 
04931    astman_send_ack(s, m, "Queue status will follow");
04932    time(&now);
04933    AST_LIST_LOCK(&queues);
04934    if (!ast_strlen_zero(id))
04935       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
04936 
04937    AST_LIST_TRAVERSE(&queues, q, list) {
04938       ast_mutex_lock(&q->lock);
04939 
04940       /* List queue properties */
04941       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
04942          sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
04943          astman_append(s, "Event: QueueParams\r\n"
04944             "Queue: %s\r\n"
04945             "Max: %d\r\n"
04946             "Calls: %d\r\n"
04947             "Holdtime: %d\r\n"
04948             "Completed: %d\r\n"
04949             "Abandoned: %d\r\n"
04950             "ServiceLevel: %d\r\n"
04951             "ServicelevelPerf: %2.1f\r\n"
04952             "RingLimit: %d\r\n"
04953             "Weight: %d\r\n"
04954             "%s"
04955             "\r\n",
04956             q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
04957             q->callsabandoned, q->servicelevel, sl,  q->ringlimit, q->weight, idText);
04958          /* List Queue Members */
04959          mem_iter = ao2_iterator_init(q->members, 0);
04960          while ((mem = ao2_iterator_next(&mem_iter))) {
04961             if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
04962                astman_append(s, "Event: QueueMember\r\n"
04963                   "Queue: %s\r\n"
04964                   "Name: %s\r\n"
04965                   "Location: %s\r\n"
04966                   "Membership: %s\r\n"
04967                   "Penalty: %d\r\n"
04968                   "CallsTaken: %d\r\n"
04969                   "LastCall: %d\r\n"
04970                   "Status: %d\r\n"
04971                   "Paused: %d\r\n"
04972                   "%s"
04973                   "\r\n",
04974                   q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
04975                   mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
04976             }
04977             ao2_ref(mem, -1);
04978          }
04979          ao2_iterator_destroy(&mem_iter);
04980          /* List Queue Entries */
04981          pos = 1;
04982          for (qe = q->head; qe; qe = qe->next) {
04983             astman_append(s, "Event: QueueEntry\r\n"
04984                "Queue: %s\r\n"
04985                "Position: %d\r\n"
04986                "Channel: %s\r\n"
04987                "CallerID: %s\r\n"
04988                "CallerIDName: %s\r\n"
04989                "Wait: %ld\r\n"
04990                "%s"
04991                "\r\n",
04992                q->name, pos++, qe->chan->name,
04993                S_OR(qe->chan->cid.cid_num, "unknown"),
04994                S_OR(qe->chan->cid.cid_name, "unknown"),
04995                (long) (now - qe->start), idText);
04996          }
04997       }
04998       ast_mutex_unlock(&q->lock);
04999    }
05000 
05001    astman_append(s,
05002       "Event: QueueStatusComplete\r\n"
05003       "%s"
05004       "\r\n",idText);
05005 
05006    AST_LIST_UNLOCK(&queues);
05007 
05008 
05009    return RESULT_SUCCESS;
05010 }

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

Definition at line 5063 of file app_queue.c.

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

Referenced by load_module().

05064 {
05065    const char *queuename, *interface;
05066 
05067    queuename = astman_get_header(m, "Queue");
05068    interface = astman_get_header(m, "Interface");
05069 
05070    if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
05071       astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
05072       return 0;
05073    }
05074 
05075    switch (remove_from_queue(queuename, interface)) {
05076    case RES_OKAY:
05077       ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
05078       astman_send_ack(s, m, "Removed interface from queue");
05079       break;
05080    case RES_EXISTS:
05081       astman_send_error(s, m, "Unable to remove interface: Not there");
05082       break;
05083    case RES_NOSUCHQUEUE:
05084       astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
05085       break;
05086    case RES_OUTOFMEMORY:
05087       astman_send_error(s, m, "Out of memory");
05088       break;
05089    case RES_NOT_DYNAMIC:
05090       astman_send_error(s, m, "Member not dynamic");
05091       break;
05092    }
05093 
05094    return 0;
05095 }

static int member_cmp_fn ( void *  obj1,
void *  obj2,
int  flags 
) [static]

Definition at line 825 of file app_queue.c.

References member::interface.

Referenced by init_queue().

00826 {
00827    struct member *mem1 = obj1, *mem2 = obj2;
00828    return strcmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
00829 }

static int member_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 813 of file app_queue.c.

References compress_char(), and member::interface.

Referenced by init_queue().

00814 {
00815    const struct member *mem = obj;
00816    const char *chname = strchr(mem->interface, '/');
00817    int ret = 0, i;
00818    if (!chname)
00819       chname = mem->interface;
00820    for (i = 0; i < 5 && chname[i]; i++)
00821       ret += compress_char(chname[i]) << (i * 6);
00822    return ret;
00823 }

static void monjoin_dep_warning ( void   )  [static]

Definition at line 478 of file app_queue.c.

References ast_log(), and LOG_NOTICE.

Referenced by queue_set_param().

00479 {
00480    static unsigned int warned = 0;
00481    if (!warned) {
00482       ast_log(LOG_NOTICE, "The 'monitor-join' queue option is deprecated. Please use monitor-type=mixmonitor instead.\n");
00483       warned = 1;
00484    }
00485 }

static int num_available_members ( struct call_queue q  )  [static]

Get the number of members available to accept a call.

Note:
The queue passed in should be locked prior to this function call
Parameters:
[in] q The queue for which we are couting the number of available members
Returns:
Return the number of available members in queue q

Definition at line 1769 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNKNOWN, call_queue::autofill, call_queue::members, member::paused, QUEUE_STRATEGY_RINGALL, call_queue::ringinuse, member::status, and call_queue::strategy.

Referenced by compare_weight(), and is_our_turn().

01770 {
01771    struct member *mem;
01772    int avl = 0;
01773    struct ao2_iterator mem_iter;
01774 
01775    mem_iter = ao2_iterator_init(q->members, 0);
01776    while ((mem = ao2_iterator_next(&mem_iter))) {
01777       switch (mem->status) {
01778       case AST_DEVICE_INUSE:
01779          if (!q->ringinuse)
01780             break;
01781          /* else fall through */
01782       case AST_DEVICE_NOT_INUSE:
01783       case AST_DEVICE_UNKNOWN:
01784          if (!mem->paused) {
01785             avl++;
01786          }
01787          break;
01788       }
01789       ao2_ref(mem, -1);
01790 
01791       /* If autofill is not enabled or if the queue's strategy is ringall, then
01792        * we really don't care about the number of available members so much as we
01793        * do that there is at least one available.
01794        *
01795        * In fact, we purposely will return from this function stating that only
01796        * one member is available if either of those conditions hold. That way,
01797        * functions which determine what action to take based on the number of available
01798        * members will operate properly. The reasoning is that even if multiple
01799        * members are available, only the head caller can actually be serviced.
01800        */
01801       if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
01802          break;
01803       }
01804    }
01805    ao2_iterator_destroy(&mem_iter);
01806 
01807    return avl;
01808 }

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

Definition at line 1525 of file app_queue.c.

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

Referenced by say_periodic_announcement(), and say_position().

01526 {
01527    int res;
01528 
01529    if (ast_strlen_zero(filename)) {
01530       return 0;
01531    }
01532 
01533    ast_stopstream(chan);
01534 
01535    res = ast_streamfile(chan, filename, chan->language);
01536    if (!res)
01537       res = ast_waitstream(chan, AST_DIGIT_ANY);
01538 
01539    ast_stopstream(chan);
01540 
01541    return res;
01542 }

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

Definition at line 3701 of file app_queue.c.

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

Referenced by load_module().

03702 {
03703    struct ast_module_user *lu;
03704    char *parse;
03705    int priority_jump = 0;
03706    int ignore_fail = 0;
03707    AST_DECLARE_APP_ARGS(args,
03708       AST_APP_ARG(queuename);
03709       AST_APP_ARG(interface);
03710       AST_APP_ARG(options);
03711    );
03712 
03713    if (ast_strlen_zero(data)) {
03714       ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
03715       return -1;
03716    }
03717 
03718    parse = ast_strdupa(data);
03719 
03720    AST_STANDARD_APP_ARGS(args, parse);
03721 
03722    lu = ast_module_user_add(chan);
03723 
03724    if (args.options) {
03725       if (strchr(args.options, 'j'))
03726          priority_jump = 1;
03727       if (strchr(args.options, 'i'))
03728          ignore_fail = 1;
03729    }
03730 
03731    if (ast_strlen_zero(args.interface)) {
03732       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
03733       ast_module_user_remove(lu);
03734       return -1;
03735    }
03736 
03737    if (set_member_paused(args.queuename, args.interface, 1)) {
03738       ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
03739       pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
03740       if (priority_jump || ast_opt_priority_jumping) {
03741          if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
03742             ast_module_user_remove(lu);
03743             return 0;
03744          }
03745       }
03746       ast_module_user_remove(lu);
03747       if (ignore_fail) {
03748          return 0;
03749       } else {
03750          return -1;
03751       }
03752    }
03753 
03754    ast_module_user_remove(lu);
03755    pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
03756    return 0;
03757 }

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

Definition at line 3959 of file app_queue.c.

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

Referenced by load_module().

03960 {
03961    struct ast_module_user *u;
03962    char *parse;
03963 
03964    AST_DECLARE_APP_ARGS(args,
03965       AST_APP_ARG(queuename);
03966       AST_APP_ARG(uniqueid);
03967       AST_APP_ARG(membername);
03968       AST_APP_ARG(event);
03969       AST_APP_ARG(params);
03970    );
03971 
03972    if (ast_strlen_zero(data)) {
03973       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n");
03974       return -1;
03975    }
03976 
03977    u = ast_module_user_add(chan);
03978 
03979    parse = ast_strdupa(data);
03980 
03981    AST_STANDARD_APP_ARGS(args, parse);
03982 
03983    if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
03984        || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
03985       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n");
03986       ast_module_user_remove(u);
03987       return -1;
03988    }
03989 
03990    ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 
03991       "%s", args.params ? args.params : "");
03992 
03993    ast_module_user_remove(u);
03994 
03995    return 0;
03996 }

static int qmc_handler ( const char *  queuename,
char *  buffer,
int  len 
) [static]

Definition at line 5342 of file app_queue.c.

References queue_member_count(), RESULT_FAILURE, and RESULT_SUCCESS.

Referenced by cli_queue_member_count(), and manager_queue_member_count().

05343 {
05344       struct member_count qmc;
05345       memset(&qmc, 0, sizeof(qmc));
05346       if (queue_member_count(queuename, &qmc) != 0) {
05347             return RESULT_FAILURE; 
05348       } else {
05349             snprintf(buffer, len, 
05350                          "valid:%d inuse:%d paused:%d active:%d free:%d all:%d",
05351                          qmc.valid, qmc.inuse, qmc.paused, qmc.active, qmc.free, qmc.all);   
05352             return RESULT_SUCCESS;
05353       }
05354 }

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

The starting point for all queue calls.

The process involved here is to 1. Parse the options specified in the call to Queue() 2. Join the queue 3. Wait in a loop until it is our turn to try calling a queue member 4. Attempt to call a queue member 5. If 4. did not result in a bridged call, then check for between call options such as periodic announcements etc. 6. Try 4 again uless some condition (such as an expiration time) causes us to exit the queue.

Definition at line 4010 of file app_queue.c.

References AST_APP_ARG, ast_cdr_noanswer(), AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_indicate(), ast_log(), ast_module_user_add, ast_moh_start(), ast_moh_stop(), ast_queue_log(), AST_STANDARD_APP_ARGS, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verbose(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, get_member_status(), is_our_turn(), join_queue(), leave_queue(), LOG_DEBUG, LOG_WARNING, ast_channel::name, option_verbose, parse(), pbx_builtin_getvar_helper(), QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), S_OR, say_periodic_announcement(), say_position(), set_queue_result(), stop, try_calling(), ast_channel::uniqueid, update_realtime_members(), VERBOSE_PREFIX_3, wait_a_bit(), and wait_our_turn().

Referenced by load_module().

04011 {
04012    int res=-1;
04013    int ringing=0;
04014    struct ast_module_user *lu;
04015    const char *user_priority;
04016    const char *max_penalty_str;
04017    int prio;
04018    int max_penalty;
04019    enum queue_result reason = QUEUE_UNKNOWN;
04020    /* whether to exit Queue application after the timeout hits */
04021    int tries = 0;
04022    int noption = 0;
04023    char *parse;
04024    AST_DECLARE_APP_ARGS(args,
04025       AST_APP_ARG(queuename);
04026       AST_APP_ARG(options);
04027       AST_APP_ARG(url);
04028       AST_APP_ARG(announceoverride);
04029       AST_APP_ARG(queuetimeoutstr);
04030       AST_APP_ARG(agi);
04031    );
04032    /* Our queue entry */
04033    struct queue_ent qe;
04034    
04035    if (ast_strlen_zero(data)) {
04036       ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n");
04037       return -1;
04038    }
04039    
04040    parse = ast_strdupa(data);
04041    AST_STANDARD_APP_ARGS(args, parse);
04042 
04043    lu = ast_module_user_add(chan);
04044 
04045    /* Setup our queue entry */
04046    memset(&qe, 0, sizeof(qe));
04047    qe.start = time(NULL);
04048 
04049    /* set the expire time based on the supplied timeout; */
04050    if (!ast_strlen_zero(args.queuetimeoutstr))
04051       qe.expire = qe.start + atoi(args.queuetimeoutstr);
04052    else
04053       qe.expire = 0;
04054 
04055    /* Get the priority from the variable ${QUEUE_PRIO} */
04056    user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
04057    if (user_priority) {
04058       if (sscanf(user_priority, "%30d", &prio) == 1) {
04059          if (option_debug)
04060             ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
04061                chan->name, prio);
04062       } else {
04063          ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
04064             user_priority, chan->name);
04065          prio = 0;
04066       }
04067    } else {
04068       if (option_debug > 2)
04069          ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
04070       prio = 0;
04071    }
04072 
04073    /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
04074    if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
04075       if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
04076          if (option_debug)
04077             ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
04078                chan->name, max_penalty);
04079       } else {
04080          ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
04081             max_penalty_str, chan->name);
04082          max_penalty = 0;
04083       }
04084    } else {
04085       max_penalty = 0;
04086    }
04087 
04088    if (args.options && (strchr(args.options, 'r')))
04089       ringing = 1;
04090 
04091    if (option_debug)
04092       ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
04093          args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
04094 
04095    qe.chan = chan;
04096    qe.prio = prio;
04097    qe.max_penalty = max_penalty;
04098    qe.last_pos_said = 0;
04099    qe.last_pos = 0;
04100    qe.last_periodic_announce_time = time(NULL);
04101    qe.last_periodic_announce_sound = 0;
04102    qe.valid_digits = 0;
04103    if (!join_queue(args.queuename, &qe, &reason)) {
04104       int makeannouncement = 0;
04105 
04106       ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
04107          S_OR(chan->cid.cid_num, ""));
04108 check_turns:
04109       if (ringing) {
04110          ast_indicate(chan, AST_CONTROL_RINGING);
04111       } else {
04112          ast_moh_start(chan, qe.moh, NULL);
04113       }
04114 
04115       /* This is the wait loop for callers 2 through maxlen */
04116       res = wait_our_turn(&qe, ringing, &reason);
04117       if (res)
04118          goto stop;
04119 
04120       for (;;) {
04121          /* This is the wait loop for the head caller*/
04122          /* To exit, they may get their call answered; */
04123          /* they may dial a digit from the queue context; */
04124          /* or, they may timeout. */
04125 
04126          enum queue_member_status stat;
04127 
04128          /* Leave if we have exceeded our queuetimeout */
04129          if (qe.expire && (time(NULL) >= qe.expire)) {
04130             record_abandoned(&qe);
04131             ast_cdr_noanswer(qe.chan->cdr);
04132             reason = QUEUE_TIMEOUT;
04133             res = 0;
04134             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04135             break;
04136          }
04137 
04138          if (makeannouncement) {
04139             /* Make a position announcement, if enabled */
04140             if (qe.parent->announcefrequency && !ringing)
04141                if ((res = say_position(&qe)))
04142                   goto stop;
04143 
04144          }
04145          makeannouncement = 1;
04146 
04147          /* Leave if we have exceeded our queuetimeout */
04148          if (qe.expire && (time(NULL) >= qe.expire)) {
04149             record_abandoned(&qe);
04150             ast_cdr_noanswer(qe.chan->cdr);
04151             reason = QUEUE_TIMEOUT;
04152             res = 0;
04153             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04154             break;
04155          }
04156          /* Make a periodic announcement, if enabled */
04157          if (qe.parent->periodicannouncefrequency && !ringing)
04158             if ((res = say_periodic_announcement(&qe)))
04159                goto stop;
04160 
04161          /* Leave if we have exceeded our queuetimeout */
04162          if (qe.expire && (time(NULL) >= qe.expire)) {
04163             record_abandoned(&qe);
04164             ast_cdr_noanswer(qe.chan->cdr);
04165             reason = QUEUE_TIMEOUT;
04166             res = 0;
04167             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04168             break;
04169          }
04170          /* Try calling all queue members for 'timeout' seconds */
04171          res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi);
04172          if (res)
04173             goto stop;
04174 
04175          stat = get_member_status(qe.parent, qe.max_penalty);
04176 
04177          /* exit after 'timeout' cycle if 'n' option enabled */
04178          if (noption && tries >= qe.parent->membercount) {
04179             if (option_verbose > 2)
04180                ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
04181             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04182             record_abandoned(&qe);
04183             ast_cdr_noanswer(qe.chan->cdr);
04184             reason = QUEUE_TIMEOUT;
04185             res = 0;
04186             break;
04187          }
04188 
04189          /* leave the queue if no agents, if enabled */
04190          if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
04191             record_abandoned(&qe);
04192             ast_cdr_noanswer(qe.chan->cdr);
04193             reason = QUEUE_LEAVEEMPTY;
04194             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
04195             res = 0;
04196             break;
04197          }
04198 
04199          /* leave the queue if no reachable agents, if enabled */
04200          if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
04201             record_abandoned(&qe);
04202             ast_cdr_noanswer(qe.chan->cdr);
04203             reason = QUEUE_LEAVEUNAVAIL;
04204             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
04205             res = 0;
04206             break;
04207          }
04208 
04209          /* Leave if we have exceeded our queuetimeout */
04210          if (qe.expire && (time(NULL) >= qe.expire)) {
04211             record_abandoned(&qe);
04212             ast_cdr_noanswer(qe.chan->cdr);
04213             reason = QUEUE_TIMEOUT;
04214             res = 0;
04215             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04216             break;
04217          }
04218 
04219          /* If using dynamic realtime members, we should regenerate the member list for this queue */
04220          update_realtime_members(qe.parent);
04221 
04222          /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
04223          res = wait_a_bit(&qe);
04224          if (res)
04225             goto stop;
04226 
04227          /* Since this is a priority queue and
04228           * it is not sure that we are still at the head
04229           * of the queue, go and check for our turn again.
04230           */
04231          if (!is_our_turn(&qe)) {
04232             if (option_debug)
04233                ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
04234                   qe.chan->name);
04235             goto check_turns;
04236          }
04237       }
04238 
04239 stop:
04240       if (res) {
04241          if (res < 0) {
04242             if (!qe.handled) {
04243                record_abandoned(&qe);
04244                ast_cdr_noanswer(qe.chan->cdr);
04245                ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
04246                   "%d|%d|%ld", qe.pos, qe.opos,
04247                   (long) time(NULL) - qe.start);
04248             }
04249             res = -1;
04250          } else if (qe.valid_digits) {
04251             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
04252                "%s|%d", qe.digits, qe.pos);
04253          }
04254       }
04255 
04256       /* Don't allow return code > 0 */
04257       if (res >= 0) {
04258          res = 0; 
04259          if (ringing) {
04260             ast_indicate(chan, -1);
04261          } else {
04262             ast_moh_stop(chan);
04263          }        
04264          ast_stopstream(chan);
04265       }
04266       leave_queue(&qe);
04267       if (reason != QUEUE_UNKNOWN)
04268          set_queue_result(chan, reason);
04269    } else {
04270       ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
04271       set_queue_result(chan, reason);
04272       res = 0;
04273    }
04274    ast_module_user_remove(lu);
04275 
04276    return res;
04277 }

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

Definition at line 4287 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), load_realtime_queue(), call_queue::lock, LOG_ERROR, LOG_WARNING, call_queue::members, name, member::paused, QMC_ACTIVE, QMC_FREE, QMC_PAUSED, QMC_VALID, and member::status.

04288 {
04289    int count = 0;
04290    struct call_queue *q;
04291    struct ast_module_user *lu;
04292    struct member *m;
04293    struct ao2_iterator mem_iter;
04294    char *name, *item;
04295    enum qmc_status mode = QMC_VALID;
04296 
04297    buf[0] = '\0';
04298    
04299    if (ast_strlen_zero(data)) {
04300       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
04301       return -1;
04302    }
04303 
04304    name = ast_strdupa(data);
04305 
04306    lu = ast_module_user_add(chan);
04307 
04308    if ((item = strchr(name, ':'))) {
04309       *item = '\0';
04310       item++;
04311    } else {
04312       item = "";
04313    }
04314 
04315    if (!strcasecmp(item, "valid")) {
04316       mode = QMC_VALID;
04317    } else  if (!strcasecmp(item, "paused")) {
04318       mode = QMC_PAUSED;
04319    } else  if (!strcasecmp(item, "active")) {
04320       mode = QMC_ACTIVE;
04321    } else  if (!strcasecmp(item, "free")) {
04322       mode = QMC_FREE;
04323    } else  if (!strcasecmp(item, "all")) {
04324       mode = QMC_ALL;
04325    }
04326 
04327    if ((q = load_realtime_queue(name))) {
04328       ast_mutex_lock(&q->lock);
04329       mem_iter = ao2_iterator_init(q->members, 0);
04330       while ((m = ao2_iterator_next(&mem_iter))) {
04331          switch (mode) {
04332          case QMC_VALID:
04333             /* Count the queue members who are logged in and presently answering calls */
04334             if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
04335                count++;
04336             }
04337             break;
04338          case QMC_PAUSED:
04339             /* Count paused members */
04340             if (m->paused) {
04341                count++;
04342             }
04343             break;
04344          case QMC_ACTIVE:
04345             /* Count not paused members who are logged in and presently answering calls */
04346             if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
04347                count++;
04348             }
04349             break;
04350          case QMC_FREE:
04351             /* Count free members in the queue */
04352             if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) {
04353                count++;
04354             }
04355             break;
04356          default:
04357             count++;
04358             break;
04359          }
04360          ao2_ref(m, -1);
04361       }
04362       ao2_iterator_destroy(&mem_iter);
04363       ast_mutex_unlock(&q->lock);
04364    } else
04365       ast_log(LOG_WARNING, "queue %s was not found\n", name);
04366 
04367    snprintf(buf, len, "%d", count);
04368    ast_module_user_remove(lu);
04369 
04370    return 0;
04371 }

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

Definition at line 4416 of file app_queue.c.

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

04417 {
04418    struct ast_module_user *u;
04419    struct call_queue *q;
04420    struct member *m;
04421 
04422    /* Ensure an otherwise empty list doesn't return garbage */
04423    buf[0] = '\0';
04424 
04425    if (ast_strlen_zero(data)) {
04426       ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
04427       return -1;
04428    }
04429    
04430    u = ast_module_user_add(chan);
04431 
04432    AST_LIST_LOCK(&queues);
04433    AST_LIST_TRAVERSE(&queues, q, list) {
04434       if (!strcasecmp(q->name, data)) {
04435          ast_mutex_lock(&q->lock);
04436          break;
04437       }
04438    }
04439    AST_LIST_UNLOCK(&queues);
04440 
04441    if (q) {
04442       int buflen = 0, count = 0;
04443       struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
04444 
04445       while ((m = ao2_iterator_next(&mem_iter))) {
04446          /* strcat() is always faster than printf() */
04447          if (count++) {
04448             strncat(buf + buflen, ",", len - buflen - 1);
04449             buflen++;
04450          }
04451          strncat(buf + buflen, m->interface, len - buflen - 1);
04452          buflen += strlen(m->interface);
04453          /* Safeguard against overflow (negative length) */
04454          if (buflen >= len - 2) {
04455             ao2_ref(m, -1);
04456             ast_log(LOG_WARNING, "Truncating list\n");
04457             break;
04458          }
04459          ao2_ref(m, -1);
04460       }
04461       ao2_iterator_destroy(&mem_iter);
04462       ast_mutex_unlock(&q->lock);
04463    } else
04464       ast_log(LOG_WARNING, "queue %s was not found\n", data);
04465 
04466    /* We should already be terminated, but let's make sure. */
04467    buf[len - 1] = '\0';
04468    ast_module_user_remove(u);
04469 
04470    return 0;
04471 }

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

Definition at line 4373 of file app_queue.c.

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

04374 {
04375    int count = 0;
04376    struct call_queue *q;
04377    struct ast_module_user *lu;
04378    struct ast_variable *var = NULL;
04379 
04380    buf[0] = '\0';
04381    
04382    if (ast_strlen_zero(data)) {
04383       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
04384       return -1;
04385    }
04386 
04387    lu = ast_module_user_add(chan);
04388    
04389    AST_LIST_LOCK(&queues);
04390    AST_LIST_TRAVERSE(&queues, q, list) {
04391       if (!strcasecmp(q->name, data)) {
04392          ast_mutex_lock(&q->lock);
04393          break;
04394       }
04395    }
04396    AST_LIST_UNLOCK(&queues);
04397 
04398    if (q) {
04399       count = q->count;
04400       ast_mutex_unlock(&q->lock);
04401    } else if ((var = ast_load_realtime("queues", "name", data, NULL))) {
04402       /* if the queue is realtime but was not found in memory, this
04403        * means that the queue had been deleted from memory since it was 
04404        * "dead." This means it has a 0 waiting count
04405        */
04406       count = 0;
04407       ast_variables_destroy(var);
04408    } else
04409       ast_log(LOG_WARNING, "queue %s was not found\n", data);
04410 
04411    snprintf(buf, len, "%d", count);
04412    ast_module_user_remove(lu);
04413    return 0;
04414 }

static int queue_member_count ( const char *  qname,
struct member_count qmc 
) [static]

Definition at line 5300 of file app_queue.c.

References member_count::active, member_count::all, ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), member_count::free, member_count::inuse, load_realtime_queue(), call_queue::lock, LOG_WARNING, call_queue::members, member_count::paused, member::paused, member::status, and member_count::valid.

Referenced by qmc_handler().

05301 {
05302       int res = 0;
05303       struct call_queue *q;
05304       struct member *m;
05305       struct ao2_iterator mem_iter;
05306       
05307       if ((q = load_realtime_queue(qname))) {
05308             ast_mutex_lock(&q->lock);
05309             mem_iter = ao2_iterator_init(q->members, 0);
05310             while ((m = ao2_iterator_next(&mem_iter))) {
05311                   /* Count the queue members in use */
05312                   if (m->status == AST_DEVICE_INUSE) {
05313                         qmc->inuse++;
05314                   }
05315                   /* Count the queue members who are logged in and presently answering calls */
05316                   if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
05317                         qmc->valid++;
05318                   }
05319                   /* Count paused members */
05320                   if (m->paused) {
05321                         qmc->paused++;
05322                   }
05323                   /* Count not paused members who are logged in and presently answering calls */
05324                   if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
05325                         qmc->active++;
05326                   }
05327                   /* Count free members in the queue */
05328                   if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) {
05329                         qmc->free++;
05330                   }
05331                   qmc->all++;
05332                   ao2_ref(m, -1);
05333             }
05334             ast_mutex_unlock(&q->lock);
05335       } else {
05336             ast_log(LOG_WARNING, "Queue %s was not found\n", qname);
05337             res = -1;
05338       }
05339       return res;
05340 }

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

References call_queue::announce, call_queue::announcefrequency, call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, ast_copy_string(), ast_log(), ast_strdupa, ast_true(), call_queue::autofill, call_queue::autopause, call_queue::context, DEFAULT_RETRY, DEFAULT_TIMEOUT, call_queue::eventwhencalled, call_queue::joinempty, call_queue::leavewhenempty, LOG_WARNING, call_queue::maskmemberstatus, MAX_PERIODIC_ANNOUNCEMENTS, call_queue::maxlen, call_queue::memberdelay, call_queue::moh, call_queue::monfmt, call_queue::monjoin, monjoin_dep_warning(), call_queue::montype, call_queue::name, call_queue::periodicannouncefrequency, QUEUE_EMPTY_NORMAL, QUEUE_EMPTY_STRICT, QUEUE_EVENT_VARIABLES, QUEUE_STRATEGY_RINGALL, call_queue::reportholdtime, call_queue::retry, call_queue::ringinuse, call_queue::ringlimit, call_queue::roundingseconds, s, call_queue::servicelevel, call_queue::setinterfacevar, call_queue::sound_calls, call_queue::sound_holdtime, call_queue::sound_lessthan, call_queue::sound_minutes, call_queue::sound_next, call_queue::sound_periodicannounce, call_queue::sound_reporthold, call_queue::sound_seconds, call_queue::sound_thanks, call_queue::sound_thereare, strat2int(), call_queue::strategy, call_queue::timeout, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.

Referenced by find_queue_by_name_rt(), and reload_queues().

00988 {
00989    if (!strcasecmp(param, "musicclass") || 
00990       !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
00991       ast_copy_string(q->moh, val, sizeof(q->moh));
00992    } else if (!strcasecmp(param, "announce")) {
00993       ast_copy_string(q->announce, val, sizeof(q->announce));
00994    } else if (!strcasecmp(param, "context")) {
00995       ast_copy_string(q->context, val, sizeof(q->context));
00996    } else if (!strcasecmp(param, "timeout")) {
00997       q->timeout = atoi(val);
00998       if (q->timeout < 0)
00999          q->timeout = DEFAULT_TIMEOUT;
01000    } else if (!strcasecmp(param, "ringinuse")) {
01001       q->ringinuse = ast_true(val);
01002    } else if (!strcasecmp(param, "setinterfacevar")) {
01003       q->setinterfacevar = ast_true(val);
01004    } else if (!strcasecmp(param, "monitor-join")) {
01005       monjoin_dep_warning();
01006       q->monjoin = ast_true(val);
01007    } else if (!strcasecmp(param, "monitor-format")) {
01008       ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
01009    } else if (!strcasecmp(param, "queue-youarenext")) {
01010       ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
01011    } else if (!strcasecmp(param, "queue-thereare")) {
01012       ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
01013    } else if (!strcasecmp(param, "queue-callswaiting")) {
01014       ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
01015    } else if (!strcasecmp(param, "queue-holdtime")) {
01016       ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
01017    } else if (!strcasecmp(param, "queue-minutes")) {
01018       ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
01019    } else if (!strcasecmp(param, "queue-seconds")) {
01020       ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
01021    } else if (!strcasecmp(param, "queue-lessthan")) {
01022       ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
01023    } else if (!strcasecmp(param, "queue-thankyou")) {
01024       ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
01025    } else if (!strcasecmp(param, "queue-reporthold")) {
01026       ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
01027    } else if (!strcasecmp(param, "announce-frequency")) {
01028       q->announcefrequency = atoi(val);
01029    } else if (!strcasecmp(param, "announce-round-seconds")) {
01030       q->roundingseconds = atoi(val);
01031       if (q->roundingseconds>60 || q->roundingseconds<0) {
01032          if (linenum >= 0) {
01033             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01034                "using 0 instead for queue '%s' at line %d of queues.conf\n",
01035                val, param, q->name, linenum);
01036          } else {
01037             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01038                "using 0 instead for queue '%s'\n", val, param, q->name);
01039          }
01040          q->roundingseconds=0;
01041       }
01042    } else if (!strcasecmp(param, "announce-holdtime")) {
01043       if (!strcasecmp(val, "once"))
01044          q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
01045       else if (ast_true(val))
01046          q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
01047       else
01048          q->announceholdtime = 0;
01049    } else if (!strcasecmp(param, "periodic-announce")) {
01050       if (strchr(val, '|')) {
01051          char *s, *buf = ast_strdupa(val);
01052          unsigned int i = 0;
01053 
01054          while ((s = strsep(&buf, "|"))) {
01055             ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i]));
01056             i++;
01057             if (i == MAX_PERIODIC_ANNOUNCEMENTS)
01058                break;
01059          }
01060       } else {
01061          ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0]));
01062       }
01063    } else if (!strcasecmp(param, "periodic-announce-frequency")) {
01064       q->periodicannouncefrequency = atoi(val);
01065    } else if (!strcasecmp(param, "retry")) {
01066       q->retry = atoi(val);
01067       if (q->retry <= 0)
01068          q->retry = DEFAULT_RETRY;
01069    } else if (!strcasecmp(param, "wrapuptime")) {
01070       q->wrapuptime = atoi(val);
01071    } else if (!strcasecmp(param, "autofill")) {
01072       q->autofill = ast_true(val);
01073    } else if (!strcasecmp(param, "monitor-type")) {
01074       if (!strcasecmp(val, "mixmonitor"))
01075          q->montype = 1;
01076    } else if (!strcasecmp(param, "autopause")) {
01077       q->autopause = ast_true(val);
01078    } else if (!strcasecmp(param, "maxlen")) {
01079       q->maxlen = atoi(val);
01080       if (q->maxlen < 0)
01081          q->maxlen = 0;
01082    } else if (!strcasecmp(param, "ringlimit")) {
01083       q->ringlimit = atoi(val);
01084       if (q->ringlimit < 0)
01085          q->ringlimit = 0;
01086    } else if (!strcasecmp(param, "servicelevel")) {
01087       q->servicelevel= atoi(val);
01088    } else if (!strcasecmp(param, "strategy")) {
01089       q->strategy = strat2int(val);
01090       if (q->strategy < 0) {
01091          ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
01092             val, q->name);
01093          q->strategy = QUEUE_STRATEGY_RINGALL;
01094       }
01095    } else if (!strcasecmp(param, "joinempty")) {
01096       if (!strcasecmp(val, "strict"))
01097          q->joinempty = QUEUE_EMPTY_STRICT;
01098       else if (ast_true(val))
01099          q->joinempty = QUEUE_EMPTY_NORMAL;
01100       else
01101          q->joinempty = 0;
01102    } else if (!strcasecmp(param, "leavewhenempty")) {
01103       if (!strcasecmp(val, "strict"))
01104          q->leavewhenempty = QUEUE_EMPTY_STRICT;
01105       else if (ast_true(val))
01106          q->leavewhenempty = QUEUE_EMPTY_NORMAL;
01107       else
01108          q->leavewhenempty = 0;
01109    } else if (!strcasecmp(param, "eventmemberstatus")) {
01110       q->maskmemberstatus = !ast_true(val);
01111    } else if (!strcasecmp(param, "eventwhencalled")) {
01112       if (!strcasecmp(val, "vars")) {
01113          q->eventwhencalled = QUEUE_EVENT_VARIABLES;
01114       } else {
01115          q->eventwhencalled = ast_true(val) ? 1 : 0;
01116       }
01117    } else if (!strcasecmp(param, "reportholdtime")) {
01118       q->reportholdtime = ast_true(val);
01119    } else if (!strcasecmp(param, "memberdelay")) {
01120       q->memberdelay = atoi(val);
01121    } else if (!strcasecmp(param, "weight")) {
01122       q->weight = atoi(val);
01123       if (q->weight)
01124          use_weight++;
01125       /* With Realtime queues, if the last queue using weights is deleted in realtime,
01126          we will not see any effect on use_weight until next reload. */
01127    } else if (!strcasecmp(param, "timeoutrestart")) {
01128       q->timeoutrestart = ast_true(val);
01129    } else if (failunknown) {
01130       if (linenum >= 0) {
01131          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
01132             q->name, param, linenum);
01133       } else {
01134          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
01135       }
01136    }
01137 }

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

Definition at line 4872 of file app_queue.c.

References __queues_show().

Referenced by __queues_show().

04873 {
04874    return __queues_show(NULL, 0, fd, argc, argv);
04875 }

static void queue_transfer_destroy ( void *  data  )  [static]

Definition at line 2688 of file app_queue.c.

References ast_free.

02689 {
02690    struct queue_transfer_ds *qtds = data;
02691    ast_free(qtds);
02692 }

static void queue_transfer_fixup ( void *  data,
struct ast_channel old_chan,
struct ast_channel new_chan 
) [static]

Log an attended transfer when a queue caller channel is masqueraded.

When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when the actual transfer occurs. This happens during the masquerade after datastores are moved from old_chan to new_chan. This is why new_chan is referenced for exten, context, and datastore information.

At the end of this, we want to remove the datastore so that this fixup function is not called on any future masquerades of the caller during the current call.

Definition at line 2711 of file app_queue.c.

References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_log(), ast_queue_log(), queue_transfer_ds::callcompletedinsl, queue_ent::chan, ast_channel::context, ast_channel::exten, LOG_WARNING, queue_transfer_ds::member, member::membername, call_queue::name, queue_ent::parent, queue_transfer_ds::qe, queue_transfer_info, queue_ent::start, queue_transfer_ds::starttime, ast_channel::uniqueid, and update_queue().

02712 {
02713    struct queue_transfer_ds *qtds = data;
02714    struct queue_ent *qe = qtds->qe;
02715    struct member *member = qtds->member;
02716    time_t callstart = qtds->starttime;
02717    int callcompletedinsl = qtds->callcompletedinsl;
02718    struct ast_datastore *datastore;
02719 
02720    ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
02721             new_chan->exten, new_chan->context, (long) (callstart - qe->start),
02722             (long) (time(NULL) - callstart));
02723 
02724    update_queue(qe->parent, member, callcompletedinsl);
02725    
02726    /* No need to lock the channels because they are already locked in ast_do_masquerade */
02727    if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
02728       ast_channel_datastore_remove(old_chan, datastore);
02729    } else {
02730       ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
02731    }
02732 }

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

Definition at line 1686 of file app_queue.c.

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

01687 {
01688    int oldvalue;
01689 
01690    /* Calculate holdtime using an exponential average */
01691    /* Thanks to SRT for this contribution */
01692    /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
01693 
01694    ast_mutex_lock(&qe->parent->lock);
01695    oldvalue = qe->parent->holdtime;
01696    qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
01697    ast_mutex_unlock(&qe->parent->lock);
01698 }

static void record_abandoned ( struct queue_ent qe  )  [static]

Definition at line 2170 of file app_queue.c.

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

Referenced by queue_exec().

02171 {
02172    ast_mutex_lock(&qe->parent->lock);
02173    manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
02174       "Queue: %s\r\n"
02175       "Uniqueid: %s\r\n"
02176       "Position: %d\r\n"
02177       "OriginalPosition: %d\r\n"
02178       "HoldTime: %d\r\n",
02179       qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
02180 
02181    qe->parent->callsabandoned++;
02182    ast_mutex_unlock(&qe->parent->lock);
02183 }

static int reload ( void   )  [static]

Definition at line 5538 of file app_queue.c.

References reload_queues().

05539 {
05540    reload_queues();
05541    return 0;
05542 }

static void reload_queue_members ( void   )  [static]

Definition at line 3604 of file app_queue.c.

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

Referenced by load_module().

03605 {
03606    char *cur_ptr;
03607    char *queue_name;
03608    char *member;
03609    char *interface;
03610    char *membername = NULL;
03611    char *state_interface;
03612    char *penalty_tok;
03613    int penalty = 0;
03614    char *paused_tok;
03615    int paused = 0;
03616    struct ast_db_entry *db_tree;
03617    struct ast_db_entry *entry;
03618    struct call_queue *cur_queue;
03619    char queue_data[PM_MAX_LEN];
03620 
03621    AST_LIST_LOCK(&queues);
03622 
03623    /* Each key in 'pm_family' is the name of a queue */
03624    db_tree = ast_db_gettree(pm_family, NULL);
03625    for (entry = db_tree; entry; entry = entry->next) {
03626 
03627       queue_name = entry->key + strlen(pm_family) + 2;
03628 
03629       AST_LIST_TRAVERSE(&queues, cur_queue, list) {
03630          ast_mutex_lock(&cur_queue->lock);
03631          if (!strcmp(queue_name, cur_queue->name))
03632             break;
03633          ast_mutex_unlock(&cur_queue->lock);
03634       }
03635       
03636       if (!cur_queue)
03637          cur_queue = load_realtime_queue(queue_name);
03638 
03639       if (!cur_queue) {
03640          /* If the queue no longer exists, remove it from the
03641           * database */
03642          ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
03643          ast_db_del(pm_family, queue_name);
03644          continue;
03645       } else
03646          ast_mutex_unlock(&cur_queue->lock);
03647 
03648       if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
03649          continue;
03650 
03651       cur_ptr = queue_data;
03652       while ((member = strsep(&cur_ptr, "|"))) {
03653          if (ast_strlen_zero(member))
03654             continue;
03655 
03656          interface = strsep(&member, ";");
03657          penalty_tok = strsep(&member, ";");
03658          paused_tok = strsep(&member, ";");
03659          membername = strsep(&member, ";");
03660          state_interface = strsep(&member,";");
03661 
03662          if (!penalty_tok) {
03663             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
03664             break;
03665          }
03666          penalty = strtol(penalty_tok, NULL, 10);
03667          if (errno == ERANGE) {
03668             ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
03669             break;
03670          }
03671          
03672          if (!paused_tok) {
03673             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
03674             break;
03675          }
03676          paused = strtol(paused_tok, NULL, 10);
03677          if ((errno == ERANGE) || paused < 0 || paused > 1) {
03678             ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
03679             break;
03680          }
03681          if (ast_strlen_zero(membername))
03682             membername = interface;
03683 
03684          if (option_debug)
03685             ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Name: %s  Penalty: %d  Paused: %d\n", queue_name, interface, membername, penalty, paused);
03686          
03687          if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
03688             ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
03689             break;
03690          }
03691       }
03692    }
03693 
03694    AST_LIST_UNLOCK(&queues);
03695    if (db_tree) {
03696       ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
03697       ast_db_freetree(db_tree);
03698    }
03699 }

static int reload_queues ( void   )  [static]

Definition at line 4516 of file app_queue.c.

References add_to_interfaces(), alloc_queue(), ao2_find(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ao2_unlink(), AST_APP_ARG, ast_category_browse(), ast_config_load(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_free, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_NONSTANDARD_APP_ARGS, ast_skip_blanks(), ast_strdup, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), clear_queue(), create_queue_member(), call_queue::dead, member::delme, member::dynamic, call_queue::found, init_queue(), call_queue::lock, LOG_NOTICE, LOG_WARNING, call_queue::membercount, call_queue::members, call_queue::name, parse(), member::paused, queue_set_param(), QUEUE_STRATEGY_ROUNDROBIN, call_queue::realtime, remove_from_interfaces(), rr_dep_warning(), member::state_interface, call_queue::strategy, and var.

Referenced by load_module(), and reload().

04517 {
04518    struct call_queue *q;
04519    struct ast_config *cfg;
04520    char *cat, *tmp;
04521    struct ast_variable *var;
04522    struct member *cur, *newm;
04523    struct ao2_iterator mem_iter;
04524    int new;
04525    const char *general_val = NULL;
04526    char *parse;
04527    char *interface, *state_interface;
04528    char *membername = NULL;
04529    int penalty;
04530    AST_DECLARE_APP_ARGS(args,
04531       AST_APP_ARG(interface);
04532       AST_APP_ARG(penalty);
04533       AST_APP_ARG(membername);
04534       AST_APP_ARG(state_interface);
04535    );
04536    
04537    if (!(cfg = ast_config_load("queues.conf"))) {
04538       ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
04539       return 0;
04540    }
04541    AST_LIST_LOCK(&queues);
04542    use_weight=0;
04543    /* Mark all non-realtime queues as dead for the moment */
04544    AST_LIST_TRAVERSE(&queues, q, list) {
04545       if (!q->realtime) {
04546          q->dead = 1;
04547          q->found = 0;
04548       }
04549    }
04550 
04551    /* Chug through config file */
04552    cat = NULL;
04553    while ((cat = ast_category_browse(cfg, cat)) ) {
04554       if (!strcasecmp(cat, "general")) {  
04555          /* Initialize global settings */
04556          queue_debug = 0;
04557          if ((general_val = ast_variable_retrieve(cfg, "general", "debug")))
04558             queue_debug = ast_true(general_val);
04559          queue_persistent_members = 0;
04560          if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
04561             queue_persistent_members = ast_true(general_val);
04562          autofill_default = 0;
04563          if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
04564             autofill_default = ast_true(general_val);
04565          montype_default = 0;
04566          if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type")))
04567             if (!strcasecmp(general_val, "mixmonitor"))
04568                montype_default = 1;
04569       } else { /* Define queue */
04570          /* Look for an existing one */
04571          AST_LIST_TRAVERSE(&queues, q, list) {
04572             if (!strcmp(q->name, cat))
04573                break;
04574          }
04575          if (!q) {
04576             /* Make one then */
04577             if (!(q = alloc_queue(cat))) {
04578                /* TODO: Handle memory allocation failure */
04579             }
04580             new = 1;
04581          } else
04582             new = 0;
04583          if (q) {
04584             if (!new)
04585                ast_mutex_lock(&q->lock);
04586             /* Check if a queue with this name already exists */
04587             if (q->found) {
04588                ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
04589                if (!new)
04590                   ast_mutex_unlock(&q->lock);
04591                continue;
04592             }
04593             /* Re-initialize the queue, and clear statistics */
04594             init_queue(q);
04595             clear_queue(q);
04596             mem_iter = ao2_iterator_init(q->members, 0);
04597             while ((cur = ao2_iterator_next(&mem_iter))) {
04598                if (!cur->dynamic) {
04599                   cur->delme = 1;
04600                }
04601                ao2_ref(cur, -1);
04602             }
04603             ao2_iterator_destroy(&mem_iter);
04604             for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04605                if (!strcasecmp(var->name, "member")) {
04606                   struct member tmpmem;
04607                   membername = NULL;
04608 
04609                   if (ast_strlen_zero(var->value)) {
04610                      ast_log(LOG_WARNING, "Empty queue member definition at line %d. Moving on!\n", var->lineno);
04611                      continue;
04612                   }
04613 
04614                   /* Add a new member */
04615                   if (!(parse = ast_strdup(var->value))) {
04616                      continue;
04617                   }
04618                   
04619                   AST_NONSTANDARD_APP_ARGS(args, parse, ',');
04620 
04621                   interface = args.interface;
04622                   if (!ast_strlen_zero(args.penalty)) {
04623                      tmp = ast_skip_blanks(args.penalty);
04624                      penalty = atoi(tmp);
04625                      if (penalty < 0) {
04626                         penalty = 0;
04627                      }
04628                   } else
04629                      penalty = 0;
04630 
04631                   if (!ast_strlen_zero(args.membername)) {
04632                      membername = ast_skip_blanks(args.membername);
04633                   }
04634 
04635                   if (!ast_strlen_zero(args.state_interface)) {
04636                      state_interface = ast_skip_blanks(args.state_interface);
04637                   } else {
04638                      state_interface = interface;
04639                   }
04640 
04641                   /* Find the old position in the list */
04642                   ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
04643                   cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
04644 
04645                   /* Only attempt removing from interfaces list if the new state_interface is different than the old one */
04646                   if (cur && strcasecmp(cur->state_interface, state_interface)) {
04647                      remove_from_interfaces(cur->state_interface);
04648                   }
04649 
04650                   newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface);
04651                   if (!cur || (cur && strcasecmp(cur->state_interface, state_interface))) {
04652                      add_to_interfaces(state_interface);
04653                   }
04654                   ao2_link(q->members, newm);
04655                   ao2_ref(newm, -1);
04656                   newm = NULL;
04657 
04658                   if (cur)
04659                      ao2_ref(cur, -1);
04660                   else {
04661                      q->membercount++;
04662                   }
04663                   ast_free(parse);
04664                } else {
04665                   queue_set_param(q, var->name, var->value, var->lineno, 1);
04666                }
04667             }
04668 
04669             /* Free remaining members marked as delme */
04670             mem_iter = ao2_iterator_init(q->members, 0);
04671             while ((cur = ao2_iterator_next(&mem_iter))) {
04672                if (! cur->delme) {
04673                   ao2_ref(cur, -1);
04674                   continue;
04675                }
04676 
04677                q->membercount--;
04678                ao2_unlink(q->members, cur);
04679                remove_from_interfaces(cur->state_interface);
04680                ao2_ref(cur, -1);
04681             }
04682             ao2_iterator_destroy(&mem_iter);
04683 
04684             if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
04685                rr_dep_warning();
04686 
04687             if (new) {
04688                AST_LIST_INSERT_HEAD(&queues, q, list);
04689             } else
04690                ast_mutex_unlock(&q->lock);
04691          }
04692       }
04693    }
04694    ast_config_destroy(cfg);
04695    AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
04696       if (q->dead) {
04697          AST_LIST_REMOVE_CURRENT(&queues, list);
04698          if (!q->count)
04699             destroy_queue(q);
04700          else
04701             ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n");
04702       } else {
04703          ast_mutex_lock(&q->lock);
04704          mem_iter = ao2_iterator_init(q->members, 0);
04705          while ((cur = ao2_iterator_next(&mem_iter))) {
04706             if (cur->dynamic)
04707                q->membercount++;
04708             cur->status = ast_device_state(cur->state_interface);
04709             ao2_ref(cur, -1);
04710          }
04711          ao2_iterator_destroy(&mem_iter);
04712          ast_mutex_unlock(&q->lock);
04713       }
04714    }
04715    AST_LIST_TRAVERSE_SAFE_END;
04716    AST_LIST_UNLOCK(&queues);
04717    return 1;
04718 }

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

Definition at line 947 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(), member_interface::list, LOG_DEBUG, and option_debug.

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

00948 {
00949    struct member_interface *curint;
00950 
00951    if (interface_exists_global(interface))
00952       return 0;
00953 
00954    AST_LIST_LOCK(&interfaces);
00955    AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
00956       if (!strcasecmp(curint->interface, interface)) {
00957          if (option_debug)
00958             ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
00959          AST_LIST_REMOVE_CURRENT(&interfaces, list);
00960          free(curint);
00961          break;
00962       }
00963    }
00964    AST_LIST_TRAVERSE_SAFE_END;
00965    AST_LIST_UNLOCK(&interfaces);
00966 
00967    return 0;
00968 }

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

Definition at line 3452 of file app_queue.c.

References ao2_find(), ao2_ref(), ao2_unlink(), ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, call_queue::lock, manager_event(), call_queue::membercount, member::membername, call_queue::members, call_queue::name, remove_from_interfaces(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and member::state_interface.

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

03453 {
03454    struct call_queue *q;
03455    struct member *mem, tmpmem;
03456    int res = RES_NOSUCHQUEUE;
03457 
03458    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
03459 
03460    AST_LIST_LOCK(&queues);
03461    AST_LIST_TRAVERSE(&queues, q, list) {
03462       ast_mutex_lock(&q->lock);
03463       if (strcmp(q->name, queuename)) {
03464          ast_mutex_unlock(&q->lock);
03465          continue;
03466       }
03467 
03468       if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
03469          /* XXX future changes should beware of this assumption!! */
03470          if (!mem->dynamic) {
03471             res = RES_NOT_DYNAMIC;
03472             ao2_ref(mem, -1);
03473             ast_mutex_unlock(&q->lock);
03474             break;
03475          }
03476          q->membercount--;
03477          manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
03478             "Queue: %s\r\n"
03479             "Location: %s\r\n"
03480             "MemberName: %s\r\n",
03481             q->name, mem->interface, mem->membername);
03482          ao2_unlink(q->members, mem);
03483          remove_from_interfaces(mem->state_interface);
03484          ao2_ref(mem, -1);
03485 
03486          if (queue_persistent_members)
03487             dump_queue_members(q);
03488          
03489          res = RES_OKAY;
03490       } else {
03491          res = RES_EXISTS;
03492       }
03493       ast_mutex_unlock(&q->lock);
03494       break;
03495    }
03496 
03497    AST_LIST_UNLOCK(&queues);
03498 
03499    return res;
03500 }

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

Part 2 of ring_one.

Does error checking before attempting to request a channel and call a member. This function is only called from ring_one

Definition at line 1889 of file app_queue.c.

References ast_cdr::accountcode, ast_channel::adsicpe, ast_cdr::amaflags, ast_channel::appl, ast_call(), ast_cdr_busy(), ast_cdr_isset_unanswered(), ast_cdr_setdestchan(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DEVICE_NOT_INUSE, ast_device_state(), AST_DEVICE_UNKNOWN, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_request(), ast_strdup, ast_strlen_zero(), ast_verbose(), ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_cdr::clid, compare_weight(), ast_channel::context, ast_channel::data, ast_cdr::dcontext, ast_channel::dialcontext, do_hang(), ast_cdr::dst, EVENT_FLAG_AGENT, call_queue::eventwhencalled, ast_channel::exten, free, callattempt::interface, ast_cdr::lastapp, callattempt::lastcall, ast_cdr::lastdata, call_queue::lock, LOG_DEBUG, LOG_NOTICE, manager_event(), callattempt::member, member::membername, ast_channel::name, call_queue::name, ast_channel::nativeformats, option_debug, option_verbose, queue_ent::parent, member::paused, pbx_builtin_getvar_helper(), ast_channel::priority, QUEUE_EVENT_VARIABLES, member::ringcount, call_queue::ringinuse, call_queue::rrpos, ast_cdr::src, member::state_interface, member::status, callattempt::stillgoing, update_status(), ast_cdr::userfield, vars2manager(), VERBOSE_PREFIX_3, ast_channel::whentohangup, and call_queue::wrapuptime.

Referenced by ring_one().

01890 {
01891    int res;
01892    int status;
01893    char tech[256];
01894    char *location;
01895    const char *macrocontext, *macroexten;
01896 
01897    /* on entry here, we know that tmp->chan == NULL */
01898    if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
01899       if (queue_debug)
01900          ast_log(LOG_NOTICE, "Wrapuptime not yet expired for %s\n", tmp->interface);
01901       if (qe->chan->cdr)
01902          ast_cdr_busy(qe->chan->cdr);
01903       tmp->stillgoing = 0;
01904       (*busies)++;
01905       return 0;
01906    }
01907 
01908    if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
01909       if (queue_debug)
01910          ast_log(LOG_NOTICE, "%s in use, can't receive call\n", tmp->interface);
01911       if (qe->chan->cdr)
01912          ast_cdr_busy(qe->chan->cdr);
01913       tmp->stillgoing = 0;
01914       return 0;
01915    }
01916 
01917    if (tmp->member->paused) {
01918       if (queue_debug)
01919          ast_log(LOG_NOTICE, "%s paused, can't receive call\n", tmp->interface);
01920       if (qe->chan->cdr)
01921          ast_cdr_busy(qe->chan->cdr);
01922       tmp->stillgoing = 0;
01923       return 0;
01924    }
01925    if (use_weight && compare_weight(qe->parent,tmp->member)) {
01926       if (queue_debug)
01927          ast_log(LOG_NOTICE, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
01928       if (qe->chan->cdr)
01929          ast_cdr_busy(qe->chan->cdr);
01930       tmp->stillgoing = 0;
01931       (*busies)++;
01932       return 0;
01933    }
01934 
01935    ast_copy_string(tech, tmp->interface, sizeof(tech));
01936    if ((location = strchr(tech, '/')))
01937       *location++ = '\0';
01938    else
01939       location = "";
01940 
01941    /* Request the peer */
01942    tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
01943    if (!tmp->chan) {       /* If we can't, just go on to the next call */
01944       if (queue_debug)
01945          ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", tech);
01946       if (qe->chan->cdr)
01947          ast_cdr_busy(qe->chan->cdr);
01948       tmp->stillgoing = 0;
01949 
01950       update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface));
01951 
01952       ast_mutex_lock(&qe->parent->lock);
01953       qe->parent->rrpos++;
01954       ast_mutex_unlock(&qe->parent->lock);
01955 
01956       (*busies)++;
01957       return 0;
01958    }
01959    
01960    /* Increment ring count */
01961    tmp->member->ringcount++;
01962    tmp->chan->appl = "AppQueue";
01963    tmp->chan->data = "(Outgoing Line)";
01964    tmp->chan->whentohangup = 0;
01965    if (tmp->chan->cid.cid_num)
01966       free(tmp->chan->cid.cid_num);
01967    tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
01968    if (tmp->chan->cid.cid_name)
01969       free(tmp->chan->cid.cid_name);
01970    tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
01971    if (tmp->chan->cid.cid_ani)
01972       free(tmp->chan->cid.cid_ani);
01973    tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
01974 
01975    /* Inherit specially named variables from parent channel */
01976    ast_channel_inherit_variables(qe->chan, tmp->chan);
01977    ast_channel_datastore_inherit(qe->chan, tmp->chan);
01978 
01979    /* Presense of ADSI CPE on outgoing channel follows ours */
01980    tmp->chan->adsicpe = qe->chan->adsicpe;
01981 
01982    /* Inherit context and extension */
01983    ast_channel_lock(qe->chan);
01984    macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
01985    if (!ast_strlen_zero(macrocontext))
01986       ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext));
01987    else
01988       ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext));
01989    macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
01990    if (!ast_strlen_zero(macroexten))
01991       ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
01992    else
01993       ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
01994    if (ast_cdr_isset_unanswered()) {
01995       /* they want to see the unanswered dial attempts! */
01996       /* set up the CDR fields on all the CDRs to give sensical information */
01997       ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name);
01998       strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid);
01999       strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel);
02000       strcpy(tmp->chan->cdr->src, qe->chan->cdr->src);
02001       strcpy(tmp->chan->cdr->dst, qe->chan->exten);
02002       strcpy(tmp->chan->cdr->dcontext, qe->chan->context);
02003       strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp);
02004       strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata);
02005       tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags;
02006       strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode);
02007       strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
02008    }
02009    ast_channel_unlock(qe->chan);
02010 
02011    /* Place the call, but don't wait on the answer */
02012    if ((res = ast_call(tmp->chan, location, 0))) {
02013       /* Again, keep going even if there's an error */
02014       if (option_debug)
02015          ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
02016       if (option_verbose > 2)
02017          ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
02018       do_hang(tmp);
02019       (*busies)++;
02020       update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface));
02021       return 0;
02022    } else if (qe->parent->eventwhencalled) {
02023       char vars[2048];
02024 
02025       manager_event(EVENT_FLAG_AGENT, "AgentCalled",
02026                "AgentCalled: %s\r\n"
02027                "AgentName: %s\r\n"
02028                "ChannelCalling: %s\r\n"
02029                "CallerID: %s\r\n"
02030                "CallerIDName: %s\r\n"
02031                "Context: %s\r\n"
02032                "Extension: %s\r\n"
02033                "Priority: %d\r\n"
02034                "%s",
02035                tmp->interface, tmp->member->membername, qe->chan->name,
02036                tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
02037                tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
02038                qe->chan->context, qe->chan->exten, qe->chan->priority,
02039                qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
02040       if (option_verbose > 2)
02041          ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
02042    }
02043 
02044    update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface));
02045    return 1;
02046 }

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

Place a call to a queue member.

Once metrics have been calculated for each member, this function is used to place a call to the appropriate member (or members). The low-level channel-handling and error detection is handled in ring_entry

Returns 1 if a member was called successfully, 0 otherwise

Definition at line 2072 of file app_queue.c.

References ast_log(), callattempt::chan, find_best(), callattempt::interface, LOG_DEBUG, callattempt::metric, option_debug, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_entry(), callattempt::stillgoing, and call_queue::strategy.

Referenced by try_calling(), and wait_for_answer().

02073 {
02074    int ret = 0;
02075 
02076    while (ret == 0) {
02077       struct callattempt *best = find_best(outgoing);
02078       if (!best) {
02079          if (option_debug)
02080             ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
02081          break;
02082       }
02083       if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
02084          struct callattempt *cur;
02085          /* Ring everyone who shares this best metric (for ringall) */
02086          for (cur = outgoing; cur; cur = cur->q_next) {
02087             if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
02088                if (option_debug)
02089                   ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
02090                ret |= ring_entry(qe, cur, busies);
02091             }
02092          }
02093       } else {
02094          /* Ring just the best channel */
02095          if (option_debug)
02096             ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
02097          ret = ring_entry(qe, best, busies);
02098       }
02099    }
02100 
02101    return ret;
02102 }

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

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

Definition at line 2186 of file app_queue.c.

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

02187 {
02188    if (option_verbose > 2)
02189       ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
02190    ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
02191    if (qe->parent->autopause && pause) {
02192       if (!set_member_paused(qe->parent->name, interface, 1)) {
02193          if (option_verbose > 2)
02194             ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
02195       } else {
02196          if (option_verbose > 2)
02197             ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
02198       }
02199    }
02200    return;
02201 }

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

Definition at line 3817 of file app_queue.c.

References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_opt_priority_jumping, ast_queue_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_channel::context, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_channel::name, parse(), pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_NOT_DYNAMIC, RES_OKAY, and ast_channel::uniqueid.

Referenced by load_module().

03818 {
03819    int res=-1;
03820    struct ast_module_user *lu;
03821    char *parse, *temppos = NULL;
03822    int priority_jump = 0;
03823    AST_DECLARE_APP_ARGS(args,
03824       AST_APP_ARG(queuename);
03825       AST_APP_ARG(interface);
03826       AST_APP_ARG(options);
03827    );
03828 
03829 
03830    if (ast_strlen_zero(data)) {
03831       ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
03832       return -1;
03833    }
03834 
03835    parse = ast_strdupa(data);
03836 
03837    AST_STANDARD_APP_ARGS(args, parse);
03838 
03839    lu = ast_module_user_add(chan);
03840 
03841    if (ast_strlen_zero(args.interface)) {
03842       args.interface = ast_strdupa(chan->name);
03843       temppos = strrchr(args.interface, '-');
03844       if (temppos)
03845          *temppos = '\0';
03846    }
03847 
03848    if (args.options) {
03849       if (strchr(args.options, 'j'))
03850          priority_jump = 1;
03851    }
03852 
03853    switch (remove_from_queue(args.queuename, args.interface)) {
03854    case RES_OKAY:
03855       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
03856       ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
03857       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
03858       res = 0;
03859       break;
03860    case RES_EXISTS:
03861       ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
03862       if (priority_jump || ast_opt_priority_jumping)
03863          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
03864       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
03865       res = 0;
03866       break;
03867    case RES_NOSUCHQUEUE:
03868       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
03869       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
03870       res = 0;
03871       break;
03872    case RES_NOT_DYNAMIC:
03873       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
03874       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
03875       res = 0;
03876       break;
03877    }
03878 
03879    ast_module_user_remove(lu);
03880 
03881    return res;
03882 }

static void rr_dep_warning ( void   )  [static]

Definition at line 468 of file app_queue.c.

References ast_log(), and LOG_NOTICE.

Referenced by reload_queues().

00469 {
00470    static unsigned int warned = 0;
00471 
00472    if (!warned) {
00473       ast_log(LOG_NOTICE, "The 'roundrobin' queue strategy is deprecated. Please use the 'rrmemory' strategy instead.\n");
00474       warned = 1;
00475    }
00476 }

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

Definition at line 1139 of file app_queue.c.

References add_to_interfaces(), ao2_find(), ao2_ref(), ast_copy_string(), create_queue_member(), member::dead, member::interface, call_queue::membercount, call_queue::members, member::paused, member::penalty, member::realtime, remove_from_interfaces(), and member::state_interface.

Referenced by update_realtime_members().

01140 {
01141    struct member *m, tmpmem;
01142    int penalty = 0;
01143    int paused  = 0;
01144 
01145    if (penalty_str) {
01146       penalty = atoi(penalty_str);
01147       if (penalty < 0)
01148          penalty = 0;
01149    }
01150 
01151    if (paused_str) {
01152       paused = atoi(paused_str);
01153       if (paused < 0)
01154          paused = 0;
01155    }
01156 
01157    /* Find the member, or the place to put a new one. */
01158    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
01159    m = ao2_find(q->members, &tmpmem, OBJ_POINTER);
01160 
01161    /* Create a new one if not found, else update penalty */
01162    if (!m) {
01163       if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
01164          m->dead = 0;
01165          m->realtime = 1;
01166          add_to_interfaces(m->state_interface);
01167          ao2_link(q->members, m);
01168          ao2_ref(m, -1);
01169          m = NULL;
01170          q->membercount++;
01171       }
01172    } else {
01173       m->dead = 0;   /* Do not delete this one. */
01174       if (paused_str)
01175          m->paused = paused;
01176       if (strcasecmp(state_interface, m->state_interface)) {
01177          remove_from_interfaces(m->state_interface);
01178          ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
01179          add_to_interfaces(m->state_interface);
01180       }
01181       m->penalty = penalty;
01182       ao2_ref(m, -1);
01183    }
01184 }

static int say_periodic_announcement ( struct queue_ent qe  )  [static]

Definition at line 2128 of file app_queue.c.

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

Referenced by queue_exec(), and wait_our_turn().

02129 {
02130    int res = 0;
02131    time_t now;
02132 
02133    /* Get the current time */
02134    time(&now);
02135 
02136    /* Check to see if it is time to announce */
02137    if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
02138       return 0;
02139 
02140    /* Stop the music on hold so we can play our own file */
02141    ast_moh_stop(qe->chan);
02142 
02143    if (option_verbose > 2)
02144       ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
02145 
02146    /* Check to make sure we have a sound file. If not, reset to the first sound file */
02147    if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
02148       qe->last_periodic_announce_sound = 0;
02149    }
02150    
02151    /* play the announcement */
02152    res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
02153 
02154    if (res > 0 && !valid_exit(qe, res))
02155       res = 0;
02156 
02157    /* Resume Music on Hold if the caller is going to stay in the queue */
02158    if (!res)
02159       ast_moh_start(qe->chan, qe->moh, NULL);
02160 
02161    /* update last_periodic_announce_time */
02162    qe->last_periodic_announce_time = now;
02163 
02164    /* Update the current periodic announcement to the next announcement */
02165    qe->last_periodic_announce_sound++;
02166    
02167    return res;
02168 }

static int say_position ( struct queue_ent qe  )  [static]

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

01578 {
01579    int res = 0, avgholdmins, avgholdsecs;
01580    time_t now;
01581 
01582    /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
01583    time(&now);
01584    if ((now - qe->last_pos) < 15)
01585       return 0;
01586 
01587    /* If either our position has changed, or we are over the freq timer, say position */
01588    if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
01589       return 0;
01590 
01591    ast_moh_stop(qe->chan);
01592    /* Say we're next, if we are */
01593    if (qe->pos == 1) {
01594       res = play_file(qe->chan, qe->parent->sound_next);
01595       if (res)
01596          goto playout;
01597       else
01598          goto posout;
01599    } else {
01600       res = play_file(qe->chan, qe->parent->sound_thereare);
01601       if (res)
01602          goto playout;
01603       res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
01604       if (res)
01605          goto playout;
01606       res = play_file(qe->chan, qe->parent->sound_calls);
01607       if (res)
01608          goto playout;
01609    }
01610    /* Round hold time to nearest minute */
01611    avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
01612 
01613    /* If they have specified a rounding then round the seconds as well */
01614    if (qe->parent->roundingseconds) {
01615       avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
01616       avgholdsecs *= qe->parent->roundingseconds;
01617    } else {
01618       avgholdsecs = 0;
01619    }
01620 
01621    if (option_verbose > 2)
01622       ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
01623 
01624    /* If the hold time is >1 min, if it's enabled, and if it's not
01625       supposed to be only once and we have already said it, say it */
01626     if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
01627         ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
01628         !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
01629       res = play_file(qe->chan, qe->parent->sound_holdtime);
01630       if (res)
01631          goto playout;
01632 
01633       if (avgholdmins > 0) {
01634          if (avgholdmins < 2) {
01635             res = play_file(qe->chan, qe->parent->sound_lessthan);
01636             if (res)
01637                goto playout;
01638 
01639             res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
01640             if (res)
01641                goto playout;
01642          } else {
01643             res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
01644             if (res)
01645                goto playout;
01646          }
01647          
01648          res = play_file(qe->chan, qe->parent->sound_minutes);
01649          if (res)
01650             goto playout;
01651       }
01652       if (avgholdsecs>0) {
01653          res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
01654          if (res)
01655             goto playout;
01656 
01657          res = play_file(qe->chan, qe->parent->sound_seconds);
01658          if (res)
01659             goto playout;
01660       }
01661 
01662    }
01663 
01664 posout:
01665    if (option_verbose > 2)
01666       ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
01667          qe->chan->name, qe->parent->name, qe->pos);
01668    res = play_file(qe->chan, qe->parent->sound_thanks);
01669 
01670 playout:
01671 
01672    if ((res > 0 && !valid_exit(qe, res)))
01673       res = 0;
01674 
01675    /* Set our last_pos indicators */
01676    qe->last_pos = now;
01677    qe->last_pos_said = qe->pos;
01678 
01679    /* Don't restart music on hold if we're about to exit the caller from the queue */
01680    if (!res)
01681       ast_moh_start(qe->chan, qe->moh, NULL);
01682 
01683    return res;
01684 }

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

Definition at line 3558 of file app_queue.c.

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

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

03559 {
03560    int found = 0;
03561    struct call_queue *q;
03562    struct member *mem;
03563 
03564    /* Special event for when all queues are paused - individual events still generated */
03565    /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
03566    if (ast_strlen_zero(queuename))
03567       ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
03568 
03569    AST_LIST_LOCK(&queues);
03570    AST_LIST_TRAVERSE(&queues, q, list) {
03571       ast_mutex_lock(&q->lock);
03572       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
03573          if ((mem = interface_exists(q, interface))) {
03574             found++;
03575             if (mem->paused == paused)
03576                ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
03577             mem->paused = paused;
03578 
03579             if (queue_persistent_members)
03580                dump_queue_members(q);
03581 
03582             if (mem->realtime)
03583                update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
03584 
03585             ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
03586 
03587             manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
03588                "Queue: %s\r\n"
03589                "Location: %s\r\n"
03590                "MemberName: %s\r\n"
03591                "Paused: %d\r\n",
03592                   q->name, mem->interface, mem->membername, paused);
03593             ao2_ref(mem, -1);
03594          }
03595       }
03596       ast_mutex_unlock(&q->lock);
03597    }
03598    AST_LIST_UNLOCK(&queues);
03599 
03600    return found ? RESULT_SUCCESS : RESULT_FAILURE;
03601 }

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

sets the QUEUESTATUS channel variable

Definition at line 487 of file app_queue.c.

References queue_ent::chan, pbx_builtin_setvar_helper(), queue_results, and text.

Referenced by queue_exec().

00488 {
00489    int i;
00490 
00491    for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
00492       if (queue_results[i].id == res) {
00493          pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
00494          return;
00495       }
00496    }
00497 }

static struct ast_datastore* setup_transfer_datastore ( struct queue_ent qe,
struct member member,
time_t  starttime,
int  callcompletedinsl 
) [static]

create a datastore for storing relevant info to log attended transfers in the queue_log

Definition at line 2749 of file app_queue.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_lock, ast_channel_unlock, ast_log(), queue_ent::chan, ast_datastore::data, LOG_WARNING, queue_transfer_ds::member, queue_transfer_ds::qe, and queue_transfer_info.

02750 {
02751    struct ast_datastore *ds;
02752    struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
02753 
02754    if (!qtds) {
02755       ast_log(LOG_WARNING, "Memory allocation error!\n");
02756       return NULL;
02757    }
02758 
02759    ast_channel_lock(qe->chan);
02760    if (!(ds = ast_channel_datastore_alloc(&queue_transfer_info, NULL))) {
02761       ast_channel_unlock(qe->chan);
02762       ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
02763       return NULL;
02764    }
02765 
02766    qtds->qe = qe;
02767    /* This member is refcounted in try_calling, so no need to add it here, too */
02768    qtds->member = member;
02769    qtds->starttime = starttime;
02770    qtds->callcompletedinsl = callcompletedinsl;
02771    ds->data = qtds;
02772    ast_channel_datastore_add(qe->chan, ds);
02773    ast_channel_unlock(qe->chan);
02774    return ds;
02775 }

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

Producer of the statechange queue.

Definition at line 749 of file app_queue.c.

References ast_calloc, ast_cond_signal(), AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), device_state, and statechange::entry.

Referenced by load_module(), and unload_module().

00750 {
00751    struct statechange *sc;
00752 
00753    if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
00754       return 0;
00755 
00756    sc->state = state;
00757    strcpy(sc->dev, dev);
00758 
00759    ast_mutex_lock(&device_state.lock);
00760    AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
00761    ast_cond_signal(&device_state.cond);
00762    ast_mutex_unlock(&device_state.lock);
00763 
00764    return 0;
00765 }

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

Definition at line 2104 of file app_queue.c.

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

Referenced by try_calling().

02105 {
02106    struct callattempt *best = find_best(outgoing);
02107 
02108    if (best) {
02109       /* Ring just the best channel */
02110       if (option_debug)
02111          ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
02112       qe->parent->rrpos = best->metric % 1000;
02113    } else {
02114       /* Just increment rrpos */
02115       if (qe->parent->wrapped) {
02116          /* No more channels, start over */
02117          qe->parent->rrpos = 0;
02118       } else {
02119          /* Prioritize next entry */
02120          qe->parent->rrpos++;
02121       }
02122    }
02123    qe->parent->wrapped = 0;
02124 
02125    return 0;
02126 }

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

Definition at line 511 of file app_queue.c.

References name, and strategies.

Referenced by queue_set_param().

00512 {
00513    int x;
00514 
00515    for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
00516       if (!strcasecmp(strategy, strategies[x].name))
00517          return strategies[x].strategy;
00518    }
00519 
00520    return -1;
00521 }

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

A large function which calls members, updates statistics, and bridges the caller and a member.

Here is the process of this function 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue() 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also during each iteration, we call calc_metric to determine which members should be rung when. 3. Call ring_one to place a call to the appropriate member(s) 4. Call wait_for_answer to wait for an answer. If no one answers, return. 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered. 6. Start the monitor or mixmonitor if the option is set 7. Remove the caller from the queue to allow other callers to advance 8. Bridge the call. 9. Do any post processing after the call has disconnected.

Parameters:
[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
[in] options the options passed as the third parameter to the Queue() application
[in] url the url passed as the fourth parameter to the Queue() application
[in,out] tries the number of times we have tried calling queue members
[out] noption set if the call to Queue() has the 'n' option set.
[in] agi the agi passed as the fifth parameter to the Queue() application

Definition at line 2802 of file app_queue.c.

References ast_channel::_state, queue_ent::announce, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ast_calloc, AST_CDR_FLAG_DONT_TOUCH, AST_CDR_FLAG_POST_DISABLED, ast_cdr_isset_unanswered(), ast_cdr_noanswer(), ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_REDIRECT, AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, AST_STATE_UP, ast_strlen_zero(), ast_test_flag, calc_metric(), ast_channel::cdr, callattempt::chan, queue_ent::chan, ast_datastore::data, DATASTORE_INHERIT_FOREVER, di, dialed_interface_info, ast_cdr::dstchannel, EVENT_FLAG_AGENT, call_queue::eventwhencalled, queue_ent::expire, free, ast_datastore::inheritance, member::interface, member::lastcall, ast_dialed_interface::list, call_queue::lock, LOG_DEBUG, LOG_NOTICE, manager_event(), call_queue::membercount, call_queue::members, call_queue::name, ast_channel::name, option_debug, queue_ent::parent, queue_ent::pending, callattempt::q_next, QUEUE_STRATEGY_ROUNDROBIN, ring_one(), member::ringcount, call_queue::ringlimit, queue_ent::start, member::status, store_next(), call_queue::strategy, call_queue::timeout, queue_ent::tries, ast_channel::uniqueid, and wait_for_answer().

Referenced by queue_exec().

02803 {
02804    struct member *cur;
02805    struct callattempt *outgoing = NULL; /* the list of calls we are building */
02806    int to;
02807    char oldexten[AST_MAX_EXTENSION]="";
02808    char oldcontext[AST_MAX_CONTEXT]="";
02809    char queuename[256]="";
02810    struct ast_channel *peer;
02811    struct ast_channel *which;
02812    struct callattempt *lpeer;
02813    struct member *member;
02814    struct ast_app *app;
02815    int res = 0, bridge = 0;
02816    int numbusies = 0;
02817    int x=0;
02818    char *announce = NULL;
02819    char digit = 0;
02820    time_t callstart;
02821    time_t now = time(NULL);
02822    struct ast_bridge_config bridge_config;
02823    char nondataquality = 1;
02824    char *agiexec = NULL;
02825    int ret = 0;
02826    const char *monitorfilename;
02827    const char *monitor_exec;
02828    const char *monitor_options;
02829    char tmpid[256], tmpid2[256];
02830    char meid[1024], meid2[1024];
02831    char mixmonargs[1512];
02832    struct ast_app *mixmonapp = NULL;
02833    char *p;
02834    char vars[2048];
02835    int forwardsallowed = 1;
02836    int callcompletedinsl;
02837    struct ao2_iterator memi;
02838    struct ast_datastore *datastore, *transfer_ds;
02839 
02840    ast_channel_lock(qe->chan);
02841    datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
02842    ast_channel_unlock(qe->chan);
02843 
02844    memset(&bridge_config, 0, sizeof(bridge_config));
02845    time(&now);
02846 
02847    /* If we've already exceeded our timeout, then just stop
02848     * This should be extremely rare. queue_exec will take care
02849     * of removing the caller and reporting the timeout as the reason.
02850     */
02851    if (qe->expire && now >= qe->expire) {
02852       res = 0;
02853       goto out;
02854    }
02855       
02856    for (; options && *options; options++)
02857       switch (*options) {
02858       case 't':
02859          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
02860          break;
02861       case 'T':
02862          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
02863          break;
02864       case 'w':
02865          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
02866          break;
02867       case 'W':
02868          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
02869          break;
02870       case 'd':
02871          nondataquality = 0;
02872          break;
02873       case 'h':
02874          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
02875          break;
02876       case 'H':
02877          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
02878          break;
02879       case 'n':
02880          if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY)
02881             (*tries)++;
02882          else
02883             *tries = qe->parent->membercount;
02884          *noption = 1;
02885          break;
02886       case 'i':
02887          forwardsallowed = 0;
02888          break;
02889       }
02890 
02891    /* Hold the lock while we setup the outgoing calls */
02892    if (use_weight)
02893       AST_LIST_LOCK(&queues);
02894    ast_mutex_lock(&qe->parent->lock);
02895    if (option_debug)
02896       ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
02897                      qe->chan->name);
02898    ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
02899    if (!ast_strlen_zero(qe->announce))
02900       announce = qe->announce;
02901    if (!ast_strlen_zero(announceoverride))
02902       announce = announceoverride;
02903 
02904    memi = ao2_iterator_init(qe->parent->members, 0);
02905    while ((cur = ao2_iterator_next(&memi))) {
02906       struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
02907       struct ast_dialed_interface *di;
02908       AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
02909       if (!tmp) {
02910          ao2_iterator_destroy(&memi);
02911          ao2_ref(cur, -1);
02912          ast_mutex_unlock(&qe->parent->lock);
02913          if (use_weight)
02914             AST_LIST_UNLOCK(&queues);
02915          goto out;
02916       }
02917       if (!datastore) {
02918          if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) {
02919             ao2_iterator_destroy(&memi);
02920             ao2_ref(cur, -1);
02921             ast_mutex_unlock(&qe->parent->lock);
02922             if (use_weight)
02923                AST_LIST_UNLOCK(&queues);
02924             free(tmp);
02925             goto out;
02926          }
02927          datastore->inheritance = DATASTORE_INHERIT_FOREVER;
02928          if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
02929             ao2_iterator_destroy(&memi);
02930             ao2_ref(cur, -1);
02931             ast_mutex_unlock(&qe->parent->lock);
02932             if (use_weight)
02933                AST_LIST_UNLOCK(&queues);
02934             free(tmp);
02935             goto out;
02936          }
02937          datastore->data = dialed_interfaces;
02938          AST_LIST_HEAD_INIT(dialed_interfaces);
02939 
02940          ast_channel_lock(qe->chan);
02941          ast_channel_datastore_add(qe->chan, datastore);
02942          ast_channel_unlock(qe->chan);
02943       } else
02944          dialed_interfaces = datastore->data;
02945 
02946       AST_LIST_LOCK(dialed_interfaces);
02947       AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
02948          if (!strcasecmp(cur->interface, di->interface)) {
02949             ast_log(LOG_DEBUG, "Skipping dialing interface '%s' since it has already been dialed\n", 
02950                di->interface);
02951             break;
02952          }
02953       }
02954       AST_LIST_UNLOCK(dialed_interfaces);
02955       
02956       if (di) {
02957          free(tmp);
02958          continue;
02959       }
02960 
02961       /* It is always ok to dial a Local interface.  We only keep track of
02962        * which "real" interfaces have been dialed.  The Local channel will
02963        * inherit this list so that if it ends up dialing a real interface,
02964        * it won't call one that has already been called. */
02965       if (strncasecmp(cur->interface, "Local/", 6)) {
02966          if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
02967             ao2_iterator_destroy(&memi);
02968             ao2_ref(cur, -1);
02969             ast_mutex_unlock(&qe->parent->lock);
02970             if (use_weight)
02971                AST_LIST_UNLOCK(&queues);
02972             free(tmp);
02973             goto out;
02974          }
02975          strcpy(di->interface, cur->interface);
02976 
02977          AST_LIST_LOCK(dialed_interfaces);
02978          AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
02979          AST_LIST_UNLOCK(dialed_interfaces);
02980       }
02981 
02982       tmp->stillgoing = -1;
02983       tmp->member = cur;
02984       tmp->oldstatus = cur->status;
02985       tmp->lastcall = cur->lastcall;
02986       ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
02987       if (qe->tries == 0 && (cur->ringcount >= qe->parent->ringlimit)) {
02988          cur->ringcount = 0;
02989       }
02990       /* Special case: If we ring everyone, go ahead and ring them, otherwise
02991          just calculate their metric for the appropriate strategy */
02992       if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
02993          /* Put them in the list of outgoing thingies...  We're ready now.
02994             XXX If we're forcibly removed, these outgoing calls won't get
02995             hung up XXX */
02996          tmp->q_next = outgoing;
02997          outgoing = tmp;      
02998          /* If this line is up, don't try anybody else */
02999          if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
03000             break;
03001       } else {
03002          ao2_ref(cur, -1);
03003          free(tmp);
03004       }
03005    }
03006    ao2_iterator_destroy(&memi);
03007    if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
03008       to = (qe->expire - now) * 1000;
03009    else
03010       to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
03011    ++qe->pending;
03012    ++qe->tries;
03013    if (option_debug)
03014       ast_log(LOG_DEBUG, "%s is trying to ring one member from %s. This is try number %d\n",
03015                   qe->chan->name, queuename, qe->tries);
03016    ast_mutex_unlock(&qe->parent->lock);
03017    ring_one(qe, outgoing, &numbusies);
03018    if (use_weight)
03019       AST_LIST_UNLOCK(&queues);
03020    lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
03021    /* The ast_channel_datastore_remove() function could fail here if the
03022     * datastore was moved to another channel during a masquerade. If this is
03023     * the case, don't free the datastore here because later, when the channel
03024     * to which the datastore was moved hangs up, it will attempt to free this
03025     * datastore again, causing a crash
03026     */
03027    ast_channel_lock(qe->chan);
03028    if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
03029       ast_channel_datastore_free(datastore);
03030    }
03031    ast_channel_unlock(qe->chan);
03032    ast_mutex_lock(&qe->parent->lock);
03033    if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
03034       store_next(qe, outgoing);
03035    }
03036    ast_mutex_unlock(&qe->parent->lock);
03037    peer = lpeer ? lpeer->chan : NULL;
03038    if (!peer) {
03039       qe->pending = 0;
03040       if (to) {
03041          /* Must gotten hung up */
03042          res = -1;
03043       } else {
03044          /* User exited by pressing a digit */
03045          res = digit;
03046       }
03047       if (res == -1) {
03048          /* Post this CDR, and mark call as NOANSWER */
03049          ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_DONT_TOUCH);
03050          ast_cdr_noanswer(qe->chan->cdr);
03051          if (queue_debug)
03052             ast_log(LOG_NOTICE, "%s: Nobody answered.\n", qe->chan->name);
03053       }
03054       if (qe->parent->eventwhencalled) {
03055          manager_event(EVENT_FLAG_AGENT, "AgentTimeout",
03056                               "Queue: %s\r\n"
03057                               "ChannelCalling: %s\r\n"
03058                               "Uniqueid: %s\r\n"
03059                               "Tries: %d\r\n"
03060                               "Holdtime: %ld\r\n",
03061                               queuename, qe->chan->name, qe->chan->uniqueid, qe->tries,
03062                               (long)time(NULL) - qe->start);
03063       }
03064       if (ast_cdr_isset_unanswered()) {
03065          /* channel contains the name of one of the outgoing channels
03066             in its CDR; zero out this CDR to avoid a dual-posting */
03067          struct callattempt *o;
03068          for (o = outgoing; o; o = o->q_next) {
03069             if (!o->chan) {
03070                continue;
03071             }
03072             if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) {
03073                ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED);
03074                break;
03075             }
03076          }
03077       }
03078    } else { /* peer is valid */
03079       /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
03080          we will always return with -1 so that it is hung up properly after the
03081          conversation.  */
03082       if (!strcmp(qe->chan->tech->type, "Zap"))
03083          ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
03084       if (!strcmp(peer->tech->type, "Zap"))
03085          ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
03086       /* Update parameters for the queue */
03087       time(&now);
03088       recalc_holdtime(qe, (now - qe->start));
03089       ast_mutex_lock(&qe->parent->lock);
03090       callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
03091       ast_mutex_unlock(&qe->parent->lock);
03092       member = lpeer->member;
03093       /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
03094       ao2_ref(member, 1);
03095       hangupcalls(outgoing, peer);
03096       outgoing = NULL;
03097       if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
03098          int res2;
03099 
03100          res2 = ast_autoservice_start(qe->chan);
03101          if (!res2) {
03102             if (qe->parent->memberdelay) {
03103                ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
03104                res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
03105             }
03106             if (!res2 && announce) {
03107                play_file(peer, announce);
03108             }
03109             if (!res2 && qe->parent->reportholdtime) {
03110                if (!play_file(peer, qe->parent->sound_reporthold)) {
03111                   int holdtime;
03112 
03113                   time(&now);
03114                   holdtime = abs((now - qe->start) / 60);
03115                   if (holdtime < 2) {
03116                      play_file(peer, qe->parent->sound_lessthan);
03117                      ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
03118                   } else
03119                      ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
03120                   play_file(peer, qe->parent->sound_minutes);
03121                }
03122             }
03123          }
03124          res2 |= ast_autoservice_stop(qe->chan);
03125          if (peer->_softhangup) {
03126             /* Agent must have hung up */
03127             ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
03128             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
03129             if (qe->parent->eventwhencalled)
03130                manager_event(EVENT_FLAG_AGENT, "AgentDump",
03131                      "Queue: %s\r\n"
03132                      "Uniqueid: %s\r\n"
03133                      "Channel: %s\r\n"
03134                      "Member: %s\r\n"
03135                      "MemberName: %s\r\n"
03136                      "%s",
03137                      queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
03138                      qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03139             ast_hangup(peer);
03140             ao2_ref(member, -1);
03141             goto out;
03142          } else if (res2) {
03143             /* Caller must have hung up just before being connected*/
03144             ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
03145             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
03146             record_abandoned(qe);
03147             ast_cdr_noanswer(qe->chan->cdr);
03148             ast_hangup(peer);
03149             ao2_ref(member, -1);
03150             return -1;
03151          }
03152       }
03153       /* Stop music on hold */
03154       ast_moh_stop(qe->chan);
03155       /* If appropriate, log that we have a destination channel */
03156       if (qe->chan->cdr)
03157          ast_cdr_setdestchan(qe->chan->cdr, peer->name);
03158       /* Make sure channels are compatible */
03159       res = ast_channel_make_compatible(qe->chan, peer);
03160       if (res < 0) {
03161          ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
03162          ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
03163          record_abandoned(qe);
03164          ast_cdr_failed(qe->chan->cdr);
03165          ast_hangup(peer);
03166          ao2_ref(member, -1);
03167          return -1;
03168       }
03169 
03170       if (qe->parent->setinterfacevar)
03171             pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface);
03172 
03173       /* Begin Monitoring */
03174       if (qe->parent->monfmt && *qe->parent->monfmt) {
03175          if (!qe->parent->montype) {
03176             if (option_debug)
03177                ast_log(LOG_DEBUG, "Starting Monitor as requested.\n");
03178             monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
03179             if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
03180                which = qe->chan;
03181             else
03182                which = peer;
03183             if (monitorfilename)
03184                ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
03185             else if (qe->chan->cdr)
03186                ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
03187             else {
03188                /* Last ditch effort -- no CDR, make up something */
03189                snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
03190                ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
03191             }
03192             if (qe->parent->monjoin)
03193                ast_monitor_setjoinfiles(which, 1);
03194          } else {
03195             if (option_debug)
03196                ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n");
03197             monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
03198             if (!monitorfilename) {
03199                if (qe->chan->cdr)
03200                   ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1);
03201                else
03202                   snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
03203             } else {
03204                ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1);
03205                for (p = tmpid2; *p ; p++) {
03206                   if (*p == '^' && *(p+1) == '{') {
03207                      *p = '$';
03208                   }
03209                }
03210 
03211                memset(tmpid, 0, sizeof(tmpid));
03212                pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
03213             }
03214 
03215             monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
03216             monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
03217 
03218             if (monitor_exec) {
03219                ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1);
03220                for (p = meid2; *p ; p++) {
03221                   if (*p == '^' && *(p+1) == '{') {
03222                      *p = '$';
03223                   }
03224                }
03225 
03226                memset(meid, 0, sizeof(meid));
03227                pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
03228             }
03229    
03230             snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt);
03231 
03232             mixmonapp = pbx_findapp("MixMonitor");
03233 
03234             if (strchr(tmpid2, '|')) {
03235                ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
03236                mixmonapp = NULL;
03237             }
03238 
03239             if (!monitor_options)
03240                monitor_options = "";
03241             
03242             if (strchr(monitor_options, '|')) {
03243                ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
03244                mixmonapp = NULL;
03245             }
03246 
03247             if (mixmonapp) {
03248                if (!ast_strlen_zero(monitor_exec))
03249                   snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
03250                else
03251                   snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options);
03252                   
03253                if (option_debug)
03254                   ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
03255                /* We purposely lock the CDR so that pbx_exec does not update the application data */
03256                if (qe->chan->cdr)
03257                   ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
03258                ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
03259                if (qe->chan->cdr)
03260                   ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
03261 
03262             } else
03263                ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
03264 
03265          }
03266       }
03267       /* Drop out of the queue at this point, to prepare for next caller */
03268       leave_queue(qe);        
03269       if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
03270          if (option_debug)
03271             ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
03272          ast_channel_sendurl(peer, url);
03273       }
03274       if (!ast_strlen_zero(agi)) {
03275          if (option_debug)
03276             ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi);
03277          app = pbx_findapp("agi");
03278          if (app) {
03279             agiexec = ast_strdupa(agi);
03280             ret = pbx_exec(qe->chan, app, agiexec);
03281          } else
03282             ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
03283       }
03284       qe->handled++;
03285       ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid);
03286       if (qe->parent->eventwhencalled)
03287          manager_event(EVENT_FLAG_AGENT, "AgentConnect",
03288                "Queue: %s\r\n"
03289                "Uniqueid: %s\r\n"
03290                "Channel: %s\r\n"
03291                "Member: %s\r\n"
03292                "MemberName: %s\r\n"
03293                "Holdtime: %ld\r\n"
03294                "BridgedChannel: %s\r\n"
03295                "%s",
03296                queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
03297                (long)time(NULL) - qe->start, peer->uniqueid,
03298                qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03299       ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
03300       ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
03301       time(&callstart);
03302 
03303       if (member->status == AST_DEVICE_NOT_INUSE)
03304          ast_log(LOG_WARNING, "The device state of this queue member, %s, is still 'Not in Use' when it probably should not be! Please check UPGRADE.txt for correct configuration settings.\n", member->membername);
03305          
03306       transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
03307       bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
03308 
03309       ast_channel_lock(qe->chan);
03310       if (!attended_transfer_occurred(qe->chan)) {
03311          struct ast_datastore *tds;
03312 
03313          /* detect a blind transfer */
03314          if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) {
03315             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
03316                qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
03317                (long) (time(NULL) - callstart));
03318          } else if (qe->chan->_softhangup) {
03319             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
03320                (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
03321             if (qe->parent->eventwhencalled)
03322                manager_event(EVENT_FLAG_AGENT, "AgentComplete",
03323                      "Queue: %s\r\n"
03324                      "Uniqueid: %s\r\n"
03325                      "Channel: %s\r\n"
03326                      "Member: %s\r\n"
03327                      "MemberName: %s\r\n"
03328                      "HoldTime: %ld\r\n"
03329                      "TalkTime: %ld\r\n"
03330                      "Reason: caller\r\n"
03331                      "%s",
03332                      queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
03333                      (long)(callstart - qe->start), (long)(time(NULL) - callstart),
03334                      qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03335          } else {
03336             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
03337                (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
03338             if (qe->parent->eventwhencalled)
03339                manager_event(EVENT_FLAG_AGENT, "AgentComplete",
03340                      "Queue: %s\r\n"
03341                      "Uniqueid: %s\r\n"
03342                      "Channel: %s\r\n"
03343                      "MemberName: %s\r\n"
03344                      "HoldTime: %ld\r\n"
03345                      "TalkTime: %ld\r\n"
03346                      "Reason: agent\r\n"
03347                      "%s",
03348                      queuename, qe->chan->uniqueid, peer->name, member->membername, (long)(callstart - qe->start),
03349                      (long)(time(NULL) - callstart),
03350                      qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03351          }
03352          if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) {  
03353             ast_channel_datastore_remove(qe->chan, tds);
03354          }
03355          update_queue(qe->parent, member, callcompletedinsl);
03356       }
03357 
03358       if (transfer_ds) {
03359          ast_channel_datastore_free(transfer_ds);
03360       }
03361       ast_channel_unlock(qe->chan);
03362       ast_hangup(peer);
03363       res = bridge ? bridge : 1;
03364       ao2_ref(member, -1);
03365    }
03366 out:
03367    hangupcalls(outgoing, NULL);
03368 
03369    return res;
03370 }

static int unload_module ( void   )  [static]

Definition at line 5465 of file app_queue.c.

References ast_cli_unregister_multiple(), ast_cond_signal(), ast_custom_function_unregister(), ast_devstate_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, ast_unregister_application(), clear_and_free_interfaces(), cli_queue, device_state, queueagentcount_function, queuemembercount_function, queuememberlist_function, queuewaitingcount_function, and statechange_queue().

05466 {
05467    int res;
05468 
05469    if (device_state.thread != AST_PTHREADT_NULL) {
05470       device_state.stop = 1;
05471       ast_mutex_lock(&device_state.lock);
05472       ast_cond_signal(&device_state.cond);
05473       ast_mutex_unlock(&device_state.lock);
05474       pthread_join(device_state.thread, NULL);
05475    }
05476 
05477    ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
05478    res = ast_manager_unregister("QueueStatus");
05479    res |= ast_manager_unregister("Queues");
05480    res |= ast_manager_unregister("QueueAdd");
05481    res |= ast_manager_unregister("QueueRemove");
05482    res |= ast_manager_unregister("QueuePause");
05483    res |= ast_unregister_application(app_aqm);
05484    res |= ast_unregister_application(app_rqm);
05485    res |= ast_unregister_application(app_pqm);
05486    res |= ast_unregister_application(app_upqm);
05487    res |= ast_unregister_application(app_ql);
05488    res |= ast_unregister_application(app);
05489    res |= ast_custom_function_unregister(&queueagentcount_function);
05490    res |= ast_custom_function_unregister(&queuemembercount_function);
05491    res |= ast_custom_function_unregister(&queuememberlist_function);
05492    res |= ast_custom_function_unregister(&queuewaitingcount_function);
05493    ast_devstate_del(statechange_queue, NULL);
05494 
05495    ast_module_user_hangup_all();
05496 
05497    clear_and_free_interfaces();
05498 
05499    return res;
05500 }

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

Definition at line 2602 of file app_queue.c.

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

Referenced by queue_transfer_fixup().

02603 {
02604    ast_mutex_lock(&q->lock);
02605    time(&member->lastcall);
02606    member->calls++;
02607    q->callscompleted++;
02608    if (callcompletedinsl)
02609       q->callscompletedinsl++;
02610    ast_mutex_unlock(&q->lock);
02611    return 0;
02612 }

static int update_realtime_member_field ( struct member mem,
const char *  queue_name,
const char *  field,
const char *  value 
) [static]

Definition at line 1339 of file app_queue.c.

References ast_load_realtime(), ast_strlen_zero(), ast_update_realtime(), ast_variables_destroy(), member::interface, and var.

Referenced by set_member_paused().

01340 {
01341    struct ast_variable *var, *save;
01342    int ret = -1;
01343 
01344    if (!(var = ast_load_realtime("queue_members", "interface", mem->interface, "queue_name", queue_name, NULL))) 
01345       return ret;
01346    save = var;
01347    while (var) {
01348       if (!strcmp(var->name, "uniqueid"))
01349          break;
01350       var = var->next;
01351    }
01352    if (var && !ast_strlen_zero(var->value)) {
01353       if ((ast_update_realtime("queue_members", "uniqueid", var->value, field, value, NULL)) > -1)
01354          ret = 0;
01355    }
01356    ast_variables_destroy(save);
01357    return ret;
01358 }

static void update_realtime_members ( struct call_queue q  )  [static]

Definition at line 1360 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ao2_unlink(), ast_category_browse(), ast_config_destroy(), ast_load_realtime_multientry(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_variable_retrieve(), member::dead, member_interface::interface, call_queue::lock, LOG_DEBUG, call_queue::membercount, call_queue::members, call_queue::name, option_debug, member::realtime, remove_from_interfaces(), rt_handle_member_record(), S_OR, and member::state_interface.

Referenced by load_realtime_queue(), and queue_exec().

01361 {
01362    struct ast_config *member_config = NULL;
01363    struct member *m;
01364    char *interface = NULL;
01365    struct ao2_iterator mem_iter;
01366 
01367    if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL))) {
01368       /*This queue doesn't have realtime members*/
01369       if (option_debug > 2)
01370          ast_log(LOG_DEBUG, "Queue %s has no realtime members defined. No need for update\n", q->name);
01371       return;
01372    }
01373 
01374    ast_mutex_lock(&q->lock);
01375    
01376    /* Temporarily set realtime  members dead so we can detect deleted ones.*/ 
01377    mem_iter = ao2_iterator_init(q->members, 0);
01378    while ((m = ao2_iterator_next(&mem_iter))) {
01379       if (m->realtime)
01380          m->dead = 1;
01381       ao2_ref(m, -1);
01382    }
01383    ao2_iterator_destroy(&mem_iter);
01384 
01385    while ((interface = ast_category_browse(member_config, interface))) {
01386       rt_handle_member_record(q, interface,
01387          S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
01388          ast_variable_retrieve(member_config, interface, "penalty"),
01389          ast_variable_retrieve(member_config, interface, "paused"),
01390          S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
01391    }
01392 
01393    /* Delete all realtime members that have been deleted in DB. */
01394    mem_iter = ao2_iterator_init(q->members, 0);
01395    while ((m = ao2_iterator_next(&mem_iter))) {
01396       if (m->dead) {
01397          ao2_unlink(q->members, m);
01398          ast_mutex_unlock(&q->lock);
01399          remove_from_interfaces(m->state_interface);
01400          ast_mutex_lock(&q->lock);
01401          q->membercount--;
01402       }
01403       ao2_ref(m, -1);
01404    }
01405    ao2_iterator_destroy(&mem_iter);
01406    ast_mutex_unlock(&q->lock);
01407    ast_config_destroy(member_config);
01408 }

static int update_status ( const char *  interface,
const int  status 
) [static]

Definition at line 600 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), member::calls, member::dynamic, EVENT_FLAG_AGENT, member::interface, member::lastcall, member_interface::list, call_queue::lock, manager_event(), call_queue::maskmemberstatus, member::membername, call_queue::members, call_queue::name, member::paused, member::penalty, member::realtime, member::state_interface, and member::status.

Referenced by handle_statechange(), and ring_entry().

00601 {
00602    struct member *cur;
00603    struct ao2_iterator mem_iter;
00604    struct call_queue *q;
00605    char tmp_interface[80];
00606 
00607    AST_LIST_LOCK(&queues);
00608    AST_LIST_TRAVERSE(&queues, q, list) {
00609       ast_mutex_lock(&q->lock);
00610       mem_iter = ao2_iterator_init(q->members, 0);
00611       while ((cur = ao2_iterator_next(&mem_iter))) {
00612          char *slash_pos;
00613          ast_copy_string(tmp_interface, cur->state_interface, sizeof(tmp_interface));
00614          if ((slash_pos = strchr(tmp_interface, '/')))
00615             if ((slash_pos = strchr(slash_pos + 1, '/')))
00616                *slash_pos = '\0';
00617 
00618          if (strcasecmp(interface, tmp_interface)) {
00619             ao2_ref(cur, -1);
00620             continue;
00621          }
00622 
00623          if (cur->status != status) {
00624             cur->status = status;
00625             if (q->maskmemberstatus) {
00626                ao2_ref(cur, -1);
00627                continue;
00628             }
00629 
00630             manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
00631                "Queue: %s\r\n"
00632                "Location: %s\r\n"
00633                "MemberName: %s\r\n"
00634                "Membership: %s\r\n"
00635                "Penalty: %d\r\n"
00636                "CallsTaken: %d\r\n"
00637                "LastCall: %d\r\n"
00638                "Status: %d\r\n"
00639                "Paused: %d\r\n",
00640                q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
00641                cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
00642          }
00643          ao2_ref(cur, -1);
00644       }
00645       ao2_iterator_destroy(&mem_iter);
00646       ast_mutex_unlock(&q->lock);
00647    }
00648    AST_LIST_UNLOCK(&queues);
00649 
00650    return 0;
00651 }

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

Definition at line 3759 of file app_queue.c.

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

Referenced by load_module().

03760 {
03761    struct ast_module_user *lu;
03762    char *parse;
03763    int priority_jump = 0;
03764    int ignore_fail = 0;
03765    AST_DECLARE_APP_ARGS(args,
03766       AST_APP_ARG(queuename);
03767       AST_APP_ARG(interface);
03768       AST_APP_ARG(options);
03769    );
03770 
03771    if (ast_strlen_zero(data)) {
03772       ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
03773       return -1;
03774    }
03775 
03776    parse = ast_strdupa(data);
03777 
03778    AST_STANDARD_APP_ARGS(args, parse);
03779 
03780    lu = ast_module_user_add(chan);
03781 
03782    if (args.options) {
03783       if (strchr(args.options, 'j'))
03784          priority_jump = 1;
03785       if (strchr(args.options, 'i'))
03786          ignore_fail = 1;
03787    }
03788 
03789    if (ast_strlen_zero(args.interface)) {
03790       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
03791       ast_module_user_remove(lu);
03792       return -1;
03793    }
03794 
03795    if (set_member_paused(args.queuename, args.interface, 0)) {
03796       ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
03797       pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
03798       if (priority_jump || ast_opt_priority_jumping) {
03799          if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
03800             ast_module_user_remove(lu);
03801             return 0;
03802          }
03803       }
03804       ast_module_user_remove(lu);
03805       if (ignore_fail) {
03806          return 0;
03807       } else {
03808          return -1;
03809       }
03810    }
03811 
03812    ast_module_user_remove(lu);
03813    pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
03814    return 0;
03815 }

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

Definition at line 1544 of file app_queue.c.

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

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

01545 {
01546    int digitlen = strlen(qe->digits);
01547 
01548    /* Prevent possible buffer overflow */
01549    if (digitlen < sizeof(qe->digits) - 2) {
01550       qe->digits[digitlen] = digit;
01551       qe->digits[digitlen + 1] = '\0';
01552    } else {
01553       qe->digits[0] = '\0';
01554       return 0;
01555    }
01556 
01557    /* If there's no context to goto, short-circuit */
01558    if (ast_strlen_zero(qe->context))
01559       return 0;
01560 
01561    /* If the extension is bad, then reset the digits to blank */
01562    if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
01563       qe->digits[0] = '\0';
01564       return 0;
01565    }
01566 
01567    /* We have an exact match */
01568    if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
01569       qe->valid_digits = 1;
01570       /* Return 1 on a successful goto */
01571       return 1;
01572    }
01573 
01574    return 0;
01575 }

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

Definition at line 1849 of file app_queue.c.

References ast_copy_string(), and pbx_builtin_serialize_variables().

Referenced by ring_entry().

01850 {
01851    char *tmp = alloca(len);
01852 
01853    if (pbx_builtin_serialize_variables(chan, tmp, len)) {
01854       int i, j;
01855 
01856       /* convert "\n" to "\nVariable: " */
01857       strcpy(vars, "Variable: ");
01858 
01859       for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
01860          vars[j] = tmp[i];
01861 
01862          if (tmp[i + 1] == '\0')
01863             break;
01864          if (tmp[i] == '\n') {
01865             vars[j++] = '\r';
01866             vars[j++] = '\n';
01867 
01868             ast_copy_string(&(vars[j]), "Variable: ", len - j);
01869             j += 9;
01870          }
01871       }
01872       if (j > len - 3)
01873          j = len - 3;
01874       vars[j++] = '\r';
01875       vars[j++] = '\n';
01876       vars[j] = '\0';
01877    } else {
01878       /* there are no channel variables; leave it blank */
01879       *vars = '\0';
01880    }
01881    return vars;
01882 }

static int wait_a_bit ( struct queue_ent qe  )  [static]

Definition at line 3372 of file app_queue.c.

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

Referenced by queue_exec().

03373 {
03374    /* Don't need to hold the lock while we setup the outgoing calls */
03375    int retrywait = qe->parent->retry * 1000;
03376 
03377    int res = ast_waitfordigit(qe->chan, retrywait);
03378    if (res > 0 && !valid_exit(qe, res))
03379       res = 0;
03380 
03381    return res;
03382 }

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

Wait for a member to answer the call.

Parameters:
[in] qe the queue_ent corresponding to the caller in the queue
[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
[in] to the amount of time (in milliseconds) to wait for a response
[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
[in] prebusies number of busy members calculated prior to calling wait_for_answer
[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()

Definition at line 2214 of file app_queue.c.

References AST_MAX_WATCHERS, callattempt::call_next, callattempt::chan, queue_ent::chan, f, call_queue::name, queue_ent::parent, callattempt::q_next, QUEUE_STRATEGY_RINGALL, ring_one(), starttime, callattempt::stillgoing, and call_queue::strategy.

02215 {
02216    char *queue = qe->parent->name;
02217    struct callattempt *o, *start = NULL, *prev = NULL;
02218    int status;
02219    int numbusies = prebusies;
02220    int numnochan = 0;
02221    int stillgoing = 0;
02222    int orig = *to;
02223    struct ast_frame *f;
02224    struct callattempt *peer = NULL;
02225    struct ast_channel *winner;
02226    struct ast_channel *in = qe->chan;
02227    char on[80] = "";
02228    char membername[80] = "";
02229    long starttime = 0;
02230    long endtime = 0; 
02231 
02232    starttime = (long) time(NULL);
02233    
02234    while (*to && !peer) {
02235       int numlines, retry, pos = 1;
02236       struct ast_channel *watchers[AST_MAX_WATCHERS];
02237       watchers[0] = in;
02238       start = NULL;
02239 
02240       for (retry = 0; retry < 2; retry++) {
02241          numlines = 0;
02242          for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
02243             if (o->stillgoing) { /* Keep track of important channels */
02244                stillgoing = 1;
02245                if (o->chan) {
02246                   watchers[pos++] = o->chan;
02247                   if (!start)
02248                      start = o;
02249                   else
02250                      prev->call_next = o;
02251                   prev = o;
02252                }
02253             }
02254             numlines++;
02255          }
02256          if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
02257             (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
02258             break;
02259          /* On "ringall" strategy we only move to the next penalty level
02260             when *all* ringing phones are done in the current penalty level */
02261          ring_one(qe, outgoing, &numbusies);
02262          /* and retry... */
02263       }
02264       if (pos == 1 /* not found */) {
02265          if (numlines == (numbusies + numnochan)) {
02266             ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
02267          } else {
02268             ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
02269          }
02270          *to = 0;
02271          return NULL;
02272       }
02273 
02274       /* Poll for events from both the incoming channel as well as any outgoing channels */
02275       winner = ast_waitfor_n(watchers, pos, to);
02276 
02277       /* Service all of the outgoing channels */
02278       for (o = start; o; o = o->call_next) {
02279          if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
02280             if (!peer) {
02281                if (option_verbose > 2)
02282                   ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
02283                peer = o;
02284             }
02285          } else if (o->chan && (o->chan == winner)) {
02286 
02287             ast_copy_string(on, o->member->interface, sizeof(on));
02288             ast_copy_string(membername, o->member->membername, sizeof(membername));
02289 
02290             if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
02291                if (option_verbose > 2)
02292                   ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
02293                numnochan++;
02294                do_hang(o);
02295                winner = NULL;
02296                continue;
02297             } else if (!ast_strlen_zero(o->chan->call_forward)) {
02298                char tmpchan[256];
02299                char *stuff;
02300                char *tech;
02301 
02302                ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
02303                if ((stuff = strchr(tmpchan, '/'))) {
02304                   *stuff++ = '\0';
02305                   tech = tmpchan;
02306                } else {
02307                   snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
02308                   stuff = tmpchan;
02309                   tech = "Local";
02310                }
02311                /* Before processing channel, go ahead and check for forwarding */
02312                if (option_verbose > 2)
02313                   ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
02314                /* Setup parameters */
02315                o->chan = ast_request(tech, in->nativeformats, stuff, &status);
02316                if (!o->chan) {
02317                   ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
02318                   o->stillgoing = 0;
02319                   numnochan++;
02320                } else {
02321                   ast_channel_inherit_variables(in, o->chan);
02322                   ast_channel_datastore_inherit(in, o->chan);
02323                   if (o->chan->cid.cid_num)
02324                      free(o->chan->cid.cid_num);
02325                   o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
02326 
02327                   if (o->chan->cid.cid_name)
02328                      free(o->chan->cid.cid_name);
02329                   o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
02330 
02331                   ast_string_field_set(o->chan, accountcode, in->accountcode);
02332                   o->chan->cdrflags = in->cdrflags;
02333 
02334                   if (in->cid.cid_ani) {
02335                      if (o->chan->cid.cid_ani)
02336                         free(o->chan->cid.cid_ani);
02337                      o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
02338                   }
02339                   if (o->chan->cid.cid_rdnis)
02340                      free(o->chan->cid.cid_rdnis);
02341                   o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
02342                   if (ast_call(o->chan, tmpchan, 0)) {
02343                      ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
02344                      do_hang(o);
02345                      numnochan++;
02346                   }
02347                }
02348                /* Hangup the original channel now, in case we needed it */
02349                ast_hangup(winner);
02350                continue;
02351             }
02352             f = ast_read(winner);
02353             if (f) {
02354                if (f->frametype == AST_FRAME_CONTROL) {
02355                   switch (f->subclass) {
02356                   case AST_CONTROL_ANSWER:
02357                      /* This is our guy if someone answered. */
02358                      if (!peer) {
02359                         if (option_verbose > 2)
02360                            ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
02361                         peer = o;
02362                      }
02363                      break;
02364                   case AST_CONTROL_BUSY:
02365                      if (option_verbose > 2)
02366                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
02367                      if (in->cdr)
02368                         ast_cdr_busy(in->cdr);
02369                      do_hang(o);
02370                      endtime = (long)time(NULL);
02371                      endtime -= starttime;
02372                      rna(endtime * 1000, qe, on, membername, 0);
02373                      if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02374                         if (qe->parent->timeoutrestart)
02375                            *to = orig;
02376                         /* Have enough time for a queue member to answer? */
02377                         if (*to > 500) {
02378                            ring_one(qe, outgoing, &numbusies);
02379                            starttime = (long) time(NULL);
02380                         }
02381                      }
02382                      numbusies++;
02383                      break;
02384                   case AST_CONTROL_CONGESTION:
02385                      if (option_verbose > 2)
02386                         ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
02387                      if (in->cdr)
02388                         ast_cdr_busy(in->cdr);
02389                      endtime = (long)time(NULL);
02390                      endtime -= starttime;
02391                      rna(endtime * 1000, qe, on, membername, 0);
02392                      do_hang(o);
02393                      if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02394                         if (qe->parent->timeoutrestart)
02395                            *to = orig;
02396                         if (*to > 500) {
02397                            ring_one(qe, outgoing, &numbusies);
02398                            starttime = (long) time(NULL);
02399                         }
02400                      }
02401                      numbusies++;
02402                      break;
02403                   case AST_CONTROL_RINGING:
02404                      if (option_verbose > 2)
02405                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
02406                      break;
02407                   case AST_CONTROL_OFFHOOK:
02408                      /* Ignore going off hook */
02409                      break;
02410                   default:
02411                      ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
02412                   }
02413                }
02414                ast_frfree(f);
02415             } else { /* ast_read() returned NULL */
02416                endtime = (long) time(NULL) - starttime;
02417                rna(endtime * 1000, qe, on, membername, 1);
02418                do_hang(o);
02419                if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02420                   if (qe->parent->timeoutrestart)
02421                      *to = orig;
02422                   if (*to > 500) {
02423                      ring_one(qe, outgoing, &numbusies);
02424                      starttime = (long) time(NULL);
02425                   }
02426                }
02427             }
02428          }
02429       }
02430 
02431       /* If we received an event from the caller, deal with it. */
02432       if (winner == in) {
02433          f = ast_read(in);
02434          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
02435             /* Got hung up */
02436             *to = -1;
02437             if (f)
02438                ast_frfree(f);
02439             return NULL;
02440          }
02441          /* First check if DTMF digit is a valid exit */
02442          if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
02443             if (option_verbose > 3)
02444                ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
02445             *to = 0;
02446             *digit = f->subclass;
02447             ast_frfree(f);
02448             return NULL;
02449          }
02450          /* Else check if DTMF should be interpreted as caller disconnect */
02451          if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
02452             if (option_verbose > 3)
02453                ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
02454             *to = 0;
02455             ast_frfree(f);
02456             return NULL;
02457          }
02458          ast_frfree(f);
02459       }
02460       if (!*to) {
02461          for (o = start; o; o = o->call_next)
02462             rna(orig, qe, o->interface, o->member->membername, 1);
02463       }
02464    }
02465 
02466    return peer;
02467 }

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

The waiting areas for callers who are not actively calling members.

This function is one large loop. This function will return if a caller either exits the queue or it becomes that caller's turn to attempt calling queue members. Inside the loop, we service the caller with periodic announcements, holdtime announcements, etc. as configured in queues.conf

Return values:
0 if the caller's turn has arrived
-1 if the caller should exit the queue.

Definition at line 2527 of file app_queue.c.

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

Referenced by queue_exec().

02528 {
02529    int res = 0;
02530 
02531    /* This is the holding pen for callers 2 through maxlen */
02532    for (;;) {
02533       enum queue_member_status stat;
02534 
02535       if (is_our_turn(qe))
02536          break;
02537 
02538       /* If we have timed out, break out */
02539       if (qe->expire && (time(NULL) >= qe->expire)) {
02540          *reason = QUEUE_TIMEOUT;
02541          break;
02542       }
02543 
02544       stat = get_member_status(qe->parent, qe->max_penalty);
02545 
02546       /* leave the queue if no agents, if enabled */
02547       if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
02548          *reason = QUEUE_LEAVEEMPTY;
02549          ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02550          leave_queue(qe);
02551          break;
02552       }
02553 
02554       /* leave the queue if no reachable agents, if enabled */
02555       if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
02556          *reason = QUEUE_LEAVEUNAVAIL;
02557          ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02558          leave_queue(qe);
02559          break;
02560       }
02561 
02562       /* Make a position announcement, if enabled */
02563       if (qe->parent->announcefrequency && !ringing &&
02564          (res = say_position(qe)))
02565          break;
02566 
02567       /* If we have timed out, break out */
02568       if (qe->expire && (time(NULL) >= qe->expire)) {
02569          *reason = QUEUE_TIMEOUT;
02570          break;
02571       }
02572 
02573       /* Make a periodic announcement, if enabled */
02574       if (qe->parent->periodicannouncefrequency && !ringing &&
02575          (res = say_periodic_announcement(qe)))
02576          break;
02577 
02578       /* If we have timed out, break out */
02579       if (qe->expire && (time(NULL) >= qe->expire)) {
02580          *reason = QUEUE_TIMEOUT;
02581          break;
02582       }
02583       
02584       /* Wait a second before checking again */
02585       if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
02586          if (res > 0 && !valid_exit(qe, res))
02587             res = 0;
02588          else
02589             break;
02590       }
02591       
02592       /* If we have timed out, break out */
02593       if (qe->expire && (time(NULL) >= qe->expire)) {
02594          *reason = QUEUE_TIMEOUT;
02595          break;
02596       }
02597    }
02598 
02599    return res;
02600 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "True Call Queueing" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 5548 of file app_queue.c.

char* app = "Queue" [static]

Definition at line 148 of file app_queue.c.

char* app_aqm = "AddQueueMember" [static]

Definition at line 192 of file app_queue.c.

char* app_aqm_descrip [static]

Definition at line 194 of file app_queue.c.

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

Definition at line 193 of file app_queue.c.

char* app_pqm = "PauseQueueMember" [static]

Definition at line 227 of file app_queue.c.

char* app_pqm_descrip [static]

Definition at line 229 of file app_queue.c.

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

Definition at line 228 of file app_queue.c.

char* app_ql = "QueueLog" [static]

Definition at line 266 of file app_queue.c.

char* app_ql_descrip [static]

Initial value:

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

Definition at line 268 of file app_queue.c.

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

Definition at line 267 of file app_queue.c.

char* app_rqm = "RemoveQueueMember" [static]

Definition at line 211 of file app_queue.c.

char* app_rqm_descrip [static]

Definition at line 213 of file app_queue.c.

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

Definition at line 212 of file app_queue.c.

char* app_upqm = "UnpauseQueueMember" [static]

Definition at line 250 of file app_queue.c.

char* app_upqm_descrip [static]

Definition at line 252 of file app_queue.c.

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

Definition at line 251 of file app_queue.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 5548 of file app_queue.c.

int autofill_default = 0 [static]

queues.conf [general] option

Definition at line 288 of file app_queue.c.

struct ast_cli_entry cli_add_queue_member_deprecated [static]

Initial value:

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

Definition at line 5431 of file app_queue.c.

struct ast_cli_entry cli_queue[] [static]

Definition at line 5441 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry cli_remove_queue_member_deprecated [static]

Initial value:

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

Definition at line 5436 of file app_queue.c.

struct ast_cli_entry cli_show_queue_deprecated [static]

Initial value:

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

Definition at line 5426 of file app_queue.c.

ast_cond_t cond

Condition for the state change queue

Definition at line 707 of file app_queue.c.

char* descrip [static]

Definition at line 152 of file app_queue.c.

struct { ... } device_state [static]

Data used by the device state thread.

Referenced by device_state_thread(), load_module(), statechange_queue(), and unload_module().

struct statechange* first

Definition at line 709 of file app_queue.c.

enum queue_result id

Definition at line 304 of file app_queue.c.

Referenced by _sip_show_peers().

struct statechange* last

Definition at line 709 of file app_queue.c.

ast_mutex_t lock

Lock for the state change queue

Definition at line 705 of file app_queue.c.

int montype_default = 0 [static]

queues.conf [general] option

Definition at line 291 of file app_queue.c.

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

Persistent Members astdb family.

Definition at line 274 of file app_queue.c.

char qam_cmd_usage[] [static]

Initial value:

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

Definition at line 5420 of file app_queue.c.

char qmc_cmd_usage[] [static]

Initial value:

"Usage: queue member count <queue>\n"
"       Provides member count information on a specified queue.\n"

Definition at line 5397 of file app_queue.c.

char qrm_cmd_usage[] [static]

Initial value:

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

Definition at line 5423 of file app_queue.c.

int queue_debug = 0 [static]

queues.conf [general] extra debug option

Definition at line 279 of file app_queue.c.

int queue_persistent_members = 0 [static]

queues.conf [general] option

Definition at line 282 of file app_queue.c.

struct { ... } queue_results[]

Referenced by set_queue_result().

char queue_show_usage[] [static]

Initial value:

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

Definition at line 5416 of file app_queue.c.

struct ast_datastore_info queue_transfer_info [static]

Initial value:

 {
   .type = "queue_transfer",
   .chan_fixup = queue_transfer_fixup,
   .destroy = queue_transfer_destroy,
}
a datastore used to help correctly log attended transfers of queue callers

Definition at line 2696 of file app_queue.c.

Referenced by attended_transfer_occurred(), queue_transfer_fixup(), and setup_transfer_datastore().

struct ast_custom_function queueagentcount_function [static]

Definition at line 4473 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuemembercount_function [static]

Definition at line 4483 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuememberlist_function [static]

Definition at line 4507 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuewaitingcount_function [static]

Definition at line 4498 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct { ... } state_change_q

Queue of state changes

unsigned int stop

Set to 1 to stop the thread

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

char* text

Definition at line 305 of file app_queue.c.

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

pthread_t thread

The device state monitoring thread

Definition at line 703 of file app_queue.c.

int use_weight = 0 [static]

queues.conf per-queue weight option

Definition at line 285 of file app_queue.c.


Generated on Thu Dec 17 17:40:18 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7