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