Fri Apr 20 10:47:59 2012

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, QUEUE_STRATEGY_RRORDERED
}
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 (void *obj)
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 void remove_queue (struct call_queue *q)
 removes a call_queue from the list of call_queues
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 394 of file app_queue.c.

Referenced by queue_set_param().

#define ANNOUNCEHOLDTIME_ONCE   2

Definition at line 395 of file app_queue.c.

Referenced by queue_set_param(), and say_position().

#define AST_MAX_WATCHERS   256

Definition at line 2269 of file app_queue.c.

#define DEFAULT_RETRY   5

Definition at line 139 of file app_queue.c.

Referenced by init_queue(), and queue_set_param().

#define DEFAULT_TIMEOUT   15

Definition at line 140 of file app_queue.c.

Referenced by queue_set_param().

#define MAX_PERIODIC_ANNOUNCEMENTS   10

Definition at line 142 of file app_queue.c.

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

#define PM_MAX_LEN   8192

Definition at line 279 of file app_queue.c.

Referenced by dump_queue_members(), and reload_queue_members().

#define QUEUE_EMPTY_NORMAL   1

Definition at line 392 of file app_queue.c.

Referenced by queue_set_param().

#define QUEUE_EMPTY_STRICT   2

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

Referenced by queue_set_param(), and ring_entry().

#define RECHECK   1

Definition at line 141 of file app_queue.c.

Referenced by wait_our_turn().

#define RES_EXISTS   (-1)

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_NOSUCHQUEUE   (-3)

Definition at line 147 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 148 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 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(), remove_from_queue(), and rqm_exec().

#define RES_OUTOFMEMORY   (-2)

Definition at line 146 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 
QUEUE_STRATEGY_RRORDERED 

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

04389                 {
04390    QMC_VALID = 0, /* Count valid members */
04391    QMC_PAUSED,    /* Count paused members */
04392    QMC_ACTIVE,    /* Count active members */
04393    QMC_FREE,      /* Count free members */
04394    QMC_ALL        /* Count all queue members */
04395 };

enum queue_member_status

Enumerator:
QUEUE_NO_MEMBERS 
QUEUE_NO_REACHABLE_MEMBERS 
QUEUE_NORMAL 

Definition at line 572 of file app_queue.c.

00572                          {
00573    QUEUE_NO_MEMBERS,
00574    QUEUE_NO_REACHABLE_MEMBERS,
00575    QUEUE_NORMAL
00576 };

enum queue_result

Enumerator:
QUEUE_UNKNOWN 
QUEUE_TIMEOUT 
QUEUE_JOINEMPTY 
QUEUE_LEAVEEMPTY 
QUEUE_JOINUNAVAIL 
QUEUE_LEAVEUNAVAIL 
QUEUE_FULL 

Definition at line 296 of file app_queue.c.

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


Function Documentation

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

Definition at line 4844 of file app_queue.c.

References ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), 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_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::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().

04845 {
04846    struct call_queue *q;
04847    struct queue_ent *qe;
04848    struct member *mem;
04849    int pos, queue_show;
04850    time_t now;
04851    char max_buf[150];
04852    char *max;
04853    size_t max_left;
04854    float sl = 0;
04855    char *term = manager ? "\r\n" : "\n";
04856    struct ao2_iterator mem_iter;
04857 
04858    time(&now);
04859    if (argc == 2)
04860       queue_show = 0;
04861    else if (argc == 3)
04862       queue_show = 1;
04863    else
04864       return RESULT_SHOWUSAGE;
04865 
04866    /* We only want to load realtime queues when a specific queue is asked for. */
04867    if (queue_show) {
04868       load_realtime_queue(argv[2]);
04869    } else if (ast_check_realtime("queues")) {
04870       struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", (char *) NULL);
04871       char *queuename;
04872       if (cfg) {
04873          for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
04874             load_realtime_queue(queuename);
04875          }
04876          ast_config_destroy(cfg);
04877       }
04878    }
04879 
04880    AST_LIST_LOCK(&queues);
04881    if (AST_LIST_EMPTY(&queues)) {
04882       AST_LIST_UNLOCK(&queues);
04883       if (queue_show) {
04884          if (s)
04885             astman_append(s, "No such queue: %s.%s",argv[2], term);
04886          else
04887             ast_cli(fd, "No such queue: %s.%s",argv[2], term);
04888       } else {
04889          if (s)
04890             astman_append(s, "No queues.%s", term);
04891          else
04892             ast_cli(fd, "No queues.%s", term);
04893       }
04894       return RESULT_SUCCESS;
04895    }
04896    AST_LIST_TRAVERSE(&queues, q, list) {
04897       ao2_lock(q);
04898       if (queue_show) {
04899          if (strcasecmp(q->name, argv[2]) != 0) {
04900             ao2_unlock(q);
04901             if (!AST_LIST_NEXT(q, list)) {
04902                ast_cli(fd, "No such queue: %s.%s",argv[2], term);
04903                break;
04904             }
04905             continue;
04906          }
04907       }
04908       max_buf[0] = '\0';
04909       max = max_buf;
04910       max_left = sizeof(max_buf);
04911       if (q->maxlen)
04912          ast_build_string(&max, &max_left, "%d", q->maxlen);
04913       else
04914          ast_build_string(&max, &max_left, "unlimited");
04915       sl = 0;
04916       if (q->callscompleted > 0)
04917          sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
04918       if (s)
04919          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",
04920                               q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit,
04921                               q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term);
04922       else
04923          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",
04924                      q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit,
04925                      q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term);
04926       if (ao2_container_count(q->members)) {
04927          if (s)
04928             astman_append(s, "   Members: %s", term);
04929          else
04930             ast_cli(fd, "   Members: %s", term);
04931          mem_iter = ao2_iterator_init(q->members, 0);
04932          while ((mem = ao2_iterator_next(&mem_iter))) {
04933             max_buf[0] = '\0';
04934             max = max_buf;
04935             max_left = sizeof(max_buf);
04936             if (strcasecmp(mem->membername, mem->interface)) {
04937                ast_build_string(&max, &max_left, " (%s)", mem->interface);
04938             }
04939             if (mem->penalty)
04940                ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
04941             if (mem->dynamic)
04942                ast_build_string(&max, &max_left, " (dynamic)");
04943             if (mem->realtime)
04944                ast_build_string(&max, &max_left, " (realtime)");
04945             if (mem->paused)
04946                ast_build_string(&max, &max_left, " (paused)");
04947             ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
04948             if (mem->calls) {
04949                ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
04950                   mem->calls, (long) (time(NULL) - mem->lastcall));
04951             } else
04952                ast_build_string(&max, &max_left, " has taken no calls yet");
04953             if (s)
04954                astman_append(s, "      %s%s%s", mem->membername, max_buf, term);
04955             else
04956                ast_cli(fd, "      %s%s%s", mem->membername, max_buf, term);
04957             ao2_ref(mem, -1);
04958          }
04959          ao2_iterator_destroy(&mem_iter);
04960       } else if (s)
04961          astman_append(s, "   No Members%s", term);
04962       else  
04963          ast_cli(fd, "   No Members%s", term);
04964       if (q->head) {
04965          pos = 1;
04966          if (s)
04967             astman_append(s, "   Callers: %s", term);
04968          else
04969             ast_cli(fd, "   Callers: %s", term);
04970          for (qe = q->head; qe; qe = qe->next) {
04971             if (s)
04972                astman_append(s, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
04973                   pos++, qe->chan->name, (long) (now - qe->start) / 60,
04974                   (long) (now - qe->start) % 60, qe->prio, term);
04975             else
04976                ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
04977                   qe->chan->name, (long) (now - qe->start) / 60,
04978                   (long) (now - qe->start) % 60, qe->prio, term);
04979          }
04980       } else if (s)
04981          astman_append(s, "   No Callers%s", term);
04982       else
04983          ast_cli(fd, "   No Callers%s", term);
04984       if (s)
04985          astman_append(s, "%s", term);
04986       else
04987          ast_cli(fd, "%s", term);
04988       ao2_unlock(q);
04989       if (queue_show)
04990          break;
04991    }
04992    AST_LIST_UNLOCK(&queues);
04993    return RESULT_SUCCESS;
04994 }

static void __reg_module ( void   )  [static]

Definition at line 5672 of file app_queue.c.

static void __unreg_module ( void   )  [static]

Definition at line 5672 of file app_queue.c.

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

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

00934 {
00935    struct member_interface *curint;
00936 
00937    AST_LIST_LOCK(&interfaces);
00938    AST_LIST_TRAVERSE(&interfaces, curint, list) {
00939       if (!strcasecmp(curint->interface, interface))
00940          break;
00941    }
00942 
00943    if (curint) {
00944       AST_LIST_UNLOCK(&interfaces);
00945       return 0;
00946    }
00947 
00948    if (option_debug)
00949       ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
00950    
00951    if ((curint = ast_calloc(1, sizeof(*curint)))) {
00952       ast_copy_string(curint->interface, interface, sizeof(curint->interface));
00953       AST_LIST_INSERT_HEAD(&interfaces, curint, list);
00954    }
00955    AST_LIST_UNLOCK(&interfaces);
00956 
00957    return 0;
00958 }

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

References add_to_interfaces(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_LOCK, AST_LIST_UNLOCK, member::calls, create_queue_member(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, interface_exists(), member::lastcall, load_realtime_queue(), 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().

03613 {
03614    struct call_queue *q;
03615    struct member *new_member, *old_member;
03616    int res = RES_NOSUCHQUEUE;
03617 
03618    /* \note Ensure the appropriate realtime queue is loaded.  Note that this
03619     * short-circuits if the queue is already in memory. */
03620    if (!(q = load_realtime_queue(queuename)))
03621       return res;
03622 
03623    AST_LIST_LOCK(&queues);
03624 
03625    ao2_lock(q);
03626    if ((old_member = interface_exists(q, interface)) == NULL) {
03627       if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
03628          add_to_interfaces(new_member->state_interface);
03629          new_member->dynamic = 1;
03630          ao2_link(q->members, new_member);
03631          q->membercount++;
03632          manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
03633             "Queue: %s\r\n"
03634             "Location: %s\r\n"
03635             "MemberName: %s\r\n"
03636             "Membership: %s\r\n"
03637             "Penalty: %d\r\n"
03638             "CallsTaken: %d\r\n"
03639             "LastCall: %d\r\n"
03640             "Status: %d\r\n"
03641             "Paused: %d\r\n",
03642             q->name, new_member->interface, new_member->membername,
03643             "dynamic",
03644             new_member->penalty, new_member->calls, (int) new_member->lastcall,
03645             new_member->status, new_member->paused);
03646          
03647          ao2_ref(new_member, -1);
03648          new_member = NULL;
03649 
03650          if (dump)
03651             dump_queue_members(q);
03652          
03653          res = RES_OKAY;
03654       } else {
03655          res = RES_OUTOFMEMORY;
03656       }
03657    } else {
03658       ao2_ref(old_member, -1);
03659       res = RES_EXISTS;
03660    }
03661    ao2_unlock(q);
03662    AST_LIST_UNLOCK(&queues);
03663 
03664    return res;
03665 }

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

Definition at line 830 of file app_queue.c.

References ao2_alloc(), ast_copy_string(), and destroy_queue().

Referenced by find_queue_by_name_rt(), and reload_queues().

00831 {
00832    struct call_queue *q;
00833 
00834    if ((q = ao2_alloc(sizeof(*q), destroy_queue))) {
00835       ast_copy_string(q->name, queuename, sizeof(q->name));
00836    }
00837    return q;
00838 }

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

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

03994 {
03995    int res=-1;
03996    struct ast_module_user *lu;
03997    char *parse, *temppos = NULL;
03998    int priority_jump = 0;
03999    AST_DECLARE_APP_ARGS(args,
04000       AST_APP_ARG(queuename);
04001       AST_APP_ARG(interface);
04002       AST_APP_ARG(penalty);
04003       AST_APP_ARG(options);
04004       AST_APP_ARG(membername);
04005       AST_APP_ARG(state_interface);
04006    );
04007    int penalty = 0;
04008 
04009    if (ast_strlen_zero(data)) {
04010       ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|interface[|penalty[|options[|membername[|state_interface]]]]])\n");
04011       return -1;
04012    }
04013 
04014    parse = ast_strdupa(data);
04015 
04016    AST_STANDARD_APP_ARGS(args, parse);
04017 
04018    lu = ast_module_user_add(chan);
04019 
04020    if (ast_strlen_zero(args.interface)) {
04021       args.interface = ast_strdupa(chan->name);
04022       temppos = strrchr(args.interface, '-');
04023       if (temppos)
04024          *temppos = '\0';
04025    }
04026 
04027    if (!ast_strlen_zero(args.penalty)) {
04028       if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
04029          ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
04030          penalty = 0;
04031       }
04032    }
04033    
04034    if (args.options) {
04035       if (strchr(args.options, 'j'))
04036          priority_jump = 1;
04037    }
04038 
04039    switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
04040    case RES_OKAY:
04041       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
04042       ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
04043       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
04044       res = 0;
04045       break;
04046    case RES_EXISTS:
04047       ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
04048       if (priority_jump || ast_opt_priority_jumping)
04049          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
04050       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
04051       res = 0;
04052       break;
04053    case RES_NOSUCHQUEUE:
04054       ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
04055       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
04056       res = 0;
04057       break;
04058    case RES_OUTOFMEMORY:
04059       ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
04060       break;
04061    }
04062 
04063    ast_module_user_remove(lu);
04064 
04065    return res;
04066 }

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

References ast_channel_datastore_find(), and queue_transfer_info.

02821 {
02822    return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
02823 }

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 2697 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, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, member::ringcount, call_queue::ringlimit, call_queue::rrpos, call_queue::strategy, and call_queue::wrapped.

Referenced by try_calling().

02698 {
02699    if (qe->max_penalty && (mem->penalty > qe->max_penalty))
02700       return -1;
02701 
02702    switch (q->strategy) {
02703    case QUEUE_STRATEGY_RINGALL:
02704       /* Everyone equal, except for penalty */
02705       tmp->metric = mem->penalty * 1000000;
02706       break;
02707    case QUEUE_STRATEGY_ROUNDROBIN:
02708       if (!pos) {
02709          if (!q->wrapped) {
02710             /* No more channels, start over */
02711             q->rrpos = 0;
02712          } else {
02713             /* Prioritize next entry */
02714             q->rrpos++;
02715          }
02716          q->wrapped = 0;
02717       }
02718       /* Fall through */
02719    case QUEUE_STRATEGY_RRORDERED:
02720    case QUEUE_STRATEGY_RRMEMORY:
02721       if (pos < q->rrpos) {
02722          tmp->metric = 1000 + pos;
02723       } else {
02724          if (pos > q->rrpos)
02725             /* Indicate there is another priority */
02726             q->wrapped = 1;
02727          tmp->metric = pos;
02728       }
02729       tmp->metric += mem->penalty * 1000000;
02730       break;
02731    case QUEUE_STRATEGY_RANDOM:
02732       tmp->metric = ast_random() % 1000;
02733       tmp->metric += mem->penalty * 1000000;
02734       break;
02735    case QUEUE_STRATEGY_FEWESTCALLS:
02736       tmp->metric = mem->calls;
02737       tmp->metric += mem->penalty * 1000000;
02738       break;
02739    case QUEUE_STRATEGY_LEASTRECENT:
02740       if (!mem->lastcall)
02741          tmp->metric = 0;
02742       else
02743          tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
02744       tmp->metric += mem->penalty * 1000000;
02745       break;
02746    default:
02747       ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
02748       break;
02749    }
02750    if (q->ringlimit && (mem->ringcount >= q->ringlimit)) {
02751       tmp->metric += (mem->ringcount / q->ringlimit) * 10000000;
02752    }
02753    if (option_debug)
02754       ast_log(LOG_DEBUG, "New metric %d for member %s with %d rings (limit %d)\n", 
02755                   tmp->metric, mem->interface, mem->ringcount, q->ringlimit);
02756    return 0;
02757 }

static void clear_and_free_interfaces ( void   )  [static]

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

01013 {
01014    struct member_interface *curint;
01015 
01016    AST_LIST_LOCK(&interfaces);
01017    while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
01018       free(curint);
01019    AST_LIST_UNLOCK(&interfaces);
01020 }

static void clear_queue ( struct call_queue q  )  [static]

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

00925 {
00926    q->holdtime = 0;
00927    q->callscompleted = 0;
00928    q->callsabandoned = 0;
00929    q->callscompletedinsl = 0;
00930    q->wrapuptime = 0;
00931 }

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

Definition at line 5499 of file app_queue.c.

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

05500 {
05501    char buffer[256] = "";
05502    char *queuename;
05503    
05504    if (argc != 4) {
05505       return RESULT_SHOWUSAGE;
05506    }
05507    queuename = argv[3];
05508 
05509    if (qmc_handler(queuename, buffer, sizeof(buffer)) == RESULT_SUCCESS) {
05510          ast_cli(fd, 
05511                      "Member count for queue '%s'\n"
05512                      "%s\n",
05513                      queuename, buffer); 
05514          return RESULT_SUCCESS;
05515    } else {
05516          ast_cli(fd, "No such queue: '%s'\n", queuename);
05517          return RESULT_FAILURE;
05518    }
05519 }

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

Definition at line 1871 of file app_queue.c.

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

Referenced by ring_entry().

01872 {
01873    struct call_queue *q;
01874    struct member *mem;
01875    int found = 0;
01876    
01877    /* &qlock and &rq->lock already set by try_calling()
01878     * to solve deadlock */
01879    AST_LIST_TRAVERSE(&queues, q, list) {
01880       if (q == rq) /* don't check myself, could deadlock */
01881          continue;
01882       ao2_lock(q);
01883       if (q->count && q->members) {
01884          if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
01885             ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
01886             if (q->weight > rq->weight && q->count >= num_available_members(q)) {
01887                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);
01888                found = 1;
01889             }
01890             ao2_ref(mem, -1);
01891          }
01892       }
01893       ao2_unlock(q);
01894       if (found)
01895          break;
01896    }
01897    return found;
01898 }

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

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

