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