#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/config.h"
#include "asterisk/monitor.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
Include dependency graph for app_queue.c:
Go to the source code of this file.
Data Structures | |
struct | ast_call_queue |
struct | localuser |
We define a custom "local user" structure because we use it not only for keeping track of what is in use but also for keeping track of who we're dialing. More... | |
struct | member |
struct | queue_ent |
struct | statechange |
struct | strategy |
Defines | |
#define | ANNOUNCEHOLDTIME_ALWAYS 1 |
#define | ANNOUNCEHOLDTIME_ONCE 2 |
#define | AST_MAX_WATCHERS 256 |
#define | BUILD_WATCHERS |
#define | DEFAULT_RETRY 5 |
#define | DEFAULT_TIMEOUT 15 |
#define | PM_MAX_LEN 2048 |
#define | QUEUE_EMPTY_NORMAL 1 |
#define | QUEUE_EMPTY_STRICT 2 |
#define | QUEUE_STRATEGY_FEWESTCALLS 3 |
#define | QUEUE_STRATEGY_LEASTRECENT 2 |
#define | QUEUE_STRATEGY_RANDOM 4 |
#define | QUEUE_STRATEGY_RINGALL 0 |
#define | QUEUE_STRATEGY_ROUNDROBIN 1 |
#define | QUEUE_STRATEGY_RRMEMORY 5 |
#define | RECHECK 1 |
#define | RES_EXISTS (-1) |
#define | RES_NOSUCHQUEUE (-3) |
#define | RES_OKAY 0 |
#define | RES_OUTOFMEMORY (-2) |
Enumerations | |
enum | queue_member_status { QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NORMAL } |
enum | queue_result { QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, QUEUE_JOINEMPTY = 2, QUEUE_LEAVEEMPTY = 3, QUEUE_JOINUNAVAIL = 4, QUEUE_LEAVEUNAVAIL = 5, QUEUE_FULL = 6 } |
Functions | |
static int | __queues_show (int manager, int fd, int argc, char **argv, int queue_show) |
static int | add_to_queue (char *queuename, char *interface, int penalty, int paused, int dump) |
static struct ast_call_queue * | alloc_queue (const char *queuename) |
static int | aqm_exec (struct ast_channel *chan, void *data) |
AST_MUTEX_DEFINE_STATIC (qlock) | |
static int | background_file (struct queue_ent *qe, struct ast_channel *chan, char *filename) |
static int | calc_metric (struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp) |
static void * | changethread (void *data) |
static void | clear_queue (struct ast_call_queue *q) |
static int | compare_weight (struct ast_call_queue *rq, struct member *member) |
static char * | complete_add_queue_member (char *line, char *word, int pos, int state) |
static char * | complete_queue (char *line, char *word, int pos, int state) |
static char * | complete_remove_queue_member (char *line, char *word, int pos, int state) |
static struct member * | create_queue_member (char *interface, int penalty, int paused) |
char * | description (void) |
Provides a description of the module. | |
static void | destroy_queue (struct ast_call_queue *q) |
static void | dump_queue_members (struct ast_call_queue *pm_queue) |
static struct ast_call_queue * | find_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 ast_call_queue *q, int all) |
static enum queue_member_status | get_member_status (const struct ast_call_queue *q) |
static int | handle_add_queue_member (int fd, int argc, char *argv[]) |
static int | handle_remove_queue_member (int fd, int argc, char *argv[]) |
static void | hangupcalls (struct localuser *outgoing, struct ast_channel *exception) |
static void | init_queue (struct ast_call_queue *q) |
static void | insert_entry (struct ast_call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos) |
Insert the 'new' entry after the 'prev' entry of queue 'q'. | |
static char * | int2strat (int strategy) |
static struct member * | interface_exists (struct ast_call_queue *q, char *interface) |
static int | is_our_turn (struct queue_ent *qe) |
static int | join_queue (char *queuename, struct queue_ent *qe, enum queue_result *reason) |
char * | key () |
Returns the ASTERISK_GPL_KEY. | |
static void | leave_queue (struct queue_ent *qe) |
int | load_module (void) |
Initialize the module. | |
static struct ast_call_queue * | load_realtime_queue (char *queuename) |
static int | manager_add_queue_member (struct mansession *s, struct message *m) |
static int | manager_pause_queue_member (struct mansession *s, struct message *m) |
static int | manager_queues_show (struct mansession *s, struct message *m) |
static int | manager_queues_status (struct mansession *s, struct message *m) |
static int | manager_remove_queue_member (struct mansession *s, struct message *m) |
static int | play_file (struct ast_channel *chan, char *filename) |
static int | pqm_exec (struct ast_channel *chan, void *data) |
static int | queue_exec (struct ast_channel *chan, void *data) |
static char * | queue_function_qac (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) |
static void | queue_set_param (struct ast_call_queue *q, const char *param, const char *val, int linenum, int failunknown) |
Configure a queue parameter. | |
static int | queue_show (int fd, int argc, char **argv) |
static int | queues_show (int fd, int argc, char **argv) |
static void | recalc_holdtime (struct queue_ent *qe) |
static void | record_abandoned (struct queue_ent *qe) |
int | reload (void) |
Reload stuff. | |
static void | reload_queue_members (void) |
static void | reload_queues (void) |
static int | remove_from_queue (char *queuename, char *interface) |
static void | remove_queue (struct ast_call_queue *q) |
static int | ring_entry (struct queue_ent *qe, struct localuser *tmp, int *busies) |
static int | ring_one (struct queue_ent *qe, struct localuser *outgoing, int *busies) |
static int | rqm_exec (struct ast_channel *chan, void *data) |
static void | rt_handle_member_record (struct ast_call_queue *q, char *interface, const char *penalty_str) |
static int | say_periodic_announcement (struct queue_ent *qe) |
static int | say_position (struct queue_ent *qe) |
static int | set_member_paused (char *queuename, char *interface, int paused) |
static void | set_queue_result (struct ast_channel *chan, enum queue_result res) |
static int | statechange_queue (const char *dev, int state, void *ign) |
static int | store_next (struct queue_ent *qe, struct localuser *outgoing) |
static int | strat2int (const char *strategy) |
static int | try_calling (struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on) |
int | unload_module (void) |
Cleanup all module structures, sockets, etc. | |
static int | update_dial_status (struct ast_call_queue *q, struct member *member, int status) |
static int | update_queue (struct ast_call_queue *q, struct member *member) |
static int | update_status (struct ast_call_queue *q, struct member *member, int status) |
static int | upqm_exec (struct ast_channel *chan, void *data) |
int | usecount (void) |
Provides a usecount. | |
static int | valid_exit (struct queue_ent *qe, char digit) |
static int | wait_a_bit (struct queue_ent *qe) |
static struct localuser * | wait_for_answer (struct queue_ent *qe, struct localuser *outgoing, int *to, char *digit, int prebusies, int caller_disconnect) |
static int | wait_our_turn (struct queue_ent *qe, int ringing, enum queue_result *reason) |
Variables | |
static char * | app = "Queue" |
static char * | app_aqm = "AddQueueMember" |
static char * | app_aqm_descrip |
static char * | app_aqm_synopsis = "Dynamically adds queue members" |
static char * | app_pqm = "PauseQueueMember" |
static char * | app_pqm_descrip |
static char * | app_pqm_synopsis = "Pauses a queue member" |
static char * | app_rqm = "RemoveQueueMember" |
static char * | app_rqm_descrip |
static char * | app_rqm_synopsis = "Dynamically removes queue members" |
static char * | app_upqm = "UnpauseQueueMember" |
static char * | app_upqm_descrip |
static char * | app_upqm_synopsis = "Unpauses a queue member" |
static char | aqm_cmd_usage [] |
static struct ast_cli_entry | cli_add_queue_member |
static struct ast_cli_entry | cli_remove_queue_member |
static struct ast_cli_entry | cli_show_queue |
static struct ast_cli_entry | cli_show_queues |
static char * | descrip |
LOCAL_USER_DECL | |
static const char * | pm_family = "/Queue/PersistentMembers" |
Persistent Members astdb family. | |
static int | queue_persistent_members = 0 |
queues.conf [general] option | |
struct { | |
int alarm | |
char * description | |
unsigned int event_log:1 | |
enum queue_result id | |
char * name | |
char * name | |
char * name | |
rtpPayloadType payloadType | |
unsigned int queue_log:1 | |
char * subtype | |
char * text | |
char * type | |
int val | |
} | queue_results [] |
static struct ast_custom_function | queueagentcount_function |
static struct ast_call_queue * | queues = NULL |
static char | rqm_cmd_usage [] |
static char | show_queue_usage [] |
static char | show_queues_usage [] |
static struct strategy | strategies [] |
static char * | synopsis = "Queue a call for a call queue" |
static char * | tdesc = "True Call Queueing" |
static int | use_weight = 0 |
queues.conf per-queue weight option |
These features added by David C. Troy <dave@toad.net>:
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.
|
Definition at line 308 of file app_queue.c. Referenced by queue_set_param(). |
|
Definition at line 309 of file app_queue.c. Referenced by queue_set_param(), and say_position(). |
|
Definition at line 1609 of file app_queue.c. |
|
Definition at line 1611 of file app_queue.c. Referenced by wait_for_answer(). |
|
Definition at line 112 of file app_queue.c. Referenced by init_queue(), and queue_set_param(). |
|
Definition at line 113 of file app_queue.c. Referenced by queue_set_param(). |
|
Definition at line 225 of file app_queue.c. Referenced by dump_queue_members(), and reload_queue_members(). |
|
Definition at line 306 of file app_queue.c. Referenced by queue_set_param(). |
|
Definition at line 307 of file app_queue.c. Referenced by join_queue(), and queue_set_param(). |
|
Definition at line 96 of file app_queue.c. Referenced by calc_metric(). |
|
Definition at line 95 of file app_queue.c. Referenced by calc_metric(). |
|
Definition at line 97 of file app_queue.c. Referenced by calc_metric(). |
|
Definition at line 93 of file app_queue.c. Referenced by calc_metric(). |
|
Definition at line 94 of file app_queue.c. Referenced by calc_metric(). |
|
Definition at line 98 of file app_queue.c. Referenced by calc_metric(). |
|
Definition at line 114 of file app_queue.c. |
|
Definition at line 117 of file app_queue.c. Referenced by add_to_queue(), aqm_exec(), handle_add_queue_member(), handle_remove_queue_member(), manager_add_queue_member(), manager_remove_queue_member(), and rqm_exec(). |
|
Definition at line 119 of file app_queue.c. Referenced by add_to_queue(), aqm_exec(), handle_add_queue_member(), handle_remove_queue_member(), manager_add_queue_member(), manager_remove_queue_member(), remove_from_queue(), and rqm_exec(). |
|
Definition at line 116 of file app_queue.c. Referenced by add_to_queue(), aqm_exec(), handle_add_queue_member(), handle_remove_queue_member(), manager_add_queue_member(), manager_remove_queue_member(), and rqm_exec(). |
|
Definition at line 118 of file app_queue.c. Referenced by add_to_queue(), aqm_exec(), handle_add_queue_member(), handle_remove_queue_member(), manager_add_queue_member(), manager_remove_queue_member(), and rqm_exec(). |
|
Definition at line 421 of file app_queue.c. 00421 { 00422 QUEUE_NO_MEMBERS, 00423 QUEUE_NO_REACHABLE_MEMBERS, 00424 QUEUE_NORMAL 00425 };
|
|
Definition at line 233 of file app_queue.c. 00233 { 00234 QUEUE_UNKNOWN = 0, 00235 QUEUE_TIMEOUT = 1, 00236 QUEUE_JOINEMPTY = 2, 00237 QUEUE_LEAVEEMPTY = 3, 00238 QUEUE_JOINUNAVAIL = 4, 00239 QUEUE_LEAVEUNAVAIL = 5, 00240 QUEUE_FULL = 6, 00241 };
|
|
Definition at line 3280 of file app_queue.c. References ast_build_string(), ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), member::calls, ast_call_queue::callsabandoned, ast_call_queue::callscompleted, ast_call_queue::callscompletedinsl, queue_ent::chan, ast_call_queue::count, devstate2str(), member::dynamic, ast_call_queue::head, ast_call_queue::holdtime, int2strat(), member::interface, member::lastcall, load_realtime_queue(), ast_call_queue::lock, ast_call_queue::maxlen, ast_call_queue::members, ast_channel::name, ast_call_queue::name, queue_ent::next, member::next, ast_call_queue::next, member::paused, member::penalty, queue_ent::prio, queues, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_call_queue::servicelevel, queue_ent::start, member::status, ast_call_queue::strategy, and ast_call_queue::weight. Referenced by manager_queues_show(), queue_show(), and queues_show(). 03281 { 03282 struct ast_call_queue *q; 03283 struct queue_ent *qe; 03284 struct member *mem; 03285 int pos; 03286 time_t now; 03287 char max_buf[80]; 03288 char *max; 03289 size_t max_left; 03290 float sl = 0; 03291 char *term = manager ? "\r\n" : "\n"; 03292 03293 time(&now); 03294 if ((!queue_show && argc != 2) || (queue_show && argc != 3)) 03295 return RESULT_SHOWUSAGE; 03296 03297 /* We only want to load realtime queues when a specific queue is asked for. */ 03298 if (queue_show) 03299 load_realtime_queue(argv[2]); 03300 03301 ast_mutex_lock(&qlock); 03302 03303 q = queues; 03304 if (!q) { 03305 ast_mutex_unlock(&qlock); 03306 if (queue_show) 03307 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 03308 else 03309 ast_cli(fd, "No queues.%s", term); 03310 return RESULT_SUCCESS; 03311 } 03312 while (q) { 03313 ast_mutex_lock(&q->lock); 03314 if (queue_show) { 03315 if (strcasecmp(q->name, argv[2]) != 0) { 03316 ast_mutex_unlock(&q->lock); 03317 q = q->next; 03318 if (!q) { 03319 ast_cli(fd, "No such queue: %s.%s",argv[2], term); 03320 break; 03321 } 03322 continue; 03323 } 03324 } 03325 max_buf[0] = '\0'; 03326 max = max_buf; 03327 max_left = sizeof(max_buf); 03328 if (q->maxlen) 03329 ast_build_string(&max, &max_left, "%d", q->maxlen); 03330 else 03331 ast_build_string(&max, &max_left, "unlimited"); 03332 sl = 0; 03333 if(q->callscompleted > 0) 03334 sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted); 03335 ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s", 03336 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term); 03337 if (q->members) { 03338 ast_cli(fd, " Members: %s", term); 03339 for (mem = q->members; mem; mem = mem->next) { 03340 max_buf[0] = '\0'; 03341 max = max_buf; 03342 max_left = sizeof(max_buf); 03343 if (mem->penalty) 03344 ast_build_string(&max, &max_left, " with penalty %d", mem->penalty); 03345 if (mem->dynamic) 03346 ast_build_string(&max, &max_left, " (dynamic)"); 03347 if (mem->paused) 03348 ast_build_string(&max, &max_left, " (paused)"); 03349 ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status)); 03350 if (mem->calls) { 03351 ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)", 03352 mem->calls, (long)(time(NULL) - mem->lastcall)); 03353 } else 03354 ast_build_string(&max, &max_left, " has taken no calls yet"); 03355 ast_cli(fd, " %s%s%s", mem->interface, max_buf, term); 03356 } 03357 } else 03358 ast_cli(fd, " No Members%s", term); 03359 if (q->head) { 03360 pos = 1; 03361 ast_cli(fd, " Callers: %s", term); 03362 for (qe = q->head; qe; qe = qe->next) 03363 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, qe->chan->name, 03364 (long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio, term); 03365 } else 03366 ast_cli(fd, " No Callers%s", term); 03367 ast_cli(fd, "%s", term); 03368 ast_mutex_unlock(&q->lock); 03369 q = q->next; 03370 if (queue_show) 03371 break; 03372 } 03373 ast_mutex_unlock(&qlock); 03374 return RESULT_SUCCESS; 03375 }
|
|
Definition at line 2423 of file app_queue.c. References ast_mutex_lock(), ast_mutex_unlock(), member::calls, create_queue_member(), dump_queue_members(), member::dynamic, EVENT_FLAG_AGENT, member::interface, interface_exists(), member::lastcall, load_realtime_queue(), ast_call_queue::lock, manager_event(), ast_call_queue::members, ast_call_queue::name, member::next, member::paused, member::penalty, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and member::status. Referenced by aqm_exec(), handle_add_queue_member(), and manager_add_queue_member(). 02424 { 02425 struct ast_call_queue *q; 02426 struct member *new_member; 02427 int res = RES_NOSUCHQUEUE; 02428 02429 /* \note Ensure the appropriate realtime queue is loaded. Note that this 02430 * short-circuits if the queue is already in memory. */ 02431 q = load_realtime_queue(queuename); 02432 02433 ast_mutex_lock(&qlock); 02434 02435 if (q) { 02436 ast_mutex_lock(&q->lock); 02437 if (interface_exists(q, interface) == NULL) { 02438 new_member = create_queue_member(interface, penalty, paused); 02439 02440 if (new_member != NULL) { 02441 new_member->dynamic = 1; 02442 new_member->next = q->members; 02443 q->members = new_member; 02444 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded", 02445 "Queue: %s\r\n" 02446 "Location: %s\r\n" 02447 "Membership: %s\r\n" 02448 "Penalty: %d\r\n" 02449 "CallsTaken: %d\r\n" 02450 "LastCall: %d\r\n" 02451 "Status: %d\r\n" 02452 "Paused: %d\r\n", 02453 q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static", 02454 new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused); 02455 02456 if (dump) 02457 dump_queue_members(q); 02458 02459 res = RES_OKAY; 02460 } else { 02461 res = RES_OUTOFMEMORY; 02462 } 02463 } else { 02464 res = RES_EXISTS; 02465 } 02466 ast_mutex_unlock(&q->lock); 02467 } 02468 ast_mutex_unlock(&qlock); 02469 return res; 02470 }
|
|
Definition at line 547 of file app_queue.c. References ast_mutex_init(), and malloc. Referenced by reload_queues(). 00548 { 00549 struct ast_call_queue *q; 00550 00551 q = malloc(sizeof(*q)); 00552 if (q) { 00553 memset(q, 0, sizeof(*q)); 00554 ast_mutex_init(&q->lock); 00555 ast_copy_string(q->name, queuename, sizeof(q->name)); 00556 } 00557 return q; 00558 }
|
|
Definition at line 2784 of file app_queue.c. References add_to_queue(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), localuser::chan, ast_channel::context, localuser::interface, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::name, option_priority_jumping, parse(), pbx_builtin_setvar_helper(), queue_persistent_members, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY. Referenced by load_module(). 02785 { 02786 int res=-1; 02787 struct localuser *u; 02788 char *parse, *temppos = NULL; 02789 int priority_jump = 0; 02790 AST_DECLARE_APP_ARGS(args, 02791 AST_APP_ARG(queuename); 02792 AST_APP_ARG(interface); 02793 AST_APP_ARG(penalty); 02794 AST_APP_ARG(options); 02795 ); 02796 int penalty = 0; 02797 02798 if (ast_strlen_zero(data)) { 02799 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n"); 02800 return -1; 02801 } 02802 02803 LOCAL_USER_ADD(u); 02804 02805 if (!(parse = ast_strdupa(data))) { 02806 ast_log(LOG_WARNING, "Memory Error!\n"); 02807 LOCAL_USER_REMOVE(u); 02808 return -1; 02809 } 02810 02811 AST_STANDARD_APP_ARGS(args, parse); 02812 02813 if (ast_strlen_zero(args.interface)) { 02814 args.interface = ast_strdupa(chan->name); 02815 temppos = strrchr(args.interface, '-'); 02816 if (temppos) 02817 *temppos = '\0'; 02818 } 02819 02820 if (!ast_strlen_zero(args.penalty)) { 02821 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) { 02822 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty); 02823 penalty = 0; 02824 } 02825 } 02826 02827 if (args.options) { 02828 if (strchr(args.options, 'j')) 02829 priority_jump = 1; 02830 } 02831 02832 02833 switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) { 02834 case RES_OKAY: 02835 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename); 02836 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED"); 02837 res = 0; 02838 break; 02839 case RES_EXISTS: 02840 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename); 02841 if (priority_jump || option_priority_jumping) 02842 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 02843 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY"); 02844 res = 0; 02845 break; 02846 case RES_NOSUCHQUEUE: 02847 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename); 02848 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE"); 02849 res = 0; 02850 break; 02851 case RES_OUTOFMEMORY: 02852 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename); 02853 break; 02854 } 02855 02856 LOCAL_USER_REMOVE(u); 02857 return res; 02858 }
|
|
|
|
Definition at line 1544 of file app_queue.c. References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_waitstream(), localuser::chan, ast_channel::language, and valid_exit(). Referenced by say_periodic_announcement(). 01545 { 01546 int res; 01547 01548 ast_stopstream(chan); 01549 res = ast_streamfile(chan, filename, chan->language); 01550 01551 if (!res) { 01552 /* Wait for a keypress */ 01553 res = ast_waitstream(chan, AST_DIGIT_ANY); 01554 if (res <= 0 || !valid_exit(qe, res)) 01555 res = 0; 01556 01557 /* Stop playback */ 01558 ast_stopstream(chan); 01559 } else { 01560 res = 0; 01561 } 01562 01563 /*if (res) { 01564 ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name); 01565 res = 0; 01566 }*/ 01567 01568 return res; 01569 }
|
|
Definition at line 1956 of file app_queue.c. References ast_log(), member::calls, member::lastcall, LOG_WARNING, localuser::metric, member::penalty, QUEUE_STRATEGY_FEWESTCALLS, QUEUE_STRATEGY_LEASTRECENT, QUEUE_STRATEGY_RANDOM, QUEUE_STRATEGY_RINGALL, QUEUE_STRATEGY_ROUNDROBIN, QUEUE_STRATEGY_RRMEMORY, ast_call_queue::rrpos, ast_call_queue::strategy, and ast_call_queue::wrapped. 01957 { 01958 switch (q->strategy) { 01959 case QUEUE_STRATEGY_RINGALL: 01960 /* Everyone equal, except for penalty */ 01961 tmp->metric = mem->penalty * 1000000; 01962 break; 01963 case QUEUE_STRATEGY_ROUNDROBIN: 01964 if (!pos) { 01965 if (!q->wrapped) { 01966 /* No more channels, start over */ 01967 q->rrpos = 0; 01968 } else { 01969 /* Prioritize next entry */ 01970 q->rrpos++; 01971 } 01972 q->wrapped = 0; 01973 } 01974 /* Fall through */ 01975 case QUEUE_STRATEGY_RRMEMORY: 01976 if (pos < q->rrpos) { 01977 tmp->metric = 1000 + pos; 01978 } else { 01979 if (pos > q->rrpos) 01980 /* Indicate there is another priority */ 01981 q->wrapped = 1; 01982 tmp->metric = pos; 01983 } 01984 tmp->metric += mem->penalty * 1000000; 01985 break; 01986 case QUEUE_STRATEGY_RANDOM: 01987 tmp->metric = rand() % 1000; 01988 tmp->metric += mem->penalty * 1000000; 01989 break; 01990 case QUEUE_STRATEGY_FEWESTCALLS: 01991 tmp->metric = mem->calls; 01992 tmp->metric += mem->penalty * 1000000; 01993 break; 01994 case QUEUE_STRATEGY_LEASTRECENT: 01995 if (!mem->lastcall) 01996 tmp->metric = 0; 01997 else 01998 tmp->metric = 1000000 - (time(NULL) - mem->lastcall); 01999 tmp->metric += mem->penalty * 1000000; 02000 break; 02001 default: 02002 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy); 02003 break; 02004 } 02005 return 0; 02006 }
|
|
Definition at line 453 of file app_queue.c. References ast_log(), ast_mutex_lock(), ast_strdupa, statechange::dev, devstate2str(), EVENT_FLAG_AGENT, free, ast_call_queue::lock, LOG_DEBUG, manager_event(), ast_call_queue::maskmemberstatus, ast_call_queue::members, ast_call_queue::name, ast_call_queue::next, option_debug, queues, statechange::state, and member::status. Referenced by statechange_queue(). 00454 { 00455 struct ast_call_queue *q; 00456 struct statechange *sc = data; 00457 struct member *cur; 00458 char *loc; 00459 char *technology; 00460 00461 technology = ast_strdupa(sc->dev); 00462 loc = strchr(technology, '/'); 00463 if (loc) { 00464 *loc = '\0'; 00465 loc++; 00466 } else { 00467 free(sc); 00468 return NULL; 00469 } 00470 if (option_debug) 00471 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state)); 00472 ast_mutex_lock(&qlock); 00473 for (q = queues; q; q = q->next) { 00474 ast_mutex_lock(&q->lock); 00475 cur = q->members; 00476 while(cur) { 00477 if (!strcasecmp(sc->dev, cur->interface)) { 00478 if (cur->status != sc->state) { 00479 cur->status = sc->state; 00480 if (!q->maskmemberstatus) { 00481 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 00482 "Queue: %s\r\n" 00483 "Location: %s\r\n" 00484 "Membership: %s\r\n" 00485 "Penalty: %d\r\n" 00486 "CallsTaken: %d\r\n" 00487 "LastCall: %d\r\n" 00488 "Status: %d\r\n" 00489 "Paused: %d\r\n", 00490 q->name, cur->interface, cur->dynamic ? "dynamic" : "static", 00491 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused); 00492 } 00493 } 00494 } 00495 cur = cur->next; 00496 } 00497 ast_mutex_unlock(&q->lock); 00498 } 00499 ast_mutex_unlock(&qlock); 00500 free(sc); 00501 return NULL; 00502 }
|
|
Definition at line 587 of file app_queue.c. References ast_call_queue::callsabandoned, ast_call_queue::callscompleted, ast_call_queue::callscompletedinsl, ast_call_queue::holdtime, and ast_call_queue::wrapuptime. Referenced by reload_queues(). 00588 { 00589 q->holdtime = 0; 00590 q->callscompleted = 0; 00591 q->callsabandoned = 0; 00592 q->callscompletedinsl = 0; 00593 q->wrapuptime = 0; 00594 }
|
|
Definition at line 1316 of file app_queue.c. References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_call_queue::count, member::interface, ast_call_queue::lock, LOG_DEBUG, ast_call_queue::members, ast_call_queue::name, member::next, ast_call_queue::next, queues, and ast_call_queue::weight. Referenced by ring_entry(). 01317 { 01318 struct ast_call_queue *q; 01319 struct member *mem; 01320 int found = 0; 01321 01322 /* &qlock and &rq->lock already set by try_calling() 01323 * to solve deadlock */ 01324 for (q = queues; q; q = q->next) { 01325 if (q == rq) /* don't check myself, could deadlock */ 01326 continue; 01327 ast_mutex_lock(&q->lock); 01328 if (q->count && q->members) { 01329 for (mem = q->members; mem; mem = mem->next) { 01330 if (!strcmp(mem->interface, member->interface)) { 01331 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name); 01332 if (q->weight > rq->weight) { 01333 ast_log(LOG_DEBUG, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count); 01334 found = 1; 01335 break; 01336 } 01337 } 01338 } 01339 } 01340 ast_mutex_unlock(&q->lock); 01341 if (found) 01342 break; 01343 } 01344 ast_mutex_unlock(&qlock); 01345 return found; 01346 }
|
|
Definition at line 3656 of file app_queue.c. References complete_queue(), malloc, and strdup. 03657 { 03658 /* 0 - add; 1 - queue; 2 - member; 3 - <member>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty> */ 03659 switch (pos) { 03660 case 3: 03661 /* Don't attempt to complete name of member (infinite possibilities) */ 03662 return NULL; 03663 case 4: 03664 if (state == 0) { 03665 return strdup("to"); 03666 } else { 03667 return NULL; 03668 } 03669 case 5: 03670 /* No need to duplicate code */ 03671 return complete_queue(line, word, pos, state); 03672 case 6: 03673 if (state == 0) { 03674 return strdup("penalty"); 03675 } else { 03676 return NULL; 03677 } 03678 case 7: 03679 if (state < 100) { /* 0-99 */ 03680 char *num = malloc(3); 03681 if (num) { 03682 sprintf(num, "%d", state); 03683 } 03684 return num; 03685 } else { 03686 return NULL; 03687 } 03688 default: 03689 return NULL; 03690 } 03691 }
|
|
Definition at line 3387 of file app_queue.c. References ast_mutex_lock(), ast_call_queue::name, ast_call_queue::next, and queues. Referenced by complete_add_queue_member(), and complete_remove_queue_member(). 03388 { 03389 struct ast_call_queue *q; 03390 int which=0; 03391 03392 ast_mutex_lock(&qlock); 03393 for (q = queues; q; q = q->next) { 03394 if (!strncasecmp(word, q->name, strlen(word))) { 03395 if (++which > state) 03396 break; 03397 } 03398 } 03399 ast_mutex_unlock(&qlock); 03400 return q ? strdup(q->name) : NULL; 03401 }
|
|
Definition at line 3724 of file app_queue.c. References ast_mutex_lock(), ast_mutex_unlock(), complete_queue(), member::interface, ast_call_queue::lock, ast_call_queue::members, member::next, ast_call_queue::next, queues, and strdup. 03725 { 03726 int which = 0; 03727 struct ast_call_queue *q; 03728 struct member *m; 03729 03730 /* 0 - add; 1 - queue; 2 - member; 3 - <member>; 4 - to; 5 - <queue> */ 03731 if ((pos > 5) || (pos < 3)) { 03732 return NULL; 03733 } 03734 if (pos == 4) { 03735 if (state == 0) { 03736 return strdup("from"); 03737 } else { 03738 return NULL; 03739 } 03740 } 03741 03742 if (pos == 5) { 03743 /* No need to duplicate code */ 03744 return complete_queue(line, word, pos, state); 03745 } 03746 03747 if (queues != NULL) { 03748 for (q = queues ; q ; q = q->next) { 03749 ast_mutex_lock(&q->lock); 03750 for (m = q->members ; m ; m = m->next) { 03751 if (++which > state) { 03752 ast_mutex_unlock(&q->lock); 03753 return strdup(m->interface); 03754 } 03755 } 03756 ast_mutex_unlock(&q->lock); 03757 } 03758 } 03759 return NULL; 03760 }
|
|
Definition at line 526 of file app_queue.c. References ast_device_state(), ast_log(), LOG_WARNING, and malloc. Referenced by add_to_queue(), reload_queues(), and rt_handle_member_record(). 00527 { 00528 struct member *cur; 00529 00530 /* Add a new member */ 00531 00532 cur = malloc(sizeof(struct member)); 00533 00534 if (cur) { 00535 memset(cur, 0, sizeof(struct member)); 00536 cur->penalty = penalty; 00537 cur->paused = paused; 00538 ast_copy_string(cur->interface, interface, sizeof(cur->interface)); 00539 if (!strchr(cur->interface, '/')) 00540 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface); 00541 cur->status = ast_device_state(interface); 00542 } 00543 00544 return cur; 00545 }
|
|
Provides a description of the module.
Definition at line 3855 of file app_queue.c. References tdesc. 03856 { 03857 return tdesc; 03858 }
|
|
Definition at line 776 of file app_queue.c. References ast_mutex_destroy(), free, free_members(), and ast_call_queue::lock. Referenced by leave_queue(), and reload_queues(). 00777 { 00778 free_members(q, 1); 00779 ast_mutex_destroy(&q->lock); 00780 free(q); 00781 }
|
|
Definition at line 2344 of file app_queue.c. References ast_db_del(), ast_db_put(), ast_log(), member::dynamic, member::interface, LOG_WARNING, ast_call_queue::members, ast_call_queue::name, member::next, member::paused, member::penalty, pm_family, and PM_MAX_LEN. Referenced by add_to_queue(), and set_member_paused(). 02345 { 02346 struct member *cur_member; 02347 char value[PM_MAX_LEN]; 02348 int value_len = 0; 02349 int res; 02350 02351 memset(value, 0, sizeof(value)); 02352 02353 if (!pm_queue) 02354 return; 02355 02356 for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) { 02357 if (!cur_member->dynamic) 02358 continue; 02359 02360 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s", 02361 cur_member->interface, cur_member->penalty, cur_member->paused, 02362 cur_member->next ? "|" : ""); 02363 if (res != strlen(value + value_len)) { 02364 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n"); 02365 break; 02366 } 02367 value_len += res; 02368 } 02369 02370 if (value_len && !cur_member) { 02371 if (ast_db_put(pm_family, pm_queue->name, value)) 02372 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n"); 02373 } else 02374 /* Delete the entry if the queue is empty or there is an error */ 02375 ast_db_del(pm_family, pm_queue->name); 02376 }
|
|
Reload a single queue via realtime.
Definition at line 804 of file app_queue.c. References member::interface, ast_call_queue::name, ast_call_queue::next, and queues. 00805 { 00806 struct ast_variable *v; 00807 struct ast_call_queue *q, *prev_q = NULL; 00808 struct member *m, *prev_m, *next_m; 00809 char *interface; 00810 char *tmp, *tmp_name; 00811 char tmpbuf[64]; /* Must be longer than the longest queue param name. */ 00812 00813 /* Find the queue in the in-core list (we will create a new one if not found). */ 00814 for (q = queues; q; q = q->next) { 00815 if (!strcasecmp(q->name, queuename)) { 00816 break; 00817 } 00818 prev_q = q; 00819 } 00820 00821 /* Static queues override realtime. */ 00822 if (q) { 00823 ast_mutex_lock(&q->lock); 00824 if (!q->realtime) { 00825 if (q->dead) { 00826 ast_mutex_unlock(&q->lock); 00827 return NULL; 00828 } else { 00829 ast_mutex_unlock(&q->lock); 00830 return q; 00831 } 00832 } 00833 } else if (!member_config) 00834 /* Not found in the list, and it's not realtime ... */ 00835 return NULL; 00836 00837 /* Check if queue is defined in realtime. */ 00838 if (!queue_vars) { 00839 /* Delete queue from in-core list if it has been deleted in realtime. */ 00840 if (q) { 00841 /*! \note Hmm, can't seem to distinguish a DB failure from a not 00842 found condition... So we might delete an in-core queue 00843 in case of DB failure. */ 00844 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename); 00845 00846 q->dead = 1; 00847 /* Delete if unused (else will be deleted when last caller leaves). */ 00848 if (!q->count) { 00849 /* Delete. */ 00850 if (!prev_q) { 00851 queues = q->next; 00852 } else { 00853 prev_q->next = q->next; 00854 } 00855 ast_mutex_unlock(&q->lock); 00856 destroy_queue(q); 00857 } else 00858 ast_mutex_unlock(&q->lock); 00859 } 00860 return NULL; 00861 } 00862 00863 /* Create a new queue if an in-core entry does not exist yet. */ 00864 if (!q) { 00865 q = alloc_queue(queuename); 00866 if (!q) 00867 return NULL; 00868 ast_mutex_lock(&q->lock); 00869 clear_queue(q); 00870 q->realtime = 1; 00871 q->next = queues; 00872 queues = q; 00873 } 00874 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */ 00875 00876 v = queue_vars; 00877 memset(tmpbuf, 0, sizeof(tmpbuf)); 00878 while(v) { 00879 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */ 00880 if((tmp = strchr(v->name, '_')) != NULL) { 00881 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf)); 00882 tmp_name = tmpbuf; 00883 tmp = tmp_name; 00884 while((tmp = strchr(tmp, '_')) != NULL) 00885 *tmp++ = '-'; 00886 } else 00887 tmp_name = v->name; 00888 queue_set_param(q, tmp_name, v->value, -1, 0); 00889 v = v->next; 00890 } 00891 00892 /* Temporarily set non-dynamic members dead so we can detect deleted ones. */ 00893 m = q->members; 00894 while (m) { 00895 if (!m->dynamic) 00896 m->dead = 1; 00897 m = m->next; 00898 } 00899 00900 interface = ast_category_browse(member_config, NULL); 00901 while (interface) { 00902 rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty")); 00903 interface = ast_category_browse(member_config, interface); 00904 } 00905 00906 /* Delete all realtime members that have been deleted in DB. */ 00907 m = q->members; 00908 prev_m = NULL; 00909 while (m) { 00910 next_m = m->next; 00911 if (m->dead) { 00912 if (prev_m) { 00913 prev_m->next = next_m; 00914 } else { 00915 q->members = next_m; 00916 } 00917 free(m); 00918 } else { 00919 prev_m = m; 00920 } 00921 m = next_m; 00922 } 00923 00924 ast_mutex_unlock(&q->lock); 00925 00926 return q; 00927 }
|
|
Definition at line 758 of file app_queue.c. References member::dynamic, free, ast_call_queue::members, and member::next. Referenced by destroy_queue(), and reload_queues(). 00759 { 00760 /* Free non-dynamic members */ 00761 struct member *curm, *next, *prev = NULL; 00762 00763 for (curm = q->members; curm; curm = next) { 00764 next = curm->next; 00765 if (all || !curm->dynamic) { 00766 if (prev) 00767 prev->next = next; 00768 else 00769 q->members = next; 00770 free(curm); 00771 } else 00772 prev = curm; 00773 } 00774 }
|
|
Definition at line 427 of file app_queue.c. References AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, ast_call_queue::members, member::next, QUEUE_NO_MEMBERS, QUEUE_NO_REACHABLE_MEMBERS, QUEUE_NORMAL, result, and member::status. Referenced by join_queue(). 00428 { 00429 struct member *member; 00430 enum queue_member_status result = QUEUE_NO_MEMBERS; 00431 00432 for (member = q->members; member; member = member->next) { 00433 switch (member->status) { 00434 case AST_DEVICE_INVALID: 00435 /* nothing to do */ 00436 break; 00437 case AST_DEVICE_UNAVAILABLE: 00438 result = QUEUE_NO_REACHABLE_MEMBERS; 00439 break; 00440 default: 00441 return QUEUE_NORMAL; 00442 } 00443 } 00444 00445 return result; 00446 }
|
|
Definition at line 3609 of file app_queue.c. References add_to_queue(), ast_cli(), member::interface, member::penalty, queue_persistent_members, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS. 03610 { 03611 char *queuename, *interface; 03612 int penalty; 03613 03614 if ((argc != 6) && (argc != 8)) { 03615 return RESULT_SHOWUSAGE; 03616 } else if (strcmp(argv[4], "to")) { 03617 return RESULT_SHOWUSAGE; 03618 } else if ((argc == 8) && strcmp(argv[6], "penalty")) { 03619 return RESULT_SHOWUSAGE; 03620 } 03621 03622 queuename = argv[5]; 03623 interface = argv[3]; 03624 if (argc == 8) { 03625 if (sscanf(argv[7], "%d", &penalty) == 1) { 03626 if (penalty < 0) { 03627 ast_cli(fd, "Penalty must be >= 0\n"); 03628 penalty = 0; 03629 } 03630 } else { 03631 ast_cli(fd, "Penalty must be an integer >= 0\n"); 03632 penalty = 0; 03633 } 03634 } else { 03635 penalty = 0; 03636 } 03637 03638 switch (add_to_queue(queuename, interface, penalty, 0, queue_persistent_members)) { 03639 case RES_OKAY: 03640 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename); 03641 return RESULT_SUCCESS; 03642 case RES_EXISTS: 03643 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename); 03644 return RESULT_FAILURE; 03645 case RES_NOSUCHQUEUE: 03646 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename); 03647 return RESULT_FAILURE; 03648 case RES_OUTOFMEMORY: 03649 ast_cli(fd, "Out of memory\n"); 03650 return RESULT_FAILURE; 03651 default: 03652 return RESULT_FAILURE; 03653 } 03654 }
|
|
Definition at line 3693 of file app_queue.c. References ast_cli(), member::interface, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS. 03694 { 03695 char *queuename, *interface; 03696 03697 if (argc != 6) { 03698 return RESULT_SHOWUSAGE; 03699 } else if (strcmp(argv[4], "from")) { 03700 return RESULT_SHOWUSAGE; 03701 } 03702 03703 queuename = argv[5]; 03704 interface = argv[3]; 03705 03706 switch (remove_from_queue(queuename, interface)) { 03707 case RES_OKAY: 03708 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename); 03709 return RESULT_SUCCESS; 03710 case RES_EXISTS: 03711 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename); 03712 return RESULT_FAILURE; 03713 case RES_NOSUCHQUEUE: 03714 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename); 03715 return RESULT_FAILURE; 03716 case RES_OUTOFMEMORY: 03717 ast_cli(fd, "Out of memory\n"); 03718 return RESULT_FAILURE; 03719 default: 03720 return RESULT_FAILURE; 03721 } 03722 }
|
|
Definition at line 1255 of file app_queue.c. References ast_hangup(), localuser::chan, free, and localuser::next. 01256 { 01257 struct localuser *oo; 01258 01259 while(outgoing) { 01260 /* Hangup any existing lines we have open */ 01261 if (outgoing->chan && (outgoing->chan != exception)) 01262 ast_hangup(outgoing->chan); 01263 oo = outgoing; 01264 outgoing=outgoing->next; 01265 free(oo); 01266 } 01267 }
|
|
|
Insert the 'new' entry after the 'prev' entry of queue 'q'.
Definition at line 402 of file app_queue.c. References ast_call_queue::head, queue_ent::next, and queue_ent::parent. Referenced by join_queue(). 00403 { 00404 struct queue_ent *cur; 00405 00406 if (!q || !new) 00407 return; 00408 if (prev) { 00409 cur = prev->next; 00410 prev->next = new; 00411 } else { 00412 cur = q->head; 00413 q->head = new; 00414 } 00415 new->next = cur; 00416 new->parent = q; 00417 new->pos = ++(*pos); 00418 new->opos = *pos; 00419 }
|
|
Definition at line 381 of file app_queue.c. References name, and strategies. Referenced by __queues_show(). 00382 { 00383 int x; 00384 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) { 00385 if (strategy == strategies[x].strategy) 00386 return strategies[x].name; 00387 } 00388 return "<unknown>"; 00389 }
|
|
Definition at line 2326 of file app_queue.c. References member::interface, ast_call_queue::members, and member::next. Referenced by add_to_queue(), remove_from_queue(), and set_member_paused(). 02327 { 02328 struct member *mem; 02329 02330 if (q) 02331 for (mem = q->members; mem; mem = mem->next) 02332 if (!strcasecmp(interface, mem->interface)) 02333 return mem; 02334 02335 return NULL; 02336 }
|
|
Definition at line 1863 of file app_queue.c. References ast_log(), queue_ent::chan, ast_call_queue::head, LOG_DEBUG, ast_channel::name, option_debug, and queue_ent::parent. Referenced by wait_our_turn(). 01864 { 01865 struct queue_ent *ch; 01866 int res; 01867 01868 /* Atomically read the parent head -- does not need a lock */ 01869 ch = qe->parent->head; 01870 /* If we are now at the top of the head, break out */ 01871 if (ch == qe) { 01872 if (option_debug) 01873 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name); 01874 res = 1; 01875 } else { 01876 if (option_debug) 01877 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name); 01878 res = 0; 01879 } 01880 return res; 01881 }
|
|
Definition at line 976 of file app_queue.c. References queue_ent::announce, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, queue_ent::context, ast_call_queue::count, EVENT_FLAG_CALL, get_member_status(), ast_call_queue::head, insert_entry(), ast_call_queue::joinempty, load_realtime_queue(), ast_call_queue::lock, LOG_NOTICE, manager_event(), ast_call_queue::maxlen, queue_ent::moh, ast_channel::name, queue_ent::next, queue_ent::pos, queue_ent::prio, QUEUE_EMPTY_STRICT, QUEUE_FULL, QUEUE_JOINEMPTY, QUEUE_JOINUNAVAIL, QUEUE_NO_MEMBERS, and QUEUE_NO_REACHABLE_MEMBERS. Referenced by queue_exec(). 00977 { 00978 struct ast_call_queue *q; 00979 struct queue_ent *cur, *prev = NULL; 00980 int res = -1; 00981 int pos = 0; 00982 int inserted = 0; 00983 enum queue_member_status stat; 00984 00985 q = load_realtime_queue(queuename); 00986 if (!q) 00987 return res; 00988 00989 ast_mutex_lock(&qlock); 00990 ast_mutex_lock(&q->lock); 00991 00992 /* This is our one */ 00993 stat = get_member_status(q); 00994 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) 00995 *reason = QUEUE_JOINEMPTY; 00996 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) 00997 *reason = QUEUE_JOINUNAVAIL; 00998 else if (q->maxlen && (q->count >= q->maxlen)) 00999 *reason = QUEUE_FULL; 01000 else { 01001 /* There's space for us, put us at the right position inside 01002 * the queue. 01003 * Take into account the priority of the calling user */ 01004 inserted = 0; 01005 prev = NULL; 01006 cur = q->head; 01007 while(cur) { 01008 /* We have higher priority than the current user, enter 01009 * before him, after all the other users with priority 01010 * higher or equal to our priority. */ 01011 if ((!inserted) && (qe->prio > cur->prio)) { 01012 insert_entry(q, prev, qe, &pos); 01013 inserted = 1; 01014 } 01015 cur->pos = ++pos; 01016 prev = cur; 01017 cur = cur->next; 01018 } 01019 /* No luck, join at the end of the queue */ 01020 if (!inserted) 01021 insert_entry(q, prev, qe, &pos); 01022 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh)); 01023 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce)); 01024 ast_copy_string(qe->context, q->context, sizeof(qe->context)); 01025 q->count++; 01026 res = 0; 01027 manager_event(EVENT_FLAG_CALL, "Join", 01028 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n", 01029 qe->chan->name, 01030 qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown", 01031 qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown", 01032 q->name, qe->pos, q->count ); 01033 #if 0 01034 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos ); 01035 #endif 01036 } 01037 ast_mutex_unlock(&q->lock); 01038 ast_mutex_unlock(&qlock); 01039 return res; 01040 }
|
|
Returns the ASTERISK_GPL_KEY. This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:
char *key(void) { return ASTERISK_GPL_KEY; }
Definition at line 3867 of file app_queue.c. References ASTERISK_GPL_KEY. 03868 { 03869 return ASTERISK_GPL_KEY; 03870 }
|
|
Definition at line 1210 of file app_queue.c. References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), queue_ent::chan, ast_call_queue::count, ast_call_queue::dead, destroy_queue(), EVENT_FLAG_CALL, ast_call_queue::head, ast_call_queue::lock, LOG_NOTICE, manager_event(), ast_call_queue::name, ast_channel::name, queue_ent::next, queue_ent::parent, queue_ent::pos, and remove_queue(). 01211 { 01212 struct ast_call_queue *q; 01213 struct queue_ent *cur, *prev = NULL; 01214 int pos = 0; 01215 01216 q = qe->parent; 01217 if (!q) 01218 return; 01219 ast_mutex_lock(&q->lock); 01220 01221 prev = NULL; 01222 cur = q->head; 01223 while(cur) { 01224 if (cur == qe) { 01225 q->count--; 01226 01227 /* Take us out of the queue */ 01228 manager_event(EVENT_FLAG_CALL, "Leave", 01229 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n", 01230 qe->chan->name, q->name, q->count); 01231 #if 0 01232 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); 01233 #endif 01234 /* Take us out of the queue */ 01235 if (prev) 01236 prev->next = cur->next; 01237 else 01238 q->head = cur->next; 01239 } else { 01240 /* Renumber the people after us in the queue based on a new count */ 01241 cur->pos = ++pos; 01242 prev = cur; 01243 } 01244 cur = cur->next; 01245 } 01246 ast_mutex_unlock(&q->lock); 01247 if (q->dead && !q->count) { 01248 /* It's dead and nobody is in it, so kill it */ 01249 remove_queue(q); 01250 destroy_queue(q); 01251 } 01252 }
|
|
|
Definition at line 929 of file app_queue.c. References ast_mutex_lock(), ast_call_queue::name, ast_call_queue::next, and queues. Referenced by __queues_show(), add_to_queue(), and join_queue(). 00930 { 00931 struct ast_variable *queue_vars = NULL; 00932 struct ast_config *member_config = NULL; 00933 struct ast_call_queue *q; 00934 00935 /* Find the queue in the in-core list first. */ 00936 ast_mutex_lock(&qlock); 00937 for (q = queues; q; q = q->next) { 00938 if (!strcasecmp(q->name, queuename)) { 00939 break; 00940 } 00941 } 00942 ast_mutex_unlock(&qlock); 00943 00944 if (!q || q->realtime) { 00945 /*! \note Load from realtime before taking the global qlock, to avoid blocking all 00946 queue operations while waiting for the DB. 00947 00948 This will be two separate database transactions, so we might 00949 see queue parameters as they were before another process 00950 changed the queue and member list as it was after the change. 00951 Thus we might see an empty member list when a queue is 00952 deleted. In practise, this is unlikely to cause a problem. */ 00953 00954 queue_vars = ast_load_realtime("queues", "name", queuename, NULL); 00955 if (queue_vars) { 00956 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL); 00957 if (!member_config) { 00958 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n"); 00959 return NULL; 00960 } 00961 } 00962 00963 ast_mutex_lock(&qlock); 00964 00965 q = find_queue_by_name_rt(queuename, queue_vars, member_config); 00966 if (member_config) 00967 ast_config_destroy(member_config); 00968 if (queue_vars) 00969 ast_variables_destroy(queue_vars); 00970 00971 ast_mutex_unlock(&qlock); 00972 } 00973 return q; 00974 }
|
|
Definition at line 3505 of file app_queue.c. References add_to_queue(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), member::interface, member::paused, member::penalty, queue_persistent_members, RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and s. Referenced by load_module(). 03506 { 03507 char *queuename, *interface, *penalty_s, *paused_s; 03508 int paused, penalty = 0; 03509 03510 queuename = astman_get_header(m, "Queue"); 03511 interface = astman_get_header(m, "Interface"); 03512 penalty_s = astman_get_header(m, "Penalty"); 03513 paused_s = astman_get_header(m, "Paused"); 03514 03515 if (ast_strlen_zero(queuename)) { 03516 astman_send_error(s, m, "'Queue' not specified."); 03517 return 0; 03518 } 03519 03520 if (ast_strlen_zero(interface)) { 03521 astman_send_error(s, m, "'Interface' not specified."); 03522 return 0; 03523 } 03524 03525 if (ast_strlen_zero(penalty_s)) 03526 penalty = 0; 03527 else if (sscanf(penalty_s, "%d", &penalty) != 1) { 03528 penalty = 0; 03529 } 03530 03531 if (ast_strlen_zero(paused_s)) 03532 paused = 0; 03533 else 03534 paused = abs(ast_true(paused_s)); 03535 03536 switch (add_to_queue(queuename, interface, penalty, paused, queue_persistent_members)) { 03537 case RES_OKAY: 03538 astman_send_ack(s, m, "Added interface to queue"); 03539 break; 03540 case RES_EXISTS: 03541 astman_send_error(s, m, "Unable to add interface: Already there"); 03542 break; 03543 case RES_NOSUCHQUEUE: 03544 astman_send_error(s, m, "Unable to add interface to queue: No such queue"); 03545 break; 03546 case RES_OUTOFMEMORY: 03547 astman_send_error(s, m, "Out of memory"); 03548 break; 03549 } 03550 return 0; 03551 }
|
|
Definition at line 3582 of file app_queue.c. References ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), member::interface, member::paused, s, and set_member_paused(). Referenced by load_module(). 03583 { 03584 char *queuename, *interface, *paused_s; 03585 int paused; 03586 03587 interface = astman_get_header(m, "Interface"); 03588 paused_s = astman_get_header(m, "Paused"); 03589 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */ 03590 03591 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) { 03592 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters."); 03593 return 0; 03594 } 03595 03596 paused = abs(ast_true(paused_s)); 03597 03598 if (set_member_paused(queuename, interface, paused)) 03599 astman_send_error(s, m, "Interface not found"); 03600 else 03601 if (paused) 03602 astman_send_ack(s, m, "Interface paused successfully"); 03603 else 03604 astman_send_ack(s, m, "Interface unpaused successfully"); 03605 03606 return 0; 03607 }
|
|
Definition at line 3406 of file app_queue.c. References __queues_show(), ast_cli(), RESULT_SUCCESS, and s. Referenced by load_module(). 03407 { 03408 char *a[] = { "show", "queues" }; 03409 __queues_show(1, s->fd, 2, a, 0); 03410 ast_cli(s->fd, "\r\n\r\n"); /* Properly terminate Manager output */ 03411 03412 return RESULT_SUCCESS; 03413 }
|
|
Definition at line 3416 of file app_queue.c. References ast_cli(), ast_mutex_lock(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), member::calls, ast_call_queue::callsabandoned, ast_call_queue::callscompleted, ast_call_queue::callscompletedinsl, ast_call_queue::count, member::dynamic, ast_call_queue::holdtime, member::interface, member::lastcall, ast_call_queue::lock, ast_call_queue::maxlen, ast_call_queue::members, ast_call_queue::name, member::next, ast_call_queue::next, member::paused, member::penalty, queues, s, ast_call_queue::servicelevel, member::status, and ast_call_queue::weight. Referenced by load_module(). 03417 { 03418 time_t now; 03419 int pos; 03420 char *id = astman_get_header(m,"ActionID"); 03421 char *queuefilter = astman_get_header(m,"Queue"); 03422 char *memberfilter = astman_get_header(m,"Member"); 03423 char idText[256] = ""; 03424 struct ast_call_queue *q; 03425 struct queue_ent *qe; 03426 float sl = 0; 03427 struct member *mem; 03428 03429 astman_send_ack(s, m, "Queue status will follow"); 03430 time(&now); 03431 ast_mutex_lock(&qlock); 03432 if (!ast_strlen_zero(id)) { 03433 snprintf(idText,256,"ActionID: %s\r\n",id); 03434 } 03435 for (q = queues; q; q = q->next) { 03436 ast_mutex_lock(&q->lock); 03437 03438 /* List queue properties */ 03439 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) { 03440 if(q->callscompleted > 0) 03441 sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted); 03442 ast_cli(s->fd, "Event: QueueParams\r\n" 03443 "Queue: %s\r\n" 03444 "Max: %d\r\n" 03445 "Calls: %d\r\n" 03446 "Holdtime: %d\r\n" 03447 "Completed: %d\r\n" 03448 "Abandoned: %d\r\n" 03449 "ServiceLevel: %d\r\n" 03450 "ServicelevelPerf: %2.1f\r\n" 03451 "Weight: %d\r\n" 03452 "%s" 03453 "\r\n", 03454 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted, 03455 q->callsabandoned, q->servicelevel, sl, q->weight, idText); 03456 /* List Queue Members */ 03457 for (mem = q->members; mem; mem = mem->next) { 03458 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) { 03459 ast_cli(s->fd, "Event: QueueMember\r\n" 03460 "Queue: %s\r\n" 03461 "Location: %s\r\n" 03462 "Membership: %s\r\n" 03463 "Penalty: %d\r\n" 03464 "CallsTaken: %d\r\n" 03465 "LastCall: %d\r\n" 03466 "Status: %d\r\n" 03467 "Paused: %d\r\n" 03468 "%s" 03469 "\r\n", 03470 q->name, mem->interface, mem->dynamic ? "dynamic" : "static", 03471 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText); 03472 } 03473 } 03474 /* List Queue Entries */ 03475 pos = 1; 03476 for (qe = q->head; qe; qe = qe->next) { 03477 ast_cli(s->fd, "Event: QueueEntry\r\n" 03478 "Queue: %s\r\n" 03479 "Position: %d\r\n" 03480 "Channel: %s\r\n" 03481 "CallerID: %s\r\n" 03482 "CallerIDName: %s\r\n" 03483 "Wait: %ld\r\n" 03484 "%s" 03485 "\r\n", 03486 q->name, pos++, qe->chan->name, 03487 qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown", 03488 qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown", 03489 (long)(now - qe->start), idText); 03490 } 03491 } 03492 ast_mutex_unlock(&q->lock); 03493 } 03494 ast_mutex_unlock(&qlock); 03495 03496 ast_cli(s->fd, 03497 "Event: QueueStatusComplete\r\n" 03498 "%s" 03499 "\r\n",idText); 03500 03501 03502 return RESULT_SUCCESS; 03503 }
|
|
Definition at line 3553 of file app_queue.c. References ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), member::interface, remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, RES_OUTOFMEMORY, and s. Referenced by load_module(). 03554 { 03555 char *queuename, *interface; 03556 03557 queuename = astman_get_header(m, "Queue"); 03558 interface = astman_get_header(m, "Interface"); 03559 03560 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) { 03561 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters."); 03562 return 0; 03563 } 03564 03565 switch (remove_from_queue(queuename, interface)) { 03566 case RES_OKAY: 03567 astman_send_ack(s, m, "Removed interface from queue"); 03568 break; 03569 case RES_EXISTS: 03570 astman_send_error(s, m, "Unable to remove interface: Not there"); 03571 break; 03572 case RES_NOSUCHQUEUE: 03573 astman_send_error(s, m, "Unable to remove interface from queue: No such queue"); 03574 break; 03575 case RES_OUTOFMEMORY: 03576 astman_send_error(s, m, "Out of memory"); 03577 break; 03578 } 03579 return 0; 03580 }
|
|
Definition at line 1042 of file app_queue.c. References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_waitstream(), queue_ent::chan, and ast_channel::language. Referenced by say_position(). 01043 { 01044 int res; 01045 01046 ast_stopstream(chan); 01047 res = ast_streamfile(chan, filename, chan->language); 01048 01049 if (!res) 01050 res = ast_waitstream(chan, AST_DIGIT_ANY); 01051 else 01052 res = 0; 01053 01054 ast_stopstream(chan); 01055 01056 return res; 01057 }
|
|
Definition at line 2605 of file app_queue.c. References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), localuser::chan, ast_channel::context, localuser::interface, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, option_priority_jumping, parse(), pbx_builtin_setvar_helper(), and set_member_paused(). Referenced by load_module(). 02606 { 02607 struct localuser *u; 02608 char *parse; 02609 int priority_jump = 0; 02610 AST_DECLARE_APP_ARGS(args, 02611 AST_APP_ARG(queuename); 02612 AST_APP_ARG(interface); 02613 AST_APP_ARG(options); 02614 ); 02615 02616 if (ast_strlen_zero(data)) { 02617 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 02618 return -1; 02619 } 02620 02621 LOCAL_USER_ADD(u); 02622 02623 if (!(parse = ast_strdupa(data))) { 02624 ast_log(LOG_WARNING, "Memory Error!\n"); 02625 LOCAL_USER_REMOVE(u); 02626 return -1; 02627 } 02628 02629 AST_STANDARD_APP_ARGS(args, parse); 02630 02631 if (args.options) { 02632 if (strchr(args.options, 'j')) 02633 priority_jump = 1; 02634 } 02635 02636 if (ast_strlen_zero(args.interface)) { 02637 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 02638 LOCAL_USER_REMOVE(u); 02639 return -1; 02640 } 02641 02642 if (set_member_paused(args.queuename, args.interface, 1)) { 02643 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface); 02644 if (priority_jump || option_priority_jumping) { 02645 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 02646 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 02647 LOCAL_USER_REMOVE(u); 02648 return 0; 02649 } 02650 } 02651 LOCAL_USER_REMOVE(u); 02652 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND"); 02653 return -1; 02654 } 02655 02656 LOCAL_USER_REMOVE(u); 02657 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED"); 02658 return 0; 02659 }
|
|
Definition at line 2860 of file app_queue.c. References AST_CONTROL_RINGING, ast_indicate(), ast_log(), ast_moh_start(), ast_queue_log(), ast_strlen_zero(), ast_verbose(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, join_queue(), LOCAL_USER_ADD, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_debug, option_verbose, pbx_builtin_getvar_helper(), QUEUE_UNKNOWN, record_abandoned(), strsep(), ast_channel::uniqueid, valid_exit(), VERBOSE_PREFIX_3, and wait_our_turn(). Referenced by load_module(). 02861 { 02862 int res=-1; 02863 int ringing=0; 02864 struct localuser *u; 02865 char *queuename; 02866 char info[512]; 02867 char *info_ptr = info; 02868 char *options = NULL; 02869 char *url = NULL; 02870 char *announceoverride = NULL; 02871 char *user_priority; 02872 int prio; 02873 char *queuetimeoutstr = NULL; 02874 enum queue_result reason = QUEUE_UNKNOWN; 02875 02876 /* whether to exit Queue application after the timeout hits */ 02877 int go_on = 0; 02878 02879 /* Our queue entry */ 02880 struct queue_ent qe; 02881 02882 if (ast_strlen_zero(data)) { 02883 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n"); 02884 return -1; 02885 } 02886 02887 LOCAL_USER_ADD(u); 02888 02889 /* Setup our queue entry */ 02890 memset(&qe, 0, sizeof(qe)); 02891 qe.start = time(NULL); 02892 02893 /* Parse our arguments XXX Check for failure XXX */ 02894 ast_copy_string(info, (char *) data, sizeof(info)); 02895 queuename = strsep(&info_ptr, "|"); 02896 options = strsep(&info_ptr, "|"); 02897 url = strsep(&info_ptr, "|"); 02898 announceoverride = strsep(&info_ptr, "|"); 02899 queuetimeoutstr = info_ptr; 02900 02901 /* set the expire time based on the supplied timeout; */ 02902 if (queuetimeoutstr) 02903 qe.expire = qe.start + atoi(queuetimeoutstr); 02904 else 02905 qe.expire = 0; 02906 02907 /* Get the priority from the variable ${QUEUE_PRIO} */ 02908 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO"); 02909 if (user_priority) { 02910 if (sscanf(user_priority, "%d", &prio) == 1) { 02911 if (option_debug) 02912 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n", 02913 chan->name, prio); 02914 } else { 02915 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", 02916 user_priority, chan->name); 02917 prio = 0; 02918 } 02919 } else { 02920 if (option_debug > 2) 02921 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n"); 02922 prio = 0; 02923 } 02924 02925 if (options && (strchr(options, 'r'))) 02926 ringing = 1; 02927 02928 if (option_debug) 02929 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", 02930 queuename, options, url, announceoverride, (long)qe.expire, (int)prio); 02931 02932 qe.chan = chan; 02933 qe.prio = (int)prio; 02934 qe.last_pos_said = 0; 02935 qe.last_pos = 0; 02936 qe.last_periodic_announce_time = time(NULL); 02937 if (!join_queue(queuename, &qe, &reason)) { 02938 ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", 02939 chan->cid.cid_num ? chan->cid.cid_num : ""); 02940 check_turns: 02941 if (ringing) { 02942 ast_indicate(chan, AST_CONTROL_RINGING); 02943 } else { 02944 ast_moh_start(chan, qe.moh); 02945 } 02946 for (;;) { 02947 /* This is the wait loop for callers 2 through maxlen */ 02948 02949 res = wait_our_turn(&qe, ringing, &reason); 02950 /* If they hungup, return immediately */ 02951 if (res < 0) { 02952 /* Record this abandoned call */ 02953 record_abandoned(&qe); 02954 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start); 02955 if (option_verbose > 2) { 02956 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename); 02957 } 02958 res = -1; 02959 break; 02960 } 02961 if (!res) 02962 break; 02963 if (valid_exit(&qe, res)) { 02964 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos); 02965 break; 02966 } 02967 } 02968 if (!res) { 02969 int makeannouncement = 0; 02970 for (;;) { 02971 /* This is the wait loop for the head caller*/ 02972 /* To exit, they may get their call answered; */ 02973 /* they may dial a digit from the queue context; */ 02974 /* or, they may timeout. */ 02975 02976 enum queue_member_status stat; 02977 02978 /* Leave if we have exceeded our queuetimeout */ 02979 if (qe.expire && (time(NULL) > qe.expire)) { 02980 record_abandoned(&qe); 02981 reason = QUEUE_TIMEOUT; 02982 res = 0; 02983 ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 02984 break; 02985 } 02986 02987 if (makeannouncement) { 02988 /* Make a position announcement, if enabled */ 02989 if (qe.parent->announcefrequency && !ringing) 02990 res = say_position(&qe); 02991 if (res && valid_exit(&qe, res)) { 02992 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos); 02993 break; 02994 } 02995 02996 } 02997 makeannouncement = 1; 02998 02999 /* Make a periodic announcement, if enabled */ 03000 if (qe.parent->periodicannouncefrequency && !ringing) 03001 res = say_periodic_announcement(&qe); 03002 03003 if (res && valid_exit(&qe, res)) { 03004 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos); 03005 break; 03006 } 03007 03008 /* Try calling all queue members for 'timeout' seconds */ 03009 res = try_calling(&qe, options, announceoverride, url, &go_on); 03010 if (res) { 03011 if (res < 0) { 03012 if (!qe.handled) { 03013 record_abandoned(&qe); 03014 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start); 03015 } 03016 } else if (res > 0) 03017 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos); 03018 break; 03019 } 03020 03021 stat = get_member_status(qe.parent); 03022 03023 /* leave the queue if no agents, if enabled */ 03024 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 03025 record_abandoned(&qe); 03026 reason = QUEUE_LEAVEEMPTY; 03027 res = 0; 03028 break; 03029 } 03030 03031 /* leave the queue if no reachable agents, if enabled */ 03032 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 03033 record_abandoned(&qe); 03034 reason = QUEUE_LEAVEUNAVAIL; 03035 res = 0; 03036 break; 03037 } 03038 03039 /* Leave if we have exceeded our queuetimeout */ 03040 if (qe.expire && (time(NULL) > qe.expire)) { 03041 record_abandoned(&qe); 03042 reason = QUEUE_TIMEOUT; 03043 res = 0; 03044 ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 03045 break; 03046 } 03047 03048 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */ 03049 res = wait_a_bit(&qe); 03050 if (res < 0) { 03051 record_abandoned(&qe); 03052 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start); 03053 if (option_verbose > 2) { 03054 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename); 03055 } 03056 res = -1; 03057 break; 03058 } 03059 if (res && valid_exit(&qe, res)) { 03060 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos); 03061 break; 03062 } 03063 /* exit after 'timeout' cycle if 'n' option enabled */ 03064 if (go_on) { 03065 if (option_verbose > 2) 03066 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n"); 03067 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); 03068 record_abandoned(&qe); 03069 reason = QUEUE_TIMEOUT; 03070 res = 0; 03071 break; 03072 } 03073 /* Since this is a priority queue and 03074 * it is not sure that we are still at the head 03075 * of the queue, go and check for our turn again. 03076 */ 03077 if (!is_our_turn(&qe)) { 03078 if (option_debug) 03079 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n", 03080 qe.chan->name); 03081 goto check_turns; 03082 } 03083 } 03084 } 03085 /* Don't allow return code > 0 */ 03086 if (res >= 0 && res != AST_PBX_KEEPALIVE) { 03087 res = 0; 03088 if (ringing) { 03089 ast_indicate(chan, -1); 03090 } else { 03091 ast_moh_stop(chan); 03092 } 03093 ast_stopstream(chan); 03094 } 03095 leave_queue(&qe); 03096 if (reason != QUEUE_UNKNOWN) 03097 set_queue_result(chan, reason); 03098 } else { 03099 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename); 03100 set_queue_result(chan, reason); 03101 res = 0; 03102 } 03103 LOCAL_USER_REMOVE(u); 03104 return res; 03105 }
|
|
Definition at line 3107 of file app_queue.c. References ast_log(), ast_mutex_lock(), ast_strlen_zero(), LOCAL_USER_ACF_ADD, LOCAL_USER_REMOVE, ast_call_queue::lock, LOG_ERROR, ast_call_queue::name, ast_call_queue::next, and queues. 03108 { 03109 int count = 0; 03110 struct ast_call_queue *q; 03111 struct localuser *u; 03112 struct member *m; 03113 03114 LOCAL_USER_ACF_ADD(u); 03115 03116 ast_copy_string(buf, "0", len); 03117 03118 if (ast_strlen_zero(data)) { 03119 ast_log(LOG_ERROR, "QUEUEAGENTCOUNT requires an argument: queuename\n"); 03120 LOCAL_USER_REMOVE(u); 03121 return buf; 03122 } 03123 03124 ast_mutex_lock(&qlock); 03125 03126 /* Find the right queue */ 03127 for (q = queues; q; q = q->next) { 03128 if (!strcasecmp(q->name, data)) { 03129 ast_mutex_lock(&q->lock); 03130 break; 03131 } 03132 } 03133 03134 ast_mutex_unlock(&qlock); 03135 03136 if (q) { 03137 for (m = q->members; m; m = m->next) { 03138 /* Count the agents who are logged in and presently answering calls */ 03139 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) { 03140 count++; 03141 } 03142 } 03143 ast_mutex_unlock(&q->lock); 03144 } 03145 03146 snprintf(buf, len, "%d", count); 03147 LOCAL_USER_REMOVE(u); 03148 return buf; 03149 }
|
|
Configure a queue parameter.
Definition at line 603 of file app_queue.c. References ast_call_queue::announce, ast_call_queue::announcefrequency, ast_call_queue::announceholdtime, ANNOUNCEHOLDTIME_ALWAYS, ANNOUNCEHOLDTIME_ONCE, ast_log(), ast_true(), ast_call_queue::context, DEFAULT_RETRY, DEFAULT_TIMEOUT, ast_call_queue::eventwhencalled, ast_call_queue::joinempty, ast_call_queue::leavewhenempty, LOG_WARNING, ast_call_queue::maskmemberstatus, ast_call_queue::maxlen, ast_call_queue::memberdelay, ast_call_queue::moh, ast_call_queue::monfmt, ast_call_queue::monjoin, ast_call_queue::name, ast_call_queue::periodicannouncefrequency, QUEUE_EMPTY_NORMAL, QUEUE_EMPTY_STRICT, ast_call_queue::reportholdtime, ast_call_queue::retry, ast_call_queue::roundingseconds, ast_call_queue::servicelevel, ast_call_queue::sound_calls, ast_call_queue::sound_holdtime, ast_call_queue::sound_lessthan, ast_call_queue::sound_minutes, ast_call_queue::sound_next, ast_call_queue::sound_periodicannounce, ast_call_queue::sound_reporthold, ast_call_queue::sound_seconds, ast_call_queue::sound_thanks, ast_call_queue::sound_thereare, strat2int(), ast_call_queue::strategy, ast_call_queue::timeout, ast_call_queue::timeoutrestart, use_weight, ast_call_queue::weight, and ast_call_queue::wrapuptime. Referenced by reload_queues(). 00604 { 00605 if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) { 00606 ast_copy_string(q->moh, val, sizeof(q->moh)); 00607 } else if (!strcasecmp(param, "announce")) { 00608 ast_copy_string(q->announce, val, sizeof(q->announce)); 00609 } else if (!strcasecmp(param, "context")) { 00610 ast_copy_string(q->context, val, sizeof(q->context)); 00611 } else if (!strcasecmp(param, "timeout")) { 00612 q->timeout = atoi(val); 00613 if (q->timeout < 0) 00614 q->timeout = DEFAULT_TIMEOUT; 00615 } else if (!strcasecmp(param, "monitor-join")) { 00616 q->monjoin = ast_true(val); 00617 } else if (!strcasecmp(param, "monitor-format")) { 00618 ast_copy_string(q->monfmt, val, sizeof(q->monfmt)); 00619 } else if (!strcasecmp(param, "queue-youarenext")) { 00620 ast_copy_string(q->sound_next, val, sizeof(q->sound_next)); 00621 } else if (!strcasecmp(param, "queue-thereare")) { 00622 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare)); 00623 } else if (!strcasecmp(param, "queue-callswaiting")) { 00624 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls)); 00625 } else if (!strcasecmp(param, "queue-holdtime")) { 00626 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime)); 00627 } else if (!strcasecmp(param, "queue-minutes")) { 00628 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes)); 00629 } else if (!strcasecmp(param, "queue-seconds")) { 00630 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds)); 00631 } else if (!strcasecmp(param, "queue-lessthan")) { 00632 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan)); 00633 } else if (!strcasecmp(param, "queue-thankyou")) { 00634 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks)); 00635 } else if (!strcasecmp(param, "queue-reporthold")) { 00636 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold)); 00637 } else if (!strcasecmp(param, "announce-frequency")) { 00638 q->announcefrequency = atoi(val); 00639 } else if (!strcasecmp(param, "announce-round-seconds")) { 00640 q->roundingseconds = atoi(val); 00641 if (q->roundingseconds>60 || q->roundingseconds<0) { 00642 if (linenum >= 0) { 00643 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 00644 "using 0 instead for queue '%s' at line %d of queues.conf\n", 00645 val, param, q->name, linenum); 00646 } else { 00647 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s " 00648 "using 0 instead for queue '%s'\n", val, param, q->name); 00649 } 00650 q->roundingseconds=0; 00651 } 00652 } else if (!strcasecmp(param, "announce-holdtime")) { 00653 if (!strcasecmp(val, "once")) 00654 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; 00655 else if (ast_true(val)) 00656 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; 00657 else 00658 q->announceholdtime = 0; 00659 } else if (!strcasecmp(param, "periodic-announce")) { 00660 ast_copy_string(q->sound_periodicannounce, val, sizeof(q->sound_periodicannounce)); 00661 } else if (!strcasecmp(param, "periodic-announce-frequency")) { 00662 q->periodicannouncefrequency = atoi(val); 00663 } else if (!strcasecmp(param, "retry")) { 00664 q->retry = atoi(val); 00665 if (q->retry < 0) 00666 q->retry = DEFAULT_RETRY; 00667 } else if (!strcasecmp(param, "wrapuptime")) { 00668 q->wrapuptime = atoi(val); 00669 } else if (!strcasecmp(param, "maxlen")) { 00670 q->maxlen = atoi(val); 00671 if (q->maxlen < 0) 00672 q->maxlen = 0; 00673 } else if (!strcasecmp(param, "servicelevel")) { 00674 q->servicelevel= atoi(val); 00675 } else if (!strcasecmp(param, "strategy")) { 00676 q->strategy = strat2int(val); 00677 if (q->strategy < 0) { 00678 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n", 00679 val, q->name); 00680 q->strategy = 0; 00681 } 00682 } else if (!strcasecmp(param, "joinempty")) { 00683 if (!strcasecmp(val, "strict")) 00684 q->joinempty = QUEUE_EMPTY_STRICT; 00685 else if (ast_true(val)) 00686 q->joinempty = QUEUE_EMPTY_NORMAL; 00687 else 00688 q->joinempty = 0; 00689 } else if (!strcasecmp(param, "leavewhenempty")) { 00690 if (!strcasecmp(val, "strict")) 00691 q->leavewhenempty = QUEUE_EMPTY_STRICT; 00692 else if (ast_true(val)) 00693 q->leavewhenempty = QUEUE_EMPTY_NORMAL; 00694 else 00695 q->leavewhenempty = 0; 00696 } else if (!strcasecmp(param, "eventmemberstatus")) { 00697 q->maskmemberstatus = !ast_true(val); 00698 } else if (!strcasecmp(param, "eventwhencalled")) { 00699 q->eventwhencalled = ast_true(val); 00700 } else if (!strcasecmp(param, "reportholdtime")) { 00701 q->reportholdtime = ast_true(val); 00702 } else if (!strcasecmp(param, "memberdelay")) { 00703 q->memberdelay = atoi(val); 00704 } else if (!strcasecmp(param, "weight")) { 00705 q->weight = atoi(val); 00706 if (q->weight) 00707 use_weight++; 00708 /* With Realtime queues, if the last queue using weights is deleted in realtime, 00709 we will not see any effect on use_weight until next reload. */ 00710 } else if (!strcasecmp(param, "timeoutrestart")) { 00711 q->timeoutrestart = ast_true(val); 00712 } else if(failunknown) { 00713 if (linenum >= 0) { 00714 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n", 00715 q->name, param, linenum); 00716 } else { 00717 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param); 00718 } 00719 } 00720 }
|
|
Definition at line 3382 of file app_queue.c. References __queues_show(). 03383 { 03384 return __queues_show(0, fd, argc, argv, 1); 03385 }
|
|
Definition at line 3377 of file app_queue.c. References __queues_show(). 03378 { 03379 return __queues_show(0, fd, argc, argv, 0); 03380 }
|
|
Definition at line 1191 of file app_queue.c. References ast_mutex_lock(), ast_mutex_unlock(), ast_call_queue::callscompletedinsl, ast_call_queue::holdtime, ast_call_queue::lock, queue_ent::parent, ast_call_queue::servicelevel, and queue_ent::start. 01192 { 01193 int oldvalue, newvalue; 01194 01195 /* Calculate holdtime using a recursive boxcar filter */ 01196 /* Thanks to SRT for this contribution */ 01197 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */ 01198 01199 newvalue = time(NULL) - qe->start; 01200 01201 ast_mutex_lock(&qe->parent->lock); 01202 if (newvalue <= qe->parent->servicelevel) 01203 qe->parent->callscompletedinsl++; 01204 oldvalue = qe->parent->holdtime; 01205 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2; 01206 ast_mutex_unlock(&qe->parent->lock); 01207 }
|
|
Definition at line 1601 of file app_queue.c. References ast_mutex_lock(), ast_mutex_unlock(), ast_call_queue::callsabandoned, ast_call_queue::lock, and queue_ent::parent. Referenced by queue_exec(). 01602 { 01603 ast_mutex_lock(&qe->parent->lock); 01604 qe->parent->callsabandoned++; 01605 ast_mutex_unlock(&qe->parent->lock); 01606 }
|
|
Reload stuff. This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.
Definition at line 3849 of file app_queue.c. References reload_queues(). 03850 { 03851 reload_queues(); 03852 return 0; 03853 }
|
|
Definition at line 2516 of file app_queue.c. References ast_db_gettree(), ast_mutex_lock(), ast_mutex_unlock(), member::interface, ast_db_entry::key, ast_call_queue::lock, ast_call_queue::name, ast_call_queue::next, ast_db_entry::next, member::paused, member::penalty, pm_family, PM_MAX_LEN, and queues. Referenced by load_module(). 02517 { 02518 char *cur_ptr; 02519 char *queue_name; 02520 char *member; 02521 char *interface; 02522 char *penalty_tok; 02523 int penalty = 0; 02524 char *paused_tok; 02525 int paused = 0; 02526 struct ast_db_entry *db_tree; 02527 struct ast_db_entry *entry; 02528 struct ast_call_queue *cur_queue; 02529 char queue_data[PM_MAX_LEN]; 02530 02531 ast_mutex_lock(&qlock); 02532 02533 /* Each key in 'pm_family' is the name of a queue */ 02534 db_tree = ast_db_gettree(pm_family, NULL); 02535 for (entry = db_tree; entry; entry = entry->next) { 02536 02537 queue_name = entry->key + strlen(pm_family) + 2; 02538 02539 cur_queue = queues; 02540 while (cur_queue) { 02541 ast_mutex_lock(&cur_queue->lock); 02542 if (!strcmp(queue_name, cur_queue->name)) 02543 break; 02544 ast_mutex_unlock(&cur_queue->lock); 02545 cur_queue = cur_queue->next; 02546 } 02547 02548 if (!cur_queue) { 02549 /* If the queue no longer exists, remove it from the 02550 * database */ 02551 ast_db_del(pm_family, queue_name); 02552 continue; 02553 } else 02554 ast_mutex_unlock(&cur_queue->lock); 02555 02556 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) 02557 continue; 02558 02559 cur_ptr = queue_data; 02560 while ((member = strsep(&cur_ptr, "|"))) { 02561 if (ast_strlen_zero(member)) 02562 continue; 02563 02564 interface = strsep(&member, ";"); 02565 penalty_tok = strsep(&member, ";"); 02566 paused_tok = strsep(&member, ";"); 02567 02568 if (!penalty_tok) { 02569 ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name); 02570 break; 02571 } 02572 penalty = strtol(penalty_tok, NULL, 10); 02573 if (errno == ERANGE) { 02574 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok); 02575 break; 02576 } 02577 02578 if (!paused_tok) { 02579 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name); 02580 break; 02581 } 02582 paused = strtol(paused_tok, NULL, 10); 02583 if ((errno == ERANGE) || paused < 0 || paused > 1) { 02584 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok); 02585 break; 02586 } 02587 02588 if (option_debug) 02589 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Penalty: %d Paused: %d\n", queue_name, interface, penalty, paused); 02590 02591 if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) { 02592 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n"); 02593 break; 02594 } 02595 } 02596 } 02597 02598 ast_mutex_unlock(&qlock); 02599 if (db_tree) { 02600 ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n"); 02601 ast_db_freetree(db_tree); 02602 } 02603 }
|
|
Definition at line 3158 of file app_queue.c. References alloc_queue(), ast_category_browse(), ast_config_destroy(), ast_config_load(), ast_device_state(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), cfg, clear_queue(), ast_call_queue::count, create_queue_member(), ast_call_queue::dead, destroy_queue(), free_members(), init_queue(), member::interface, ast_call_queue::lock, LOG_NOTICE, LOG_WARNING, ast_call_queue::members, ast_call_queue::name, member::next, ast_call_queue::next, member::penalty, queue_persistent_members, queue_set_param(), queues, member::status, and var. Referenced by load_module(), and reload(). 03159 { 03160 struct ast_call_queue *q, *ql, *qn; 03161 struct ast_config *cfg; 03162 char *cat, *tmp; 03163 struct ast_variable *var; 03164 struct member *prev, *cur; 03165 int new; 03166 char *general_val = NULL; 03167 char interface[80]; 03168 int penalty; 03169 03170 cfg = ast_config_load("queues.conf"); 03171 if (!cfg) { 03172 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n"); 03173 return; 03174 } 03175 memset(interface, 0, sizeof(interface)); 03176 ast_mutex_lock(&qlock); 03177 use_weight=0; 03178 /* Mark all queues as dead for the moment */ 03179 q = queues; 03180 while(q) { 03181 q->dead = 1; 03182 q = q->next; 03183 } 03184 /* Chug through config file */ 03185 cat = ast_category_browse(cfg, NULL); 03186 while(cat) { 03187 if (!strcasecmp(cat, "general")) { 03188 /* Initialize global settings */ 03189 queue_persistent_members = 0; 03190 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) 03191 queue_persistent_members = ast_true(general_val); 03192 } else { /* Define queue */ 03193 /* Look for an existing one */ 03194 q = queues; 03195 while(q) { 03196 if (!strcmp(q->name, cat)) 03197 break; 03198 q = q->next; 03199 } 03200 if (!q) { 03201 /* Make one then */ 03202 q = alloc_queue(cat); 03203 new = 1; 03204 } else 03205 new = 0; 03206 if (q) { 03207 if (!new) 03208 ast_mutex_lock(&q->lock); 03209 /* Re-initialize the queue, and clear statistics */ 03210 init_queue(q); 03211 clear_queue(q); 03212 free_members(q, 0); 03213 prev = q->members; 03214 if (prev) { 03215 /* find the end of any dynamic members */ 03216 while(prev->next) 03217 prev = prev->next; 03218 } 03219 var = ast_variable_browse(cfg, cat); 03220 while(var) { 03221 if (!strcasecmp(var->name, "member")) { 03222 /* Add a new member */ 03223 ast_copy_string(interface, var->value, sizeof(interface)); 03224 if ((tmp = strchr(interface, ','))) { 03225 *tmp = '\0'; 03226 tmp++; 03227 penalty = atoi(tmp); 03228 if (penalty < 0) { 03229 penalty = 0; 03230 } 03231 } else 03232 penalty = 0; 03233 cur = create_queue_member(interface, penalty, 0); 03234 if (cur) { 03235 if (prev) 03236 prev->next = cur; 03237 else 03238 q->members = cur; 03239 prev = cur; 03240 } 03241 } else { 03242 queue_set_param(q, var->name, var->value, var->lineno, 1); 03243 } 03244 var = var->next; 03245 } 03246 if (!new) 03247 ast_mutex_unlock(&q->lock); 03248 if (new) { 03249 q->next = queues; 03250 queues = q; 03251 } 03252 } 03253 } 03254 cat = ast_category_browse(cfg, cat); 03255 } 03256 ast_config_destroy(cfg); 03257 q = queues; 03258 ql = NULL; 03259 while(q) { 03260 qn = q->next; 03261 if (q->dead) { 03262 if (ql) 03263 ql->next = q->next; 03264 else 03265 queues = q->next; 03266 if (!q->count) { 03267 destroy_queue(q); 03268 } else 03269 ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n"); 03270 } else { 03271 for (cur = q->members; cur; cur = cur->next) 03272 cur->status = ast_device_state(cur->interface); 03273 ql = q; 03274 } 03275 q = qn; 03276 } 03277 ast_mutex_unlock(&qlock); 03278 }
|
|
Definition at line 2378 of file app_queue.c. References ast_mutex_lock(), interface_exists(), ast_call_queue::lock, ast_call_queue::members, ast_call_queue::name, member::next, ast_call_queue::next, queues, and RES_NOSUCHQUEUE. Referenced by handle_remove_queue_member(), manager_remove_queue_member(), and rqm_exec(). 02379 { 02380 struct ast_call_queue *q; 02381 struct member *last_member, *look; 02382 int res = RES_NOSUCHQUEUE; 02383 02384 ast_mutex_lock(&qlock); 02385 for (q = queues ; q ; q = q->next) { 02386 ast_mutex_lock(&q->lock); 02387 if (!strcmp(q->name, queuename)) { 02388 if ((last_member = interface_exists(q, interface))) { 02389 if ((look = q->members) == last_member) { 02390 q->members = last_member->next; 02391 } else { 02392 while (look != NULL) { 02393 if (look->next == last_member) { 02394 look->next = last_member->next; 02395 break; 02396 } else { 02397 look = look->next; 02398 } 02399 } 02400 } 02401 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved", 02402 "Queue: %s\r\n" 02403 "Location: %s\r\n", 02404 q->name, last_member->interface); 02405 free(last_member); 02406 02407 if (queue_persistent_members) 02408 dump_queue_members(q); 02409 02410 res = RES_OKAY; 02411 } else { 02412 res = RES_EXISTS; 02413 } 02414 ast_mutex_unlock(&q->lock); 02415 break; 02416 } 02417 ast_mutex_unlock(&q->lock); 02418 } 02419 ast_mutex_unlock(&qlock); 02420 return res; 02421 }
|
|
Definition at line 783 of file app_queue.c. References ast_mutex_lock(), ast_call_queue::next, and queues. Referenced by leave_queue(). 00784 { 00785 struct ast_call_queue *cur, *prev = NULL; 00786 00787 ast_mutex_lock(&qlock); 00788 for (cur = queues; cur; cur = cur->next) { 00789 if (cur == q) { 00790 if (prev) 00791 prev->next = cur->next; 00792 else 00793 queues = cur->next; 00794 } else { 00795 prev = cur; 00796 } 00797 } 00798 ast_mutex_unlock(&qlock); 00799 }
|
|
Definition at line 1348 of file app_queue.c. References ast_channel::adsicpe, ast_channel::appl, ast_call(), ast_cdr_busy(), ast_channel_inherit_variables(), ast_hangup(), ast_log(), ast_request(), ast_verbose(), ast_channel::cdr, localuser::chan, queue_ent::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, compare_weight(), ast_channel::context, ast_channel::data, EVENT_FLAG_AGENT, ast_call_queue::eventwhencalled, ast_channel::exten, free, localuser::interface, localuser::lastcall, LOG_DEBUG, LOG_NOTICE, manager_event(), localuser::member, ast_channel::name, ast_call_queue::name, ast_channel::nativeformats, localuser::oldstatus, option_debug, option_verbose, queue_ent::parent, member::paused, ast_channel::priority, member::status, localuser::stillgoing, strdup, update_dial_status(), use_weight, VERBOSE_PREFIX_3, ast_channel::whentohangup, and ast_call_queue::wrapuptime. Referenced by ring_one(). 01349 { 01350 int res; 01351 int status; 01352 char tech[256]; 01353 char *location; 01354 01355 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) { 01356 if (option_debug) 01357 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface); 01358 if (qe->chan->cdr) 01359 ast_cdr_busy(qe->chan->cdr); 01360 tmp->stillgoing = 0; 01361 (*busies)++; 01362 return 0; 01363 } 01364 01365 if (tmp->member->paused) { 01366 if (option_debug) 01367 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface); 01368 if (qe->chan->cdr) 01369 ast_cdr_busy(qe->chan->cdr); 01370 tmp->stillgoing = 0; 01371 return 0; 01372 } 01373 if (use_weight && compare_weight(qe->parent,tmp->member)) { 01374 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface); 01375 if (qe->chan->cdr) 01376 ast_cdr_busy(qe->chan->cdr); 01377 tmp->stillgoing = 0; 01378 (*busies)++; 01379 return 0; 01380 } 01381 01382 ast_copy_string(tech, tmp->interface, sizeof(tech)); 01383 if ((location = strchr(tech, '/'))) 01384 *location++ = '\0'; 01385 else 01386 location = ""; 01387 01388 /* Request the peer */ 01389 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status); 01390 if (!tmp->chan) { /* If we can't, just go on to the next call */ 01391 #if 0 01392 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech); 01393 #endif 01394 if (qe->chan->cdr) 01395 ast_cdr_busy(qe->chan->cdr); 01396 tmp->stillgoing = 0; 01397 update_dial_status(qe->parent, tmp->member, status); 01398 (*busies)++; 01399 return 0; 01400 } else if (status != tmp->oldstatus) 01401 update_dial_status(qe->parent, tmp->member, status); 01402 01403 tmp->chan->appl = "AppQueue"; 01404 tmp->chan->data = "(Outgoing Line)"; 01405 tmp->chan->whentohangup = 0; 01406 if (tmp->chan->cid.cid_num) 01407 free(tmp->chan->cid.cid_num); 01408 tmp->chan->cid.cid_num = NULL; 01409 if (tmp->chan->cid.cid_name) 01410 free(tmp->chan->cid.cid_name); 01411 tmp->chan->cid.cid_name = NULL; 01412 if (tmp->chan->cid.cid_ani) 01413 free(tmp->chan->cid.cid_ani); 01414 tmp->chan->cid.cid_ani = NULL; 01415 if (qe->chan->cid.cid_num) 01416 tmp->chan->cid.cid_num = strdup(qe->chan->cid.cid_num); 01417 if (qe->chan->cid.cid_name) 01418 tmp->chan->cid.cid_name = strdup(qe->chan->cid.cid_name); 01419 if (qe->chan->cid.cid_ani) 01420 tmp->chan->cid.cid_ani = strdup(qe->chan->cid.cid_ani); 01421 01422 /* Inherit specially named variables from parent channel */ 01423 ast_channel_inherit_variables(qe->chan, tmp->chan); 01424 01425 /* Presense of ADSI CPE on outgoing channel follows ours */ 01426 tmp->chan->adsicpe = qe->chan->adsicpe; 01427 01428 /* Place the call, but don't wait on the answer */ 01429 res = ast_call(tmp->chan, location, 0); 01430 if (res) { 01431 /* Again, keep going even if there's an error */ 01432 if (option_debug) 01433 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res); 01434 else if (option_verbose > 2) 01435 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface); 01436 ast_hangup(tmp->chan); 01437 tmp->chan = NULL; 01438 tmp->stillgoing = 0; 01439 (*busies)++; 01440 return 0; 01441 } else { 01442 if (qe->parent->eventwhencalled) { 01443 manager_event(EVENT_FLAG_AGENT, "AgentCalled", 01444 "AgentCalled: %s\r\n" 01445 "ChannelCalling: %s\r\n" 01446 "CallerID: %s\r\n" 01447 "CallerIDName: %s\r\n" 01448 "Context: %s\r\n" 01449 "Extension: %s\r\n" 01450 "Priority: %d\r\n", 01451 tmp->interface, qe->chan->name, 01452 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown", 01453 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown", 01454 qe->chan->context, qe->chan->exten, qe->chan->priority); 01455 } 01456 if (option_verbose > 2) 01457 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface); 01458 } 01459 return 1; 01460 }
|
|
Definition at line 1462 of file app_queue.c. References ast_log(), localuser::chan, localuser::interface, LOG_DEBUG, localuser::metric, localuser::next, option_debug, queue_ent::parent, ring_entry(), localuser::stillgoing, and ast_call_queue::strategy. Referenced by wait_for_answer(). 01463 { 01464 struct localuser *cur; 01465 struct localuser *best; 01466 int bestmetric=0; 01467 01468 do { 01469 best = NULL; 01470 cur = outgoing; 01471 while(cur) { 01472 if (cur->stillgoing && /* Not already done */ 01473 !cur->chan && /* Isn't already going */ 01474 (!best || (cur->metric < bestmetric))) { /* We haven't found one yet, or it's better */ 01475 bestmetric = cur->metric; 01476 best = cur; 01477 } 01478 cur = cur->next; 01479 } 01480 if (best) { 01481 if (!qe->parent->strategy) { 01482 /* Ring everyone who shares this best metric (for ringall) */ 01483 cur = outgoing; 01484 while(cur) { 01485 if (cur->stillgoing && !cur->chan && (cur->metric <= bestmetric)) { 01486 if (option_debug) 01487 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric); 01488 ring_entry(qe, cur, busies); 01489 } 01490 cur = cur->next; 01491 } 01492 } else { 01493 /* Ring just the best channel */ 01494 if (option_debug) 01495 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric); 01496 ring_entry(qe, best, busies); 01497 } 01498 } 01499 } while (best && !best->chan); 01500 if (!best) { 01501 if (option_debug) 01502 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n"); 01503 return 0; 01504 } 01505 return 1; 01506 }
|
|
Definition at line 2717 of file app_queue.c. References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), localuser::chan, ast_channel::context, localuser::interface, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::name, option_priority_jumping, parse(), pbx_builtin_setvar_helper(), remove_from_queue(), RES_EXISTS, RES_NOSUCHQUEUE, RES_OKAY, and RES_OUTOFMEMORY. Referenced by load_module(). 02718 { 02719 int res=-1; 02720 struct localuser *u; 02721 char *parse, *temppos = NULL; 02722 int priority_jump = 0; 02723 AST_DECLARE_APP_ARGS(args, 02724 AST_APP_ARG(queuename); 02725 AST_APP_ARG(interface); 02726 AST_APP_ARG(options); 02727 ); 02728 02729 02730 if (ast_strlen_zero(data)) { 02731 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n"); 02732 return -1; 02733 } 02734 02735 LOCAL_USER_ADD(u); 02736 02737 if (!(parse = ast_strdupa(data))) { 02738 ast_log(LOG_WARNING, "Memory Error!\n"); 02739 LOCAL_USER_REMOVE(u); 02740 return -1; 02741 } 02742 02743 AST_STANDARD_APP_ARGS(args, parse); 02744 02745 if (ast_strlen_zero(args.interface)) { 02746 args.interface = ast_strdupa(chan->name); 02747 temppos = strrchr(args.interface, '-'); 02748 if (temppos) 02749 *temppos = '\0'; 02750 } 02751 02752 if (args.options) { 02753 if (strchr(args.options, 'j')) 02754 priority_jump = 1; 02755 } 02756 02757 switch (remove_from_queue(args.queuename, args.interface)) { 02758 case RES_OKAY: 02759 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename); 02760 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED"); 02761 res = 0; 02762 break; 02763 case RES_EXISTS: 02764 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename); 02765 if (priority_jump || option_priority_jumping) 02766 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); 02767 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE"); 02768 res = 0; 02769 break; 02770 case RES_NOSUCHQUEUE: 02771 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename); 02772 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE"); 02773 res = 0; 02774 break; 02775 case RES_OUTOFMEMORY: 02776 ast_log(LOG_ERROR, "Out of memory\n"); 02777 break; 02778 } 02779 02780 LOCAL_USER_REMOVE(u); 02781 return res; 02782 }
|
|
Definition at line 722 of file app_queue.c. References create_queue_member(), member::dead, member::interface, ast_call_queue::members, member::next, and member::penalty. 00723 { 00724 struct member *m, *prev_m; 00725 int penalty = 0; 00726 00727 if(penalty_str) { 00728 penalty = atoi(penalty_str); 00729 if(penalty < 0) 00730 penalty = 0; 00731 } 00732 00733 /* Find the member, or the place to put a new one. */ 00734 prev_m = NULL; 00735 m = q->members; 00736 while (m && strcmp(m->interface, interface)) { 00737 prev_m = m; 00738 m = m->next; 00739 } 00740 00741 /* Create a new one if not found, else update penalty */ 00742 if (!m) { 00743 m = create_queue_member(interface, penalty, 0); 00744 if (m) { 00745 m->dead = 0; 00746 if (prev_m) { 00747 prev_m->next = m; 00748 } else { 00749 q->members = m; 00750 } 00751 } 00752 } else { 00753 m->dead = 0; /* Do not delete this one. */ 00754 m->penalty = penalty; 00755 } 00756 }
|
|
Definition at line 1571 of file app_queue.c. References ast_moh_start(), ast_moh_stop(), ast_verbose(), background_file(), queue_ent::chan, queue_ent::last_periodic_announce_time, queue_ent::moh, option_verbose, queue_ent::parent, ast_call_queue::periodicannouncefrequency, ast_call_queue::sound_periodicannounce, and VERBOSE_PREFIX_3. 01572 { 01573 int res = 0; 01574 time_t now; 01575 01576 /* Get the current time */ 01577 time(&now); 01578 01579 /* Check to see if it is time to announce */ 01580 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) 01581 return 0; 01582 01583 /* Stop the music on hold so we can play our own file */ 01584 ast_moh_stop(qe->chan); 01585 01586 if (option_verbose > 2) 01587 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n"); 01588 01589 /* play the announcement */ 01590 res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce); 01591 01592 /* Resume Music on Hold */ 01593 ast_moh_start(qe->chan, qe->moh); 01594 01595 /* update last_periodic_announce_time */ 01596 qe->last_periodic_announce_time = now; 01597 01598 return res; 01599 }
|
|
Definition at line 1090 of file app_queue.c. References ast_call_queue::announcefrequency, ast_call_queue::announceholdtime, ANNOUNCEHOLDTIME_ONCE, AST_DIGIT_ANY, ast_moh_start(), ast_moh_stop(), ast_say_number(), ast_verbose(), queue_ent::chan, ast_call_queue::holdtime, ast_channel::language, queue_ent::last_pos, queue_ent::last_pos_said, queue_ent::moh, ast_channel::name, ast_call_queue::name, option_verbose, queue_ent::parent, play_file(), queue_ent::pos, ast_call_queue::roundingseconds, ast_call_queue::sound_calls, ast_call_queue::sound_holdtime, ast_call_queue::sound_lessthan, ast_call_queue::sound_minutes, ast_call_queue::sound_next, ast_call_queue::sound_seconds, ast_call_queue::sound_thanks, ast_call_queue::sound_thereare, queue_ent::start, valid_exit(), and VERBOSE_PREFIX_3. 01091 { 01092 int res = 0, avgholdmins, avgholdsecs; 01093 time_t now; 01094 01095 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/ 01096 time(&now); 01097 if ( (now - qe->last_pos) < 15 ) 01098 return 0; 01099 01100 /* If either our position has changed, or we are over the freq timer, say position */ 01101 if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) ) 01102 return 0; 01103 01104 ast_moh_stop(qe->chan); 01105 /* Say we're next, if we are */ 01106 if (qe->pos == 1) { 01107 res = play_file(qe->chan, qe->parent->sound_next); 01108 if (res && valid_exit(qe, res)) 01109 goto playout; 01110 else 01111 goto posout; 01112 } else { 01113 res = play_file(qe->chan, qe->parent->sound_thereare); 01114 if (res && valid_exit(qe, res)) 01115 goto playout; 01116 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */ 01117 if (res && valid_exit(qe, res)) 01118 goto playout; 01119 res = play_file(qe->chan, qe->parent->sound_calls); 01120 if (res && valid_exit(qe, res)) 01121 goto playout; 01122 } 01123 /* Round hold time to nearest minute */ 01124 avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60); 01125 01126 /* If they have specified a rounding then round the seconds as well */ 01127 if(qe->parent->roundingseconds) { 01128 avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds; 01129 avgholdsecs*= qe->parent->roundingseconds; 01130 } else { 01131 avgholdsecs=0; 01132 } 01133 01134 if (option_verbose > 2) 01135 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs); 01136 01137 /* If the hold time is >1 min, if it's enabled, and if it's not 01138 supposed to be only once and we have already said it, say it */ 01139 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) && 01140 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) { 01141 res = play_file(qe->chan, qe->parent->sound_holdtime); 01142 if (res && valid_exit(qe, res)) 01143 goto playout; 01144 01145 if (avgholdmins>0) { 01146 if (avgholdmins < 2) { 01147 res = play_file(qe->chan, qe->parent->sound_lessthan); 01148 if (res && valid_exit(qe, res)) 01149 goto playout; 01150 01151 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL); 01152 if (res && valid_exit(qe, res)) 01153 goto playout; 01154 } else { 01155 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL); 01156 if (res && valid_exit(qe, res)) 01157 goto playout; 01158 } 01159 01160 res = play_file(qe->chan, qe->parent->sound_minutes); 01161 if (res && valid_exit(qe, res)) 01162 goto playout; 01163 } 01164 if (avgholdsecs>0) { 01165 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL); 01166 if (res && valid_exit(qe, res)) 01167 goto playout; 01168 01169 res = play_file(qe->chan, qe->parent->sound_seconds); 01170 if (res && valid_exit(qe, res)) 01171 goto playout; 01172 } 01173 01174 } 01175 01176 posout: 01177 if (option_verbose > 2) 01178 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n", 01179 qe->chan->name, qe->parent->name, qe->pos); 01180 res = play_file(qe->chan, qe->parent->sound_thanks); 01181 01182 playout: 01183 /* Set our last_pos indicators */ 01184 qe->last_pos = now; 01185 qe->last_pos_said = qe->pos; 01186 ast_moh_start(qe->chan, qe->moh); 01187 01188 return res; 01189 }
|
|
Definition at line 2472 of file app_queue.c. References ast_log(), ast_mutex_lock(), ast_queue_log(), ast_strlen_zero(), dump_queue_members(), EVENT_FLAG_AGENT, member::interface, interface_exists(), ast_call_queue::lock, LOG_DEBUG, manager_event(), ast_call_queue::name, ast_call_queue::next, member::paused, queue_persistent_members, and queues. Referenced by manager_pause_queue_member(), pqm_exec(), and upqm_exec(). 02473 { 02474 int found = 0; 02475 struct ast_call_queue *q; 02476 struct member *mem; 02477 02478 /* Special event for when all queues are paused - individual events still generated */ 02479 02480 if (ast_strlen_zero(queuename)) 02481 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", ""); 02482 02483 ast_mutex_lock(&qlock); 02484 for (q = queues ; q ; q = q->next) { 02485 ast_mutex_lock(&q->lock); 02486 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) { 02487 if ((mem = interface_exists(q, interface))) { 02488 found++; 02489 if (mem->paused == paused) 02490 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface); 02491 mem->paused = paused; 02492 02493 if (queue_persistent_members) 02494 dump_queue_members(q); 02495 02496 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", ""); 02497 02498 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused", 02499 "Queue: %s\r\n" 02500 "Location: %s\r\n" 02501 "Paused: %d\r\n", 02502 q->name, mem->interface, paused); 02503 } 02504 } 02505 ast_mutex_unlock(&q->lock); 02506 } 02507 ast_mutex_unlock(&qlock); 02508 02509 if (found) 02510 return RESULT_SUCCESS; 02511 else 02512 return RESULT_FAILURE; 02513 }
|
|
Definition at line 369 of file app_queue.c. References pbx_builtin_setvar_helper(), queue_results, and text. 00370 { 00371 int i; 00372 00373 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) { 00374 if (queue_results[i].id == res) { 00375 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); 00376 return; 00377 } 00378 } 00379 }
|
|
Definition at line 504 of file app_queue.c. References ast_log(), ast_pthread_create, changethread(), statechange::dev, free, LOG_WARNING, malloc, statechange::state, and t. Referenced by load_module(), and unload_module(). 00505 { 00506 /* Avoid potential for deadlocks by spawning a new thread to handle 00507 the event */ 00508 struct statechange *sc; 00509 pthread_t t; 00510 pthread_attr_t attr; 00511 00512 sc = malloc(sizeof(struct statechange) + strlen(dev) + 1); 00513 if (sc) { 00514 sc->state = state; 00515 strcpy(sc->dev, dev); 00516 pthread_attr_init(&attr); 00517 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00518 if (ast_pthread_create(&t, &attr, changethread, sc)) { 00519 ast_log(LOG_WARNING, "Failed to create update thread!\n"); 00520 free(sc); 00521 } 00522 } 00523 return 0; 00524 }
|
|
Definition at line 1508 of file app_queue.c. References ast_log(), localuser::chan, localuser::interface, LOG_DEBUG, localuser::metric, localuser::next, option_debug, queue_ent::parent, ast_call_queue::rrpos, localuser::stillgoing, and ast_call_queue::wrapped. 01509 { 01510 struct localuser *cur; 01511 struct localuser *best; 01512 int bestmetric=0; 01513 01514 best = NULL; 01515 cur = outgoing; 01516 while(cur) { 01517 if (cur->stillgoing && /* Not already done */ 01518 !cur->chan && /* Isn't already going */ 01519 (!best || (cur->metric < bestmetric))) { /* We haven't found one yet, or it's better */ 01520 bestmetric = cur->metric; 01521 best = cur; 01522 } 01523 cur = cur->next; 01524 } 01525 if (best) { 01526 /* Ring just the best channel */ 01527 if (option_debug) 01528 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric); 01529 qe->parent->rrpos = best->metric % 1000; 01530 } else { 01531 /* Just increment rrpos */ 01532 if (qe->parent->wrapped) { 01533 /* No more channels, start over */ 01534 qe->parent->rrpos = 0; 01535 } else { 01536 /* Prioritize next entry */ 01537 qe->parent->rrpos++; 01538 } 01539 } 01540 qe->parent->wrapped = 0; 01541 return 0; 01542 }
|
|
Definition at line 391 of file app_queue.c. References name, and strategies. Referenced by queue_set_param(). 00392 { 00393 int x; 00394 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) { 00395 if (!strcasecmp(strategy, strategies[x].name)) 00396 return strategies[x].strategy; 00397 } 00398 return -1; 00399 }
|
|
Definition at line 2008 of file app_queue.c. References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_REDIRECT, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_set_flag, queue_ent::parent, queue_ent::start, and ast_call_queue::timeout. 02009 { 02010 struct member *cur; 02011 struct localuser *outgoing=NULL, *tmp = NULL; 02012 int to; 02013 char restofit[AST_MAX_EXTENSION]; 02014 char oldexten[AST_MAX_EXTENSION]=""; 02015 char oldcontext[AST_MAX_CONTEXT]=""; 02016 char queuename[256]=""; 02017 char *newnum; 02018 char *monitorfilename; 02019 struct ast_channel *peer; 02020 struct ast_channel *which; 02021 struct localuser *lpeer; 02022 struct member *member; 02023 int res = 0, bridge = 0; 02024 int numbusies = 0; 02025 int x=0; 02026 char *announce = NULL; 02027 char digit = 0; 02028 time_t callstart; 02029 time_t now = time(NULL); 02030 struct ast_bridge_config bridge_config; 02031 char nondataquality = 1; 02032 02033 memset(&bridge_config, 0, sizeof(bridge_config)); 02034 time(&now); 02035 02036 for (; options && *options; options++) 02037 switch (*options) { 02038 case 't': 02039 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); 02040 break; 02041 case 'T': 02042 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); 02043 break; 02044 case 'w': 02045 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON); 02046 break; 02047 case 'W': 02048 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON); 02049 break; 02050 case 'd': 02051 nondataquality = 0; 02052 break; 02053 case 'h': 02054 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); 02055 break; 02056 case 'H': 02057 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); 02058 break; 02059 case 'n': 02060 if ((now - qe->start >= qe->parent->timeout)) 02061 *go_on = 1; 02062 break; 02063 } 02064 02065 /* Hold the lock while we setup the outgoing calls */ 02066 if (use_weight) 02067 ast_mutex_lock(&qlock); 02068 ast_mutex_lock(&qe->parent->lock); 02069 if (option_debug) 02070 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 02071 qe->chan->name); 02072 ast_copy_string(queuename, qe->parent->name, sizeof(queuename)); 02073 cur = qe->parent->members; 02074 if (!ast_strlen_zero(qe->announce)) 02075 announce = qe->announce; 02076 if (!ast_strlen_zero(announceoverride)) 02077 announce = announceoverride; 02078 02079 while(cur) { 02080 tmp = malloc(sizeof(*tmp)); 02081 if (!tmp) { 02082 ast_mutex_unlock(&qe->parent->lock); 02083 if (use_weight) 02084 ast_mutex_unlock(&qlock); 02085 ast_log(LOG_WARNING, "Out of memory\n"); 02086 goto out; 02087 } 02088 memset(tmp, 0, sizeof(*tmp)); 02089 tmp->stillgoing = -1; 02090 if (option_debug) { 02091 if (url) 02092 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url); 02093 else 02094 ast_log(LOG_DEBUG, "Simple queue (no URL)\n"); 02095 } 02096 02097 tmp->member = cur; /* Never directly dereference! Could change on reload */ 02098 tmp->oldstatus = cur->status; 02099 tmp->lastcall = cur->lastcall; 02100 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface)); 02101 /* If we're dialing by extension, look at the extension to know what to dial */ 02102 if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) { 02103 newnum++; 02104 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1); 02105 snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit); 02106 if (option_debug) 02107 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface); 02108 } 02109 /* Special case: If we ring everyone, go ahead and ring them, otherwise 02110 just calculate their metric for the appropriate strategy */ 02111 calc_metric(qe->parent, cur, x++, qe, tmp); 02112 /* Put them in the list of outgoing thingies... We're ready now. 02113 XXX If we're forcibly removed, these outgoing calls won't get 02114 hung up XXX */ 02115 tmp->next = outgoing; 02116 outgoing = tmp; 02117 /* If this line is up, don't try anybody else */ 02118 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP)) 02119 break; 02120 02121 cur = cur->next; 02122 } 02123 if (qe->parent->timeout) 02124 to = qe->parent->timeout * 1000; 02125 else 02126 to = -1; 02127 ring_one(qe, outgoing, &numbusies); 02128 ast_mutex_unlock(&qe->parent->lock); 02129 if (use_weight) 02130 ast_mutex_unlock(&qlock); 02131 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT)); 02132 ast_mutex_lock(&qe->parent->lock); 02133 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) { 02134 store_next(qe, outgoing); 02135 } 02136 ast_mutex_unlock(&qe->parent->lock); 02137 if (lpeer) 02138 peer = lpeer->chan; 02139 else 02140 peer = NULL; 02141 if (!peer) { 02142 if (to) { 02143 /* Musta gotten hung up */ 02144 res = -1; 02145 } else { 02146 res = digit; 02147 } 02148 if (option_debug) 02149 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name); 02150 goto out; 02151 } 02152 if (peer) { 02153 /* Ah ha! Someone answered within the desired timeframe. Of course after this 02154 we will always return with -1 so that it is hung up properly after the 02155 conversation. */ 02156 qe->handled++; 02157 if (!strcmp(qe->chan->type,"Zap")) 02158 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 02159 if (!strcmp(peer->type,"Zap")) 02160 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); 02161 /* Update parameters for the queue */ 02162 recalc_holdtime(qe); 02163 member = lpeer->member; 02164 hangupcalls(outgoing, peer); 02165 outgoing = NULL; 02166 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { 02167 int res2; 02168 res2 = ast_autoservice_start(qe->chan); 02169 if (!res2) { 02170 if (qe->parent->memberdelay) { 02171 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay); 02172 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000); 02173 } 02174 if (!res2 && announce) { 02175 if (play_file(peer, announce)) 02176 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce); 02177 } 02178 if (!res2 && qe->parent->reportholdtime) { 02179 if (!play_file(peer, qe->parent->sound_reporthold)) { 02180 int holdtime; 02181 02182 time(&now); 02183 holdtime = abs((now - qe->start) / 60); 02184 if (holdtime < 2) { 02185 play_file(peer, qe->parent->sound_lessthan); 02186 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL); 02187 } else 02188 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL); 02189 play_file(peer, qe->parent->sound_minutes); 02190 } 02191 } 02192 } 02193 res2 |= ast_autoservice_stop(qe->chan); 02194 if (peer->_softhangup) { 02195 /* Agent must have hung up */ 02196 ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name); 02197 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", ""); 02198 record_abandoned(qe); 02199 if (qe->parent->eventwhencalled) { 02200 manager_event(EVENT_FLAG_AGENT, "AgentDump", 02201 "Queue: %s\r\n" 02202 "Uniqueid: %s\r\n" 02203 "Channel: %s\r\n" 02204 "Member: %s\r\n", 02205 queuename, qe->chan->uniqueid, peer->name, member->interface); 02206 } 02207 ast_hangup(peer); 02208 goto out; 02209 } else if (res2) { 02210 /* Caller must have hung up just before being connected*/ 02211 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name); 02212 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start); 02213 record_abandoned(qe); 02214 ast_hangup(peer); 02215 return -1; 02216 } 02217 } 02218 /* Stop music on hold */ 02219 ast_moh_stop(qe->chan); 02220 /* If appropriate, log that we have a destination channel */ 02221 if (qe->chan->cdr) 02222 ast_cdr_setdestchan(qe->chan->cdr, peer->name); 02223 /* Make sure channels are compatible */ 02224 res = ast_channel_make_compatible(qe->chan, peer); 02225 if (res < 0) { 02226 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", ""); 02227 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); 02228 record_abandoned(qe); 02229 ast_hangup(peer); 02230 return -1; 02231 } 02232 /* Begin Monitoring */ 02233 if (qe->parent->monfmt && *qe->parent->monfmt) { 02234 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); 02235 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) 02236 which = qe->chan; 02237 else 02238 which = peer; 02239 if (monitorfilename) 02240 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 ); 02241 else if (qe->chan->cdr) 02242 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 ); 02243 else { 02244 /* Last ditch effort -- no CDR, make up something */ 02245 char tmpid[256]; 02246 snprintf(tmpid, sizeof(tmpid), "chan-%x", rand()); 02247 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 ); 02248 } 02249 if (qe->parent->monjoin) 02250 ast_monitor_setjoinfiles(which, 1); 02251 } 02252 /* Drop out of the queue at this point, to prepare for next caller */ 02253 leave_queue(qe); 02254 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) { 02255 if (option_debug) 02256 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url); 02257 ast_channel_sendurl(peer, url); 02258 } 02259 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start); 02260 if (qe->parent->eventwhencalled) 02261 manager_event(EVENT_FLAG_AGENT, "AgentConnect", 02262 "Queue: %s\r\n" 02263 "Uniqueid: %s\r\n" 02264 "Channel: %s\r\n" 02265 "Member: %s\r\n" 02266 "Holdtime: %ld\r\n", 02267 queuename, qe->chan->uniqueid, peer->name, member->interface, 02268 (long)time(NULL) - qe->start); 02269 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext)); 02270 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten)); 02271 time(&callstart); 02272 02273 bridge = ast_bridge_call(qe->chan,peer, &bridge_config); 02274 02275 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) { 02276 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context); 02277 } else if (qe->chan->_softhangup) { 02278 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld", 02279 (long)(callstart - qe->start), (long)(time(NULL) - callstart)); 02280 if (qe->parent->eventwhencalled) 02281 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 02282 "Queue: %s\r\n" 02283 "Uniqueid: %s\r\n" 02284 "Channel: %s\r\n" 02285 "Member: %s\r\n" 02286 "HoldTime: %ld\r\n" 02287 "TalkTime: %ld\r\n" 02288 "Reason: caller\r\n", 02289 queuename, qe->chan->uniqueid, peer->name, member->interface, 02290 (long)(callstart - qe->start), (long)(time(NULL) - callstart)); 02291 } else { 02292 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart)); 02293 if (qe->parent->eventwhencalled) 02294 manager_event(EVENT_FLAG_AGENT, "AgentComplete", 02295 "Queue: %s\r\n" 02296 "Uniqueid: %s\r\n" 02297 "Channel: %s\r\n" 02298 "HoldTime: %ld\r\n" 02299 "TalkTime: %ld\r\n" 02300 "Reason: agent\r\n", 02301 queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start), 02302 (long)(time(NULL) - callstart)); 02303 } 02304 02305 if(bridge != AST_PBX_NO_HANGUP_PEER) 02306 ast_hangup(peer); 02307 update_queue(qe->parent, member); 02308 if (bridge == 0) 02309 res = 1; /* JDG: bridge successfull, leave app_queue */ 02310 else 02311 res = bridge; /* bridge error, stay in the queue */ 02312 } 02313 out: 02314 hangupcalls(outgoing, NULL); 02315 return res; 02316 }
|
|
|
Definition at line 1301 of file app_queue.c. References AST_CAUSE_BUSY, AST_CAUSE_NOSUCHDRIVER, AST_CAUSE_UNREGISTERED, AST_DEVICE_BUSY, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, and update_status(). Referenced by ring_entry(), and wait_for_answer(). 01302 { 01303 if (status == AST_CAUSE_BUSY) 01304 status = AST_DEVICE_BUSY; 01305 else if (status == AST_CAUSE_UNREGISTERED) 01306 status = AST_DEVICE_UNAVAILABLE; 01307 else if (status == AST_CAUSE_NOSUCHDRIVER) 01308 status = AST_DEVICE_INVALID; 01309 else 01310 status = AST_DEVICE_UNKNOWN; 01311 return update_status(q, member, status); 01312 }
|
|
Definition at line 1935 of file app_queue.c. References ast_mutex_lock(), ast_mutex_unlock(), member::calls, ast_call_queue::callscompleted, member::lastcall, ast_call_queue::lock, ast_call_queue::members, and member::next. 01936 { 01937 struct member *cur; 01938 01939 /* Since a reload could have taken place, we have to traverse the list to 01940 be sure it's still valid */ 01941 ast_mutex_lock(&q->lock); 01942 cur = q->members; 01943 while(cur) { 01944 if (member == cur) { 01945 time(&cur->lastcall); 01946 cur->calls++; 01947 break; 01948 } 01949 cur = cur->next; 01950 } 01951 q->callscompleted++; 01952 ast_mutex_unlock(&q->lock); 01953 return 0; 01954 }
|
|
Definition at line 1269 of file app_queue.c. References ast_mutex_lock(), ast_mutex_unlock(), member::calls, member::dynamic, EVENT_FLAG_AGENT, member::interface, member::lastcall, ast_call_queue::lock, manager_event(), ast_call_queue::maskmemberstatus, ast_call_queue::members, ast_call_queue::name, member::next, member::paused, member::penalty, and member::status. Referenced by update_dial_status(). 01270 { 01271 struct member *cur; 01272 01273 /* Since a reload could have taken place, we have to traverse the list to 01274 be sure it's still valid */ 01275 ast_mutex_lock(&q->lock); 01276 cur = q->members; 01277 while(cur) { 01278 if (member == cur) { 01279 cur->status = status; 01280 if (!q->maskmemberstatus) { 01281 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus", 01282 "Queue: %s\r\n" 01283 "Location: %s\r\n" 01284 "Membership: %s\r\n" 01285 "Penalty: %d\r\n" 01286 "CallsTaken: %d\r\n" 01287 "LastCall: %d\r\n" 01288 "Status: %d\r\n" 01289 "Paused: %d\r\n", 01290 q->name, cur->interface, cur->dynamic ? "dynamic" : "static", 01291 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused); 01292 } 01293 break; 01294 } 01295 cur = cur->next; 01296 } 01297 ast_mutex_unlock(&q->lock); 01298 return 0; 01299 }
|
|
Definition at line 2661 of file app_queue.c. References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_goto_if_exists(), ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), localuser::chan, ast_channel::context, localuser::interface, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, option_priority_jumping, parse(), pbx_builtin_setvar_helper(), and set_member_paused(). Referenced by load_module(). 02662 { 02663 struct localuser *u; 02664 char *parse; 02665 int priority_jump = 0; 02666 AST_DECLARE_APP_ARGS(args, 02667 AST_APP_ARG(queuename); 02668 AST_APP_ARG(interface); 02669 AST_APP_ARG(options); 02670 ); 02671 02672 if (ast_strlen_zero(data)) { 02673 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n"); 02674 return -1; 02675 } 02676 02677 LOCAL_USER_ADD(u); 02678 02679 if (!(parse = ast_strdupa(data))) { 02680 ast_log(LOG_WARNING, "Memory Error!\n"); 02681 LOCAL_USER_REMOVE(u); 02682 return -1; 02683 } 02684 02685 AST_STANDARD_APP_ARGS(args, parse); 02686 02687 if (args.options) { 02688 if (strchr(args.options, 'j')) 02689 priority_jump = 1; 02690 } 02691 02692 if (ast_strlen_zero(args.interface)) { 02693 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n"); 02694 LOCAL_USER_REMOVE(u); 02695 return -1; 02696 } 02697 02698 if (set_member_paused(args.queuename, args.interface, 0)) { 02699 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface); 02700 if (priority_jump || option_priority_jumping) { 02701 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) { 02702 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 02703 LOCAL_USER_REMOVE(u); 02704 return 0; 02705 } 02706 } 02707 LOCAL_USER_REMOVE(u); 02708 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND"); 02709 return -1; 02710 } 02711 02712 LOCAL_USER_REMOVE(u); 02713 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED"); 02714 return 0; 02715 }
|
|
Provides a usecount. This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.
Definition at line 3860 of file app_queue.c. References STANDARD_USECOUNT. 03861 { 03862 int res; 03863 STANDARD_USECOUNT(res); 03864 return res; 03865 }
|
|
Definition at line 1059 of file app_queue.c. References ast_canmatch_extension(), ast_goto_if_exists(), ast_strlen_zero(), queue_ent::chan, ast_channel::cid, ast_callerid::cid_num, queue_ent::context, and queue_ent::digits. Referenced by background_file(), queue_exec(), say_position(), and wait_for_answer(). 01060 { 01061 int digitlen = strlen(qe->digits); 01062 01063 /* Prevent possible buffer overflow */ 01064 if (digitlen < sizeof(qe->digits) - 2) { 01065 qe->digits[digitlen] = digit; 01066 qe->digits[digitlen + 1] = '\0'; 01067 } else { 01068 qe->digits[0] = '\0'; 01069 return 0; 01070 } 01071 01072 /* If there's no context to goto, short-circuit */ 01073 if (ast_strlen_zero(qe->context)) 01074 return 0; 01075 01076 /* If the extension is bad, then reset the digits to blank */ 01077 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) { 01078 qe->digits[0] = '\0'; 01079 return 0; 01080 } 01081 01082 /* We have an exact match */ 01083 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) { 01084 /* Return 1 on a successful goto */ 01085 return 1; 01086 } 01087 return 0; 01088 }
|
|
Definition at line 2318 of file app_queue.c. References ast_waitfordigit(), queue_ent::chan, queue_ent::parent, and ast_call_queue::retry. 02319 { 02320 /* Don't need to hold the lock while we setup the outgoing calls */ 02321 int retrywait = qe->parent->retry * 1000; 02322 02323 return ast_waitfordigit(qe->chan, retrywait); 02324 }
|
|
Definition at line 1631 of file app_queue.c. References ast_channel::_state, ast_channel::accountcode, ast_call(), ast_cdr_busy(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_OFFHOOK, AST_CONTROL_RINGING, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_WATCHERS, ast_read(), ast_request(), AST_STATE_UP, ast_strlen_zero(), ast_verbose(), ast_waitfor_n(), BUILD_WATCHERS, ast_channel::call_forward, ast_channel::cdr, ast_channel::cdrflags, localuser::chan, queue_ent::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_channel::context, ast_channel::exten, ast_frame::frametype, free, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_channel::macroexten, malloc, localuser::member, ast_channel::name, ast_call_queue::name, ast_channel::nativeformats, localuser::next, localuser::oldstatus, option_verbose, queue_ent::parent, ring_one(), localuser::stillgoing, ast_call_queue::strategy, strdup, ast_frame::subclass, ast_channel::tech, ast_call_queue::timeoutrestart, update_dial_status(), valid_exit(), and VERBOSE_PREFIX_3. 01632 { 01633 char *queue = qe->parent->name; 01634 struct localuser *o; 01635 int found; 01636 int numlines; 01637 int status; 01638 int sentringing = 0; 01639 int numbusies = prebusies; 01640 int numnochan = 0; 01641 int stillgoing = 0; 01642 int orig = *to; 01643 struct ast_frame *f; 01644 struct localuser *peer = NULL; 01645 struct ast_channel *watchers[AST_MAX_WATCHERS]; 01646 int pos; 01647 struct ast_channel *winner; 01648 struct ast_channel *in = qe->chan; 01649 01650 while(*to && !peer) { 01651 BUILD_WATCHERS; 01652 if ((found < 0) && stillgoing && !qe->parent->strategy) { 01653 /* On "ringall" strategy we only move to the next penalty level 01654 when *all* ringing phones are done in the current penalty level */ 01655 ring_one(qe, outgoing, &numbusies); 01656 BUILD_WATCHERS; 01657 } 01658 if (found < 0) { 01659 if (numlines == (numbusies + numnochan)) { 01660 ast_log(LOG_DEBUG, "Everyone is busy at this time\n"); 01661 } else { 01662 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan); 01663 } 01664 *to = 0; 01665 return NULL; 01666 } 01667 winner = ast_waitfor_n(watchers, pos, to); 01668 o = outgoing; 01669 while(o) { 01670 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) { 01671 if (!peer) { 01672 if (option_verbose > 2) 01673 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 01674 peer = o; 01675 } 01676 } else if (o->chan && (o->chan == winner)) { 01677 if (!ast_strlen_zero(o->chan->call_forward)) { 01678 char tmpchan[256]=""; 01679 char *stuff; 01680 char *tech; 01681 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan)); 01682 if ((stuff = strchr(tmpchan, '/'))) { 01683 *stuff = '\0'; 01684 stuff++; 01685 tech = tmpchan; 01686 } else { 01687 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context); 01688 stuff = tmpchan; 01689 tech = "Local"; 01690 } 01691 /* Before processing channel, go ahead and check for forwarding */ 01692 if (option_verbose > 2) 01693 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name); 01694 /* Setup parameters */ 01695 o->chan = ast_request(tech, in->nativeformats, stuff, &status); 01696 if (status != o->oldstatus) 01697 update_dial_status(qe->parent, o->member, status); 01698 if (!o->chan) { 01699 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff); 01700 o->stillgoing = 0; 01701 numnochan++; 01702 } else { 01703 if (o->chan->cid.cid_num) 01704 free(o->chan->cid.cid_num); 01705 o->chan->cid.cid_num = NULL; 01706 if (o->chan->cid.cid_name) 01707 free(o->chan->cid.cid_name); 01708 o->chan->cid.cid_name = NULL; 01709 01710 if (in->cid.cid_num) { 01711 o->chan->cid.cid_num = strdup(in->cid.cid_num); 01712 if (!o->chan->cid.cid_num) 01713 ast_log(LOG_WARNING, "Out of memory\n"); 01714 } 01715 if (in->cid.cid_name) { 01716 o->chan->cid.cid_name = strdup(in->cid.cid_name); 01717 if (!o->chan->cid.cid_name) 01718 ast_log(LOG_WARNING, "Out of memory\n"); 01719 } 01720 ast_copy_string(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode)); 01721 o->chan->cdrflags = in->cdrflags; 01722 01723 if (in->cid.cid_ani) { 01724 if (o->chan->cid.cid_ani) 01725 free(o->chan->cid.cid_ani); 01726 o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1); 01727 if (o->chan->cid.cid_ani) 01728 strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1); 01729 else 01730 ast_log(LOG_WARNING, "Out of memory\n"); 01731 } 01732 if (o->chan->cid.cid_rdnis) 01733 free(o->chan->cid.cid_rdnis); 01734 if (!ast_strlen_zero(in->macroexten)) 01735 o->chan->cid.cid_rdnis = strdup(in->macroexten); 01736 else 01737 o->chan->cid.cid_rdnis = strdup(in->exten); 01738 if (ast_call(o->chan, tmpchan, 0)) { 01739 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); 01740 o->stillgoing = 0; 01741 ast_hangup(o->chan); 01742 o->chan = NULL; 01743 numnochan++; 01744 } 01745 } 01746 /* Hangup the original channel now, in case we needed it */ 01747 ast_hangup(winner); 01748 continue; 01749 } 01750 f = ast_read(winner); 01751 if (f) { 01752 if (f->frametype == AST_FRAME_CONTROL) { 01753 switch(f->subclass) { 01754 case AST_CONTROL_ANSWER: 01755 /* This is our guy if someone answered. */ 01756 if (!peer) { 01757 if (option_verbose > 2) 01758 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); 01759 peer = o; 01760 } 01761 break; 01762 case AST_CONTROL_BUSY: 01763 if (option_verbose > 2) 01764 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name); 01765 o->stillgoing = 0; 01766 if (in->cdr) 01767 ast_cdr_busy(in->cdr); 01768 ast_hangup(o->chan); 01769 o->chan = NULL; 01770 if (qe->parent->strategy) { 01771 if (qe->parent->timeoutrestart) 01772 *to = orig; 01773 ring_one(qe, outgoing, &numbusies); 01774 } 01775 numbusies++; 01776 break; 01777 case AST_CONTROL_CONGESTION: 01778 if (option_verbose > 2) 01779 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name); 01780 o->stillgoing = 0; 01781 if (in->cdr) 01782 ast_cdr_busy(in->cdr); 01783 ast_hangup(o->chan); 01784 o->chan = NULL; 01785 if (qe->parent->strategy) { 01786 if (qe->parent->timeoutrestart) 01787 *to = orig; 01788 ring_one(qe, outgoing, &numbusies); 01789 } 01790 numbusies++; 01791 break; 01792 case AST_CONTROL_RINGING: 01793 if (option_verbose > 2) 01794 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name); 01795 if (!sentringing) { 01796 #if 0 01797 ast_indicate(in, AST_CONTROL_RINGING); 01798 #endif 01799 sentringing++; 01800 } 01801 break; 01802 case AST_CONTROL_OFFHOOK: 01803 /* Ignore going off hook */ 01804 break; 01805 default: 01806 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass); 01807 } 01808 } 01809 ast_frfree(f); 01810 } else { 01811 o->stillgoing = 0; 01812 ast_hangup(o->chan); 01813 o->chan = NULL; 01814 if (qe->parent->strategy) { 01815 if (qe->parent->timeoutrestart) 01816 *to = orig; 01817 ring_one(qe, outgoing, &numbusies); 01818 } 01819 } 01820 } 01821 o = o->next; 01822 } 01823 if (winner == in) { 01824 f = ast_read(in); 01825 #if 0 01826 if (f && (f->frametype != AST_FRAME_VOICE)) 01827 printf("Frame type: %d, %d\n", f->frametype, f->subclass); 01828 else if (!f || (f->frametype != AST_FRAME_VOICE)) 01829 printf("Hangup received on %s\n", in->name); 01830 #endif 01831 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 01832 /* Got hung up */ 01833 *to=-1; 01834 if (f) 01835 ast_frfree(f); 01836 return NULL; 01837 } 01838 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) { 01839 if (option_verbose > 3) 01840 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass); 01841 *to=0; 01842 ast_frfree(f); 01843 return NULL; 01844 } 01845 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) { 01846 if (option_verbose > 3) 01847 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass); 01848 *to=0; 01849 *digit=f->subclass; 01850 ast_frfree(f); 01851 return NULL; 01852 } 01853 ast_frfree(f); 01854 } 01855 if (!*to && (option_verbose > 2)) 01856 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig); 01857 } 01858 01859 return peer; 01860 01861 }
|
|
Definition at line 1883 of file app_queue.c. References ast_queue_log(), is_our_turn(), and QUEUE_TIMEOUT. Referenced by queue_exec(). 01884 { 01885 int res = 0; 01886 01887 /* This is the holding pen for callers 2 through maxlen */ 01888 for (;;) { 01889 enum queue_member_status stat; 01890 01891 if (is_our_turn(qe)) 01892 break; 01893 01894 /* If we have timed out, break out */ 01895 if (qe->expire && (time(NULL) > qe->expire)) { 01896 *reason = QUEUE_TIMEOUT; 01897 ast_queue_log(qe->parent->name, qe->chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe->pos); 01898 break; 01899 } 01900 01901 stat = get_member_status(qe->parent); 01902 01903 /* leave the queue if no agents, if enabled */ 01904 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { 01905 *reason = QUEUE_LEAVEEMPTY; 01906 leave_queue(qe); 01907 break; 01908 } 01909 01910 /* leave the queue if no reachable agents, if enabled */ 01911 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { 01912 *reason = QUEUE_LEAVEUNAVAIL; 01913 leave_queue(qe); 01914 break; 01915 } 01916 01917 /* Make a position announcement, if enabled */ 01918 if (qe->parent->announcefrequency && !ringing) 01919 res = say_position(qe); 01920 if (res) 01921 break; 01922 01923 /* Make a periodic announcement, if enabled */ 01924 if (qe->parent->periodicannouncefrequency && !ringing) 01925 res = say_periodic_announcement(qe); 01926 01927 /* Wait a second before checking again */ 01928 if (!res) res = ast_waitfordigit(qe->chan, RECHECK * 1000); 01929 if (res) 01930 break; 01931 } 01932 return res; 01933 }
|
|
Definition at line 123 of file app_queue.c. |
|
Definition at line 153 of file app_queue.c. Referenced by load_module(), and unload_module(). |
|
Definition at line 155 of file app_queue.c. Referenced by load_module(). |
|
Definition at line 154 of file app_queue.c. Referenced by load_module(). |
|
Definition at line 185 of file app_queue.c. Referenced by load_module(), and unload_module(). |
|
Definition at line 187 of file app_queue.c. Referenced by load_module(). |
|
Definition at line 186 of file app_queue.c. Referenced by load_module(). |
|
Definition at line 169 of file app_queue.c. Referenced by load_module(), and unload_module(). |
|
Definition at line 171 of file app_queue.c. Referenced by load_module(). |
|
Definition at line 170 of file app_queue.c. Referenced by load_module(). |
|
Definition at line 207 of file app_queue.c. Referenced by load_module(), and unload_module(). |
|
Definition at line 209 of file app_queue.c. Referenced by load_module(). |
|
Definition at line 208 of file app_queue.c. Referenced by load_module(). |
|
Initial value:
"Usage: add queue member <channel> to <queue> [penalty <penalty>]\n"
Definition at line 3778 of file app_queue.c. |
|
Initial value: { { "add", "queue", "member", NULL }, handle_add_queue_member, "Add a channel to a specified queue", aqm_cmd_usage, complete_add_queue_member } Definition at line 3781 of file app_queue.c. Referenced by load_module(), and unload_module(). |
|
Initial value: { { "remove", "queue", "member", NULL }, handle_remove_queue_member, "Removes a channel from a specified queue", rqm_cmd_usage, complete_remove_queue_member } Definition at line 3788 of file app_queue.c. Referenced by load_module(), and unload_module(). |
|
Initial value: { { "show", "queue", NULL }, queue_show, "Show status of a specified queue", show_queue_usage, complete_queue } Definition at line 3774 of file app_queue.c. Referenced by load_module(), and unload_module(). |
|
Initial value: { { "show", "queues", NULL }, queues_show, "Show status of queues", show_queues_usage, NULL } Definition at line 3766 of file app_queue.c. Referenced by load_module(), and unload_module(). |
|
Definition at line 127 of file app_queue.c. |
|
Definition at line 244 of file app_queue.c. Referenced by _sip_show_peers(), aPGSQL_clear(), aPGSQL_connect(), aPGSQL_disconnect(), aPGSQL_fetch(), aPGSQL_query(), aPGSQL_reset(), config_odbc(), and manager_iax2_show_peers(). |
|
Definition at line 271 of file app_queue.c. |
|
Persistent Members astdb family.
Definition at line 223 of file app_queue.c. Referenced by dump_queue_members(), and reload_queue_members(). |
|
queues.conf [general] option
Definition at line 228 of file app_queue.c. Referenced by aqm_exec(), handle_add_queue_member(), load_module(), manager_add_queue_member(), reload_queues(), and set_member_paused(). |
|
Referenced by set_queue_result(). |
|
Definition at line 3151 of file app_queue.c. Referenced by load_module(), and unload_module(). |
|
Definition at line 366 of file app_queue.c. Referenced by __queues_show(), changethread(), compare_weight(), complete_queue(), complete_remove_queue_member(), find_queue_by_name_rt(), load_realtime_queue(), manager_queues_status(), queue_function_qac(), reload_queue_members(), reload_queues(), remove_from_queue(), remove_queue(), and set_member_paused(). |
|
Initial value:
"Usage: remove queue member <channel> from <queue>\n"
Definition at line 3785 of file app_queue.c. |
|
Initial value: "Usage: show queue\n" " Provides summary information on a specified queue.\n" Definition at line 3770 of file app_queue.c. |
|
Initial value: "Usage: show queues\n" " Provides summary information on call queues.\n" Definition at line 3762 of file app_queue.c. |
|
Referenced by int2strat(), and strat2int(). |
|
Definition at line 125 of file app_queue.c. |
|
Definition at line 121 of file app_queue.c. |
|
Definition at line 245 of file app_queue.c. Referenced by _sip_show_peer(), build_reply_digest(), check_auth(), find_sip_method(), handle_response(), parse_sip_options(), reqprep(), sendtext_exec(), set_queue_result(), sip_alloc(), and sip_show_channel(). |
|
queues.conf per-queue weight option
Definition at line 231 of file app_queue.c. Referenced by queue_set_param(), and ring_entry(). |