05002 {
05003    struct call_queue *q;
05004    char *ret = NULL;
05005    int which = 0;
05006    int wordlen = strlen(word);
05007    
05008    AST_LIST_LOCK(&queues);
05009    AST_LIST_TRAVERSE(&queues, q, list) {
05010       if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
05011          ret = ast_strdup(q->name); 
05012          break;
05013       }
05014    }
05015    AST_LIST_UNLOCK(&queues);
05016 
05017    return ret;
05018 }

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

Definition at line 5304 of file app_queue.c.

References ast_malloc, ast_strdup, and complete_queue().

05305 {
05306    /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
05307    switch (pos) {
05308    case 3:  /* Don't attempt to complete name of interface (infinite possibilities) */
05309       return NULL;
05310    case 4:  /* only one possible match, "to" */
05311       return state == 0 ? ast_strdup("to") : NULL;
05312    case 5:  /* <queue> */
05313       return complete_queue(line, word, pos, state);
05314    case 6: /* only one possible match, "penalty" */
05315       return state == 0 ? ast_strdup("penalty") : NULL;
05316    case 7:
05317       if (state < 100) {   /* 0-99 */
05318          char *num;
05319          if ((num = ast_malloc(3))) {
05320             sprintf(num, "%d", state);
05321          }
05322          return num;
05323       } else {
05324          return NULL;
05325       }
05326    case 8: /* only one possible match, "as" */
05327       return state == 0 ? ast_strdup("as") : NULL;
05328    case 9:  /* Don't attempt to complete name of member (infinite possibilities) */
05329       return NULL;
05330    case 10:
05331       return state == 0 ? ast_strdup("state_interface") : NULL;
05332    default:
05333       return NULL;
05334    }
05335 }

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

Definition at line 5526 of file app_queue.c.

References complete_queue().

05527 {
05528       /* 0 - queue; 1 - member; 2 - count; 3 - <queue> */
05529       switch (pos) {
05530       case 3:  /* <queue> */
05531             return complete_queue(line, word, pos, state);
05532       default:
05533          return NULL;
05534       }
05535 }

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

Definition at line 5372 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_EMPTY, AST_LIST_TRAVERSE, ast_strdup, complete_queue(), member::interface, and call_queue::members.

05373 {
05374    int which = 0;
05375    struct call_queue *q;
05376    struct member *m;
05377    struct ao2_iterator mem_iter;
05378 
05379    /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
05380    if (pos > 5 || pos < 3)
05381       return NULL;
05382    if (pos == 4)  /* only one possible match, 'from' */
05383       return state == 0 ? ast_strdup("from") : NULL;
05384 
05385    if (pos == 5)  /* No need to duplicate code */
05386       return complete_queue(line, word, pos, state);
05387 
05388    /* here is the case for 3, <member> */
05389    if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */
05390       AST_LIST_TRAVERSE(&queues, q, list) {
05391          ao2_lock(q);
05392          mem_iter = ao2_iterator_init(q->members, 0);
05393          while ((m = ao2_iterator_next(&mem_iter))) {
05394             if (++which > state) {
05395                char *tmp;
05396                ao2_iterator_destroy(&mem_iter);
05397                ao2_unlock(q);
05398                tmp = ast_strdup(m->interface);
05399                ao2_ref(m, -1);
05400                return tmp;
05401             }
05402             ao2_ref(m, -1);
05403          }
05404          ao2_iterator_destroy(&mem_iter);
05405          ao2_unlock(q);
05406       }
05407    }
05408 
05409    return NULL;
05410 }

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

Definition at line 5020 of file app_queue.c.

References complete_queue().

05021 {
05022    if (pos == 2)
05023       return complete_queue(line, word, pos, state);
05024    return NULL;
05025 }

static int compress_char ( const char  c  )  [static]

Definition at line 840 of file app_queue.c.

00841 {
00842    if (c < 32)
00843       return 0;
00844    else if (c > 96)
00845       return c - 64;
00846    else
00847       return c - 32;
00848 }

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

00806 {
00807    struct member *cur;
00808    
00809    if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
00810       cur->penalty = penalty;
00811       cur->paused = paused;
00812       ast_copy_string(cur->interface, interface, sizeof(cur->interface));
00813       if (!ast_strlen_zero(state_interface)) {
00814          ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
00815       } else {
00816          ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
00817       }
00818       if (!ast_strlen_zero(membername))
00819          ast_copy_string(cur->membername, membername, sizeof(cur->membername));
00820       else
00821          ast_copy_string(cur->membername, interface, sizeof(cur->membername));
00822       if (!strchr(cur->interface, '/'))
00823          ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
00824       cur->status = ast_device_state(cur->state_interface);
00825    }
00826 
00827    return cur;
00828 }

static void destroy_queue ( void *  obj  )  [static]

Definition at line 538 of file app_queue.c.

References ao2_ref(), free_members(), and call_queue::members.

Referenced by alloc_queue().

00539 {
00540    struct call_queue *q = obj;
00541    if (q->members) {
00542       free_members(q, 1);
00543       ao2_ref(q->members, -1);
00544    }
00545 }

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

Consumer of the statechange queue.

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

00754 {
00755    struct statechange *sc = NULL;
00756 
00757    while (!device_state.stop) {
00758       ast_mutex_lock(&device_state.lock);
00759       if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
00760          ast_cond_wait(&device_state.cond, &device_state.lock);
00761          sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry);
00762       }
00763       ast_mutex_unlock(&device_state.lock);
00764 
00765       /* Check to see if we were woken up to see the request to stop */
00766       if (device_state.stop)
00767          break;
00768 
00769       if (!sc)
00770          continue;
00771 
00772       handle_statechange(sc);
00773 
00774       free(sc);
00775       sc = NULL;
00776    }
00777 
00778    if (sc)
00779       free(sc);
00780 
00781    while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry)))
00782       free(sc);
00783 
00784    return NULL;
00785 }

static void do_hang ( struct callattempt o  )  [static]

common hangup actions

Definition at line 1901 of file app_queue.c.

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

Referenced by ring_entry().

01902 {
01903    o->stillgoing = 0;
01904    ast_hangup(o->chan);
01905    o->chan = NULL;
01906 }

static void dump_queue_members ( struct call_queue pm_queue  )  [static]

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

03521 {
03522    struct member *cur_member;
03523    char value[PM_MAX_LEN];
03524    int value_len = 0;
03525    int res;
03526    struct ao2_iterator mem_iter;
03527 
03528    memset(value, 0, sizeof(value));
03529 
03530    if (!pm_queue)
03531       return;
03532 
03533    mem_iter = ao2_iterator_init(pm_queue->members, 0);
03534    while ((cur_member = ao2_iterator_next(&mem_iter))) {
03535       if (!cur_member->dynamic) {
03536          ao2_ref(cur_member, -1);
03537          continue;
03538       }
03539 
03540       res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s",
03541          value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface);
03542 
03543       ao2_ref(cur_member, -1);
03544 
03545       if (res != strlen(value + value_len)) {
03546          ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
03547          break;
03548       }
03549       value_len += res;
03550    }
03551    ao2_iterator_destroy(&mem_iter);
03552    
03553    if (value_len && !cur_member) {
03554       if (ast_db_put(pm_family, pm_queue->name, value))
03555          ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
03556    } else
03557       /* Delete the entry if the queue is empty or there is an error */
03558       ast_db_del(pm_family, pm_queue->name);
03559 }

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

find the entry with the best metric, or NULL

Definition at line 2108 of file app_queue.c.

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

02109 {
02110    struct callattempt *best = NULL, *cur;
02111 
02112    for (cur = outgoing; cur; cur = cur->q_next) {
02113       if (cur->stillgoing &&              /* Not already done */
02114          !cur->chan &&              /* Isn't already going */
02115          (!best || cur->metric < best->metric)) {     /* We haven't found one yet, or it's better */
02116          best = cur;
02117       }
02118    }
02119 
02120    return best;
02121 }

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

References alloc_queue(), ao2_lock(), ao2_unlock(), AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), clear_queue(), member_interface::interface, member_interface::list, LOG_DEBUG, LOG_WARNING, ast_variable::name, call_queue::name, ast_variable::next, QUEUE_STRATEGY_RINGALL, call_queue::realtime, remove_queue(), strat2int(), call_queue::strategy, and ast_variable::value.

Referenced by load_realtime_queue().

01249 {
01250    struct ast_variable *v;
01251    struct call_queue *q;
01252    struct member *m;
01253    struct ao2_iterator mem_iter;
01254    char *interface = NULL;
01255    char *tmp, *tmp_name;
01256    char tmpbuf[64];  /* Must be longer than the longest queue param name. */
01257 
01258    /* Find the queue in the in-core list (we will create a new one if not found). */
01259    AST_LIST_TRAVERSE(&queues, q, list) {
01260       if (!strcasecmp(q->name, queuename))
01261          break;
01262    }
01263 
01264    /* Static queues override realtime. */
01265    if (q) {
01266       ao2_lock(q);
01267       if (!q->realtime) {
01268          if (q->dead) {
01269             ao2_unlock(q);
01270             return NULL;
01271          } else {
01272             ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
01273             ao2_unlock(q);
01274             return q;
01275          }
01276       }
01277    } else if (!member_config)
01278       /* Not found in the list, and it's not realtime ... */
01279       return NULL;
01280 
01281    /* Check if queue is defined in realtime. */
01282    if (!queue_vars) {
01283       /* Delete queue from in-core list if it has been deleted in realtime. */
01284       if (q) {
01285          /*! \note Hmm, can't seem to distinguish a DB failure from a not
01286             found condition... So we might delete an in-core queue
01287             in case of DB failure. */
01288          ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
01289 
01290          q->dead = 1;
01291          /* Delete if unused (else will be deleted when last caller leaves). */
01292          if (!q->count) {
01293             /* Delete. */
01294             ao2_unlock(q);
01295             remove_queue(q);
01296          } else
01297             ao2_unlock(q);
01298       }
01299       return NULL;
01300    }
01301 
01302    /* Create a new queue if an in-core entry does not exist yet. */
01303    if (!q) {
01304       struct ast_variable *tmpvar;
01305       if (!(q = alloc_queue(queuename)))
01306          return NULL;
01307       ao2_lock(q);
01308       clear_queue(q);
01309       q->realtime = 1;
01310       AST_LIST_INSERT_HEAD(&queues, q, list);
01311    
01312       /* Due to the fact that the "rrordered" strategy will have a different allocation
01313        * scheme for queue members, we must devise the queue's strategy before other initializations.
01314        * To be specific, the rrordered strategy needs to function like a linked list, meaning the ao2
01315        * container used will have only a single bucket instead of the typical number.
01316        */
01317       for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
01318          if (!strcasecmp(tmpvar->name, "strategy")) {
01319             q->strategy = strat2int(tmpvar->value);
01320             if (q->strategy < 0) {
01321                ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
01322                tmpvar->value, q->name);
01323                q->strategy = QUEUE_STRATEGY_RINGALL;
01324             }
01325             break;
01326          }
01327       }
01328       /* We traversed all variables and didn't find a strategy */
01329       if (!tmpvar) {
01330          q->strategy = QUEUE_STRATEGY_RINGALL;
01331       }
01332    }
01333    init_queue(q);    /* Ensure defaults for all parameters not set explicitly. */
01334 
01335    memset(tmpbuf, 0, sizeof(tmpbuf));
01336    for (v = queue_vars; v; v = v->next) {
01337       /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
01338       if ((tmp = strchr(v->name, '_'))) {
01339          ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
01340          tmp_name = tmpbuf;
01341          tmp = tmp_name;
01342          while ((tmp = strchr(tmp, '_')))
01343             *tmp++ = '-';
01344       } else
01345          tmp_name = v->name;
01346 
01347       /* NULL values don't get returned from realtime; blank values should
01348        * still get set.  If someone doesn't want a value to be set, they
01349        * should set the realtime column to NULL, not blank. */
01350       queue_set_param(q, tmp_name, v->value, -1, 0);
01351    }
01352 
01353    if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
01354       rr_dep_warning();
01355 
01356    /* Temporarily set realtime members dead so we can detect deleted ones. 
01357     * Also set the membercount correctly for realtime*/
01358    mem_iter = ao2_iterator_init(q->members, 0);
01359    while ((m = ao2_iterator_next(&mem_iter))) {
01360       q->membercount++;
01361       if (m->realtime)
01362          m->dead = 1;
01363       ao2_ref(m, -1);
01364    }
01365    ao2_iterator_destroy(&mem_iter);
01366 
01367    while ((interface = ast_category_browse(member_config, interface))) {
01368       rt_handle_member_record(q, interface,
01369          ast_variable_retrieve(member_config, interface, "membername"),
01370          ast_variable_retrieve(member_config, interface, "penalty"),
01371          ast_variable_retrieve(member_config, interface, "paused"),
01372          S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
01373    }
01374 
01375    /* Delete all realtime members that have been deleted in DB. */
01376    mem_iter = ao2_iterator_init(q->members, 0);
01377    while ((m = ao2_iterator_next(&mem_iter))) {
01378       if (m->dead) {
01379          ao2_unlink(q->members, m);
01380          ao2_unlock(q);
01381          remove_from_interfaces(m->state_interface);
01382          ao2_lock(q);
01383          q->membercount--;
01384       }
01385       ao2_ref(m, -1);
01386    }
01387    ao2_iterator_destroy(&mem_iter);
01388 
01389    ao2_unlock(q);
01390 
01391    return q;
01392 }

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

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

01229 {
01230    /* Free non-dynamic members */
01231    struct member *cur;
01232    struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
01233 
01234    while ((cur = ao2_iterator_next(&mem_iter))) {
01235       if (all || !cur->dynamic) {
01236          ao2_unlink(q->members, cur);
01237          remove_from_interfaces(cur->state_interface);
01238          q->membercount--;
01239       }
01240       ao2_ref(cur, -1);
01241    }
01242    ao2_iterator_destroy(&mem_iter);
01243 }

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

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, 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().

00585 {
00586    struct member *member;
00587    struct ao2_iterator mem_iter;
00588    enum queue_member_status result = QUEUE_NO_MEMBERS;
00589    int allpaused = 1, empty = 1;
00590 
00591    ao2_lock(q);
00592    mem_iter = ao2_iterator_init(q->members, 0);
00593    while ((member = ao2_iterator_next(&mem_iter))) {
00594       empty = 0;
00595 
00596       if (max_penalty && (member->penalty > max_penalty)) {
00597          ao2_ref(member, -1);
00598          continue;
00599       }
00600 
00601       if (member->paused) {
00602          ao2_ref(member, -1);
00603          continue;
00604       } else {
00605          allpaused = 0;
00606       }
00607 
00608       switch (member->status) {
00609       case AST_DEVICE_INVALID:
00610          /* nothing to do */
00611          ao2_ref(member, -1);
00612          break;
00613       case AST_DEVICE_UNAVAILABLE:
00614          result = QUEUE_NO_REACHABLE_MEMBERS;
00615          ao2_ref(member, -1);
00616          break;
00617       default:
00618          ao2_unlock(q);
00619          ao2_ref(member, -1);
00620          return QUEUE_NORMAL;
00621       }
00622    }
00623    ao2_iterator_destroy(&mem_iter);
00624    ao2_unlock(q);
00625 
00626    if (!empty && allpaused) {
00627       result = QUEUE_NO_REACHABLE_MEMBERS;
00628    }
00629    return result;
00630 }

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

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

05245 {
05246    char *queuename, *interface, *membername = NULL, *state_interface = NULL;
05247    int penalty;
05248 
05249    if ((argc != 6) && (argc != 8) && (argc != 10) && (argc != 12)) {
05250       return RESULT_SHOWUSAGE;
05251    } else if (strcmp(argv[4], "to")) {
05252       return RESULT_SHOWUSAGE;
05253    } else if ((argc == 8) && strcmp(argv[6], "penalty")) {
05254       return RESULT_SHOWUSAGE;
05255    } else if ((argc == 10) && strcmp(argv[8], "as")) {
05256       return RESULT_SHOWUSAGE;
05257    } else if ((argc == 12) && strcmp(argv[10], "state_interface")) {
05258       return RESULT_SHOWUSAGE;
05259    }
05260 
05261    queuename = argv[5];
05262    interface = argv[3];
05263    if (argc >= 8) {
05264       if (sscanf(argv[7], "%30d", &penalty) == 1) {
05265          if (penalty < 0) {
05266             ast_cli(fd, "Penalty must be >= 0\n");
05267             penalty = 0;
05268          }
05269       } else {
05270          ast_cli(fd, "Penalty must be an integer >= 0\n");
05271          penalty = 0;
05272       }
05273    } else {
05274       penalty = 0;
05275    }
05276 
05277    if (argc >= 10) {
05278       membername = argv[9];
05279    }
05280 
05281    if (argc >= 12) {
05282       state_interface = argv[11];
05283    }
05284 
05285    switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
05286    case RES_OKAY:
05287       ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
05288       ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
05289       return RESULT_SUCCESS;
05290    case RES_EXISTS:
05291       ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
05292       return RESULT_FAILURE;
05293    case RES_NOSUCHQUEUE:
05294       ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
05295       return RESULT_FAILURE;
05296    case RES_OUTOFMEMORY:
05297       ast_cli(fd, "Out of memory\n");
05298       return RESULT_FAILURE;
05299    default:
05300       return RESULT_FAILURE;
05301    }
05302 }

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

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

05338 {
05339    char *queuename, *interface;
05340 
05341    if (argc != 6) {
05342       return RESULT_SHOWUSAGE;
05343    } else if (strcmp(argv[4], "from")) {
05344       return RESULT_SHOWUSAGE;
05345    }
05346 
05347    queuename = argv[5];
05348    interface = argv[3];
05349 
05350    switch (remove_from_queue(queuename, interface)) {
05351    case RES_OKAY:
05352       ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
05353       ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
05354       return RESULT_SUCCESS;
05355    case RES_EXISTS:
05356       ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
05357       return RESULT_FAILURE;
05358    case RES_NOSUCHQUEUE:
05359       ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
05360       return RESULT_FAILURE;
05361    case RES_OUTOFMEMORY:
05362       ast_cli(fd, "Out of memory\n");
05363       return RESULT_FAILURE;
05364    case RES_NOT_DYNAMIC:
05365       ast_cli(fd, "Member not dynamic\n");
05366       return RESULT_FAILURE;
05367    default:
05368       return RESULT_FAILURE;
05369    }
05370 }

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

00693 {
00694    struct member_interface *curint;
00695    char *loc;
00696    char *technology;
00697    char interface[80];
00698 
00699    technology = ast_strdupa(sc->dev);
00700    loc = strchr(technology, '/');
00701    if (loc) {
00702       *loc++ = '\0';
00703    } else {
00704       return NULL;
00705    }
00706 
00707    AST_LIST_LOCK(&interfaces);
00708    AST_LIST_TRAVERSE(&interfaces, curint, list) {
00709       char *slash_pos;
00710       ast_copy_string(interface, curint->interface, sizeof(interface));
00711       if ((slash_pos = strchr(interface, '/')))
00712          if ((slash_pos = strchr(slash_pos + 1, '/')))
00713             *slash_pos = '\0';
00714 
00715       if (!strcasecmp(interface, sc->dev))
00716          break;
00717    }
00718    AST_LIST_UNLOCK(&interfaces);
00719 
00720    if (!curint) {
00721       if (option_debug > 2)
00722          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));
00723       return NULL;
00724    }
00725 
00726    if (option_debug)
00727       ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
00728 
00729    update_status(sc->dev, sc->state);
00730 
00731    return NULL;
00732 }

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

Definition at line 1801 of file app_queue.c.

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

01802 {
01803    struct callattempt *oo;
01804 
01805    while (outgoing) {
01806       /* Hangup any existing lines we have open */
01807       if (outgoing->chan && (outgoing->chan != exception))
01808          ast_hangup(outgoing->chan);
01809       oo = outgoing;
01810       outgoing = outgoing->q_next;
01811       if (oo->member)
01812          ao2_ref(oo->member, -1);
01813       free(oo);
01814    }
01815 }

static void init_queue ( struct call_queue q  )  [static]

Definition at line 868 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, QUEUE_STRATEGY_RRORDERED, 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::strategy, call_queue::timeout, call_queue::timeoutrestart, call_queue::weight, and call_queue::wrapuptime.

Referenced by reload_queues().

00869 {
00870    int i;
00871 
00872    q->dead = 0;
00873    q->retry = DEFAULT_RETRY;
00874    q->timeout = -1;
00875    q->maxlen = 0;
00876    q->ringlimit = 0;
00877    q->announcefrequency = 0;
00878    q->announceholdtime = 0;
00879    q->roundingseconds = 0; /* Default - don't announce seconds */
00880    q->servicelevel = 0;
00881    q->ringinuse = 1;
00882    q->setinterfacevar = 0;
00883    q->autofill = autofill_default;
00884    q->montype = montype_default;
00885    q->moh[0] = '\0';
00886    q->announce[0] = '\0';
00887    q->context[0] = '\0';
00888    q->monfmt[0] = '\0';
00889    q->periodicannouncefrequency = 0;
00890    q->reportholdtime = 0;
00891    q->monjoin = 0;
00892    q->wrapuptime = 0;
00893    q->joinempty = 0;
00894    q->leavewhenempty = 0;
00895    q->memberdelay = 0;
00896    q->maskmemberstatus = 0;
00897    q->eventwhencalled = 0;
00898    q->weight = 0;
00899    q->timeoutrestart = 0;
00900    if (!q->members) {
00901       if (q->strategy == QUEUE_STRATEGY_RRORDERED) {
00902          q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
00903       } else {
00904          q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
00905       }
00906    }
00907    q->membercount = 0;
00908    q->found = 1;
00909    ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
00910    ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
00911    ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
00912    ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
00913    ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
00914    ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
00915    ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
00916    ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
00917    ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
00918    ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
00919    for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
00920       q->sound_periodicannounce[i][0]='\0';
00921    }
00922 }

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

References ao2_ref(), call_queue::head, and queue_ent::next.

Referenced by join_queue().

00549 {
00550    struct queue_ent *cur;
00551 
00552    if (!q || !new)
00553       return;
00554    if (prev) {
00555       cur = prev->next;
00556       prev->next = new;
00557    } else {
00558       cur = q->head;
00559       q->head = new;
00560    }
00561    new->next = cur;
00562 
00563    /* every queue_ent must have a reference to it's parent call_queue, this
00564     * reference does not go away until the end of the queue_ent's life, meaning
00565     * that even when the queue_ent leaves the call_queue this ref must remain. */
00566    ao2_ref(q, +1);
00567    new->parent = q;
00568    new->pos = ++(*pos);
00569    new->opos = *pos;
00570 }

static char* int2strat ( int  strategy  )  [static]

Definition at line 502 of file app_queue.c.

References name, and strategies.

Referenced by __queues_show().

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

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

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

03494 {
03495    struct member *mem;
03496    struct ao2_iterator mem_iter;
03497 
03498    if (!q)
03499       return NULL;
03500 
03501    mem_iter = ao2_iterator_init(q->members, 0);
03502    while ((mem = ao2_iterator_next(&mem_iter))) {
03503       if (!strcasecmp(interface, mem->interface)) {
03504          ao2_iterator_destroy(&mem_iter);
03505          return mem;
03506       }
03507       ao2_ref(mem, -1);
03508    }
03509    ao2_iterator_destroy(&mem_iter);
03510 
03511    return NULL;
03512 }

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

Definition at line 960 of file app_queue.c.

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

Referenced by remove_from_interfaces().

00961 {
00962    struct call_queue *q;
00963    struct member *mem;
00964    struct ao2_iterator mem_iter;
00965    int ret = 0;
00966 
00967    AST_LIST_LOCK(&queues);
00968    AST_LIST_TRAVERSE(&queues, q, list) {
00969       ao2_lock(q);
00970       mem_iter = ao2_iterator_init(q->members, 0);
00971       while ((mem = ao2_iterator_next(&mem_iter))) {
00972          if (!strcasecmp(mem->state_interface, interface)) {
00973             ao2_ref(mem, -1);
00974             ret = 1;
00975             break;
00976          }
00977          ao2_ref(mem, -1);
00978       }
00979       ao2_iterator_destroy(&mem_iter);
00980       ao2_unlock(q);
00981       if (ret)
00982          break;
00983    }
00984    AST_LIST_UNLOCK(&queues);
00985 
00986    return ret;
00987 }

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

References ao2_lock(), ao2_unlock(), ast_log(), call_queue::autofill, queue_ent::chan, call_queue::head, LOG_DEBUG, ast_channel::name, queue_ent::next, num_available_members(), option_debug, queue_ent::parent, queue_ent::pending, and queue_ent::pos.

Referenced by queue_exec(), and wait_our_turn().

02555 {
02556    struct queue_ent *ch;
02557    int res;
02558    int avl;
02559    int idx = 0;
02560    /* This needs a lock. How many members are available to be served? */
02561    ao2_lock(qe->parent);
02562 
02563    avl = num_available_members(qe->parent);
02564 
02565    ch = qe->parent->head;
02566 
02567    if (option_debug) {
02568       ast_log(LOG_DEBUG, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
02569    }
02570 
02571    while ((idx < avl) && (ch) && (ch != qe)) {
02572       if (!ch->pending)
02573          idx++;
02574       ch = ch->next;       
02575    }
02576 
02577    ao2_unlock(qe->parent);
02578    /* If the queue entry is within avl [the number of available members] calls from the top ... 
02579     * Autofill and position check added to support autofill=no (as only calls
02580     * from the front of the queue are valid when autofill is disabled)
02581     */
02582    if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
02583       if (option_debug)
02584          ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
02585       res = 1;
02586    } else {
02587       if (option_debug)
02588          ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
02589       res = 0;
02590    }
02591 
02592    return res;
02593 }

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

Definition at line 1515 of file app_queue.c.

References queue_ent::announce, ao2_lock(), ao2_unlock(), ast_copy_string(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), 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(), 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().

01516 {
01517    struct call_queue *q;
01518    struct queue_ent *cur, *prev = NULL;
01519    int res = -1;
01520    int pos = 0;
01521    int inserted = 0;
01522    enum queue_member_status stat;
01523 
01524    if (!(q = load_realtime_queue(queuename)))
01525       return res;
01526 
01527    AST_LIST_LOCK(&queues);
01528    ao2_lock(q);
01529 
01530    /* This is our one */
01531    stat = get_member_status(q, qe->max_penalty);
01532    if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
01533       *reason = QUEUE_JOINEMPTY;
01534    else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS))
01535       *reason = QUEUE_JOINUNAVAIL;
01536    else if (q->maxlen && (q->count >= q->maxlen))
01537       *reason = QUEUE_FULL;
01538    else {
01539       /* There's space for us, put us at the right position inside
01540        * the queue.
01541        * Take into account the priority of the calling user */
01542       inserted = 0;
01543       prev = NULL;
01544       cur = q->head;
01545       while (cur) {
01546          /* We have higher priority than the current user, enter
01547           * before him, after all the other users with priority
01548           * higher or equal to our priority. */
01549          if ((!inserted) && (qe->prio > cur->prio)) {
01550             insert_entry(q, prev, qe, &pos);
01551             inserted = 1;
01552          }
01553          cur->pos = ++pos;
01554          prev = cur;
01555          cur = cur->next;
01556       }
01557       /* No luck, join at the end of the queue */
01558       if (!inserted)
01559          insert_entry(q, prev, qe, &pos);
01560       ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
01561       ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
01562       ast_copy_string(qe->context, q->context, sizeof(qe->context));
01563       q->count++;
01564       res = 0;
01565       manager_event(EVENT_FLAG_CALL, "Join",
01566          "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
01567          qe->chan->name,
01568          S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
01569          S_OR(qe->chan->cid.cid_name, "unknown"),
01570          q->name, qe->pos, q->count, qe->chan->uniqueid );
01571       if (option_debug)
01572          ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
01573    }
01574    ao2_unlock(q);
01575    AST_LIST_UNLOCK(&queues);
01576 
01577    return res;
01578 }

static void leave_queue ( struct queue_ent qe  )  [static]

Definition at line 1760 of file app_queue.c.

References ao2_lock(), ao2_unlock(), ast_log(), queue_ent::chan, call_queue::count, call_queue::dead, EVENT_FLAG_CALL, call_queue::head, LOG_DEBUG, manager_event(), call_queue::name, ast_channel::name, queue_ent::next, option_debug, queue_ent::parent, queue_ent::pos, remove_queue(), and ast_channel::uniqueid.

Referenced by queue_exec(), and wait_our_turn().

01761 {
01762    struct call_queue *q;
01763    struct queue_ent *cur, *prev = NULL;
01764    int pos = 0;
01765 
01766    if (!(q = qe->parent))
01767       return;
01768    ao2_lock(q);
01769 
01770    prev = NULL;
01771    for (cur = q->head; cur; cur = cur->next) {
01772       if (cur == qe) {
01773          q->count--;
01774 
01775          /* Take us out of the queue */
01776          manager_event(EVENT_FLAG_CALL, "Leave",
01777             "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
01778             qe->chan->name, q->name,  q->count, qe->chan->uniqueid);
01779          if (option_debug)
01780             ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
01781          /* Take us out of the queue */
01782          if (prev)
01783             prev->next = cur->next;
01784          else
01785             q->head = cur->next;
01786       } else {
01787          /* Renumber the people after us in the queue based on a new count */
01788          cur->pos = ++pos;
01789          prev = cur;
01790       }
01791    }
01792    ao2_unlock(q);
01793 
01794    if (q->dead && !q->count) {   
01795       /* It's dead and nobody is in it, so kill it */
01796       remove_queue(q);
01797    }
01798 }

static int load_module ( void   )  [static]

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

05627 {
05628    int res;
05629 
05630    if (!reload_queues())
05631       return AST_MODULE_LOAD_DECLINE;
05632 
05633    if (queue_persistent_members)
05634       reload_queue_members();
05635 
05636    ast_mutex_init(&device_state.lock);
05637    ast_cond_init(&device_state.cond, NULL);
05638    ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL);
05639 
05640    ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
05641    res = ast_register_application(app, queue_exec, synopsis, descrip);
05642    res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip);
05643    res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip);
05644    res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip);
05645    res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip);
05646    res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip);
05647    res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues");
05648    res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status");
05649    res |= ast_manager_register("QueueMemberCount", 0, manager_queue_member_count, "Queue Member Count");
05650    res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue.");
05651    res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
05652    res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
05653    res |= ast_custom_function_register(&queueagentcount_function);
05654    res |= ast_custom_function_register(&queuemembercount_function);
05655    res |= ast_custom_function_register(&queuememberlist_function);
05656    res |= ast_custom_function_register(&queuewaitingcount_function);
05657    res |= ast_devstate_add(statechange_queue, NULL);
05658 
05659    return res;
05660 }

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

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

01466 {
01467    struct ast_variable *queue_vars;
01468    struct ast_config *member_config = NULL;
01469    struct call_queue *q;
01470 
01471    /* Find the queue in the in-core list first. */
01472    AST_LIST_LOCK(&queues);
01473    AST_LIST_TRAVERSE(&queues, q, list) {
01474       if (!strcasecmp(q->name, queuename)) {
01475          break;
01476       }
01477    }
01478    AST_LIST_UNLOCK(&queues);
01479 
01480    if (!q || q->realtime) {
01481       /*! \note Load from realtime before taking the global qlock, to avoid blocking all
01482          queue operations while waiting for the DB.
01483 
01484          This will be two separate database transactions, so we might
01485          see queue parameters as they were before another process
01486          changed the queue and member list as it was after the change.
01487          Thus we might see an empty member list when a queue is
01488          deleted. In practise, this is unlikely to cause a problem. */
01489 
01490       queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
01491       if (queue_vars) {
01492          member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
01493          if (!member_config) {
01494             ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
01495             ast_variables_destroy(queue_vars);
01496             return NULL;
01497          }
01498       }
01499 
01500       AST_LIST_LOCK(&queues);
01501 
01502       q = find_queue_by_name_rt(queuename, queue_vars, member_config);
01503       if (member_config)
01504          ast_config_destroy(member_config);
01505       if (queue_vars)
01506          ast_variables_destroy(queue_vars);
01507 
01508       AST_LIST_UNLOCK(&queues);
01509    } else { 
01510       update_realtime_members(q);
01511    }
01512    return q;
01513 }

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

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

05137 {
05138    const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
05139    int paused, penalty = 0;
05140 
05141    queuename = astman_get_header(m, "Queue");
05142    interface = astman_get_header(m, "Interface");
05143    penalty_s = astman_get_header(m, "Penalty");
05144    paused_s = astman_get_header(m, "Paused");
05145    membername = astman_get_header(m, "MemberName");
05146    state_interface = astman_get_header(m, "StateInterface");
05147 
05148    if (ast_strlen_zero(queuename)) {
05149       astman_send_error(s, m, "'Queue' not specified.");
05150       return 0;
05151    }
05152 
05153    if (ast_strlen_zero(interface)) {
05154       astman_send_error(s, m, "'Interface' not specified.");
05155       return 0;
05156    }
05157 
05158    if (ast_strlen_zero(penalty_s))
05159       penalty = 0;
05160    else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0)
05161       penalty = 0;
05162 
05163    if (ast_strlen_zero(paused_s))
05164       paused = 0;
05165    else
05166       paused = abs(ast_true(paused_s));
05167 
05168    switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
05169    case RES_OKAY:
05170       ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
05171       astman_send_ack(s, m, "Added interface to queue");
05172       break;
05173    case RES_EXISTS:
05174       astman_send_error(s, m, "Unable to add interface: Already there");
05175       break;
05176    case RES_NOSUCHQUEUE:
05177       astman_send_error(s, m, "Unable to add interface to queue: No such queue");
05178       break;
05179    case RES_OUTOFMEMORY:
05180       astman_send_error(s, m, "Out of memory");
05181       break;
05182    }
05183 
05184    return 0;
05185 }

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

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

05222 {
05223    const char *queuename, *interface, *paused_s;
05224    int paused;
05225 
05226    interface = astman_get_header(m, "Interface");
05227    paused_s = astman_get_header(m, "Paused");
05228    queuename = astman_get_header(m, "Queue");   /* Optional - if not supplied, pause the given Interface in all queues */
05229 
05230    if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
05231       astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
05232       return 0;
05233    }
05234 
05235    paused = abs(ast_true(paused_s));
05236 
05237    if (set_member_paused(queuename, interface, paused))
05238       astman_send_error(s, m, "Interface not found");
05239    else
05240       astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
05241    return 0;
05242 }

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

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

05482 {
05483    char buffer[256] = "";
05484    const char *queuename = astman_get_header(m,"Queue");
05485 
05486    if (ast_strlen_zero(queuename)) {
05487          astman_send_error(s, m, "'Queue' not specified.");
05488          return 0;
05489    }
05490    if (qmc_handler(queuename, buffer, sizeof(buffer)) == RESULT_SUCCESS) {
05491          astman_send_ack(s, m, buffer);
05492          return RESULT_SUCCESS;
05493    } else {
05494          astman_send_error(s, m, "Queue not found.");
05495          return 0;
05496    }
05497 }

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

Definition at line 5030 of file app_queue.c.

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

Referenced by load_module().

05031 {
05032    char *a[] = { "queue", "show" };
05033 
05034    __queues_show(s, 1, -1, 2, a);
05035    astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
05036 
05037    return RESULT_SUCCESS;
05038 }

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

Definition at line 5041 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_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::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().

05042 {
05043    time_t now;
05044    int pos;
05045    const char *id = astman_get_header(m,"ActionID");
05046    const char *queuefilter = astman_get_header(m,"Queue");
05047    const char *memberfilter = astman_get_header(m,"Member");
05048    char idText[256] = "";
05049    struct call_queue *q;
05050    struct queue_ent *qe;
05051    float sl = 0;
05052    struct member *mem;
05053    struct ao2_iterator mem_iter;
05054 
05055    astman_send_ack(s, m, "Queue status will follow");
05056    time(&now);
05057    AST_LIST_LOCK(&queues);
05058    if (!ast_strlen_zero(id))
05059       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
05060 
05061    AST_LIST_TRAVERSE(&queues, q, list) {
05062       ao2_lock(q);
05063 
05064       /* List queue properties */
05065       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
05066          sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
05067          astman_append(s, "Event: QueueParams\r\n"
05068             "Queue: %s\r\n"
05069             "Max: %d\r\n"
05070             "Calls: %d\r\n"
05071             "Holdtime: %d\r\n"
05072             "Completed: %d\r\n"
05073             "Abandoned: %d\r\n"
05074             "ServiceLevel: %d\r\n"
05075             "ServicelevelPerf: %2.1f\r\n"
05076             "RingLimit: %d\r\n"
05077             "Weight: %d\r\n"
05078             "%s"
05079             "\r\n",
05080             q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
05081             q->callsabandoned, q->servicelevel, sl,  q->ringlimit, q->weight, idText);
05082          /* List Queue Members */
05083          mem_iter = ao2_iterator_init(q->members, 0);
05084          while ((mem = ao2_iterator_next(&mem_iter))) {
05085             if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
05086                astman_append(s, "Event: QueueMember\r\n"
05087                   "Queue: %s\r\n"
05088                   "Name: %s\r\n"
05089                   "Location: %s\r\n"
05090                   "Membership: %s\r\n"
05091                   "Penalty: %d\r\n"
05092                   "CallsTaken: %d\r\n"
05093                   "LastCall: %d\r\n"
05094                   "Status: %d\r\n"
05095                   "Paused: %d\r\n"
05096                   "%s"
05097                   "\r\n",
05098                   q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
05099                   mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
05100             }
05101             ao2_ref(mem, -1);
05102          }
05103          ao2_iterator_destroy(&mem_iter);
05104          /* List Queue Entries */
05105          pos = 1;
05106          for (qe = q->head; qe; qe = qe->next) {
05107             astman_append(s, "Event: QueueEntry\r\n"
05108                "Queue: %s\r\n"
05109                "Position: %d\r\n"
05110                "Channel: %s\r\n"
05111                "CallerID: %s\r\n"
05112                "CallerIDName: %s\r\n"
05113                "Wait: %ld\r\n"
05114                "%s"
05115                "\r\n",
05116                q->name, pos++, qe->chan->name,
05117                S_OR(qe->chan->cid.cid_num, "unknown"),
05118                S_OR(qe->chan->cid.cid_name, "unknown"),
05119                (long) (now - qe->start), idText);
05120          }
05121       }
05122       ao2_unlock(q);
05123    }
05124 
05125    astman_append(s,
05126       "Event: QueueStatusComplete\r\n"
05127       "%s"
05128       "\r\n",idText);
05129 
05130    AST_LIST_UNLOCK(&queues);
05131 
05132 
05133    return RESULT_SUCCESS;
05134 }

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

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

05188 {
05189    const char *queuename, *interface;
05190 
05191    queuename = astman_get_header(m, "Queue");
05192    interface = astman_get_header(m, "Interface");
05193 
05194    if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
05195       astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
05196       return 0;
05197    }
05198 
05199    switch (remove_from_queue(queuename, interface)) {
05200    case RES_OKAY:
05201       ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
05202       astman_send_ack(s, m, "Removed interface from queue");
05203       break;
05204    case RES_EXISTS:
05205       astman_send_error(s, m, "Unable to remove interface: Not there");
05206       break;
05207    case RES_NOSUCHQUEUE:
05208       astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
05209       break;
05210    case RES_OUTOFMEMORY:
05211       astman_send_error(s, m, "Out of memory");
05212       break;
05213    case RES_NOT_DYNAMIC:
05214       astman_send_error(s, m, "Member not dynamic");
05215       break;
05216    }
05217 
05218    return 0;
05219 }

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

Definition at line 862 of file app_queue.c.

References member::interface.

Referenced by init_queue().

00863 {
00864    struct member *mem1 = obj1, *mem2 = obj2;
00865    return strcmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
00866 }

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

Definition at line 850 of file app_queue.c.

References compress_char(), and member::interface.

Referenced by init_queue().

00851 {
00852    const struct member *mem = obj;
00853    const char *chname = strchr(mem->interface, '/');
00854    int ret = 0, i;
00855    if (!chname)
00856       chname = mem->interface;
00857    for (i = 0; i < 5 && chname[i]; i++)
00858       ret += compress_char(chname[i]) << (i * 6);
00859    return ret;
00860 }

static void monjoin_dep_warning ( void   )  [static]

Definition at line 481 of file app_queue.c.

References ast_log(), and LOG_NOTICE.

Referenced by queue_set_param().

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

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 1825 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_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_RINGINUSE, 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().

01826 {
01827    struct member *mem;
01828    int avl = 0;
01829    struct ao2_iterator mem_iter;
01830 
01831    mem_iter = ao2_iterator_init(q->members, 0);
01832    while ((mem = ao2_iterator_next(&mem_iter))) {
01833       switch (mem->status) {
01834       case AST_DEVICE_INUSE:
01835          if (!q->ringinuse)
01836             break;
01837          /* else fall through */
01838       case AST_DEVICE_NOT_INUSE:
01839       case AST_DEVICE_ONHOLD:
01840       case AST_DEVICE_RINGINUSE:
01841       case AST_DEVICE_RINGING:
01842       case AST_DEVICE_UNKNOWN:
01843          if (!mem->paused) {
01844             avl++;
01845          }
01846          break;
01847       }
01848       ao2_ref(mem, -1);
01849 
01850       /* If autofill is not enabled or if the queue's strategy is ringall, then
01851        * we really don't care about the number of available members so much as we
01852        * do that there is at least one available.
01853        *
01854        * In fact, we purposely will return from this function stating that only
01855        * one member is available if either of those conditions hold. That way,
01856        * functions which determine what action to take based on the number of available
01857        * members will operate properly. The reasoning is that even if multiple
01858        * members are available, only the head caller can actually be serviced.
01859        */
01860       if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
01861          break;
01862       }
01863    }
01864    ao2_iterator_destroy(&mem_iter);
01865 
01866    return avl;
01867 }

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

Definition at line 1580 of file app_queue.c.

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

Referenced by say_periodic_announcement(), and say_position().

01581 {
01582    int res;
01583 
01584    if (ast_strlen_zero(filename)) {
01585       return 0;
01586    }
01587 
01588    if (!ast_fileexists(filename, NULL, chan->language)) {
01589       return 0;
01590    }
01591 
01592    ast_stopstream(chan);
01593 
01594    res = ast_streamfile(chan, filename, chan->language);
01595    if (!res)
01596       res = ast_waitstream(chan, AST_DIGIT_ANY);
01597 
01598    ast_stopstream(chan);
01599 
01600    return res;
01601 }

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

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

03811 {
03812    struct ast_module_user *lu;
03813    char *parse;
03814    int priority_jump = 0;
03815    int ignore_fail = 0;
03816    AST_DECLARE_APP_ARGS(args,
03817       AST_APP_ARG(queuename);
03818       AST_APP_ARG(interface);
03819       AST_APP_ARG(options);
03820    );
03821 
03822    if (ast_strlen_zero(data)) {
03823       ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
03824       return -1;
03825    }
03826 
03827    parse = ast_strdupa(data);
03828 
03829    AST_STANDARD_APP_ARGS(args, parse);
03830 
03831    lu = ast_module_user_add(chan);
03832 
03833    if (args.options) {
03834       if (strchr(args.options, 'j'))
03835          priority_jump = 1;
03836       if (strchr(args.options, 'i'))
03837          ignore_fail = 1;
03838    }
03839 
03840    if (ast_strlen_zero(args.interface)) {
03841       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
03842       ast_module_user_remove(lu);
03843       return -1;
03844    }
03845 
03846    if (set_member_paused(args.queuename, args.interface, 1)) {
03847       ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
03848       pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
03849       if (priority_jump || ast_opt_priority_jumping) {
03850          if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
03851             ast_module_user_remove(lu);
03852             return 0;
03853          }
03854       }
03855       ast_module_user_remove(lu);
03856       if (ignore_fail) {
03857          return 0;
03858       } else {
03859          return -1;
03860       }
03861    }
03862 
03863    ast_module_user_remove(lu);
03864    pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
03865    return 0;
03866 }

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

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

04069 {
04070    struct ast_module_user *u;
04071    char *parse;
04072 
04073    AST_DECLARE_APP_ARGS(args,
04074       AST_APP_ARG(queuename);
04075       AST_APP_ARG(uniqueid);
04076       AST_APP_ARG(membername);
04077       AST_APP_ARG(event);
04078       AST_APP_ARG(params);
04079    );
04080 
04081    if (ast_strlen_zero(data)) {
04082       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n");
04083       return -1;
04084    }
04085 
04086    u = ast_module_user_add(chan);
04087 
04088    parse = ast_strdupa(data);
04089 
04090    AST_STANDARD_APP_ARGS(args, parse);
04091 
04092    if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
04093        || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
04094       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n");
04095       ast_module_user_remove(u);
04096       return -1;
04097    }
04098 
04099    ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 
04100       "%s", args.params ? args.params : "");
04101 
04102    ast_module_user_remove(u);
04103 
04104    return 0;
04105 }

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

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

05467 {
05468       struct member_count qmc;
05469       memset(&qmc, 0, sizeof(qmc));
05470       if (queue_member_count(queuename, &qmc) != 0) {
05471             return RESULT_FAILURE; 
05472       } else {
05473             snprintf(buffer, len, 
05474                          "valid:%d inuse:%d paused:%d active:%d free:%d all:%d",
05475                          qmc.valid, qmc.inuse, qmc.paused, qmc.active, qmc.free, qmc.all);   
05476             return RESULT_SUCCESS;
05477       }
05478 }

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

References call_queue::announcefrequency, AST_APP_ARG, 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, queue_ent::digits, queue_ent::expire, get_member_status(), queue_ent::handled, is_our_turn(), join_queue(), queue_ent::last_periodic_announce_sound, queue_ent::last_periodic_announce_time, queue_ent::last_pos, queue_ent::last_pos_said, leave_queue(), call_queue::leavewhenempty, LOG_DEBUG, LOG_WARNING, queue_ent::max_penalty, call_queue::membercount, queue_ent::moh, ast_channel::name, queue_ent::opos, option_verbose, queue_ent::parent, parse(), pbx_builtin_getvar_helper(), call_queue::periodicannouncefrequency, queue_ent::pos, queue_ent::prio, QUEUE_EMPTY_STRICT, QUEUE_LEAVEEMPTY, QUEUE_LEAVEUNAVAIL, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_TIMEOUT, QUEUE_UNKNOWN, record_abandoned(), queue_ent::ring_when_ringing, S_OR, say_periodic_announcement(), say_position(), set_queue_result(), queue_ent::start, stop, try_calling(), ast_channel::uniqueid, update_realtime_members(), queue_ent::valid_digits, VERBOSE_PREFIX_3, wait_a_bit(), and wait_our_turn().

Referenced by load_module().

04120 {
04121    int res=-1;
04122    int ringing=0;
04123    struct ast_module_user *lu;
04124    const char *user_priority;
04125    const char *max_penalty_str;
04126    int prio;
04127    int max_penalty;
04128    enum queue_result reason = QUEUE_UNKNOWN;
04129    /* whether to exit Queue application after the timeout hits */
04130    int tries = 0;
04131    int noption = 0;
04132    char *parse;
04133    AST_DECLARE_APP_ARGS(args,
04134       AST_APP_ARG(queuename);
04135       AST_APP_ARG(options);
04136       AST_APP_ARG(url);
04137       AST_APP_ARG(announceoverride);
04138       AST_APP_ARG(queuetimeoutstr);
04139       AST_APP_ARG(agi);
04140    );
04141    /* Our queue entry */
04142    struct queue_ent qe = { 0 };
04143    
04144    if (ast_strlen_zero(data)) {
04145       ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n");
04146       return -1;
04147    }
04148    
04149    parse = ast_strdupa(data);
04150    AST_STANDARD_APP_ARGS(args, parse);
04151 
04152    lu = ast_module_user_add(chan);
04153 
04154    /* Setup our queue entry */
04155    qe.start = time(NULL);
04156 
04157    /* set the expire time based on the supplied timeout; */
04158    if (!ast_strlen_zero(args.queuetimeoutstr))
04159       qe.expire = qe.start + atoi(args.queuetimeoutstr);
04160    else
04161       qe.expire = 0;
04162 
04163    /* Get the priority from the variable ${QUEUE_PRIO} */
04164    user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
04165    if (user_priority) {
04166       if (sscanf(user_priority, "%30d", &prio) == 1) {
04167          if (option_debug)
04168             ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
04169                chan->name, prio);
04170       } else {
04171          ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
04172             user_priority, chan->name);
04173          prio = 0;
04174       }
04175    } else {
04176       if (option_debug > 2)
04177          ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
04178       prio = 0;
04179    }
04180 
04181    /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
04182    if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
04183       if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
04184          if (option_debug)
04185             ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
04186                chan->name, max_penalty);
04187       } else {
04188          ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
04189             max_penalty_str, chan->name);
04190          max_penalty = 0;
04191       }
04192    } else {
04193       max_penalty = 0;
04194    }
04195 
04196    if (args.options && (strchr(args.options, 'r')))
04197       ringing = 1;
04198 
04199    if (ringing != 1 && args.options && (strchr(args.options, 'R'))) {
04200       qe.ring_when_ringing = 1;
04201    }
04202 
04203    if (option_debug)
04204       ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
04205          args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
04206 
04207    qe.chan = chan;
04208    qe.prio = prio;
04209    qe.max_penalty = max_penalty;
04210    qe.last_pos_said = 0;
04211    qe.last_pos = 0;
04212    qe.last_periodic_announce_time = time(NULL);
04213    qe.last_periodic_announce_sound = 0;
04214    qe.valid_digits = 0;
04215    if (!join_queue(args.queuename, &qe, &reason)) {
04216       int makeannouncement = 0;
04217 
04218       ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
04219          S_OR(chan->cid.cid_num, ""));
04220 check_turns:
04221       if (ringing) {
04222          ast_indicate(chan, AST_CONTROL_RINGING);
04223       } else {
04224          ast_moh_start(chan, qe.moh, NULL);
04225       }
04226 
04227       /* This is the wait loop for callers 2 through maxlen */
04228       res = wait_our_turn(&qe, ringing, &reason);
04229       if (res)
04230          goto stop;
04231 
04232       for (;;) {
04233          /* This is the wait loop for the head caller*/
04234          /* To exit, they may get their call answered; */
04235          /* they may dial a digit from the queue context; */
04236          /* or, they may timeout. */
04237 
04238          enum queue_member_status stat;
04239 
04240          /* Leave if we have exceeded our queuetimeout */
04241          if (qe.expire && (time(NULL) >= qe.expire)) {
04242             record_abandoned(&qe);
04243             reason = QUEUE_TIMEOUT;
04244             res = 0;
04245             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04246             break;
04247          }
04248 
04249          if (makeannouncement) {
04250             /* Make a position announcement, if enabled */
04251             if (qe.parent->announcefrequency && !ringing)
04252                if ((res = say_position(&qe)))
04253                   goto stop;
04254 
04255          }
04256          makeannouncement = 1;
04257 
04258          /* Leave if we have exceeded our queuetimeout */
04259          if (qe.expire && (time(NULL) >= qe.expire)) {
04260             record_abandoned(&qe);
04261             reason = QUEUE_TIMEOUT;
04262             res = 0;
04263             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04264             break;
04265          }
04266          /* Make a periodic announcement, if enabled */
04267          if (qe.parent->periodicannouncefrequency && !ringing)
04268             if ((res = say_periodic_announcement(&qe)))
04269                goto stop;
04270 
04271          /* Leave if we have exceeded our queuetimeout */
04272          if (qe.expire && (time(NULL) >= qe.expire)) {
04273             record_abandoned(&qe);
04274             reason = QUEUE_TIMEOUT;
04275             res = 0;
04276             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04277             break;
04278          }
04279          /* Try calling all queue members for 'timeout' seconds */
04280          res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi);
04281          if (res)
04282             goto stop;
04283 
04284          stat = get_member_status(qe.parent, qe.max_penalty);
04285 
04286          /* exit after 'timeout' cycle if 'n' option enabled */
04287          if (noption && tries >= qe.parent->membercount) {
04288             if (option_verbose > 2)
04289                ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
04290             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04291             record_abandoned(&qe);
04292             reason = QUEUE_TIMEOUT;
04293             res = 0;
04294             break;
04295          }
04296 
04297          /* leave the queue if no agents, if enabled */
04298          if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
04299             record_abandoned(&qe);
04300             reason = QUEUE_LEAVEEMPTY;
04301             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
04302             res = 0;
04303             break;
04304          }
04305 
04306          /* leave the queue if no reachable agents, if enabled */
04307          if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
04308             record_abandoned(&qe);
04309             reason = QUEUE_LEAVEUNAVAIL;
04310             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
04311             res = 0;
04312             break;
04313          }
04314 
04315          /* Leave if we have exceeded our queuetimeout */
04316          if (qe.expire && (time(NULL) >= qe.expire)) {
04317             record_abandoned(&qe);
04318             reason = QUEUE_TIMEOUT;
04319             res = 0;
04320             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04321             break;
04322          }
04323 
04324          /* If using dynamic realtime members, we should regenerate the member list for this queue */
04325          update_realtime_members(qe.parent);
04326 
04327          /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
04328          res = wait_a_bit(&qe);
04329          if (res)
04330             goto stop;
04331 
04332          /* Since this is a priority queue and
04333           * it is not sure that we are still at the head
04334           * of the queue, go and check for our turn again.
04335           */
04336          if (!is_our_turn(&qe)) {
04337             if (option_debug)
04338                ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
04339                   qe.chan->name);
04340             goto check_turns;
04341          }
04342       }
04343 
04344 stop:
04345       if (res) {
04346          if (res < 0) {
04347             if (!qe.handled) {
04348                record_abandoned(&qe);
04349                ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
04350                   "%d|%d|%ld", qe.pos, qe.opos,
04351                   (long) time(NULL) - qe.start);
04352             }
04353             res = -1;
04354          } else if (qe.valid_digits) {
04355             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
04356                "%s|%d", qe.digits, qe.pos);
04357          }
04358       }
04359 
04360       /* Don't allow return code > 0 */
04361       if (res >= 0) {
04362          res = 0; 
04363          if (ringing) {
04364             ast_indicate(chan, -1);
04365          } else {
04366             ast_moh_stop(chan);
04367          }        
04368          ast_stopstream(chan);
04369       }
04370       leave_queue(&qe);
04371       if (reason != QUEUE_UNKNOWN)
04372          set_queue_result(chan, reason);
04373    } else {
04374       ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
04375       set_queue_result(chan, reason);
04376       res = 0;
04377    }
04378    if (qe.parent) {
04379       /* every queue_ent is given a reference to it's parent call_queue when it joins the queue.
04380        * This ref must be taken away right before the queue_ent is destroyed.  In this case
04381        * the queue_ent is about to be returned on the stack */
04382       ao2_ref(qe.parent, -1);
04383    }
04384    ast_module_user_remove(lu);
04385 
04386    return res;
04387 }

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

Definition at line 4397 of file app_queue.c.

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

04398 {
04399    int count = 0;
04400    struct call_queue *q;
04401    struct ast_module_user *lu;
04402    struct member *m;
04403    struct ao2_iterator mem_iter;
04404    char *name, *item;
04405    enum qmc_status mode = QMC_VALID;
04406 
04407    buf[0] = '\0';
04408    
04409    if (ast_strlen_zero(data)) {
04410       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
04411       return -1;
04412    }
04413 
04414    name = ast_strdupa(data);
04415 
04416    lu = ast_module_user_add(chan);
04417 
04418    if ((item = strchr(name, ':'))) {
04419       *item = '\0';
04420       item++;
04421    } else {
04422       item = "";
04423    }
04424 
04425    if (!strcasecmp(item, "valid")) {
04426       mode = QMC_VALID;
04427    } else  if (!strcasecmp(item, "paused")) {
04428       mode = QMC_PAUSED;
04429    } else  if (!strcasecmp(item, "active")) {
04430       mode = QMC_ACTIVE;
04431    } else  if (!strcasecmp(item, "free")) {
04432       mode = QMC_FREE;
04433    } else  if (!strcasecmp(item, "all")) {
04434       mode = QMC_ALL;
04435    }
04436 
04437    if ((q = load_realtime_queue(name))) {
04438       ao2_lock(q);
04439       mem_iter = ao2_iterator_init(q->members, 0);
04440       while ((m = ao2_iterator_next(&mem_iter))) {
04441          switch (mode) {
04442          case QMC_VALID:
04443             /* Count the queue members who are logged in and presently answering calls */
04444             if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
04445                count++;
04446             }
04447             break;
04448          case QMC_PAUSED:
04449             /* Count paused members */
04450             if (m->paused) {
04451                count++;
04452             }
04453             break;
04454          case QMC_ACTIVE:
04455             /* Count not paused members who are logged in and presently answering calls */
04456             if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
04457                count++;
04458             }
04459             break;
04460          case QMC_FREE:
04461             /* Count free members in the queue */
04462             if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) {
04463                count++;
04464             }
04465             break;
04466          default:
04467             count++;
04468             break;
04469          }
04470          ao2_ref(m, -1);
04471       }
04472       ao2_iterator_destroy(&mem_iter);
04473       ao2_unlock(q);
04474    } else
04475       ast_log(LOG_WARNING, "queue %s was not found\n", name);
04476 
04477    snprintf(buf, len, "%d", count);
04478    ast_module_user_remove(lu);
04479 
04480    return 0;
04481 }

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

Definition at line 4526 of file app_queue.c.

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

04527 {
04528    struct ast_module_user *u;
04529    struct call_queue *q;
04530    struct member *m;
04531 
04532    /* Ensure an otherwise empty list doesn't return garbage */
04533    buf[0] = '\0';
04534 
04535    if (ast_strlen_zero(data)) {
04536       ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
04537       return -1;
04538    }
04539    
04540    u = ast_module_user_add(chan);
04541 
04542    AST_LIST_LOCK(&queues);
04543    AST_LIST_TRAVERSE(&queues, q, list) {
04544       if (!strcasecmp(q->name, data)) {
04545          ao2_lock(q);
04546          break;
04547       }
04548    }
04549    AST_LIST_UNLOCK(&queues);
04550 
04551    if (q) {
04552       int buflen = 0, count = 0;
04553       struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
04554 
04555       while ((m = ao2_iterator_next(&mem_iter))) {
04556          /* strcat() is always faster than printf() */
04557          if (count++) {
04558             strncat(buf + buflen, ",", len - buflen - 1);
04559             buflen++;
04560          }
04561          strncat(buf + buflen, m->interface, len - buflen - 1);
04562          buflen += strlen(m->interface);
04563          /* Safeguard against overflow (negative length) */
04564          if (buflen >= len - 2) {
04565             ao2_ref(m, -1);
04566             ast_log(LOG_WARNING, "Truncating list\n");
04567             break;
04568          }
04569          ao2_ref(m, -1);
04570       }
04571       ao2_iterator_destroy(&mem_iter);
04572       ao2_unlock(q);
04573    } else
04574       ast_log(LOG_WARNING, "queue %s was not found\n", data);
04575 
04576    /* We should already be terminated, but let's make sure. */
04577    buf[len - 1] = '\0';
04578    ast_module_user_remove(u);
04579 
04580    return 0;
04581 }

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

Definition at line 4483 of file app_queue.c.

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

04484 {
04485    int count = 0;
04486    struct call_queue *q;
04487    struct ast_module_user *lu;
04488    struct ast_variable *var = NULL;
04489 
04490    buf[0] = '\0';
04491    
04492    if (ast_strlen_zero(data)) {
04493       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
04494       return -1;
04495    }
04496 
04497    lu = ast_module_user_add(chan);
04498    
04499    AST_LIST_LOCK(&queues);
04500    AST_LIST_TRAVERSE(&queues, q, list) {
04501       if (!strcasecmp(q->name, data)) {
04502          ao2_lock(q);
04503          break;
04504       }
04505    }
04506    AST_LIST_UNLOCK(&queues);
04507 
04508    if (q) {
04509       count = q->count;
04510       ao2_unlock(q);
04511    } else if ((var = ast_load_realtime("queues", "name", data, NULL))) {
04512       /* if the queue is realtime but was not found in memory, this
04513        * means that the queue had been deleted from memory since it was 
04514        * "dead." This means it has a 0 waiting count
04515        */
04516       count = 0;
04517       ast_variables_destroy(var);
04518    } else
04519       ast_log(LOG_WARNING, "queue %s was not found\n", data);
04520 
04521    snprintf(buf, len, "%d", count);
04522    ast_module_user_remove(lu);
04523    return 0;
04524 }

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

Definition at line 5424 of file app_queue.c.

References member_count::active, member_count::all, ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_log(), member_count::free, member_count::inuse, load_realtime_queue(), LOG_WARNING, member_count::paused, member::paused, member::status, and member_count::valid.

Referenced by qmc_handler().

05425 {
05426       int res = 0;
05427       struct call_queue *q;
05428       struct member *m;
05429       struct ao2_iterator mem_iter;
05430       
05431       if ((q = load_realtime_queue(qname))) {
05432             ao2_lock(q);
05433             mem_iter = ao2_iterator_init(q->members, 0);
05434             while ((m = ao2_iterator_next(&mem_iter))) {
05435                   /* Count the queue members in use */
05436                   if (m->status == AST_DEVICE_INUSE) {
05437                         qmc->inuse++;
05438                   }
05439                   /* Count the queue members who are logged in and presently answering calls */
05440                   if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
05441                         qmc->valid++;
05442                   }
05443                   /* Count paused members */
05444                   if (m->paused) {
05445                         qmc->paused++;
05446                   }
05447                   /* Count not paused members who are logged in and presently answering calls */
05448                   if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
05449                         qmc->active++;
05450                   }
05451                   /* Count free members in the queue */
05452                   if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) {
05453                         qmc->free++;
05454                   }
05455                   qmc->all++;
05456                   ao2_ref(m, -1);
05457             }
05458             ao2_unlock(q);
05459       } else {
05460             ast_log(LOG_WARNING, "Queue %s was not found\n", qname);
05461             res = -1;
05462       }
05463       return res;
05464 }

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

01030 {
01031    if (!strcasecmp(param, "musicclass") || 
01032       !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
01033       ast_copy_string(q->moh, val, sizeof(q->moh));
01034    } else if (!strcasecmp(param, "announce")) {
01035       ast_copy_string(q->announce, val, sizeof(q->announce));
01036    } else if (!strcasecmp(param, "context")) {
01037       ast_copy_string(q->context, val, sizeof(q->context));
01038    } else if (!strcasecmp(param, "timeout")) {
01039       q->timeout = atoi(val);
01040       if (q->timeout < 0)
01041          q->timeout = DEFAULT_TIMEOUT;
01042    } else if (!strcasecmp(param, "ringinuse")) {
01043       q->ringinuse = ast_true(val);
01044    } else if (!strcasecmp(param, "setinterfacevar")) {
01045       q->setinterfacevar = ast_true(val);
01046    } else if (!strcasecmp(param, "monitor-join")) {
01047       monjoin_dep_warning();
01048       q->monjoin = ast_true(val);
01049    } else if (!strcasecmp(param, "monitor-format")) {
01050       ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
01051    } else if (!strcasecmp(param, "queue-youarenext")) {
01052       ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
01053    } else if (!strcasecmp(param, "queue-thereare")) {
01054       ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
01055    } else if (!strcasecmp(param, "queue-callswaiting")) {
01056       ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
01057    } else if (!strcasecmp(param, "queue-holdtime")) {
01058       ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
01059    } else if (!strcasecmp(param, "queue-minutes")) {
01060       ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
01061    } else if (!strcasecmp(param, "queue-seconds")) {
01062       ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
01063    } else if (!strcasecmp(param, "queue-lessthan")) {
01064       ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
01065    } else if (!strcasecmp(param, "queue-thankyou")) {
01066       ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
01067    } else if (!strcasecmp(param, "queue-reporthold")) {
01068       ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
01069    } else if (!strcasecmp(param, "announce-frequency")) {
01070       q->announcefrequency = atoi(val);
01071    } else if (!strcasecmp(param, "announce-round-seconds")) {
01072       q->roundingseconds = atoi(val);
01073       if (q->roundingseconds>60 || q->roundingseconds<0) {
01074          if (linenum >= 0) {
01075             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01076                "using 0 instead for queue '%s' at line %d of queues.conf\n",
01077                val, param, q->name, linenum);
01078          } else {
01079             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01080                "using 0 instead for queue '%s'\n", val, param, q->name);
01081          }
01082          q->roundingseconds=0;
01083       }
01084    } else if (!strcasecmp(param, "announce-holdtime")) {
01085       if (!strcasecmp(val, "once"))
01086          q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
01087       else if (ast_true(val))
01088          q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
01089       else
01090          q->announceholdtime = 0;
01091    } else if (!strcasecmp(param, "periodic-announce")) {
01092       if (strchr(val, '|')) {
01093          char *s, *buf = ast_strdupa(val);
01094          unsigned int i = 0;
01095 
01096          while ((s = strsep(&buf, "|"))) {
01097             ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i]));
01098             i++;
01099             if (i == MAX_PERIODIC_ANNOUNCEMENTS)
01100                break;
01101          }
01102       } else {
01103          ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0]));
01104       }
01105    } else if (!strcasecmp(param, "periodic-announce-frequency")) {
01106       q->periodicannouncefrequency = atoi(val);
01107    } else if (!strcasecmp(param, "retry")) {
01108       q->retry = atoi(val);
01109       if (q->retry <= 0)
01110          q->retry = DEFAULT_RETRY;
01111    } else if (!strcasecmp(param, "wrapuptime")) {
01112       q->wrapuptime = atoi(val);
01113    } else if (!strcasecmp(param, "autofill")) {
01114       q->autofill = ast_true(val);
01115    } else if (!strcasecmp(param, "monitor-type")) {
01116       if (!strcasecmp(val, "mixmonitor"))
01117          q->montype = 1;
01118    } else if (!strcasecmp(param, "autopause")) {
01119       q->autopause = ast_true(val);
01120    } else if (!strcasecmp(param, "maxlen")) {
01121       q->maxlen = atoi(val);
01122       if (q->maxlen < 0)
01123          q->maxlen = 0;
01124    } else if (!strcasecmp(param, "ringlimit")) {
01125       q->ringlimit = atoi(val);
01126       if (q->ringlimit < 0)
01127          q->ringlimit = 0;
01128    } else if (!strcasecmp(param, "servicelevel")) {
01129       q->servicelevel= atoi(val);
01130    } else if (!strcasecmp(param, "strategy")) {
01131       q->strategy = strat2int(val);
01132       if (q->strategy < 0) {
01133          ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
01134             val, q->name);
01135          q->strategy = QUEUE_STRATEGY_RINGALL;
01136       }
01137    } else if (!strcasecmp(param, "joinempty")) {
01138       if (!strcasecmp(val, "strict"))
01139          q->joinempty = QUEUE_EMPTY_STRICT;
01140       else if (ast_true(val))
01141          q->joinempty = QUEUE_EMPTY_NORMAL;
01142       else
01143          q->joinempty = 0;
01144    } else if (!strcasecmp(param, "leavewhenempty")) {
01145       if (!strcasecmp(val, "strict"))
01146          q->leavewhenempty = QUEUE_EMPTY_STRICT;
01147       else if (ast_true(val))
01148          q->leavewhenempty = QUEUE_EMPTY_NORMAL;
01149       else
01150          q->leavewhenempty = 0;
01151    } else if (!strcasecmp(param, "eventmemberstatus")) {
01152       q->maskmemberstatus = !ast_true(val);
01153    } else if (!strcasecmp(param, "eventwhencalled")) {
01154       if (!strcasecmp(val, "vars")) {
01155          q->eventwhencalled = QUEUE_EVENT_VARIABLES;
01156       } else {
01157          q->eventwhencalled = ast_true(val) ? 1 : 0;
01158       }
01159    } else if (!strcasecmp(param, "reportholdtime")) {
01160       q->reportholdtime = ast_true(val);
01161    } else if (!strcasecmp(param, "memberdelay")) {
01162       q->memberdelay = atoi(val);
01163    } else if (!strcasecmp(param, "weight")) {
01164       q->weight = atoi(val);
01165       if (q->weight)
01166          use_weight++;
01167       /* With Realtime queues, if the last queue using weights is deleted in realtime,
01168          we will not see any effect on use_weight until next reload. */
01169    } else if (!strcasecmp(param, "timeoutrestart")) {
01170       q->timeoutrestart = ast_true(val);
01171    } else if (failunknown) {
01172       if (linenum >= 0) {
01173          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
01174             q->name, param, linenum);
01175       } else {
01176          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
01177       }
01178    }
01179 }

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

Definition at line 4996 of file app_queue.c.

References __queues_show().

Referenced by __queues_show().

04997 {
04998    return __queues_show(NULL, 0, fd, argc, argv);
04999 }

static void queue_transfer_destroy ( void *  data  )  [static]

Definition at line 2766 of file app_queue.c.

References ast_free.

02767 {
02768    struct queue_transfer_ds *qtds = data;
02769    ast_free(qtds);
02770 }

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

02790 {
02791    struct queue_transfer_ds *qtds = data;
02792    struct queue_ent *qe = qtds->qe;
02793    struct member *member = qtds->member;
02794    time_t callstart = qtds->starttime;
02795    int callcompletedinsl = qtds->callcompletedinsl;
02796    struct ast_datastore *datastore;
02797 
02798    ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
02799             new_chan->exten, new_chan->context, (long) (callstart - qe->start),
02800             (long) (time(NULL) - callstart));
02801 
02802    update_queue(qe->parent, member, callcompletedinsl);
02803    
02804    /* No need to lock the channels because they are already locked in ast_do_masquerade */
02805    if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
02806       ast_channel_datastore_remove(old_chan, datastore);
02807    } else {
02808       ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
02809    }
02810 }

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

Definition at line 1745 of file app_queue.c.

References ao2_lock(), ao2_unlock(), call_queue::holdtime, and queue_ent::parent.

01746 {
01747    int oldvalue;
01748 
01749    /* Calculate holdtime using an exponential average */
01750    /* Thanks to SRT for this contribution */
01751    /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
01752 
01753    ao2_lock(qe->parent);
01754    oldvalue = qe->parent->holdtime;
01755    qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
01756    ao2_unlock(qe->parent);
01757 }

static void record_abandoned ( struct queue_ent qe  )  [static]

Definition at line 2229 of file app_queue.c.

References ao2_lock(), ao2_unlock(), call_queue::callsabandoned, queue_ent::chan, EVENT_FLAG_AGENT, 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().

02230 {
02231    ao2_lock(qe->parent);
02232    manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
02233       "Queue: %s\r\n"
02234       "Uniqueid: %s\r\n"
02235       "Position: %d\r\n"
02236       "OriginalPosition: %d\r\n"
02237       "HoldTime: %d\r\n",
02238       qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
02239 
02240    qe->parent->callsabandoned++;
02241    ao2_unlock(qe->parent);
02242 }

static int reload ( void   )  [static]

Definition at line 5662 of file app_queue.c.

References reload_queues().

05663 {
05664    reload_queues();
05665    return 0;
05666 }

static void reload_queue_members ( void   )  [static]

Definition at line 3713 of file app_queue.c.

References add_to_queue(), ao2_lock(), ao2_unlock(), ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), errno, member::interface, ast_db_entry::key, call_queue::list, load_realtime_queue(), 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().

03714 {
03715    char *cur_ptr;
03716    char *queue_name;
03717    char *member;
03718    char *interface;
03719    char *membername = NULL;
03720    char *state_interface;
03721    char *penalty_tok;
03722    int penalty = 0;
03723    char *paused_tok;
03724    int paused = 0;
03725    struct ast_db_entry *db_tree;
03726    struct ast_db_entry *entry;
03727    struct call_queue *cur_queue;
03728    char queue_data[PM_MAX_LEN];
03729 
03730    AST_LIST_LOCK(&queues);
03731 
03732    /* Each key in 'pm_family' is the name of a queue */
03733    db_tree = ast_db_gettree(pm_family, NULL);
03734    for (entry = db_tree; entry; entry = entry->next) {
03735 
03736       queue_name = entry->key + strlen(pm_family) + 2;
03737 
03738       AST_LIST_TRAVERSE(&queues, cur_queue, list) {
03739          ao2_lock(cur_queue);
03740          if (!strcmp(queue_name, cur_queue->name))
03741             break;
03742          ao2_unlock(cur_queue);
03743       }
03744       
03745       if (!cur_queue)
03746          cur_queue = load_realtime_queue(queue_name);
03747 
03748       if (!cur_queue) {
03749          /* If the queue no longer exists, remove it from the
03750           * database */
03751          ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
03752          ast_db_del(pm_family, queue_name);
03753          continue;
03754       } else
03755          ao2_unlock(cur_queue);
03756 
03757       if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
03758          continue;
03759 
03760       cur_ptr = queue_data;
03761       while ((member = strsep(&cur_ptr, "|"))) {
03762          if (ast_strlen_zero(member))
03763             continue;
03764 
03765          interface = strsep(&member, ";");
03766          penalty_tok = strsep(&member, ";");
03767          paused_tok = strsep(&member, ";");
03768          membername = strsep(&member, ";");
03769          state_interface = strsep(&member,";");
03770 
03771          if (!penalty_tok) {
03772             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
03773             break;
03774          }
03775          penalty = strtol(penalty_tok, NULL, 10);
03776          if (errno == ERANGE) {
03777             ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
03778             break;
03779          }
03780          
03781          if (!paused_tok) {
03782             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
03783             break;
03784          }
03785          paused = strtol(paused_tok, NULL, 10);
03786          if ((errno == ERANGE) || paused < 0 || paused > 1) {
03787             ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
03788             break;
03789          }
03790          if (ast_strlen_zero(membername))
03791             membername = interface;
03792 
03793          if (option_debug)
03794             ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Name: %s  Penalty: %d  Paused: %d\n", queue_name, interface, membername, penalty, paused);
03795          
03796          if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
03797             ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
03798             break;
03799          }
03800       }
03801    }
03802 
03803    AST_LIST_UNLOCK(&queues);
03804    if (db_tree) {
03805       ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
03806       ast_db_freetree(db_tree);
03807    }
03808 }

static int reload_queues ( void   )  [static]

Definition at line 4626 of file app_queue.c.

References add_to_interfaces(), alloc_queue(), ao2_find(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlink(), ao2_unlock(), 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_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(), LOG_NOTICE, LOG_WARNING, call_queue::membercount, call_queue::members, call_queue::name, parse(), member::paused, queue_set_param(), QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_ROUNDROBIN, call_queue::realtime, remove_from_interfaces(), rr_dep_warning(), member::state_interface, strat2int(), call_queue::strategy, and var.

Referenced by load_module(), and reload().

04627 {
04628    struct call_queue *q;
04629    struct ast_config *cfg;
04630    char *cat, *tmp;
04631    struct ast_variable *var;
04632    struct member *cur, *newm;
04633    struct ao2_iterator mem_iter;
04634    int new;
04635    const char *general_val = NULL;
04636    char *parse;
04637    char *interface, *state_interface;
04638    char *membername = NULL;
04639    int penalty;
04640    AST_DECLARE_APP_ARGS(args,
04641       AST_APP_ARG(interface);
04642       AST_APP_ARG(penalty);
04643       AST_APP_ARG(membername);
04644       AST_APP_ARG(state_interface);
04645    );
04646    
04647    if (!(cfg = ast_config_load("queues.conf"))) {
04648       ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
04649       return 0;
04650    }
04651    AST_LIST_LOCK(&queues);
04652    use_weight=0;
04653    /* Mark all non-realtime queues as dead for the moment */
04654    AST_LIST_TRAVERSE(&queues, q, list) {
04655       if (!q->realtime) {
04656          q->dead = 1;
04657          q->found = 0;
04658       }
04659    }
04660 
04661    /* Chug through config file */
04662    cat = NULL;
04663    while ((cat = ast_category_browse(cfg, cat)) ) {
04664       if (!strcasecmp(cat, "general")) {  
04665          /* Initialize global settings */
04666          queue_debug = 0;
04667          if ((general_val = ast_variable_retrieve(cfg, "general", "debug")))
04668             queue_debug = ast_true(general_val);
04669          queue_persistent_members = 0;
04670          if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
04671             queue_persistent_members = ast_true(general_val);
04672          autofill_default = 0;
04673          if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
04674             autofill_default = ast_true(general_val);
04675          montype_default = 0;
04676          if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type")))
04677             if (!strcasecmp(general_val, "mixmonitor"))
04678                montype_default = 1;
04679       } else { /* Define queue */
04680          /* Look for an existing one */
04681          AST_LIST_TRAVERSE(&queues, q, list) {
04682             if (!strcmp(q->name, cat))
04683                break;
04684          }
04685          if (!q) {
04686             /* Make one then */
04687             if (!(q = alloc_queue(cat))) {
04688                /* TODO: Handle memory allocation failure */
04689             }
04690             new = 1;
04691          } else
04692             new = 0;
04693          if (q) {
04694             const char *tmpvar;
04695             if (!new)
04696                ao2_lock(q);
04697             /* Check if a queue with this name already exists */
04698             if (q->found) {
04699                ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
04700                if (!new)
04701                   ao2_unlock(q);
04702                continue;
04703             }
04704 
04705             /* Due to the fact that the "rrordered" strategy will have a different allocation
04706              * scheme for queue members, we must devise the queue's strategy before other initializations.
04707              * To be specific, the rrordered strategy needs to function like a linked list, meaning the ao2
04708              * container used will have only a single bucket instead of the typical number.
04709              */
04710             if ((tmpvar = ast_variable_retrieve(cfg, cat, "strategy"))) {
04711                q->strategy = strat2int(tmpvar);
04712                if (q->strategy < 0) {
04713                   ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", tmpvar, q->name);
04714                   q->strategy = QUEUE_STRATEGY_RINGALL;
04715                }
04716             } else {
04717                q->strategy = QUEUE_STRATEGY_RINGALL;
04718             }
04719 
04720             /* Re-initialize the queue, and clear statistics */
04721             init_queue(q);
04722             clear_queue(q);
04723             mem_iter = ao2_iterator_init(q->members, 0);
04724             while ((cur = ao2_iterator_next(&mem_iter))) {
04725                if (!cur->dynamic) {
04726                   cur->delme = 1;
04727                }
04728                ao2_ref(cur, -1);
04729             }
04730             ao2_iterator_destroy(&mem_iter);
04731             for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04732                if (!strcasecmp(var->name, "member")) {
04733                   struct member tmpmem;
04734                   membername = NULL;
04735 
04736                   if (ast_strlen_zero(var->value)) {
04737                      ast_log(LOG_WARNING, "Empty queue member definition at line %d. Moving on!\n", var->lineno);
04738                      continue;
04739                   }
04740 
04741                   /* Add a new member */
04742                   if (!(parse = ast_strdup(var->value))) {
04743                      continue;
04744                   }
04745                   
04746                   AST_NONSTANDARD_APP_ARGS(args, parse, ',');
04747 
04748                   interface = args.interface;
04749                   if (!ast_strlen_zero(args.penalty)) {
04750                      tmp = ast_skip_blanks(args.penalty);
04751                      penalty = atoi(tmp);
04752                      if (penalty < 0) {
04753                         penalty = 0;
04754                      }
04755                   } else
04756                      penalty = 0;
04757 
04758                   if (!ast_strlen_zero(args.membername)) {
04759                      membername = ast_skip_blanks(args.membername);
04760                   }
04761 
04762                   if (!ast_strlen_zero(args.state_interface)) {
04763                      state_interface = ast_skip_blanks(args.state_interface);
04764                   } else {
04765                      state_interface = interface;
04766                   }
04767 
04768                   /* Find the old position in the list */
04769                   ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
04770                   cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
04771 
04772                   /* Only attempt removing from interfaces list if the new state_interface is different than the old one */
04773                   if (cur && strcasecmp(cur->state_interface, state_interface)) {
04774                      remove_from_interfaces(cur->state_interface);
04775                   }
04776 
04777                   newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface);
04778                   if (!cur || (cur && strcasecmp(cur->state_interface, state_interface))) {
04779                      add_to_interfaces(state_interface);
04780                   }
04781                   ao2_link(q->members, newm);
04782                   ao2_ref(newm, -1);
04783                   newm = NULL;
04784 
04785                   if (cur)
04786                      ao2_ref(cur, -1);
04787                   else {
04788                      q->membercount++;
04789                   }
04790                   ast_free(parse);
04791                } else {
04792                   queue_set_param(q, var->name, var->value, var->lineno, 1);
04793                }
04794             }
04795 
04796             /* Free remaining members marked as delme */
04797             mem_iter = ao2_iterator_init(q->members, 0);
04798             while ((cur = ao2_iterator_next(&mem_iter))) {
04799                if (! cur->delme) {
04800                   ao2_ref(cur, -1);
04801                   continue;
04802                }
04803 
04804                q->membercount--;
04805                ao2_unlink(q->members, cur);
04806                remove_from_interfaces(cur->state_interface);
04807                ao2_ref(cur, -1);
04808             }
04809             ao2_iterator_destroy(&mem_iter);
04810 
04811             if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
04812                rr_dep_warning();
04813 
04814             if (new) {
04815                AST_LIST_INSERT_HEAD(&queues, q, list);
04816             } else
04817                ao2_unlock(q);
04818          }
04819       }
04820    }
04821    ast_config_destroy(cfg);
04822    AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
04823       if (q->dead) {
04824          AST_LIST_REMOVE_CURRENT(&queues, list);
04825          ao2_ref(q, -1);
04826       } else {
04827          ao2_lock(q);
04828          mem_iter = ao2_iterator_init(q->members, 0);
04829          while ((cur = ao2_iterator_next(&mem_iter))) {
04830             if (cur->dynamic)
04831                q->membercount++;
04832             cur->status = ast_device_state(cur->state_interface);
04833             ao2_ref(cur, -1);
04834          }
04835          ao2_iterator_destroy(&mem_iter);
04836          ao2_unlock(q);
04837       }
04838    }
04839    AST_LIST_TRAVERSE_SAFE_END;
04840    AST_LIST_UNLOCK(&queues);
04841    return 1;
04842 }

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

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

00990 {
00991    struct member_interface *curint;
00992 
00993    if (interface_exists_global(interface))
00994       return 0;
00995 
00996    AST_LIST_LOCK(&interfaces);
00997    AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
00998       if (!strcasecmp(curint->interface, interface)) {
00999          if (option_debug)
01000             ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
01001          AST_LIST_REMOVE_CURRENT(&interfaces, list);
01002          free(curint);
01003          break;
01004       }
01005    }
01006    AST_LIST_TRAVERSE_SAFE_END;
01007    AST_LIST_UNLOCK(&interfaces);
01008 
01009    return 0;
01010 }

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

Definition at line 3561 of file app_queue.c.

References ao2_find(), ao2_lock(), ao2_ref(), ao2_unlink(), ao2_unlock(), ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, 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().

03562 {
03563    struct call_queue *q;
03564    struct member *mem, tmpmem;
03565    int res = RES_NOSUCHQUEUE;
03566 
03567    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
03568 
03569    AST_LIST_LOCK(&queues);
03570    AST_LIST_TRAVERSE(&queues, q, list) {
03571       ao2_lock(q);
03572       if (strcmp(q->name, queuename)) {
03573          ao2_unlock(q);
03574          continue;
03575       }
03576 
03577       if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
03578          /* XXX future changes should beware of this assumption!! */
03579          if (!mem->dynamic) {
03580             res = RES_NOT_DYNAMIC;
03581             ao2_ref(mem, -1);
03582             ao2_unlock(q);
03583             break;
03584          }
03585          q->membercount--;
03586          manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
03587             "Queue: %s\r\n"
03588             "Location: %s\r\n"
03589             "MemberName: %s\r\n",
03590             q->name, mem->interface, mem->membername);
03591          ao2_unlink(q->members, mem);
03592          remove_from_interfaces(mem->state_interface);
03593          ao2_ref(mem, -1);
03594 
03595          if (queue_persistent_members)
03596             dump_queue_members(q);
03597          
03598          res = RES_OKAY;
03599       } else {
03600          res = RES_EXISTS;
03601       }
03602       ao2_unlock(q);
03603       break;
03604    }
03605 
03606    AST_LIST_UNLOCK(&queues);
03607 
03608    return res;
03609 }

static void remove_queue ( struct call_queue q  )  [static]

removes a call_queue from the list of call_queues

Definition at line 529 of file app_queue.c.

References ao2_ref(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and member_interface::list.

Referenced by find_queue_by_name_rt(), and leave_queue().

00530 {
00531    AST_LIST_LOCK(&queues);
00532    if (AST_LIST_REMOVE(&queues, q, list)) {
00533       ao2_ref(q, -1);
00534    }
00535    AST_LIST_UNLOCK(&queues);
00536 }

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

References ast_cdr::accountcode, ast_channel::adsicpe, ast_cdr::amaflags, ao2_lock(), ao2_unlock(), 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_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, 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().

01949 {
01950    int res;
01951    int status;
01952    char tech[256];
01953    char *location;
01954    const char *macrocontext, *macroexten;
01955 
01956    /* on entry here, we know that tmp->chan == NULL */
01957    if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
01958       if (queue_debug)
01959          ast_log(LOG_NOTICE, "Wrapuptime not yet expired for %s\n", tmp->interface);
01960       if (qe->chan->cdr)
01961          ast_cdr_busy(qe->chan->cdr);
01962       tmp->stillgoing = 0;
01963       (*busies)++;
01964       return 0;
01965    }
01966 
01967    if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
01968       if (queue_debug)
01969          ast_log(LOG_NOTICE, "%s in use, can't receive call\n", tmp->interface);
01970       if (qe->chan->cdr)
01971          ast_cdr_busy(qe->chan->cdr);
01972       tmp->stillgoing = 0;
01973       return 0;
01974    }
01975 
01976    if (tmp->member->paused) {
01977       if (queue_debug)
01978          ast_log(LOG_NOTICE, "%s paused, can't receive call\n", tmp->interface);
01979       if (qe->chan->cdr)
01980          ast_cdr_busy(qe->chan->cdr);
01981       tmp->stillgoing = 0;
01982       return 0;
01983    }
01984    if (use_weight && compare_weight(qe->parent,tmp->member)) {
01985       if (queue_debug)
01986          ast_log(LOG_NOTICE, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
01987       if (qe->chan->cdr)
01988          ast_cdr_busy(qe->chan->cdr);
01989       tmp->stillgoing = 0;
01990       (*busies)++;
01991       return 0;
01992    }
01993 
01994    ast_copy_string(tech, tmp->interface, sizeof(tech));
01995    if ((location = strchr(tech, '/')))
01996       *location++ = '\0';
01997    else
01998       location = "";
01999 
02000    /* Request the peer */
02001    tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
02002    if (!tmp->chan) {       /* If we can't, just go on to the next call */
02003       if (queue_debug)
02004          ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", tech);
02005       if (qe->chan->cdr)
02006          ast_cdr_busy(qe->chan->cdr);
02007       tmp->stillgoing = 0;
02008 
02009       update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface));
02010 
02011       ao2_lock(qe->parent);
02012       qe->parent->rrpos++;
02013       ao2_unlock(qe->parent);
02014 
02015       (*busies)++;
02016       return 0;
02017    }
02018    
02019    /* Increment ring count */
02020    tmp->member->ringcount++;
02021    tmp->chan->appl = "AppQueue";
02022    tmp->chan->data = "(Outgoing Line)";
02023    tmp->chan->whentohangup = 0;
02024    if (tmp->chan->cid.cid_num)
02025       free(tmp->chan->cid.cid_num);
02026    tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
02027    if (tmp->chan->cid.cid_name)
02028       free(tmp->chan->cid.cid_name);
02029    tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
02030    if (tmp->chan->cid.cid_ani)
02031       free(tmp->chan->cid.cid_ani);
02032    tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
02033 
02034    /* Inherit specially named variables from parent channel */
02035    ast_channel_inherit_variables(qe->chan, tmp->chan);
02036    ast_channel_datastore_inherit(qe->chan, tmp->chan);
02037 
02038    /* Presense of ADSI CPE on outgoing channel follows ours */
02039    tmp->chan->adsicpe = qe->chan->adsicpe;
02040 
02041    /* Inherit context and extension */
02042    ast_channel_lock(qe->chan);
02043    macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
02044    if (!ast_strlen_zero(macrocontext))
02045       ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext));
02046    else
02047       ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext));
02048    macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
02049    if (!ast_strlen_zero(macroexten))
02050       ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
02051    else
02052       ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
02053    if (ast_cdr_isset_unanswered()) {
02054       /* they want to see the unanswered dial attempts! */
02055       /* set up the CDR fields on all the CDRs to give sensical information */
02056       ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name);
02057       strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid);
02058       strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel);
02059       strcpy(tmp->chan->cdr->src, qe->chan->cdr->src);
02060       strcpy(tmp->chan->cdr->dst, qe->chan->exten);
02061       strcpy(tmp->chan->cdr->dcontext, qe->chan->context);
02062       strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp);
02063       strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata);
02064       tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags;
02065       strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode);
02066       strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
02067    }
02068    ast_channel_unlock(qe->chan);
02069 
02070    /* Place the call, but don't wait on the answer */
02071    if ((res = ast_call(tmp->chan, location, 0))) {
02072       /* Again, keep going even if there's an error */
02073       if (option_debug)
02074          ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
02075       if (option_verbose > 2)
02076          ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
02077       do_hang(tmp);
02078       (*busies)++;
02079       update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface));
02080       return 0;
02081    } else if (qe->parent->eventwhencalled) {
02082       char vars[2048];
02083 
02084       manager_event(EVENT_FLAG_AGENT, "AgentCalled",
02085                "AgentCalled: %s\r\n"
02086                "AgentName: %s\r\n"
02087                "ChannelCalling: %s\r\n"
02088                "CallerID: %s\r\n"
02089                "CallerIDName: %s\r\n"
02090                "Context: %s\r\n"
02091                "Extension: %s\r\n"
02092                "Priority: %d\r\n"
02093                "%s",
02094                tmp->interface, tmp->member->membername, qe->chan->name,
02095                tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
02096                tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
02097                qe->chan->context, qe->chan->exten, qe->chan->priority,
02098                qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
02099       if (option_verbose > 2)
02100          ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
02101    }
02102 
02103    update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface));
02104    return 1;
02105 }

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

02132 {
02133    int ret = 0;
02134 
02135    while (ret == 0) {
02136       struct callattempt *best = find_best(outgoing);
02137       if (!best) {
02138          if (option_debug)
02139             ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
02140          break;
02141       }
02142       if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
02143          struct callattempt *cur;
02144          /* Ring everyone who shares this best metric (for ringall) */
02145          for (cur = outgoing; cur; cur = cur->q_next) {
02146             if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
02147                if (option_debug)
02148                   ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
02149                ret |= ring_entry(qe, cur, busies);
02150             }
02151          }
02152       } else {
02153          /* Ring just the best channel */
02154          if (option_debug)
02155             ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
02156          ret = ring_entry(qe, best, busies);
02157       }
02158    }
02159 
02160    return ret;
02161 }

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

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

02246 {
02247    if (option_verbose > 2)
02248       ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
02249 
02250    /* Stop ringing, and resume MOH if specified */
02251    if (qe->ring_when_ringing) {
02252       ast_indicate(qe->chan, -1);
02253       ast_moh_start(qe->chan, qe->moh, NULL);
02254    }
02255 
02256    ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
02257    if (qe->parent->autopause && pause) {
02258       if (!set_member_paused(qe->parent->name, interface, 1)) {
02259          if (option_verbose > 2)
02260             ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
02261       } else {
02262          if (option_verbose > 2)
02263             ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
02264       }
02265    }
02266    return;
02267 }

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

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

03927 {
03928    int res=-1;
03929    struct ast_module_user *lu;
03930    char *parse, *temppos = NULL;
03931    int priority_jump = 0;
03932    AST_DECLARE_APP_ARGS(args,
03933       AST_APP_ARG(queuename);
03934       AST_APP_ARG(interface);
03935       AST_APP_ARG(options);
03936    );
03937 
03938 
03939    if (ast_strlen_zero(data)) {
03940       ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
03941       return -1;
03942    }
03943 
03944    parse = ast_strdupa(data);
03945 
03946    AST_STANDARD_APP_ARGS(args, parse);
03947 
03948    lu = ast_module_user_add(chan);
03949 
03950    if (ast_strlen_zero(args.interface)) {
03951       args.interface = ast_strdupa(chan->name);
03952       temppos = strrchr(args.interface, '-');
03953       if (temppos)
03954          *temppos = '\0';
03955    }
03956 
03957    if (args.options) {
03958       if (strchr(args.options, 'j'))
03959          priority_jump = 1;
03960    }
03961 
03962    switch (remove_from_queue(args.queuename, args.interface)) {
03963    case RES_OKAY:
03964       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
03965       ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
03966       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
03967       res = 0;
03968       break;
03969    case RES_EXISTS:
03970       ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
03971       if (priority_jump || ast_opt_priority_jumping)
03972          ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
03973       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
03974       res = 0;
03975       break;
03976    case RES_NOSUCHQUEUE:
03977       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
03978       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
03979       res = 0;
03980       break;
03981    case RES_NOT_DYNAMIC:
03982       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
03983       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
03984       res = 0;
03985       break;
03986    }
03987 
03988    ast_module_user_remove(lu);
03989 
03990    return res;
03991 }

static void rr_dep_warning ( void   )  [static]

Definition at line 471 of file app_queue.c.

References ast_log(), and LOG_NOTICE.

Referenced by reload_queues().

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

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

01182 {
01183    struct member *m, tmpmem;
01184    int penalty = 0;
01185    int paused  = 0;
01186 
01187    if (penalty_str) {
01188       penalty = atoi(penalty_str);
01189       if (penalty < 0)
01190          penalty = 0;
01191    }
01192 
01193    if (paused_str) {
01194       paused = atoi(paused_str);
01195       if (paused < 0)
01196          paused = 0;
01197    }
01198 
01199    /* Find the member, or the place to put a new one. */
01200    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
01201    m = ao2_find(q->members, &tmpmem, OBJ_POINTER);
01202 
01203    /* Create a new one if not found, else update penalty */
01204    if (!m) {
01205       if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
01206          m->dead = 0;
01207          m->realtime = 1;
01208          add_to_interfaces(m->state_interface);
01209          ao2_link(q->members, m);
01210          ao2_ref(m, -1);
01211          m = NULL;
01212          q->membercount++;
01213       }
01214    } else {
01215       m->dead = 0;   /* Do not delete this one. */
01216       if (paused_str)
01217          m->paused = paused;
01218       if (strcasecmp(state_interface, m->state_interface)) {
01219          remove_from_interfaces(m->state_interface);
01220          ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
01221          add_to_interfaces(m->state_interface);
01222       }
01223       m->penalty = penalty;
01224       ao2_ref(m, -1);
01225    }
01226 }

static int say_periodic_announcement ( struct queue_ent qe  )  [static]

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

02188 {
02189    int res = 0;
02190    time_t now;
02191 
02192    /* Get the current time */
02193    time(&now);
02194 
02195    /* Check to see if it is time to announce */
02196    if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
02197       return 0;
02198 
02199    /* Stop the music on hold so we can play our own file */
02200    ast_moh_stop(qe->chan);
02201 
02202    if (option_verbose > 2)
02203       ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
02204 
02205    /* Check to make sure we have a sound file. If not, reset to the first sound file */
02206    if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
02207       qe->last_periodic_announce_sound = 0;
02208    }
02209    
02210    /* play the announcement */
02211    res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
02212 
02213    if (res > 0 && !valid_exit(qe, res))
02214       res = 0;
02215 
02216    /* Resume Music on Hold if the caller is going to stay in the queue */
02217    if (!res)
02218       ast_moh_start(qe->chan, qe->moh, NULL);
02219 
02220    /* update last_periodic_announce_time */
02221    qe->last_periodic_announce_time = now;
02222 
02223    /* Update the current periodic announcement to the next announcement */
02224    qe->last_periodic_announce_sound++;
02225    
02226    return res;
02227 }

static int say_position ( struct queue_ent qe  )  [static]

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

01637 {
01638    int res = 0, avgholdmins, avgholdsecs;
01639    time_t now;
01640 
01641    /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
01642    time(&now);
01643    if ((now - qe->last_pos) < 15)
01644       return 0;
01645 
01646    /* If either our position has changed, or we are over the freq timer, say position */
01647    if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
01648       return 0;
01649 
01650    ast_moh_stop(qe->chan);
01651    /* Say we're next, if we are */
01652    if (qe->pos == 1) {
01653       res = play_file(qe->chan, qe->parent->sound_next);
01654       if (res)
01655          goto playout;
01656       else
01657          goto posout;
01658    } else {
01659       res = play_file(qe->chan, qe->parent->sound_thereare);
01660       if (res)
01661          goto playout;
01662       res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
01663       if (res)
01664          goto playout;
01665       res = play_file(qe->chan, qe->parent->sound_calls);
01666       if (res)
01667          goto playout;
01668    }
01669    /* Round hold time to nearest minute */
01670    avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
01671 
01672    /* If they have specified a rounding then round the seconds as well */
01673    if (qe->parent->roundingseconds) {
01674       avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
01675       avgholdsecs *= qe->parent->roundingseconds;
01676    } else {
01677       avgholdsecs = 0;
01678    }
01679 
01680    if (option_verbose > 2)
01681       ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
01682 
01683    /* If the hold time is >1 min, if it's enabled, and if it's not
01684       supposed to be only once and we have already said it, say it */
01685     if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
01686         ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
01687         !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
01688       res = play_file(qe->chan, qe->parent->sound_holdtime);
01689       if (res)
01690          goto playout;
01691 
01692       if (avgholdmins > 0) {
01693          if (avgholdmins < 2) {
01694             res = play_file(qe->chan, qe->parent->sound_lessthan);
01695             if (res)
01696                goto playout;
01697 
01698             res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
01699             if (res)
01700                goto playout;
01701          } else {
01702             res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
01703             if (res)
01704                goto playout;
01705          }
01706          
01707          res = play_file(qe->chan, qe->parent->sound_minutes);
01708          if (res)
01709             goto playout;
01710       }
01711       if (avgholdsecs>0) {
01712          res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
01713          if (res)
01714             goto playout;
01715 
01716          res = play_file(qe->chan, qe->parent->sound_seconds);
01717          if (res)
01718             goto playout;
01719       }
01720 
01721    }
01722 
01723 posout:
01724    if (option_verbose > 2)
01725       ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
01726          qe->chan->name, qe->parent->name, qe->pos);
01727    res = play_file(qe->chan, qe->parent->sound_thanks);
01728 
01729 playout:
01730 
01731    if ((res > 0 && !valid_exit(qe, res)))
01732       res = 0;
01733 
01734    /* Set our last_pos indicators */
01735    qe->last_pos = now;
01736    qe->last_pos_said = qe->pos;
01737 
01738    /* Don't restart music on hold if we're about to exit the caller from the queue */
01739    if (!res)
01740       ast_moh_start(qe->chan, qe->moh, NULL);
01741 
01742    return res;
01743 }

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

Definition at line 3667 of file app_queue.c.

References ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_queue_log(), ast_strlen_zero(), dump_queue_members(), EVENT_FLAG_AGENT, member::interface, interface_exists(), 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().

03668 {
03669    int found = 0;
03670    struct call_queue *q;
03671    struct member *mem;
03672 
03673    /* Special event for when all queues are paused - individual events still generated */
03674    /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
03675    if (ast_strlen_zero(queuename))
03676       ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
03677 
03678    AST_LIST_LOCK(&queues);
03679    AST_LIST_TRAVERSE(&queues, q, list) {
03680       ao2_lock(q);
03681       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
03682          if ((mem = interface_exists(q, interface))) {
03683             found++;
03684             if (mem->paused == paused)
03685                ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
03686             mem->paused = paused;
03687 
03688             if (queue_persistent_members)
03689                dump_queue_members(q);
03690 
03691             if (mem->realtime)
03692                update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
03693 
03694             ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
03695 
03696             manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
03697                "Queue: %s\r\n"
03698                "Location: %s\r\n"
03699                "MemberName: %s\r\n"
03700                "Paused: %d\r\n",
03701                   q->name, mem->interface, mem->membername, paused);
03702             ao2_ref(mem, -1);
03703          }
03704       }
03705       ao2_unlock(q);
03706    }
03707    AST_LIST_UNLOCK(&queues);
03708 
03709    return found ? RESULT_SUCCESS : RESULT_FAILURE;
03710 }

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

sets the QUEUESTATUS channel variable

Definition at line 490 of file app_queue.c.

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

Referenced by queue_exec().

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

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

02828 {
02829    struct ast_datastore *ds;
02830    struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
02831 
02832    if (!qtds) {
02833       ast_log(LOG_WARNING, "Memory allocation error!\n");
02834       return NULL;
02835    }
02836 
02837    ast_channel_lock(qe->chan);
02838    if (!(ds = ast_channel_datastore_alloc(&queue_transfer_info, NULL))) {
02839       ast_channel_unlock(qe->chan);
02840       ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
02841       return NULL;
02842    }
02843 
02844    qtds->qe = qe;
02845    /* This member is refcounted in try_calling, so no need to add it here, too */
02846    qtds->member = member;
02847    qtds->starttime = starttime;
02848    qtds->callcompletedinsl = callcompletedinsl;
02849    ds->data = qtds;
02850    ast_channel_datastore_add(qe->chan, ds);
02851    ast_channel_unlock(qe->chan);
02852    return ds;
02853 }

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

Producer of the statechange queue.

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

00788 {
00789    struct statechange *sc;
00790 
00791    if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
00792       return 0;
00793 
00794    sc->state = state;
00795    strcpy(sc->dev, dev);
00796 
00797    ast_mutex_lock(&device_state.lock);
00798    AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
00799    ast_cond_signal(&device_state.cond);
00800    ast_mutex_unlock(&device_state.lock);
00801 
00802    return 0;
00803 }

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

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

02164 {
02165    struct callattempt *best = find_best(outgoing);
02166 
02167    if (best) {
02168       /* Ring just the best channel */
02169       if (option_debug)
02170          ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
02171       qe->parent->rrpos = best->metric % 1000;
02172    } else {
02173       /* Just increment rrpos */
02174       if (qe->parent->wrapped) {
02175          /* No more channels, start over */
02176          qe->parent->rrpos = 0;
02177       } else {
02178          /* Prioritize next entry */
02179          qe->parent->rrpos++;
02180       }
02181    }
02182    qe->parent->wrapped = 0;
02183 
02184    return 0;
02185 }

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

Definition at line 514 of file app_queue.c.

References name, and strategies.

Referenced by find_queue_by_name_rt(), queue_set_param(), and reload_queues().

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

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

References ast_channel::_state, queue_ent::announce, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), 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_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, 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, QUEUE_STRATEGY_RRMEMORY, QUEUE_STRATEGY_RRORDERED, 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().

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

static int unload_module ( void   )  [static]

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

05590 {
05591    int res;
05592 
05593    if (device_state.thread != AST_PTHREADT_NULL) {
05594       device_state.stop = 1;
05595       ast_mutex_lock(&device_state.lock);
05596       ast_cond_signal(&device_state.cond);
05597       ast_mutex_unlock(&device_state.lock);
05598       pthread_join(device_state.thread, NULL);
05599    }
05600 
05601    ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
05602    res = ast_manager_unregister("QueueStatus");
05603    res |= ast_manager_unregister("Queues");
05604    res |= ast_manager_unregister("QueueAdd");
05605    res |= ast_manager_unregister("QueueRemove");
05606    res |= ast_manager_unregister("QueuePause");
05607    res |= ast_unregister_application(app_aqm);
05608    res |= ast_unregister_application(app_rqm);
05609    res |= ast_unregister_application(app_pqm);
05610    res |= ast_unregister_application(app_upqm);
05611    res |= ast_unregister_application(app_ql);
05612    res |= ast_unregister_application(app);
05613    res |= ast_custom_function_unregister(&queueagentcount_function);
05614    res |= ast_custom_function_unregister(&queuemembercount_function);
05615    res |= ast_custom_function_unregister(&queuememberlist_function);
05616    res |= ast_custom_function_unregister(&queuewaitingcount_function);
05617    ast_devstate_del(statechange_queue, NULL);
05618 
05619    ast_module_user_hangup_all();
05620 
05621    clear_and_free_interfaces();
05622 
05623    return res;
05624 }

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

Definition at line 2679 of file app_queue.c.

References ao2_lock(), ao2_unlock(), member::calls, call_queue::callscompleted, call_queue::callscompletedinsl, and member::lastcall.

Referenced by queue_transfer_fixup().

02680 {
02681    ao2_lock(q);
02682    time(&member->lastcall);
02683    member->calls++;
02684    q->callscompleted++;
02685    if (callcompletedinsl)
02686       q->callscompletedinsl++;
02687    ao2_unlock(q);
02688    return 0;
02689 }

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

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

01395 {
01396    struct ast_variable *var, *save;
01397    int ret = -1;
01398 
01399    if (!(var = ast_load_realtime("queue_members", "interface", mem->interface, "queue_name", queue_name, NULL))) 
01400       return ret;
01401    save = var;
01402    while (var) {
01403       if (!strcmp(var->name, "uniqueid"))
01404          break;
01405       var = var->next;
01406    }
01407    if (var && !ast_strlen_zero(var->value)) {
01408       if ((ast_update_realtime("queue_members", "uniqueid", var->value, field, value, NULL)) > -1)
01409          ret = 0;
01410    }
01411    ast_variables_destroy(save);
01412    return ret;
01413 }

static void update_realtime_members ( struct call_queue q  )  [static]

Definition at line 1415 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlink(), ao2_unlock(), ast_category_browse(), ast_config_destroy(), ast_load_realtime_multientry(), ast_log(), ast_variable_retrieve(), member::dead, member_interface::interface, 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().

01416 {
01417    struct ast_config *member_config = NULL;
01418    struct member *m;
01419    char *interface = NULL;
01420    struct ao2_iterator mem_iter;
01421 
01422    if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL))) {
01423       /*This queue doesn't have realtime members*/
01424       if (option_debug > 2)
01425          ast_log(LOG_DEBUG, "Queue %s has no realtime members defined. No need for update\n", q->name);
01426       return;
01427    }
01428 
01429    ao2_lock(q);
01430    
01431    /* Temporarily set realtime  members dead so we can detect deleted ones.*/ 
01432    mem_iter = ao2_iterator_init(q->members, 0);
01433    while ((m = ao2_iterator_next(&mem_iter))) {
01434       if (m->realtime)
01435          m->dead = 1;
01436       ao2_ref(m, -1);
01437    }
01438    ao2_iterator_destroy(&mem_iter);
01439 
01440    while ((interface = ast_category_browse(member_config, interface))) {
01441       rt_handle_member_record(q, interface,
01442          S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
01443          ast_variable_retrieve(member_config, interface, "penalty"),
01444          ast_variable_retrieve(member_config, interface, "paused"),
01445          S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
01446    }
01447 
01448    /* Delete all realtime members that have been deleted in DB. */
01449    mem_iter = ao2_iterator_init(q->members, 0);
01450    while ((m = ao2_iterator_next(&mem_iter))) {
01451       if (m->dead) {
01452          ao2_unlink(q->members, m);
01453          ao2_unlock(q);
01454          remove_from_interfaces(m->state_interface);
01455          ao2_lock(q);
01456          q->membercount--;
01457       }
01458       ao2_ref(m, -1);
01459    }
01460    ao2_iterator_destroy(&mem_iter);
01461    ao2_unlock(q);
01462    ast_config_destroy(member_config);
01463 }

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

Definition at line 638 of file app_queue.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlock(), ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, member::calls, member::dynamic, EVENT_FLAG_AGENT, member::interface, member::lastcall, member_interface::list, 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().

00639 {
00640    struct member *cur;
00641    struct ao2_iterator mem_iter;
00642    struct call_queue *q;
00643    char tmp_interface[80];
00644 
00645    AST_LIST_LOCK(&queues);
00646    AST_LIST_TRAVERSE(&queues, q, list) {
00647       ao2_lock(q);
00648       mem_iter = ao2_iterator_init(q->members, 0);
00649       while ((cur = ao2_iterator_next(&mem_iter))) {
00650          char *slash_pos;
00651          ast_copy_string(tmp_interface, cur->state_interface, sizeof(tmp_interface));
00652          if ((slash_pos = strchr(tmp_interface, '/')))
00653             if ((slash_pos = strchr(slash_pos + 1, '/')))
00654                *slash_pos = '\0';
00655 
00656          if (strcasecmp(interface, tmp_interface)) {
00657             ao2_ref(cur, -1);
00658             continue;
00659          }
00660 
00661          if (cur->status != status) {
00662             cur->status = status;
00663             if (q->maskmemberstatus) {
00664                ao2_ref(cur, -1);
00665                continue;
00666             }
00667 
00668             manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
00669                "Queue: %s\r\n"
00670                "Location: %s\r\n"
00671                "MemberName: %s\r\n"
00672                "Membership: %s\r\n"
00673                "Penalty: %d\r\n"
00674                "CallsTaken: %d\r\n"
00675                "LastCall: %d\r\n"
00676                "Status: %d\r\n"
00677                "Paused: %d\r\n",
00678                q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
00679                cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
00680          }
00681          ao2_ref(cur, -1);
00682       }
00683       ao2_iterator_destroy(&mem_iter);
00684       ao2_unlock(q);
00685    }
00686    AST_LIST_UNLOCK(&queues);
00687 
00688    return 0;
00689 }

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

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

03869 {
03870    struct ast_module_user *lu;
03871    char *parse;
03872    int priority_jump = 0;
03873    int ignore_fail = 0;
03874    AST_DECLARE_APP_ARGS(args,
03875       AST_APP_ARG(queuename);
03876       AST_APP_ARG(interface);
03877       AST_APP_ARG(options);
03878    );
03879 
03880    if (ast_strlen_zero(data)) {
03881       ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
03882       return -1;
03883    }
03884 
03885    parse = ast_strdupa(data);
03886 
03887    AST_STANDARD_APP_ARGS(args, parse);
03888 
03889    lu = ast_module_user_add(chan);
03890 
03891    if (args.options) {
03892       if (strchr(args.options, 'j'))
03893          priority_jump = 1;
03894       if (strchr(args.options, 'i'))
03895          ignore_fail = 1;
03896    }
03897 
03898    if (ast_strlen_zero(args.interface)) {
03899       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
03900       ast_module_user_remove(lu);
03901       return -1;
03902    }
03903 
03904    if (set_member_paused(args.queuename, args.interface, 0)) {
03905       ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
03906       pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
03907       if (priority_jump || ast_opt_priority_jumping) {
03908          if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
03909             ast_module_user_remove(lu);
03910             return 0;
03911          }
03912       }
03913       ast_module_user_remove(lu);
03914       if (ignore_fail) {
03915          return 0;
03916       } else {
03917          return -1;
03918       }
03919    }
03920 
03921    ast_module_user_remove(lu);
03922    pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
03923    return 0;
03924 }

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

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

01604 {
01605    int digitlen = strlen(qe->digits);
01606 
01607    /* Prevent possible buffer overflow */
01608    if (digitlen < sizeof(qe->digits) - 2) {
01609       qe->digits[digitlen] = digit;
01610       qe->digits[digitlen + 1] = '\0';
01611    } else {
01612       qe->digits[0] = '\0';
01613       return 0;
01614    }
01615 
01616    /* If there's no context to goto, short-circuit */
01617    if (ast_strlen_zero(qe->context))
01618       return 0;
01619 
01620    /* If the extension is bad, then reset the digits to blank */
01621    if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
01622       qe->digits[0] = '\0';
01623       return 0;
01624    }
01625 
01626    /* We have an exact match */
01627    if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
01628       qe->valid_digits = 1;
01629       /* Return 1 on a successful goto */
01630       return 1;
01631    }
01632 
01633    return 0;
01634 }

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

Definition at line 1908 of file app_queue.c.

References ast_copy_string(), and pbx_builtin_serialize_variables().

Referenced by ring_entry().

01909 {
01910    char *tmp = alloca(len);
01911 
01912    if (pbx_builtin_serialize_variables(chan, tmp, len)) {
01913       int i, j;
01914 
01915       /* convert "\n" to "\nVariable: " */
01916       strcpy(vars, "Variable: ");
01917 
01918       for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
01919          vars[j] = tmp[i];
01920 
01921          if (tmp[i + 1] == '\0')
01922             break;
01923          if (tmp[i] == '\n') {
01924             vars[j++] = '\r';
01925             vars[j++] = '\n';
01926 
01927             ast_copy_string(&(vars[j]), "Variable: ", len - j);
01928             j += 9;
01929          }
01930       }
01931       if (j > len - 3)
01932          j = len - 3;
01933       vars[j++] = '\r';
01934       vars[j++] = '\n';
01935       vars[j] = '\0';
01936    } else {
01937       /* there are no channel variables; leave it blank */
01938       *vars = '\0';
01939    }
01940    return vars;
01941 }

static int wait_a_bit ( struct queue_ent qe  )  [static]

Definition at line 3481 of file app_queue.c.

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

Referenced by queue_exec().

03482 {
03483    /* Don't need to hold the lock while we setup the outgoing calls */
03484    int retrywait = qe->parent->retry * 1000;
03485 
03486    int res = ast_waitfordigit(qe->chan, retrywait);
03487    if (res > 0 && !valid_exit(qe, res))
03488       res = 0;
03489 
03490    return res;
03491 }

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

02281 {
02282    char *queue = qe->parent->name;
02283    struct callattempt *o, *start = NULL, *prev = NULL;
02284    int status;
02285    int numbusies = prebusies;
02286    int numnochan = 0;
02287    int stillgoing = 0;
02288    int orig = *to;
02289    struct ast_frame *f;
02290    struct callattempt *peer = NULL;
02291    struct ast_channel *winner;
02292    struct ast_channel *in = qe->chan;
02293    char on[80] = "";
02294    char membername[80] = "";
02295    long starttime = 0;
02296    long endtime = 0; 
02297 
02298    starttime = (long) time(NULL);
02299    
02300    while (*to && !peer) {
02301       int numlines, retry, pos = 1;
02302       struct ast_channel *watchers[AST_MAX_WATCHERS];
02303       watchers[0] = in;
02304       start = NULL;
02305 
02306       for (retry = 0; retry < 2; retry++) {
02307          numlines = 0;
02308          for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
02309             if (o->stillgoing) { /* Keep track of important channels */
02310                stillgoing = 1;
02311                if (o->chan) {
02312                   watchers[pos++] = o->chan;
02313                   if (!start)
02314                      start = o;
02315                   else
02316                      prev->call_next = o;
02317                   prev = o;
02318                }
02319             }
02320             numlines++;
02321          }
02322          if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
02323             (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
02324             break;
02325          /* On "ringall" strategy we only move to the next penalty level
02326             when *all* ringing phones are done in the current penalty level */
02327          ring_one(qe, outgoing, &numbusies);
02328          /* and retry... */
02329       }
02330       if (pos == 1 /* not found */) {
02331          if (numlines == (numbusies + numnochan)) {
02332             ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
02333          } else {
02334             ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
02335          }
02336          *to = 0;
02337          return NULL;
02338       }
02339 
02340       /* Poll for events from both the incoming channel as well as any outgoing channels */
02341       winner = ast_waitfor_n(watchers, pos, to);
02342 
02343       /* Service all of the outgoing channels */
02344       for (o = start; o; o = o->call_next) {
02345          if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
02346             if (!peer) {
02347                if (option_verbose > 2)
02348                   ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
02349                peer = o;
02350             }
02351          } else if (o->chan && (o->chan == winner)) {
02352 
02353             ast_copy_string(on, o->member->interface, sizeof(on));
02354             ast_copy_string(membername, o->member->membername, sizeof(membername));
02355 
02356             if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
02357                if (option_verbose > 2)
02358                   ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
02359                numnochan++;
02360                do_hang(o);
02361                winner = NULL;
02362                continue;
02363             } else if (!ast_strlen_zero(o->chan->call_forward)) {
02364                char tmpchan[256];
02365                char *stuff;
02366                char *tech;
02367 
02368                ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
02369                if ((stuff = strchr(tmpchan, '/'))) {
02370                   *stuff++ = '\0';
02371                   tech = tmpchan;
02372                } else {
02373                   snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
02374                   stuff = tmpchan;
02375                   tech = "Local";
02376                }
02377                /* Before processing channel, go ahead and check for forwarding */
02378                if (option_verbose > 2)
02379                   ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
02380                /* Setup parameters */
02381                o->chan = ast_request(tech, in->nativeformats, stuff, &status);
02382                if (!o->chan) {
02383                   ast_log(LOG_NOTICE,
02384                      "Forwarding failed to create channel to dial '%s/%s'\n",
02385                      tech, stuff);
02386                   o->stillgoing = 0;
02387                   numnochan++;
02388                } else {
02389                   ast_channel_inherit_variables(in, o->chan);
02390                   ast_channel_datastore_inherit(in, o->chan);
02391                   if (o->chan->cid.cid_num)
02392                      free(o->chan->cid.cid_num);
02393                   o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
02394 
02395                   if (o->chan->cid.cid_name)
02396                      free(o->chan->cid.cid_name);
02397                   o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
02398 
02399                   ast_string_field_set(o->chan, accountcode, in->accountcode);
02400                   o->chan->cdrflags = in->cdrflags;
02401 
02402                   if (in->cid.cid_ani) {
02403                      if (o->chan->cid.cid_ani)
02404                         free(o->chan->cid.cid_ani);
02405                      o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
02406                   }
02407                   if (o->chan->cid.cid_rdnis)
02408                      free(o->chan->cid.cid_rdnis);
02409                   o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
02410                   if (ast_call(o->chan, stuff, 0)) {
02411                      ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
02412                         tech, stuff);
02413                      do_hang(o);
02414                      numnochan++;
02415                   }
02416                }
02417                /* Hangup the original channel now, in case we needed it */
02418                ast_hangup(winner);
02419                continue;
02420             }
02421             f = ast_read(winner);
02422             if (f) {
02423                if (f->frametype == AST_FRAME_CONTROL) {
02424                   switch (f->subclass) {
02425                   case AST_CONTROL_ANSWER:
02426                      /* This is our guy if someone answered. */
02427                      if (!peer) {
02428                         if (option_verbose > 2)
02429                            ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
02430                         peer = o;
02431                      }
02432                      break;
02433                   case AST_CONTROL_BUSY:
02434                      if (option_verbose > 2)
02435                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
02436                      if (in->cdr)
02437                         ast_cdr_busy(in->cdr);
02438                      do_hang(o);
02439                      endtime = (long)time(NULL);
02440                      endtime -= starttime;
02441                      rna(endtime * 1000, qe, on, membername, 0);
02442                      if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02443                         if (qe->parent->timeoutrestart)
02444                            *to = orig;
02445                         /* Have enough time for a queue member to answer? */
02446                         if (*to > 500) {
02447                            ring_one(qe, outgoing, &numbusies);
02448                            starttime = (long) time(NULL);
02449                         }
02450                      }
02451                      numbusies++;
02452                      break;
02453                   case AST_CONTROL_CONGESTION:
02454                      if (option_verbose > 2)
02455                         ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
02456                      if (in->cdr)
02457                         ast_cdr_busy(in->cdr);
02458                      endtime = (long)time(NULL);
02459                      endtime -= starttime;
02460                      rna(endtime * 1000, qe, on, membername, 0);
02461                      do_hang(o);
02462                      if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02463                         if (qe->parent->timeoutrestart)
02464                            *to = orig;
02465                         if (*to > 500) {
02466                            ring_one(qe, outgoing, &numbusies);
02467                            starttime = (long) time(NULL);
02468                         }
02469                      }
02470                      numbusies++;
02471                      break;
02472                   case AST_CONTROL_RINGING:
02473                      if (option_verbose > 2)
02474                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
02475 
02476                      /* Start ring indication when the channel is ringing, if specified */
02477                      if (qe->ring_when_ringing) {
02478                         ast_moh_stop(qe->chan);
02479                         ast_indicate(qe->chan, AST_CONTROL_RINGING);
02480                      }
02481                      break;
02482                   case AST_CONTROL_OFFHOOK:
02483                      /* Ignore going off hook */
02484                      break;
02485                   default:
02486                      ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
02487                   }
02488                }
02489                ast_frfree(f);
02490             } else { /* ast_read() returned NULL */
02491                endtime = (long) time(NULL) - starttime;
02492                rna(endtime * 1000, qe, on, membername, 1);
02493                do_hang(o);
02494                if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02495                   if (qe->parent->timeoutrestart)
02496                      *to = orig;
02497                   if (*to > 500) {
02498                      ring_one(qe, outgoing, &numbusies);
02499                      starttime = (long) time(NULL);
02500                   }
02501                }
02502             }
02503          }
02504       }
02505 
02506       /* If we received an event from the caller, deal with it. */
02507       if (winner == in) {
02508          f = ast_read(in);
02509          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
02510             /* Got hung up */
02511             *to = -1;
02512             if (f)
02513                ast_frfree(f);
02514             return NULL;
02515          }
02516          /* First check if DTMF digit is a valid exit */
02517          if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
02518             if (option_verbose > 3)
02519                ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
02520             *to = 0;
02521             *digit = f->subclass;
02522             ast_frfree(f);
02523             return NULL;
02524          }
02525          /* Else check if DTMF should be interpreted as caller disconnect */
02526          if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
02527             if (option_verbose > 3)
02528                ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
02529             *to = 0;
02530             ast_frfree(f);
02531             return NULL;
02532          }
02533          ast_frfree(f);
02534       }
02535       if (!*to) {
02536          for (o = start; o; o = o->call_next)
02537             rna(orig, qe, o->interface, o->member->membername, 1);
02538       }
02539    }
02540 
02541    return peer;
02542 }

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

02605 {
02606    int res = 0;
02607 
02608    /* This is the holding pen for callers 2 through maxlen */
02609    for (;;) {
02610       enum queue_member_status stat;
02611 
02612       if (is_our_turn(qe))
02613          break;
02614 
02615       /* If we have timed out, break out */
02616       if (qe->expire && (time(NULL) >= qe->expire)) {
02617          *reason = QUEUE_TIMEOUT;
02618          break;
02619       }
02620 
02621       stat = get_member_status(qe->parent, qe->max_penalty);
02622 
02623       /* leave the queue if no agents, if enabled */
02624       if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
02625          *reason = QUEUE_LEAVEEMPTY;
02626          ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02627          leave_queue(qe);
02628          break;
02629       }
02630 
02631       /* leave the queue if no reachable agents, if enabled */
02632       if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
02633          *reason = QUEUE_LEAVEUNAVAIL;
02634          ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02635          leave_queue(qe);
02636          break;
02637       }
02638 
02639       /* Make a position announcement, if enabled */
02640       if (qe->parent->announcefrequency && !ringing &&
02641          (res = say_position(qe)))
02642          break;
02643 
02644       /* If we have timed out, break out */
02645       if (qe->expire && (time(NULL) >= qe->expire)) {
02646          *reason = QUEUE_TIMEOUT;
02647          break;
02648       }
02649 
02650       /* Make a periodic announcement, if enabled */
02651       if (qe->parent->periodicannouncefrequency && !ringing &&
02652          (res = say_periodic_announcement(qe)))
02653          break;
02654 
02655       /* If we have timed out, break out */
02656       if (qe->expire && (time(NULL) >= qe->expire)) {
02657          *reason = QUEUE_TIMEOUT;
02658          break;
02659       }
02660       
02661       /* Wait a second before checking again */
02662       if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
02663          if (res > 0 && !valid_exit(qe, res))
02664             res = 0;
02665          else
02666             break;
02667       }
02668       
02669       /* If we have timed out, break out */
02670       if (qe->expire && (time(NULL) >= qe->expire)) {
02671          *reason = QUEUE_TIMEOUT;
02672          break;
02673       }
02674    }
02675 
02676    return res;
02677 }


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

char* app = "Queue" [static]

Definition at line 150 of file app_queue.c.

char* app_aqm = "AddQueueMember" [static]

Definition at line 195 of file app_queue.c.

char* app_aqm_descrip [static]

Definition at line 197 of file app_queue.c.

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

Definition at line 196 of file app_queue.c.

char* app_pqm = "PauseQueueMember" [static]

Definition at line 230 of file app_queue.c.

char* app_pqm_descrip [static]

Definition at line 232 of file app_queue.c.

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

Definition at line 231 of file app_queue.c.

char* app_ql = "QueueLog" [static]

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

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

Definition at line 270 of file app_queue.c.

char* app_rqm = "RemoveQueueMember" [static]

Definition at line 214 of file app_queue.c.

char* app_rqm_descrip [static]

Definition at line 216 of file app_queue.c.

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

Definition at line 215 of file app_queue.c.

char* app_upqm = "UnpauseQueueMember" [static]

Definition at line 253 of file app_queue.c.

char* app_upqm_descrip [static]

Definition at line 255 of file app_queue.c.

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

Definition at line 254 of file app_queue.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 5672 of file app_queue.c.

int autofill_default = 0 [static]

queues.conf [general] option

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

struct ast_cli_entry cli_queue[] [static]

Definition at line 5565 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 5560 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 5550 of file app_queue.c.

ast_cond_t cond

Condition for the state change queue

Definition at line 745 of file app_queue.c.

char* descrip [static]

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

enum queue_result id

Definition at line 307 of file app_queue.c.

Referenced by _sip_show_peers().

struct statechange* last

Definition at line 747 of file app_queue.c.

ast_mutex_t lock

Lock for the state change queue

Definition at line 743 of file app_queue.c.

int montype_default = 0 [static]

queues.conf [general] option

Definition at line 294 of file app_queue.c.

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

Persistent Members astdb family.

Definition at line 277 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 5544 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 5521 of file app_queue.c.

char qrm_cmd_usage[] [static]

Initial value:

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

Definition at line 5547 of file app_queue.c.

int queue_debug = 0 [static]

queues.conf [general] extra debug option

Definition at line 282 of file app_queue.c.

int queue_persistent_members = 0 [static]

queues.conf [general] option

Definition at line 285 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 5540 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 2774 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 4583 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuemembercount_function [static]

Definition at line 4593 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuememberlist_function [static]

Definition at line 4617 of file app_queue.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function queuewaitingcount_function [static]

Definition at line 4608 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 739 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 152 of file app_queue.c.

char* text

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

int use_weight = 0 [static]

queues.conf per-queue weight option

Definition at line 288 of file app_queue.c.


Generated on Fri Apr 20 10:47:59 2012 for Asterisk - the Open Source PBX by  doxygen 1.4.7