Sun Aug 6 15:05:43 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

chan_agent.c File Reference

Implementation of Agents (proxy channel). More...

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
#include "asterisk/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/features.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"

Include dependency graph for chan_agent.c:

Go to the source code of this file.

Defines

#define AST_MAX_AGENT   80
#define AST_MAX_BUF   256
#define AST_MAX_FILENAME_LEN   256
#define CHECK_FORMATS(ast, p)
#define CLEANUP(ast, p)
#define GETAGENTBYCALLERID   "AGENTBYCALLERID"
#define PA_MAX_LEN   2048

Functions

static int __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock)
static int __login_exec (struct ast_channel *chan, void *data, int callbackmode)
 Log in agent application.
static int action_agent_callback_login (struct mansession *s, struct message *m)
static int action_agent_logoff (struct mansession *s, struct message *m)
static int action_agents (struct mansession *s, struct message *m)
static struct agent_pvtadd_agent (char *agent, int pending)
static int agent_ack_sleep (void *data)
static int agent_answer (struct ast_channel *ast)
static struct ast_channelagent_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge)
static int agent_call (struct ast_channel *ast, char *dest, int timeout)
static int agent_cleanup (struct agent_pvt *p)
static int agent_cont_sleep (void *data)
static int agent_devicestate (void *data)
static int agent_digit (struct ast_channel *ast, char digit)
static int agent_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
static int agent_hangup (struct ast_channel *ast)
static int agent_indicate (struct ast_channel *ast, int condition)
static int agent_logoff (char *agent, int soft)
static int agent_logoff_cmd (int fd, int argc, char **argv)
static struct ast_channelagent_new (struct agent_pvt *p, int state)
static struct ast_frameagent_read (struct ast_channel *ast)
static struct ast_channelagent_request (const char *type, int format, void *data, int *cause)
static int agent_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen)
static int agent_sendtext (struct ast_channel *ast, const char *text)
static int agent_start_monitoring (struct ast_channel *ast, int needlock)
static void agent_unlink (struct agent_pvt *agent)
static int agent_write (struct ast_channel *ast, struct ast_frame *f)
static int agentmonitoroutgoing_exec (struct ast_channel *chan, void *data)
static int agents_show (int fd, int argc, char **argv)
 AST_MUTEX_DEFINE_STATIC (agentlock)
 AST_MUTEX_DEFINE_STATIC (usecnt_lock)
static int callback_exec (struct ast_channel *chan, void *data)
static int check_availability (struct agent_pvt *newlyavailable, int needlock)
static int check_beep (struct agent_pvt *newlyavailable, int needlock)
static char * complete_agent_logoff_cmd (char *line, char *word, int pos, int state)
char * description ()
 Provides a description of the module.
static void dump_agents (void)
char * key ()
 Returns the ASTERISK_GPL_KEY.
int load_module ()
 Initialize the module.
static int login_exec (struct ast_channel *chan, void *data)
static int powerof (unsigned int v)
static int read_agent_config (void)
int reload ()
 Reload stuff.
static void reload_agents (void)
static void set_agentbycallerid (const char *callerid, const char *agent)
int unload_module ()
 Cleanup all module structures, sockets, etc.
int usecount ()
 Provides a usecount.

Variables

static int ackcall
static char agent_logoff_usage []
static const struct ast_channel_tech agent_tech
static char agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye"
static struct agent_pvtagents = NULL
static const char app [] = "AgentLogin"
static const char app2 [] = "AgentCallbackLogin"
static const char app3 [] = "AgentMonitorOutgoing"
static int autologoff
static char beep [AST_MAX_BUF] = "beep"
static const char channeltype [] = "Agent"
static struct ast_cli_entry cli_agent_logoff
static struct ast_cli_entry cli_show_agents
static const char config [] = "agents.conf"
static int createlink = 0
static const char desc [] = "Agent Proxy Channel"
static const char descrip []
static const char descrip2 []
static const char descrip3 []
static ast_group_t group
 LOCAL_USER_DECL
static const char mandescr_agent_callback_login []
static const char mandescr_agent_logoff []
static const char mandescr_agents []
static int maxlogintries = 3
static char moh [80] = "default"
static const char pa_family [] = "/Agents"
static int persistent_agents = 0
static int recordagentcalls = 0
static char recordformat [AST_MAX_BUF] = ""
static char recordformatext [AST_MAX_BUF] = ""
static char savecallsin [AST_MAX_BUF] = ""
static char show_agents_usage []
 STANDARD_LOCAL_USER
static const char synopsis [] = "Call agent login"
static const char synopsis2 [] = "Call agent callback login"
static const char synopsis3 [] = "Record agent's outgoing call"
static const char tdesc [] = "Call Agent Proxy Channel"
static int updatecdr = 0
static char urlprefix [AST_MAX_BUF] = ""
static int usecnt = 0
static int wrapuptime


Detailed Description

Implementation of Agents (proxy channel).

This file is the implementation of Agents modules. It is a dynamic module that is loaded by Asterisk.

See also

Definition in file chan_agent.c.


Define Documentation

#define AST_MAX_AGENT   80
 

Agent ID or Password max length

Definition at line 141 of file chan_agent.c.

Referenced by __login_exec(), agent_hangup(), agentmonitoroutgoing_exec(), and complete_agent_logoff_cmd().

#define AST_MAX_BUF   256
 

Definition at line 142 of file chan_agent.c.

Referenced by __agent_start_monitoring(), __login_exec(), agentmonitoroutgoing_exec(), agents_show(), and set_agentbycallerid().

#define AST_MAX_FILENAME_LEN   256
 

Definition at line 143 of file chan_agent.c.

Referenced by __login_exec().

#define CHECK_FORMATS ast,
 ) 
 

Definition at line 210 of file chan_agent.c.

Referenced by agent_read(), and agent_write().

#define CLEANUP ast,
 ) 
 

Definition at line 231 of file chan_agent.c.

Referenced by agent_call(), agent_read(), and agent_write().

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"
 

Definition at line 176 of file chan_agent.c.

Referenced by agentmonitoroutgoing_exec(), and set_agentbycallerid().

#define PA_MAX_LEN   2048
 

The maximum length of each persistent member agent database entry

Definition at line 148 of file chan_agent.c.


Function Documentation

static int __agent_start_monitoring struct ast_channel ast,
struct agent_pvt p,
int  needlock
[static]
 

Definition at line 430 of file chan_agent.c.

References agent_pvt::agent, ast_cdr_alloc(), ast_cdr_setuserfield(), ast_log(), AST_MAX_BUF, ast_monitor_setjoinfiles(), ast_monitor_start(), ast_verbose(), ast_channel::cdr, LOG_ERROR, ast_channel::monitor, recordformat, recordformatext, savecallsin, ast_channel::uniqueid, and urlprefix.

Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().

00431 {
00432    char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
00433    char filename[AST_MAX_BUF];
00434    int res = -1;
00435    if (!p)
00436       return -1;
00437    if (!ast->monitor) {
00438       snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
00439       /* substitute . for - */
00440       if ((pointer = strchr(filename, '.')))
00441          *pointer = '-';
00442       snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
00443       ast_monitor_start(ast, recordformat, tmp, needlock);
00444       ast_monitor_setjoinfiles(ast, 1);
00445       snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
00446 #if 0
00447       ast_verbose("name is %s, link is %s\n",tmp, tmp2);
00448 #endif
00449       if (!ast->cdr)
00450          ast->cdr = ast_cdr_alloc();
00451       ast_cdr_setuserfield(ast, tmp2);
00452       res = 0;
00453    } else
00454       ast_log(LOG_ERROR, "Recording already started on that call.\n");
00455    return res;
00456 }

static int __login_exec struct ast_channel chan,
void *  data,
int  callbackmode
[static]
 

Log in agent application.

Parameters:
chan 
data 
callbackmode non-zero for AgentCallbackLogin

Definition at line 1668 of file chan_agent.c.

References ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), agentgoodbye, agent_pvt::app_lock, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), AST_DECLARE_APP_ARGS, ast_device_state_changed(), AST_DIGIT_ANY, ast_exists_extension(), ast_getformatname(), ast_log(), AST_MAX_AGENT, AST_MAX_BUF, AST_MAX_FILENAME_LEN, ast_moh_start(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_read_format(), ast_set_write_format(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_verbose(), ast_waitstream(), agent_pvt::autologoff, agent_pvt::chan, check_availability(), check_beep(), context, agent_pvt::dead, dump_agents(), EVENT_FLAG_AGENT, free, agent_pvt::lastdisc, LOCAL_USER_ADD, LOCAL_USER_REMOVE, agent_pvt::lock, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), maxlogintries, agent_pvt::moh, ast_channel::name, agent_pvt::next, option_debug, option_verbose, agent_pvt::owner, agent_pvt::owning_app, parse(), pass, agent_pvt::password, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), agent_pvt::pending, persistent_agents, set_agentbycallerid(), strsep(), updatecdr, user, VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

Referenced by callback_exec(), and login_exec().

01669 {
01670    int res=0;
01671    int tries = 0;
01672    int max_login_tries = maxlogintries;
01673    struct agent_pvt *p;
01674    struct localuser *u;
01675    int login_state = 0;
01676    char user[AST_MAX_AGENT] = "";
01677    char pass[AST_MAX_AGENT];
01678    char agent[AST_MAX_AGENT] = "";
01679    char xpass[AST_MAX_AGENT] = "";
01680    char *errmsg;
01681    char *parse;
01682    AST_DECLARE_APP_ARGS(args,
01683               AST_APP_ARG(agent_id);
01684               AST_APP_ARG(options);
01685               AST_APP_ARG(extension);
01686       );
01687    char *tmpoptions = NULL;
01688    char *context = NULL;
01689    int play_announcement = 1;
01690    char agent_goodbye[AST_MAX_FILENAME_LEN];
01691    int update_cdr = updatecdr;
01692    char *filename = "agent-loginok";
01693    char tmpchan[AST_MAX_BUF] = "";
01694 
01695    LOCAL_USER_ADD(u);
01696 
01697    if (!(parse = ast_strdupa(data))) {
01698       ast_log(LOG_ERROR, "Out of memory!\n");
01699       LOCAL_USER_REMOVE(u);
01700       return -1;
01701    }
01702 
01703    AST_STANDARD_APP_ARGS(args, parse);
01704 
01705    ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
01706 
01707    /* Set Channel Specific Login Overrides */
01708    if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
01709       max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
01710       if (max_login_tries < 0)
01711          max_login_tries = 0;
01712       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
01713       if (option_verbose > 2)
01714          ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
01715    }
01716    if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
01717       if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
01718          update_cdr = 1;
01719       else
01720          update_cdr = 0;
01721       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
01722       if (option_verbose > 2)
01723          ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
01724    }
01725    if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
01726       strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
01727       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
01728       if (option_verbose > 2)
01729          ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
01730    }
01731    /* End Channel Specific Login Overrides */
01732    
01733    if (callbackmode && args.extension) {
01734       parse = args.extension;
01735       args.extension = strsep(&parse, "@");
01736       context = parse;
01737    }
01738 
01739    if (!ast_strlen_zero(args.options)) {
01740       if (strchr(args.options, 's')) {
01741          play_announcement = 0;
01742       }
01743    }
01744 
01745    if (chan->_state != AST_STATE_UP)
01746       res = ast_answer(chan);
01747    if (!res) {
01748       if (!ast_strlen_zero(args.agent_id))
01749          ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
01750       else
01751          res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
01752    }
01753    while (!res && (max_login_tries==0 || tries < max_login_tries)) {
01754       tries++;
01755       /* Check for password */
01756       ast_mutex_lock(&agentlock);
01757       p = agents;
01758       while(p) {
01759          if (!strcmp(p->agent, user) && !p->pending)
01760             ast_copy_string(xpass, p->password, sizeof(xpass));
01761          p = p->next;
01762       }
01763       ast_mutex_unlock(&agentlock);
01764       if (!res) {
01765          if (!ast_strlen_zero(xpass))
01766             res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
01767          else
01768             pass[0] = '\0';
01769       }
01770       errmsg = "agent-incorrect";
01771 
01772 #if 0
01773       ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
01774 #endif      
01775 
01776       /* Check again for accuracy */
01777       ast_mutex_lock(&agentlock);
01778       p = agents;
01779       while(p) {
01780          ast_mutex_lock(&p->lock);
01781          if (!strcmp(p->agent, user) &&
01782              !strcmp(p->password, pass) && !p->pending) {
01783             login_state = 1; /* Successful Login */
01784 
01785             /* Ensure we can't be gotten until we're done */
01786             gettimeofday(&p->lastdisc, NULL);
01787             p->lastdisc.tv_sec++;
01788 
01789             /* Set Channel Specific Agent Overrides */
01790             if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
01791                if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
01792                   p->ackcall = 2;
01793                else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
01794                   p->ackcall = 1;
01795                else
01796                   p->ackcall = 0;
01797                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
01798                if (option_verbose > 2)
01799                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
01800             }
01801             if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
01802                p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
01803                if (p->autologoff < 0)
01804                   p->autologoff = 0;
01805                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
01806                if (option_verbose > 2)
01807                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
01808             }
01809             if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
01810                p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
01811                if (p->wrapuptime < 0)
01812                   p->wrapuptime = 0;
01813                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
01814                if (option_verbose > 2)
01815                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
01816             }
01817             /* End Channel Specific Agent Overrides */
01818             if (!p->chan) {
01819                char last_loginchan[80] = "";
01820                long logintime;
01821                snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01822 
01823                if (callbackmode) {
01824                   int pos = 0;
01825                   /* Retrieve login chan */
01826                   for (;;) {
01827                      if (!ast_strlen_zero(args.extension)) {
01828                         ast_copy_string(tmpchan, args.extension, sizeof(tmpchan));
01829                         res = 0;
01830                      } else
01831                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
01832                      if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, !ast_strlen_zero(context) ? context : "default", tmpchan,
01833                                             1, NULL))
01834                         break;
01835                      if (args.extension) {
01836                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent);
01837                         args.extension = NULL;
01838                         pos = 0;
01839                      } else {
01840                         ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, !ast_strlen_zero(context) ? context : "default", p->agent);
01841                         res = ast_streamfile(chan, "invalid", chan->language);
01842                         if (!res)
01843                            res = ast_waitstream(chan, AST_DIGIT_ANY);
01844                         if (res > 0) {
01845                            tmpchan[0] = res;
01846                            tmpchan[1] = '\0';
01847                            pos = 1;
01848                         } else {
01849                            tmpchan[0] = '\0';
01850                            pos = 0;
01851                         }
01852                      }
01853                   }
01854                   args.extension = tmpchan;
01855                   if (!res) {
01856                      set_agentbycallerid(p->logincallerid, NULL);
01857                      if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
01858                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
01859                      else {
01860                         ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
01861                         ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
01862                      }
01863                      p->acknowledged = 0;
01864                      if (ast_strlen_zero(p->loginchan)) {
01865                         login_state = 2;
01866                         filename = "agent-loggedoff";
01867                      } else {
01868                         if (chan->cid.cid_num) {
01869                            ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
01870                            set_agentbycallerid(p->logincallerid, p->agent);
01871                         } else
01872                            p->logincallerid[0] = '\0';
01873                      }
01874 
01875                      if(update_cdr && chan->cdr)
01876                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
01877 
01878                   }
01879                } else {
01880                   p->loginchan[0] = '\0';
01881                   p->logincallerid[0] = '\0';
01882                   p->acknowledged = 0;
01883                }
01884                ast_mutex_unlock(&p->lock);
01885                ast_mutex_unlock(&agentlock);
01886                if( !res && play_announcement==1 )
01887                   res = ast_streamfile(chan, filename, chan->language);
01888                if (!res)
01889                   ast_waitstream(chan, "");
01890                ast_mutex_lock(&agentlock);
01891                ast_mutex_lock(&p->lock);
01892                if (!res) {
01893                   res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
01894                   if (res)
01895                      ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
01896                }
01897                if (!res) {
01898                   res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
01899                   if (res)
01900                      ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
01901                }
01902                /* Check once more just in case */
01903                if (p->chan)
01904                   res = -1;
01905                if (callbackmode && !res) {
01906                   /* Just say goodbye and be done with it */
01907                   if (!ast_strlen_zero(p->loginchan)) {
01908                      if (p->loginstart == 0)
01909                         time(&p->loginstart);
01910                      manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
01911                               "Agent: %s\r\n"
01912                               "Loginchan: %s\r\n"
01913                               "Uniqueid: %s\r\n",
01914                               p->agent, p->loginchan, chan->uniqueid);
01915                      ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
01916                      if (option_verbose > 1)
01917                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
01918                      ast_device_state_changed("Agent/%s", p->agent);
01919                   } else {
01920                      logintime = time(NULL) - p->loginstart;
01921                      p->loginstart = 0;
01922                      manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01923                               "Agent: %s\r\n"
01924                               "Loginchan: %s\r\n"
01925                               "Logintime: %ld\r\n"
01926                               "Uniqueid: %s\r\n",
01927                               p->agent, last_loginchan, logintime, chan->uniqueid);
01928                      ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
01929                      if (option_verbose > 1)
01930                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
01931                      ast_device_state_changed("Agent/%s", p->agent);
01932                   }
01933                   ast_mutex_unlock(&agentlock);
01934                   if (!res)
01935                      res = ast_safe_sleep(chan, 500);
01936                   ast_mutex_unlock(&p->lock);
01937                   if (persistent_agents)
01938                      dump_agents();
01939                } else if (!res) {
01940 #ifdef HONOR_MUSIC_CLASS
01941                   /* check if the moh class was changed with setmusiconhold */
01942                   if (*(chan->musicclass))
01943                      ast_copy_string(p->moh, chan->musicclass, sizeof(p->moh));
01944 #endif                        
01945                   ast_moh_start(chan, p->moh);
01946                   if (p->loginstart == 0)
01947                      time(&p->loginstart);
01948                   manager_event(EVENT_FLAG_AGENT, "Agentlogin",
01949                            "Agent: %s\r\n"
01950                            "Channel: %s\r\n"
01951                            "Uniqueid: %s\r\n",
01952                            p->agent, chan->name, chan->uniqueid);
01953                   if (update_cdr && chan->cdr)
01954                      snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
01955                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
01956                   if (option_verbose > 1)
01957                      ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
01958                             ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
01959                   /* Login this channel and wait for it to
01960                      go away */
01961                   p->chan = chan;
01962                   if (p->ackcall > 1)
01963                      check_beep(p, 0);
01964                   else
01965                      check_availability(p, 0);
01966                   ast_mutex_unlock(&p->lock);
01967                   ast_mutex_unlock(&agentlock);
01968                   ast_device_state_changed("Agent/%s", p->agent);
01969                   while (res >= 0) {
01970                      ast_mutex_lock(&p->lock);
01971                      if (p->chan != chan)
01972                         res = -1;
01973                      ast_mutex_unlock(&p->lock);
01974                      /* Yield here so other interested threads can kick in. */
01975                      sched_yield();
01976                      if (res)
01977                         break;
01978 
01979                      ast_mutex_lock(&agentlock);
01980                      ast_mutex_lock(&p->lock);
01981                      if (p->lastdisc.tv_sec) {
01982                         if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) {
01983                            if (option_debug)
01984                               ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
01985                            p->lastdisc = ast_tv(0, 0);
01986                            if (p->ackcall > 1)
01987                               check_beep(p, 0);
01988                            else
01989                               check_availability(p, 0);
01990                         }
01991                      }
01992                      ast_mutex_unlock(&p->lock);
01993                      ast_mutex_unlock(&agentlock);
01994                      /* Synchronize channel ownership between call to agent and itself. */
01995                      ast_mutex_lock( &p->app_lock );
01996                      ast_mutex_lock(&p->lock);
01997                      p->owning_app = pthread_self();
01998                      ast_mutex_unlock(&p->lock);
01999                      if (p->ackcall > 1) 
02000                         res = agent_ack_sleep(p);
02001                      else
02002                         res = ast_safe_sleep_conditional( chan, 1000,
02003                                       agent_cont_sleep, p );
02004                      ast_mutex_unlock( &p->app_lock );
02005                      if ((p->ackcall > 1)  && (res == 1)) {
02006                         ast_mutex_lock(&agentlock);
02007                         ast_mutex_lock(&p->lock);
02008                         check_availability(p, 0);
02009                         ast_mutex_unlock(&p->lock);
02010                         ast_mutex_unlock(&agentlock);
02011                         res = 0;
02012                      }
02013                      sched_yield();
02014                   }
02015                   ast_mutex_lock(&p->lock);
02016                   if (res && p->owner) 
02017                      ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
02018                   /* Log us off if appropriate */
02019                   if (p->chan == chan)
02020                      p->chan = NULL;
02021                   p->acknowledged = 0;
02022                   logintime = time(NULL) - p->loginstart;
02023                   p->loginstart = 0;
02024                   ast_mutex_unlock(&p->lock);
02025                   manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
02026                            "Agent: %s\r\n"
02027                            "Logintime: %ld\r\n"
02028                            "Uniqueid: %s\r\n",
02029                            p->agent, logintime, chan->uniqueid);
02030                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
02031                   if (option_verbose > 1)
02032                      ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
02033                   /* If there is no owner, go ahead and kill it now */
02034                   ast_device_state_changed("Agent/%s", p->agent);
02035                   if (p->dead && !p->owner) {
02036                      ast_mutex_destroy(&p->lock);
02037                      ast_mutex_destroy(&p->app_lock);
02038                      free(p);
02039                   }
02040                }
02041                else {
02042                   ast_mutex_unlock(&p->lock);
02043                   p = NULL;
02044                }
02045                res = -1;
02046             } else {
02047                ast_mutex_unlock(&p->lock);
02048                errmsg = "agent-alreadyon";
02049                p = NULL;
02050             }
02051             break;
02052          }
02053          ast_mutex_unlock(&p->lock);
02054          p = p->next;
02055       }
02056       if (!p)
02057          ast_mutex_unlock(&agentlock);
02058 
02059       if (!res && (max_login_tries==0 || tries < max_login_tries))
02060          res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
02061    }
02062       
02063    if (!res)
02064       res = ast_safe_sleep(chan, 500);
02065 
02066    /* AgentLogin() exit */
02067    if (!callbackmode) {
02068       LOCAL_USER_REMOVE(u);
02069       return -1;
02070    }
02071    /* AgentCallbackLogin() exit*/
02072    else {
02073       /* Set variables */
02074       if (login_state > 0) {
02075          pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
02076          if (login_state==1) {
02077             pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
02078             pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension);
02079          }
02080          else {
02081             pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
02082          }
02083       }
02084       else {
02085          pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
02086       }
02087       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
02088          LOCAL_USER_REMOVE(u);
02089          return 0;
02090       }
02091       /* Do we need to play agent-goodbye now that we will be hanging up? */
02092       if (play_announcement) {
02093          if (!res)
02094             res = ast_safe_sleep(chan, 1000);
02095          res = ast_streamfile(chan, agent_goodbye, chan->language);
02096          if (!res)
02097             res = ast_waitstream(chan, "");
02098          if (!res)
02099             res = ast_safe_sleep(chan, 1000);
02100       }
02101    }
02102 
02103    LOCAL_USER_REMOVE(u);
02104    
02105    /* We should never get here if next priority exists when in callbackmode */
02106    return -1;
02107 }

static int action_agent_callback_login struct mansession s,
struct message m
[static]
 

Sets an agent as logged in by callback in the Manager API. It is registered on load_module() and it gets called by the manager backend.

Parameters:
s 
m 
Returns:
See also:
action_agents(), action_agent_logoff(), load_module().

Definition at line 2143 of file chan_agent.c.

References agent_pvt::ackcall, agent_pvt::agent, ast_device_state_changed(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_strlen_zero(), ast_true(), ast_verbose(), astman_get_header(), astman_send_ack(), astman_send_error(), agent_pvt::chan, context, dump_agents(), EVENT_FLAG_AGENT, exten, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::next, option_verbose, agent_pvt::pending, persistent_agents, VERBOSE_PREFIX_2, and agent_pvt::wrapuptime.

Referenced by load_module().

02144 {
02145    char *agent = astman_get_header(m, "Agent");
02146    char *exten = astman_get_header(m, "Exten");
02147    char *context = astman_get_header(m, "Context");
02148    char *wrapuptime_s = astman_get_header(m, "WrapupTime");
02149    char *ackcall_s = astman_get_header(m, "AckCall");
02150    struct agent_pvt *p;
02151    int login_state = 0;
02152 
02153    if (ast_strlen_zero(agent)) {
02154       astman_send_error(s, m, "No agent specified");
02155       return 0;
02156    }
02157 
02158    if (ast_strlen_zero(exten)) {
02159       astman_send_error(s, m, "No extension specified");
02160       return 0;
02161    }
02162 
02163    ast_mutex_lock(&agentlock);
02164    p = agents;
02165    while(p) {
02166       if (strcmp(p->agent, agent) || p->pending) {
02167          p = p->next;
02168          continue;
02169       }
02170       if (p->chan) {
02171          login_state = 2; /* already logged in (and on the phone)*/
02172          break;
02173       }
02174       ast_mutex_lock(&p->lock);
02175       login_state = 1; /* Successful Login */
02176       
02177       if (ast_strlen_zero(context))
02178          ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
02179       else
02180          snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
02181 
02182       if (!ast_strlen_zero(wrapuptime_s)) {
02183          p->wrapuptime = atoi(wrapuptime_s);
02184          if (p->wrapuptime < 0)
02185             p->wrapuptime = 0;
02186       }
02187 
02188       if (ast_true(ackcall_s))
02189          p->ackcall = 1;
02190       else
02191          p->ackcall = 0;
02192 
02193       if (p->loginstart == 0)
02194          time(&p->loginstart);
02195       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
02196                "Agent: %s\r\n"
02197                "Loginchan: %s\r\n",
02198                p->agent, p->loginchan);
02199       ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
02200       if (option_verbose > 1)
02201          ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
02202       ast_device_state_changed("Agent/%s", p->agent);
02203       ast_mutex_unlock(&p->lock);
02204       p = p->next;
02205       if (persistent_agents)
02206          dump_agents();
02207    }
02208    ast_mutex_unlock(&agentlock);
02209 
02210    if (login_state == 1)
02211       astman_send_ack(s, m, "Agent logged in");
02212    else if (login_state == 0)
02213       astman_send_error(s, m, "No such agent");
02214    else if (login_state == 2)
02215       astman_send_error(s, m, "Agent already logged in");
02216 
02217    return 0;
02218 }

static int action_agent_logoff struct mansession s,
struct message m
[static]
 

Sets an agent as no longer logged in in the Manager API. It is registered on load_module() and it gets called by the manager backend.

Parameters:
s 
m 
Returns:
See also:
action_agents(), action_agent_callback_login(), load_module().

Definition at line 1523 of file chan_agent.c.

References agent_pvt::agent, agent_logoff(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), and astman_send_error().

Referenced by load_module().

01524 {
01525    char *agent = astman_get_header(m, "Agent");
01526    char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01527    int soft;
01528    int ret; /* return value of agent_logoff */
01529 
01530    if (ast_strlen_zero(agent)) {
01531       astman_send_error(s, m, "No agent specified");
01532       return 0;
01533    }
01534 
01535    if (ast_true(soft_s))
01536       soft = 1;
01537    else
01538       soft = 0;
01539 
01540    ret = agent_logoff(agent, soft);
01541    if (ret == 0)
01542       astman_send_ack(s, m, "Agent logged out");
01543    else
01544       astman_send_error(s, m, "No such agent");
01545 
01546    return 0;
01547 }

static int action_agents struct mansession s,
struct message m
[static]
 

Lists agents and their status to the Manager API. It is registered on load_module() and it gets called by the manager backend.

Parameters:
s 
m 
Returns:
See also:
action_agent_logoff(), action_agent_callback_login(), load_module().

Definition at line 1381 of file chan_agent.c.

References ast_channel::_bridge, agent_pvt::acknowledged, agent_pvt::agent, ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), astman_get_header(), astman_send_ack(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_num, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, ast_channel::name, agent_pvt::name, agent_pvt::next, agent_pvt::owner, and username.

Referenced by load_module().

01382 {
01383    char *id = astman_get_header(m,"ActionID");
01384    char idText[256] = "";
01385    char chanbuf[256];
01386    struct agent_pvt *p;
01387    char *username = NULL;
01388    char *loginChan = NULL;
01389    char *talkingtoChan = NULL;
01390    char *status = NULL;
01391 
01392    if (!ast_strlen_zero(id))
01393       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
01394    astman_send_ack(s, m, "Agents will follow");
01395    ast_mutex_lock(&agentlock);
01396    p = agents;
01397    while(p) {
01398          ast_mutex_lock(&p->lock);
01399 
01400       /* Status Values:
01401          AGENT_LOGGEDOFF - Agent isn't logged in
01402          AGENT_IDLE      - Agent is logged in, and waiting for call
01403          AGENT_ONCALL    - Agent is logged in, and on a call
01404          AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
01405 
01406       if(!ast_strlen_zero(p->name)) {
01407          username = p->name;
01408       } else {
01409          username = "None";
01410       }
01411 
01412       /* Set a default status. It 'should' get changed. */
01413       status = "AGENT_UNKNOWN";
01414 
01415       if (!ast_strlen_zero(p->loginchan) && !p->chan) {
01416          loginChan = p->loginchan;
01417          talkingtoChan = "n/a";
01418          status = "AGENT_IDLE";
01419          if (p->acknowledged) {
01420             snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
01421             loginChan = chanbuf;
01422          }
01423       } else if (p->chan) {
01424          loginChan = ast_strdupa(p->chan->name);
01425          if (p->owner && p->owner->_bridge) {
01426                talkingtoChan = p->chan->cid.cid_num;
01427                status = "AGENT_ONCALL";
01428          } else {
01429                talkingtoChan = "n/a";
01430                status = "AGENT_IDLE";
01431          }
01432       } else {
01433          loginChan = "n/a";
01434          talkingtoChan = "n/a";
01435          status = "AGENT_LOGGEDOFF";
01436       }
01437 
01438       ast_cli(s->fd, "Event: Agents\r\n"
01439          "Agent: %s\r\n"
01440          "Name: %s\r\n"
01441          "Status: %s\r\n"
01442          "LoggedInChan: %s\r\n"
01443          "LoggedInTime: %d\r\n"
01444          "TalkingTo: %s\r\n"
01445          "%s"
01446          "\r\n",
01447          p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText);
01448       ast_mutex_unlock(&p->lock);
01449       p = p->next;
01450    }
01451    ast_mutex_unlock(&agentlock);
01452    ast_cli(s->fd, "Event: AgentsComplete\r\n"
01453       "%s"
01454       "\r\n",idText);
01455    return 0;
01456 }

static struct agent_pvt* add_agent char *  agent,
int  pending
[static]
 

Adds an agent to the global list of agents.

Parameters:
agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
pending If it is pending or not.
Returns:
The just created agent.
See also:
agent_pvt, agents.

Definition at line 312 of file chan_agent.c.

References ackcall, agent_pvt::ackcall, agent_pvt::agent, ast_app_separate_args(), ast_log(), ast_mutex_init(), ast_strdupa, autologoff, agent_pvt::autologoff, agent_pvt::dead, group, agent_pvt::lastdisc, LOG_WARNING, malloc, moh, agent_pvt::moh, agent_pvt::name, name, agent_pvt::next, agent_pvt::password, password, wrapuptime, and agent_pvt::wrapuptime.

Referenced by agent_request(), and read_agent_config().

00313 {
00314    int argc;
00315    char *argv[3];
00316    char *args;
00317    char *password = NULL;
00318    char *name = NULL;
00319    char *agt = NULL;
00320    struct agent_pvt *p, *prev;
00321 
00322    args = ast_strdupa(agent);
00323 
00324    // Extract username (agt), password and name from agent (args).
00325    if ((argc = ast_app_separate_args(args, ',', argv, sizeof(argv) / sizeof(argv[0])))) {
00326       agt = argv[0];
00327       if (argc > 1) {
00328          password = argv[1];
00329          while (*password && *password < 33) password++;
00330       } 
00331       if (argc > 2) {
00332          name = argv[2];
00333          while (*name && *name < 33) name++;
00334       }
00335    } else {
00336       ast_log(LOG_WARNING, "A blank agent line!\n");
00337    }
00338    
00339    // Are we searching for the agent here ? to see if it exists already ?
00340    prev=NULL;
00341    p = agents;
00342    while(p) {
00343       if (!pending && !strcmp(p->agent, agt))
00344          break;
00345       prev = p;
00346       p = p->next;
00347    }
00348    if (!p) {
00349       // Build the agent.
00350       p = malloc(sizeof(struct agent_pvt));
00351       if (p) {
00352          memset(p, 0, sizeof(struct agent_pvt));
00353          ast_copy_string(p->agent, agt, sizeof(p->agent));
00354          ast_mutex_init(&p->lock);
00355          ast_mutex_init(&p->app_lock);
00356          p->owning_app = (pthread_t) -1;
00357          p->app_sleep_cond = 1;
00358          p->group = group;
00359          p->pending = pending;
00360          p->next = NULL;
00361          if (prev)
00362             prev->next = p;
00363          else
00364             agents = p;
00365          
00366       } else {
00367          return NULL;
00368       }
00369    }
00370    
00371    ast_copy_string(p->password, password ? password : "", sizeof(p->password));
00372    ast_copy_string(p->name, name ? name : "", sizeof(p->name));
00373    ast_copy_string(p->moh, moh, sizeof(p->moh));
00374    p->ackcall = ackcall;
00375    p->autologoff = autologoff;
00376 
00377    /* If someone reduces the wrapuptime and reloads, we want it
00378     * to change the wrapuptime immediately on all calls */
00379    if (p->wrapuptime > wrapuptime) {
00380       struct timeval now = ast_tvnow();
00381       /* XXX check what is this exactly */
00382 
00383       /* We won't be pedantic and check the tv_usec val */
00384       if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
00385          p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
00386          p->lastdisc.tv_usec = now.tv_usec;
00387       }
00388    }
00389    p->wrapuptime = wrapuptime;
00390 
00391    if (pending)
00392       p->dead = 1;
00393    else
00394       p->dead = 0;
00395    return p;
00396 }

static int agent_ack_sleep void *  data  )  [static]
 

Definition at line 857 of file chan_agent.c.

References agent_pvt::app_sleep_cond, AST_FRAME_DTMF, ast_frfree(), ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_waitfor(), agent_pvt::chan, ast_frame::frametype, agent_pvt::lock, and ast_frame::subclass.

Referenced by __login_exec().

00858 {
00859    struct agent_pvt *p;
00860    int res=0;
00861    int to = 1000;
00862    struct ast_frame *f;
00863 
00864    /* Wait a second and look for something */
00865 
00866    p = (struct agent_pvt *)data;
00867    if (p->chan) {
00868       for(;;) {
00869          to = ast_waitfor(p->chan, to);
00870          if (to < 0) {
00871             res = -1;
00872             break;
00873          }
00874          if (!to) {
00875             res = 0;
00876             break;
00877          }
00878          f = ast_read(p->chan);
00879          if (!f) {
00880             res = -1;
00881             break;
00882          }
00883          if (f->frametype == AST_FRAME_DTMF)
00884             res = f->subclass;
00885          else
00886             res = 0;
00887          ast_frfree(f);
00888          ast_mutex_lock(&p->lock);
00889          if (!p->app_sleep_cond) {
00890             ast_mutex_unlock(&p->lock);
00891             res = 0;
00892             break;
00893          } else if (res == '#') {
00894             ast_mutex_unlock(&p->lock);
00895             res = 1;
00896             break;
00897          }
00898          ast_mutex_unlock(&p->lock);
00899          res = 0;
00900       }
00901    } else
00902       res = -1;
00903    return res;
00904 }

static int agent_answer struct ast_channel ast  )  [static]
 

Definition at line 424 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00425 {
00426    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00427    return -1;
00428 }

static struct ast_channel * agent_bridgedchannel struct ast_channel chan,
struct ast_channel bridge
[static]
 

Definition at line 906 of file chan_agent.c.

References ast_channel::_bridge, ast_log(), agent_pvt::chan, LOG_DEBUG, ast_channel::name, option_debug, and ast_channel::tech_pvt.

00907 {
00908    struct agent_pvt *p = bridge->tech_pvt;
00909    struct ast_channel *ret=NULL;
00910 
00911    if (p) {
00912       if (chan == p->chan)
00913          ret = bridge->_bridge;
00914       else if (chan == bridge->_bridge)
00915          ret = p->chan;
00916    }
00917 
00918    if (option_debug)
00919       ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
00920    return ret;
00921 }

static int agent_call struct ast_channel ast,
char *  dest,
int  timeout
[static]
 

Definition at line 639 of file chan_agent.c.

References agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_start_monitoring(), ast_best_codec(), ast_call(), ast_channel_inherit_variables(), ast_getformatname(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_callerid(), ast_set_read_format(), ast_set_write_format(), ast_setstate(), AST_STATE_DIALING, AST_STATE_RINGING, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), beep, agent_pvt::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CLEANUP, ast_channel::language, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::loginchan, ast_channel::name, ast_channel::nativeformats, option_verbose, agent_pvt::pending, recordagentcalls, agent_pvt::start, ast_channel::tech_pvt, and VERBOSE_PREFIX_3.

00640 {
00641    struct agent_pvt *p = ast->tech_pvt;
00642    int res = -1;
00643    int newstate=0;
00644    ast_mutex_lock(&p->lock);
00645    p->acknowledged = 0;
00646    if (!p->chan) {
00647       if (p->pending) {
00648          ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
00649          newstate = AST_STATE_DIALING;
00650          res = 0;
00651       } else {
00652          ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
00653          res = -1;
00654       }
00655       ast_mutex_unlock(&p->lock);
00656       if (newstate)
00657          ast_setstate(ast, newstate);
00658       return res;
00659    } else if (!ast_strlen_zero(p->loginchan)) {
00660       time(&p->start);
00661       /* Call on this agent */
00662       if (option_verbose > 2)
00663          ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
00664       ast_set_callerid(p->chan,
00665          ast->cid.cid_num, ast->cid.cid_name, NULL);
00666       ast_channel_inherit_variables(ast, p->chan);
00667       res = ast_call(p->chan, p->loginchan, 0);
00668       CLEANUP(ast,p);
00669       ast_mutex_unlock(&p->lock);
00670       return res;
00671    }
00672    ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
00673    ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
00674    res = ast_streamfile(p->chan, beep, p->chan->language);
00675    ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
00676    if (!res) {
00677       res = ast_waitstream(p->chan, "");
00678       ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
00679    }
00680    if (!res) {
00681       res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
00682       ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
00683       if (res)
00684          ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00685    } else {
00686       /* Agent hung-up */
00687       p->chan = NULL;
00688    }
00689 
00690    if (!res) {
00691       ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
00692       ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
00693       if (res)
00694          ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00695    }
00696    if( !res )
00697    {
00698       /* Call is immediately up, or might need ack */
00699       if (p->ackcall > 1)
00700          newstate = AST_STATE_RINGING;
00701       else {
00702          newstate = AST_STATE_UP;
00703          if (recordagentcalls)
00704             agent_start_monitoring(ast,0);
00705          p->acknowledged = 1;
00706       }
00707       res = 0;
00708    }
00709    CLEANUP(ast,p);
00710    ast_mutex_unlock(&p->lock);
00711    if (newstate)
00712       ast_setstate(ast, newstate);
00713    return res;
00714 }

static int agent_cleanup struct agent_pvt p  )  [static]
 

Deletes an agent after doing some clean up. Further documentation: How safe is this function ? What state should the agent be to be cleaned.

Parameters:
p Agent to be deleted.
Returns:
Always 0.

Definition at line 404 of file chan_agent.c.

References ast_channel_free(), ast_mutex_destroy(), ast_mutex_unlock(), free, and ast_channel::tech_pvt.

Referenced by check_availability().

00405 {
00406    struct ast_channel *chan = p->owner;
00407    p->owner = NULL;
00408    chan->tech_pvt = NULL;
00409    p->app_sleep_cond = 1;
00410    /* Release ownership of the agent to other threads (presumably running the login app). */
00411    ast_mutex_unlock(&p->app_lock);
00412    if (chan)
00413       ast_channel_free(chan);
00414    if (p->dead) {
00415       ast_mutex_destroy(&p->lock);
00416       ast_mutex_destroy(&p->app_lock);
00417       free(p);
00418         }
00419    return 0;
00420 }

static int agent_cont_sleep void *  data  )  [static]
 

Definition at line 836 of file chan_agent.c.

References agent_pvt::app_sleep_cond, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, and agent_pvt::wrapuptime.

Referenced by __login_exec().

00837 {
00838    struct agent_pvt *p;
00839    int res;
00840 
00841    p = (struct agent_pvt *)data;
00842 
00843    ast_mutex_lock(&p->lock);
00844    res = p->app_sleep_cond;
00845    if (p->lastdisc.tv_sec) {
00846       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) 
00847          res = 1;
00848    }
00849    ast_mutex_unlock(&p->lock);
00850 #if 0
00851    if( !res )
00852       ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
00853 #endif      
00854    return res;
00855 }

static int agent_devicestate void *  data  )  [static]
 

Definition at line 2366 of file chan_agent.c.

References agent_pvt::agent, AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), agent_pvt::chan, agent_pvt::group, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::next, agent_pvt::owner, agent_pvt::pending, and s.

02367 {
02368    struct agent_pvt *p;
02369    char *s;
02370    ast_group_t groupmatch;
02371    int groupoff;
02372    int waitforagent=0;
02373    int res = AST_DEVICE_INVALID;
02374    
02375    s = data;
02376    if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
02377       groupmatch = (1 << groupoff);
02378    } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
02379       groupmatch = (1 << groupoff);
02380       waitforagent = 1;
02381    } else {
02382       groupmatch = 0;
02383    }
02384 
02385    /* Check actual logged in agents first */
02386    ast_mutex_lock(&agentlock);
02387    p = agents;
02388    while(p) {
02389       ast_mutex_lock(&p->lock);
02390       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02391          if (p->owner) {
02392             if (res != AST_DEVICE_INUSE)
02393                res = AST_DEVICE_BUSY;
02394          } else {
02395             if (res == AST_DEVICE_BUSY)
02396                res = AST_DEVICE_INUSE;
02397             if (p->chan || !ast_strlen_zero(p->loginchan)) {
02398                if (res == AST_DEVICE_INVALID)
02399                   res = AST_DEVICE_UNKNOWN;
02400             } else if (res == AST_DEVICE_INVALID)  
02401                res = AST_DEVICE_UNAVAILABLE;
02402          }
02403          if (!strcmp(data, p->agent)) {
02404             ast_mutex_unlock(&p->lock);
02405             break;
02406          }
02407       }
02408       ast_mutex_unlock(&p->lock);
02409       p = p->next;
02410    }
02411    ast_mutex_unlock(&agentlock);
02412    return res;
02413 }

static int agent_digit struct ast_channel ast,
char  digit
[static]
 

Definition at line 626 of file chan_agent.c.

References ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::lock, ast_channel_tech::send_digit, ast_channel::tech, and ast_channel::tech_pvt.

00627 {
00628    struct agent_pvt *p = ast->tech_pvt;
00629    int res = -1;
00630    ast_mutex_lock(&p->lock);
00631    if (p->chan)
00632       res = p->chan->tech->send_digit(p->chan, digit);
00633    else
00634       res = 0;
00635    ast_mutex_unlock(&p->lock);
00636    return res;
00637 }

static int agent_fixup struct ast_channel oldchan,
struct ast_channel newchan
[static]
 

Definition at line 599 of file chan_agent.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::lock, LOG_WARNING, agent_pvt::owner, and ast_channel::tech_pvt.

00600 {
00601    struct agent_pvt *p = newchan->tech_pvt;
00602    ast_mutex_lock(&p->lock);
00603    if (p->owner != oldchan) {
00604       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00605       ast_mutex_unlock(&p->lock);
00606       return -1;
00607    }
00608    p->owner = newchan;
00609    ast_mutex_unlock(&p->lock);
00610    return 0;
00611 }

static int agent_hangup struct ast_channel ast  )  [static]
 

Definition at line 729 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::abouttograb, agent_pvt::acknowledged, agent_pvt::agent, agent_unlink(), agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_device_state_changed(), ast_hangup(), ast_log(), AST_MAX_AGENT, ast_moh_start(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_state2str(), AST_STATE_RESERVED, AST_STATE_UP, ast_strlen_zero(), ast_tvadd(), agent_pvt::autologoff, agent_pvt::chan, agent_pvt::dead, dump_agents(), EVENT_FLAG_AGENT, free, agent_pvt::lastdisc, ast_channel::lock, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, persistent_agents, set_agentbycallerid(), agent_pvt::start, ast_channel::tech_pvt, ast_channel::uniqueid, usecnt, usecnt_lock, and agent_pvt::wrapuptime.

00730 {
00731    struct agent_pvt *p = ast->tech_pvt;
00732    int howlong = 0;
00733    ast_mutex_lock(&p->lock);
00734    p->owner = NULL;
00735    ast->tech_pvt = NULL;
00736    p->app_sleep_cond = 1;
00737    p->acknowledged = 0;
00738 
00739    /* if they really are hung up then set start to 0 so the test
00740     * later if we're called on an already downed channel
00741     * doesn't cause an agent to be logged out like when
00742     * agent_request() is followed immediately by agent_hangup()
00743     * as in apps/app_chanisavail.c:chanavail_exec()
00744     */
00745 
00746    ast_mutex_lock(&usecnt_lock);
00747    usecnt--;
00748    ast_mutex_unlock(&usecnt_lock);
00749 
00750    ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
00751    if (p->start && (ast->_state != AST_STATE_UP)) {
00752       howlong = time(NULL) - p->start;
00753       p->start = 0;
00754    } else if (ast->_state == AST_STATE_RESERVED) {
00755       howlong = 0;
00756    } else
00757       p->start = 0; 
00758    if (p->chan) {
00759       p->chan->_bridge = NULL;
00760       /* If they're dead, go ahead and hang up on the agent now */
00761       if (!ast_strlen_zero(p->loginchan)) {
00762          /* Store last disconnect time */
00763          if (p->wrapuptime)
00764             p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00765          else
00766             p->lastdisc = ast_tv(0,0);
00767          if (p->chan) {
00768             /* Recognize the hangup and pass it along immediately */
00769             ast_hangup(p->chan);
00770             p->chan = NULL;
00771          }
00772          ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
00773          if (howlong  && p->autologoff && (howlong > p->autologoff)) {
00774             char agent[AST_MAX_AGENT] = "";
00775             long logintime = time(NULL) - p->loginstart;
00776             p->loginstart = 0;
00777             ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00778             manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
00779                      "Agent: %s\r\n"
00780                      "Loginchan: %s\r\n"
00781                      "Logintime: %ld\r\n"
00782                      "Reason: Autologoff\r\n"
00783                      "Uniqueid: %s\r\n",
00784                      p->agent, p->loginchan, logintime, ast->uniqueid);
00785             snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
00786             ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
00787             set_agentbycallerid(p->logincallerid, NULL);
00788             ast_device_state_changed("Agent/%s", p->agent);
00789             p->loginchan[0] = '\0';
00790             p->logincallerid[0] = '\0';
00791             if (persistent_agents)
00792                dump_agents();
00793          }
00794       } else if (p->dead) {
00795          ast_mutex_lock(&p->chan->lock);
00796          ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00797          ast_mutex_unlock(&p->chan->lock);
00798       } else if (p->loginstart) {
00799          ast_mutex_lock(&p->chan->lock);
00800          ast_moh_start(p->chan, p->moh);
00801          ast_mutex_unlock(&p->chan->lock);
00802       }
00803    }
00804    ast_mutex_unlock(&p->lock);
00805    /* Only register a device state change if the agent is still logged in */
00806    if (p->loginstart)
00807       ast_device_state_changed("Agent/%s", p->agent);
00808 
00809    if (p->pending) {
00810       ast_mutex_lock(&agentlock);
00811       agent_unlink(p);
00812       ast_mutex_unlock(&agentlock);
00813    }
00814    if (p->abouttograb) {
00815       /* Let the "about to grab" thread know this isn't valid anymore, and let it
00816          kill it later */
00817       p->abouttograb = 0;
00818    } else if (p->dead) {
00819       ast_mutex_destroy(&p->lock);
00820       ast_mutex_destroy(&p->app_lock);
00821       free(p);
00822    } else {
00823       if (p->chan) {
00824          /* Not dead -- check availability now */
00825          ast_mutex_lock(&p->lock);
00826          /* Store last disconnect time */
00827          p->lastdisc = ast_tvnow();
00828          ast_mutex_unlock(&p->lock);
00829       }
00830       /* Release ownership of the agent to other threads (presumably running the login app). */
00831       ast_mutex_unlock(&p->app_lock);
00832    }
00833    return 0;
00834 }

static int agent_indicate struct ast_channel ast,
int  condition
[static]
 

Definition at line 613 of file chan_agent.c.

References ast_indicate(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.

00614 {
00615    struct agent_pvt *p = ast->tech_pvt;
00616    int res = -1;
00617    ast_mutex_lock(&p->lock);
00618    if (p->chan)
00619       res = ast_indicate(p->chan, condition);
00620    else
00621       res = 0;
00622    ast_mutex_unlock(&p->lock);
00623    return res;
00624 }

static int agent_logoff char *  agent,
int  soft
[static]
 

Definition at line 1458 of file chan_agent.c.

References agent_pvt::agent, ast_device_state_changed(), ast_queue_log(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agent_pvt::chan, dump_agents(), EVENT_FLAG_AGENT, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::next, agent_pvt::owner, persistent_agents, and set_agentbycallerid().

Referenced by action_agent_logoff(), and agent_logoff_cmd().

01459 {
01460    struct agent_pvt *p;
01461    long logintime;
01462    int ret = -1; /* Return -1 if no agent if found */
01463 
01464    for (p=agents; p; p=p->next) {
01465       if (!strcasecmp(p->agent, agent)) {
01466          if (!soft) {
01467             if (p->owner) {
01468                ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01469             }
01470             if (p->chan) {
01471                ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01472             }
01473          }
01474          ret = 0; /* found an agent => return 0 */
01475          logintime = time(NULL) - p->loginstart;
01476          p->loginstart = 0;
01477          
01478          manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01479                   "Agent: %s\r\n"
01480                   "Loginchan: %s\r\n"
01481                   "Logintime: %ld\r\n",
01482                   p->agent, p->loginchan, logintime);
01483          ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
01484          set_agentbycallerid(p->logincallerid, NULL);
01485          p->loginchan[0] = '\0';
01486          p->logincallerid[0] = '\0';
01487          ast_device_state_changed("Agent/%s", p->agent);
01488          if (persistent_agents)
01489             dump_agents();
01490          break;
01491       }
01492    }
01493 
01494    return ret;
01495 }

static int agent_logoff_cmd int  fd,
int  argc,
char **  argv
[static]
 

Definition at line 1497 of file chan_agent.c.

References agent_pvt::agent, agent_logoff(), ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01498 {
01499    int ret;
01500    char *agent;
01501 
01502    if (argc < 3 || argc > 4)
01503       return RESULT_SHOWUSAGE;
01504    if (argc == 4 && strcasecmp(argv[3], "soft"))
01505       return RESULT_SHOWUSAGE;
01506 
01507    agent = argv[2] + 6;
01508    ret = agent_logoff(agent, argc == 4);
01509    if (ret == 0)
01510       ast_cli(fd, "Logging out %s\n", agent);
01511 
01512    return RESULT_SUCCESS;
01513 }

static struct ast_channel* agent_new struct agent_pvt p,
int  state
[static]
 

Definition at line 924 of file chan_agent.c.

References agent_pvt::agent, agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_channel_alloc(), ast_channel_free(), AST_FLAG_BLOCKING, AST_FORMAT_SLINEAR, AST_FRAME_NULL, ast_log(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_queue_frame(), ast_setstate(), ast_test_flag, ast_update_use_count(), agent_pvt::chan, channeltype, ast_channel::context, CRASH, ast_channel::exten, ast_channel::language, agent_pvt::lock, LOG_ERROR, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, agent_pvt::owner, agent_pvt::owning_app, agent_pvt::pending, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::tech, ast_channel::tech_pvt, ast_channel::type, usecnt, usecnt_lock, and ast_channel::writeformat.

Referenced by agent_request(), and check_availability().

00925 {
00926    struct ast_channel *tmp;
00927    struct ast_frame null_frame = { AST_FRAME_NULL };
00928 #if 0
00929    if (!p->chan) {
00930       ast_log(LOG_WARNING, "No channel? :(\n");
00931       return NULL;
00932    }
00933 #endif   
00934    tmp = ast_channel_alloc(0);
00935    if (tmp) {
00936       tmp->tech = &agent_tech;
00937       if (p->chan) {
00938          tmp->nativeformats = p->chan->nativeformats;
00939          tmp->writeformat = p->chan->writeformat;
00940          tmp->rawwriteformat = p->chan->writeformat;
00941          tmp->readformat = p->chan->readformat;
00942          tmp->rawreadformat = p->chan->readformat;
00943          ast_copy_string(tmp->language, p->chan->language, sizeof(tmp->language));
00944          ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
00945          ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
00946       } else {
00947          tmp->nativeformats = AST_FORMAT_SLINEAR;
00948          tmp->writeformat = AST_FORMAT_SLINEAR;
00949          tmp->rawwriteformat = AST_FORMAT_SLINEAR;
00950          tmp->readformat = AST_FORMAT_SLINEAR;
00951          tmp->rawreadformat = AST_FORMAT_SLINEAR;
00952       }
00953       if (p->pending)
00954          snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
00955       else
00956          snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
00957       tmp->type = channeltype;
00958       /* Safe, agentlock already held */
00959       ast_setstate(tmp, state);
00960       tmp->tech_pvt = p;
00961       p->owner = tmp;
00962       ast_mutex_lock(&usecnt_lock);
00963       usecnt++;
00964       ast_mutex_unlock(&usecnt_lock);
00965       ast_update_use_count();
00966       tmp->priority = 1;
00967       /* Wake up and wait for other applications (by definition the login app)
00968        * to release this channel). Takes ownership of the agent channel
00969        * to this thread only.
00970        * For signalling the other thread, ast_queue_frame is used until we
00971        * can safely use signals for this purpose. The pselect() needs to be
00972        * implemented in the kernel for this.
00973        */
00974       p->app_sleep_cond = 0;
00975       if( ast_mutex_trylock(&p->app_lock) )
00976       {
00977          if (p->chan) {
00978             ast_queue_frame(p->chan, &null_frame);
00979             ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
00980             ast_mutex_lock(&p->app_lock);
00981             ast_mutex_lock(&p->lock);
00982          }
00983          if( !p->chan )
00984          {
00985             ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
00986             p->owner = NULL;
00987             tmp->tech_pvt = NULL;
00988             p->app_sleep_cond = 1;
00989             ast_channel_free( tmp );
00990             ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
00991             ast_mutex_unlock(&p->app_lock);
00992             return NULL;
00993          }
00994       }
00995       p->owning_app = pthread_self();
00996       /* After the above step, there should not be any blockers. */
00997       if (p->chan) {
00998          if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
00999             ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
01000             CRASH;
01001          }
01002          ast_moh_stop(p->chan);
01003       }
01004    } else
01005       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
01006    return tmp;
01007 }

static struct ast_frame * agent_read struct ast_channel ast  )  [static]
 

Definition at line 463 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_start_monitoring(), AST_CONTROL_ANSWER, ast_copy_flags, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_NULL, AST_FRAME_VOICE, ast_frfree(), ast_hangup(), ast_log(), AST_MAX_FDS, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), AST_STATE_UP, ast_strlen_zero(), ast_tvadd(), ast_verbose(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, ast_channel::fdno, ast_frame::frametype, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, agent_pvt::loginchan, ast_channel::name, option_verbose, recordagentcalls, ast_frame::subclass, ast_channel::tech_pvt, ast_channel::type, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

00464 {
00465    struct agent_pvt *p = ast->tech_pvt;
00466    struct ast_frame *f = NULL;
00467    static struct ast_frame null_frame = { AST_FRAME_NULL, };
00468    static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00469    ast_mutex_lock(&p->lock); 
00470    CHECK_FORMATS(ast, p);
00471    if (p->chan) {
00472       ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
00473       if (ast->fdno == AST_MAX_FDS - 3)
00474          p->chan->fdno = AST_MAX_FDS - 2;
00475       else
00476          p->chan->fdno = ast->fdno;
00477       f = ast_read(p->chan);
00478    } else
00479       f = &null_frame;
00480    if (!f) {
00481       /* If there's a channel, hang it up (if it's on a callback) make it NULL */
00482       if (p->chan) {
00483          p->chan->_bridge = NULL;
00484          /* Note that we don't hangup if it's not a callback because Asterisk will do it
00485             for us when the PBX instance that called login finishes */
00486          if (!ast_strlen_zero(p->loginchan)) {
00487             if (p->chan)
00488                ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
00489             ast_hangup(p->chan);
00490             if (p->wrapuptime && p->acknowledged)
00491                p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00492          }
00493          p->chan = NULL;
00494          p->acknowledged = 0;
00495       }
00496    } else {
00497       /* if acknowledgement is not required, and the channel is up, we may have missed
00498          an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
00499       if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP))
00500          p->acknowledged = 1;
00501       switch (f->frametype) {
00502       case AST_FRAME_CONTROL:
00503          if (f->subclass == AST_CONTROL_ANSWER) {
00504             if (p->ackcall) {
00505                if (option_verbose > 2)
00506                   ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
00507                /* Don't pass answer along */
00508                ast_frfree(f);
00509                f = &null_frame;
00510             } else {
00511                p->acknowledged = 1;
00512                /* Use the builtin answer frame for the 
00513                   recording start check below. */
00514                ast_frfree(f);
00515                f = &answer_frame;
00516             }
00517          }
00518          break;
00519       case AST_FRAME_DTMF:
00520          if (!p->acknowledged && (f->subclass == '#')) {
00521             if (option_verbose > 2)
00522                ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
00523             p->acknowledged = 1;
00524             ast_frfree(f);
00525             f = &answer_frame;
00526          } else if (f->subclass == '*') {
00527             /* terminates call */
00528             ast_frfree(f);
00529             f = NULL;
00530          }
00531          break;
00532       case AST_FRAME_VOICE:
00533          /* don't pass voice until the call is acknowledged */
00534          if (!p->acknowledged) {
00535             ast_frfree(f);
00536             f = &null_frame;
00537          }
00538          break;
00539       }
00540    }
00541 
00542    CLEANUP(ast,p);
00543    if (p->chan && !p->chan->_bridge) {
00544       if (strcasecmp(p->chan->type, "Local")) {
00545          p->chan->_bridge = ast;
00546          if (p->chan)
00547             ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
00548       }
00549    }
00550    ast_mutex_unlock(&p->lock);
00551    if (recordagentcalls && f == &answer_frame)
00552       agent_start_monitoring(ast,0);
00553    return f;
00554 }

static struct ast_channel * agent_request const char *  type,
int  format,
void *  data,
int *  cause
[static]
 

Definition at line 1262 of file chan_agent.c.

References add_agent(), agent_pvt::agent, agent_new(), AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_request(), AST_STATE_DOWN, ast_strlen_zero(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::loginchan, agent_pvt::next, option_debug, agent_pvt::owner, agent_pvt::pending, and s.

01263 {
01264    struct agent_pvt *p;
01265    struct ast_channel *chan = NULL;
01266    char *s;
01267    ast_group_t groupmatch;
01268    int groupoff;
01269    int waitforagent=0;
01270    int hasagent = 0;
01271    struct timeval tv;
01272 
01273    s = data;
01274    if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
01275       groupmatch = (1 << groupoff);
01276    } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
01277       groupmatch = (1 << groupoff);
01278       waitforagent = 1;
01279    } else {
01280       groupmatch = 0;
01281    }
01282 
01283    /* Check actual logged in agents first */
01284    ast_mutex_lock(&agentlock);
01285    p = agents;
01286    while(p) {
01287       ast_mutex_lock(&p->lock);
01288       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
01289           ast_strlen_zero(p->loginchan)) {
01290          if (p->chan)
01291             hasagent++;
01292          if (!p->lastdisc.tv_sec) {
01293             /* Agent must be registered, but not have any active call, and not be in a waiting state */
01294             if (!p->owner && p->chan) {
01295                /* Fixed agent */
01296                chan = agent_new(p, AST_STATE_DOWN);
01297             }
01298             if (chan) {
01299                ast_mutex_unlock(&p->lock);
01300                break;
01301             }
01302          }
01303       }
01304       ast_mutex_unlock(&p->lock);
01305       p = p->next;
01306    }
01307    if (!p) {
01308       p = agents;
01309       while(p) {
01310          ast_mutex_lock(&p->lock);
01311          if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01312             if (p->chan || !ast_strlen_zero(p->loginchan))
01313                hasagent++;
01314             tv = ast_tvnow();
01315 #if 0
01316             ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
01317 #endif
01318             if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
01319                p->lastdisc = ast_tv(0, 0);
01320                /* Agent must be registered, but not have any active call, and not be in a waiting state */
01321                if (!p->owner && p->chan) {
01322                   /* Could still get a fixed agent */
01323                   chan = agent_new(p, AST_STATE_DOWN);
01324                } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
01325                   /* Adjustable agent */
01326                   p->chan = ast_request("Local", format, p->loginchan, cause);
01327                   if (p->chan)
01328                      chan = agent_new(p, AST_STATE_DOWN);
01329                }
01330                if (chan) {
01331                   ast_mutex_unlock(&p->lock);
01332                   break;
01333                }
01334             }
01335          }
01336          ast_mutex_unlock(&p->lock);
01337          p = p->next;
01338       }
01339    }
01340 
01341    if (!chan && waitforagent) {
01342       /* No agent available -- but we're requesting to wait for one.
01343          Allocate a place holder */
01344       if (hasagent) {
01345          if (option_debug)
01346             ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
01347          p = add_agent(data, 1);
01348          p->group = groupmatch;
01349          chan = agent_new(p, AST_STATE_DOWN);
01350          if (!chan) {
01351             ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
01352          }
01353       } else
01354          ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
01355    }
01356    if (hasagent)
01357       *cause = AST_CAUSE_BUSY;
01358    else
01359       *cause = AST_CAUSE_UNREGISTERED;
01360    ast_mutex_unlock(&agentlock);
01361    return chan;
01362 }

static int agent_sendhtml struct ast_channel ast,
int  subclass,
const char *  data,
int  datalen
[static]
 

Definition at line 556 of file chan_agent.c.

References ast_channel_sendhtml(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.

00557 {
00558    struct agent_pvt *p = ast->tech_pvt;
00559    int res = -1;
00560    ast_mutex_lock(&p->lock);
00561    if (p->chan) 
00562       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00563    ast_mutex_unlock(&p->lock);
00564    return res;
00565 }

static int agent_sendtext struct ast_channel ast,
const char *  text
[static]
 

Definition at line 567 of file chan_agent.c.

References ast_mutex_lock(), ast_mutex_unlock(), ast_sendtext(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.

00568 {
00569    struct agent_pvt *p = ast->tech_pvt;
00570    int res = -1;
00571    ast_mutex_lock(&p->lock);
00572    if (p->chan) 
00573       res = ast_sendtext(p->chan, text);
00574    ast_mutex_unlock(&p->lock);
00575    return res;
00576 }

static int agent_start_monitoring struct ast_channel ast,
int  needlock
[static]
 

Definition at line 458 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00459 {
00460    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00461 }

static void agent_unlink struct agent_pvt agent  )  [static]
 

Unlink (that is, take outside of the linked list) an agent.

Parameters:
agent Agent to be unlinked.

Definition at line 281 of file chan_agent.c.

References agent_pvt::next.

Referenced by agent_hangup().

00282 {
00283    struct agent_pvt *p, *prev;
00284    prev = NULL;
00285    p = agents;
00286    // Iterate over all agents looking for the one.
00287    while(p) {
00288       if (p == agent) {
00289          // Once it wal found, check if it is the first one.
00290          if (prev)
00291             // If it is not, tell the previous agent that the next one is the next one of the current (jumping the current).
00292             prev->next = agent->next;
00293          else
00294             // If it is the first one, just change the general pointer to point to the second one.
00295             agents = agent->next;
00296          // We are done.
00297          break;
00298       }
00299       prev = p;
00300       p = p->next;
00301    }
00302 }

static int agent_write struct ast_channel ast,
struct ast_frame f
[static]
 

Definition at line 578 of file chan_agent.c.

References AST_FRAME_VOICE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_write(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, ast_frame::frametype, agent_pvt::lock, LOG_DEBUG, ast_channel::name, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.

00579 {
00580    struct agent_pvt *p = ast->tech_pvt;
00581    int res = -1;
00582    CHECK_FORMATS(ast, p);
00583    ast_mutex_lock(&p->lock);
00584    if (p->chan) {
00585       if ((f->frametype != AST_FRAME_VOICE) ||
00586           (f->subclass == p->chan->writeformat)) {
00587          res = ast_write(p->chan, f);
00588       } else {
00589          ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
00590          res = 0;
00591       }
00592    } else
00593       res = 0;
00594    CLEANUP(ast, p);
00595    ast_mutex_unlock(&p->lock);
00596    return res;
00597 }

static int agentmonitoroutgoing_exec struct ast_channel chan,
void *  data
[static]
 

Called by the AgentMonitorOutgoing application (from the dial plan).

Parameters:
chan 
data 
Returns:
See also:
login_exec(), callback_login_exec(), load_module().

Definition at line 2228 of file chan_agent.c.

References __agent_start_monitoring(), agent_pvt::agent, ast_exists_extension(), ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, GETAGENTBYCALLERID, LOG_WARNING, agent_pvt::next, option_verbose, pbx_builtin_getvar_helper(), and VERBOSE_PREFIX_3.

Referenced by load_module().

02229 {
02230    int exitifnoagentid = 0;
02231    int nowarnings = 0;
02232    int changeoutgoing = 0;
02233    int res = 0;
02234    char agent[AST_MAX_AGENT], *tmp;
02235 
02236    if (data) {
02237       if (strchr(data, 'd'))
02238          exitifnoagentid = 1;
02239       if (strchr(data, 'n'))
02240          nowarnings = 1;
02241       if (strchr(data, 'c'))
02242          changeoutgoing = 1;
02243    }
02244    if (chan->cid.cid_num) {
02245       char agentvar[AST_MAX_BUF];
02246       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02247       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02248          struct agent_pvt *p = agents;
02249          ast_copy_string(agent, tmp, sizeof(agent));
02250          ast_mutex_lock(&agentlock);
02251          while (p) {
02252             if (!strcasecmp(p->agent, tmp)) {
02253                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02254                __agent_start_monitoring(chan, p, 1);
02255                break;
02256             }
02257             p = p->next;
02258          }
02259          ast_mutex_unlock(&agentlock);
02260          
02261       } else {
02262          res = -1;
02263          if (!nowarnings)
02264             ast_log(LOG_WARNING, "Couldn't find the global variable %s, so I can't figure out which agent (if it's an agent) is placing outgoing call.\n", agentvar);
02265       }
02266    } else {
02267       res = -1;
02268       if (!nowarnings)
02269          ast_log(LOG_WARNING, "There is no callerid on that call, so I can't figure out which agent (if it's an agent) is placing outgoing call.\n");
02270    }
02271    /* check if there is n + 101 priority */
02272    if (res) {
02273       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
02274          chan->priority+=100;
02275          if (option_verbose > 2)
02276             ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
02277       }
02278       else if (exitifnoagentid)
02279          return res;
02280    }
02281    return 0;
02282 }

static int agents_show int  fd,
int  argc,
char **  argv
[static]
 

Show agents in cli.

Definition at line 1573 of file chan_agent.c.

References agent_pvt::acknowledged, agent_pvt::agent, ast_bridged_channel(), ast_cli(), AST_MAX_BUF, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), agent_pvt::chan, config, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, moh, ast_channel::name, agent_pvt::name, agent_pvt::next, agent_pvt::owner, agent_pvt::pending, powerof(), RESULT_SHOWUSAGE, RESULT_SUCCESS, and username.

01574 {
01575    struct agent_pvt *p;
01576    char username[AST_MAX_BUF];
01577    char location[AST_MAX_BUF] = "";
01578    char talkingto[AST_MAX_BUF] = "";
01579    char moh[AST_MAX_BUF];
01580    int count_agents = 0;      /* Number of agents configured */
01581    int online_agents = 0;     /* Number of online agents */
01582    int offline_agents = 0;    /* Number of offline agents */
01583    if (argc != 2)
01584       return RESULT_SHOWUSAGE;
01585    ast_mutex_lock(&agentlock);
01586    p = agents;
01587    while(p) {
01588       ast_mutex_lock(&p->lock);
01589       if (p->pending) {
01590          if (p->group)
01591             ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
01592          else
01593             ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
01594       } else {
01595          if (!ast_strlen_zero(p->name))
01596             snprintf(username, sizeof(username), "(%s) ", p->name);
01597          else
01598             username[0] = '\0';
01599          if (p->chan) {
01600             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01601             if (p->owner && ast_bridged_channel(p->owner)) {
01602                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01603             } else {
01604                strcpy(talkingto, " is idle");
01605             }
01606             online_agents++;
01607          } else if (!ast_strlen_zero(p->loginchan)) {
01608             if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
01609                snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01610             else 
01611                snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
01612             talkingto[0] = '\0';
01613             online_agents++;
01614             if (p->acknowledged)
01615                strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01616          } else {
01617             strcpy(location, "not logged in");
01618             talkingto[0] = '\0';
01619             offline_agents++;
01620          }
01621          if (!ast_strlen_zero(p->moh))
01622             snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01623          ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
01624             username, location, talkingto, moh);
01625          count_agents++;
01626       }
01627       ast_mutex_unlock(&p->lock);
01628       p = p->next;
01629    }
01630    ast_mutex_unlock(&agentlock);
01631    if ( !count_agents ) {
01632       ast_cli(fd, "No Agents are configured in %s\n",config);
01633    } else {
01634       ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01635    }
01636    ast_cli(fd, "\n");
01637                    
01638    return RESULT_SUCCESS;
01639 }

AST_MUTEX_DEFINE_STATIC agentlock   ) 
 

AST_MUTEX_DEFINE_STATIC usecnt_lock   ) 
 

static int callback_exec struct ast_channel chan,
void *  data
[static]
 

Called by the AgentCallbackLogin application (from the dial plan).

Parameters:
chan 
data 
Returns:
See also:
login_exec(), agentmonitoroutgoing_exec(), load_module().

Definition at line 2130 of file chan_agent.c.

References __login_exec().

Referenced by load_module().

02131 {
02132    return __login_exec(chan, data, 1);
02133 }

static int check_availability struct agent_pvt newlyavailable,
int  needlock
[static]
 

Definition at line 1142 of file chan_agent.c.

References agent_pvt::abouttograb, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_cleanup(), agent_new(), ast_channel_masquerade(), AST_FLAG_ZOMBIE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_waitstream(), beep, agent_pvt::chan, ast_channel::context, agent_pvt::group, ast_channel::language, agent_pvt::lock, LOG_DEBUG, ast_channel::name, agent_pvt::next, option_debug, agent_pvt::owner, and agent_pvt::pending.

Referenced by __login_exec().

01143 {
01144    struct ast_channel *chan=NULL, *parent=NULL;
01145    struct agent_pvt *p;
01146    int res;
01147 
01148    if (option_debug)
01149       ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
01150    if (needlock)
01151       ast_mutex_lock(&agentlock);
01152    p = agents;
01153    while(p) {
01154       if (p == newlyavailable) {
01155          p = p->next;
01156          continue;
01157       }
01158       ast_mutex_lock(&p->lock);
01159       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01160          if (option_debug)
01161             ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01162          /* We found a pending call, time to merge */
01163          chan = agent_new(newlyavailable, AST_STATE_DOWN);
01164          parent = p->owner;
01165          p->abouttograb = 1;
01166          ast_mutex_unlock(&p->lock);
01167          break;
01168       }
01169       ast_mutex_unlock(&p->lock);
01170       p = p->next;
01171    }
01172    if (needlock)
01173       ast_mutex_unlock(&agentlock);
01174    if (parent && chan)  {
01175       if (newlyavailable->ackcall > 1) {
01176          /* Don't do beep here */
01177          res = 0;
01178       } else {
01179          if (option_debug > 2)
01180             ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01181          res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01182          if (option_debug > 2)
01183             ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
01184          if (!res) {
01185             res = ast_waitstream(newlyavailable->chan, "");
01186             ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
01187          }
01188       }
01189       if (!res) {
01190          /* Note -- parent may have disappeared */
01191          if (p->abouttograb) {
01192             newlyavailable->acknowledged = 1;
01193             /* Safe -- agent lock already held */
01194             ast_setstate(parent, AST_STATE_UP);
01195             ast_setstate(chan, AST_STATE_UP);
01196             ast_copy_string(parent->context, chan->context, sizeof(parent->context));
01197             /* Go ahead and mark the channel as a zombie so that masquerade will
01198                destroy it for us, and we need not call ast_hangup */
01199             ast_mutex_lock(&parent->lock);
01200             ast_set_flag(chan, AST_FLAG_ZOMBIE);
01201             ast_channel_masquerade(parent, chan);
01202             ast_mutex_unlock(&parent->lock);
01203             p->abouttograb = 0;
01204          } else {
01205             if (option_debug)
01206                ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
01207             agent_cleanup(newlyavailable);
01208          }
01209       } else {
01210          if (option_debug)
01211             ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
01212          agent_cleanup(newlyavailable);
01213       }
01214    }
01215    return 0;
01216 }

static int check_beep struct agent_pvt newlyavailable,
int  needlock
[static]
 

Definition at line 1218 of file chan_agent.c.

References agent_pvt::abouttograb, agent_pvt::agent, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_streamfile(), ast_waitstream(), beep, agent_pvt::chan, agent_pvt::group, ast_channel::language, agent_pvt::lock, LOG_DEBUG, ast_channel::name, agent_pvt::next, option_debug, agent_pvt::owner, and agent_pvt::pending.

Referenced by __login_exec().

01219 {
01220    struct agent_pvt *p;
01221    int res=0;
01222 
01223    ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
01224    if (needlock)
01225       ast_mutex_lock(&agentlock);
01226    p = agents;
01227    while(p) {
01228       if (p == newlyavailable) {
01229          p = p->next;
01230          continue;
01231       }
01232       ast_mutex_lock(&p->lock);
01233       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01234          if (option_debug)
01235             ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01236          ast_mutex_unlock(&p->lock);
01237          break;
01238       }
01239       ast_mutex_unlock(&p->lock);
01240       p = p->next;
01241    }
01242    if (needlock)
01243       ast_mutex_unlock(&agentlock);
01244    if (p) {
01245       ast_mutex_unlock(&newlyavailable->lock);
01246       if (option_debug > 2)
01247          ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01248       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01249       if (option_debug > 2)
01250          ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
01251       if (!res) {
01252          res = ast_waitstream(newlyavailable->chan, "");
01253          if (option_debug)
01254             ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
01255       }
01256       ast_mutex_lock(&newlyavailable->lock);
01257    }
01258    return res;
01259 }

static char* complete_agent_logoff_cmd char *  line,
char *  word,
int  pos,
int  state
[static]
 

Definition at line 1549 of file chan_agent.c.

References agent_pvt::agent, AST_MAX_AGENT, name, agent_pvt::next, and strdup.

01550 {
01551    struct agent_pvt *p;
01552    char name[AST_MAX_AGENT];
01553    int which = 0;
01554 
01555    if (pos == 2) {
01556       for (p=agents; p; p=p->next) {
01557          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01558          if (!strncasecmp(word, name, strlen(word))) {
01559             if (++which > state) {
01560                return strdup(name);
01561             }
01562          }
01563       }
01564    } else if (pos == 3 && state == 0) {
01565       return strdup("soft");
01566    }
01567    return NULL;
01568 }

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 2498 of file chan_agent.c.

References desc.

02499 {
02500    return (char *) desc;
02501 }

static void dump_agents void   )  [static]
 

Dump AgentCallbackLogin agents to the database for persistence

Definition at line 2287 of file chan_agent.c.

References agent_pvt::agent, ast_db_del(), ast_db_put(), ast_log(), ast_strlen_zero(), agent_pvt::chan, LOG_DEBUG, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::next, option_debug, and pa_family.

Referenced by __login_exec(), action_agent_callback_login(), agent_hangup(), and agent_logoff().

02288 {
02289    struct agent_pvt *cur_agent = NULL;
02290    char buf[256];
02291 
02292    for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
02293       if (cur_agent->chan)
02294          continue;
02295 
02296       if (!ast_strlen_zero(cur_agent->loginchan)) {
02297          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02298          if (ast_db_put(pa_family, cur_agent->agent, buf))
02299             ast_log(LOG_WARNING, "failed to create persistent entry!\n");
02300          else if (option_debug)
02301             ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02302       } else {
02303          /* Delete -  no agent or there is an error */
02304          ast_db_del(pa_family, cur_agent->agent);
02305       }
02306    }
02307 }

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;
 }

Returns:
ASTERISK_GPL_KEY

Definition at line 2493 of file chan_agent.c.

References ASTERISK_GPL_KEY.

02494 {
02495    return ASTERISK_GPL_KEY;
02496 }

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.

Returns:
int Always 0.

Definition at line 2421 of file chan_agent.c.

References action_agent_callback_login(), action_agent_logoff(), action_agents(), agentmonitoroutgoing_exec(), app, app2, app3, ast_channel_register(), ast_cli_register(), ast_log(), ast_manager_register2(), ast_register_application(), callback_exec(), channeltype, descrip, descrip2, descrip3, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), mandescr_agent_callback_login, mandescr_agent_logoff, mandescr_agents, persistent_agents, read_agent_config(), reload_agents(), synopsis, synopsis2, and synopsis3.

02422 {
02423    /* Make sure we can register our agent channel type */
02424    if (ast_channel_register(&agent_tech)) {
02425       ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
02426       return -1;
02427    }
02428    /* Dialplan applications */
02429    ast_register_application(app, login_exec, synopsis, descrip);
02430    ast_register_application(app2, callback_exec, synopsis2, descrip2);
02431    ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
02432    /* Manager commands */
02433    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02434    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02435    ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
02436    /* CLI Application */
02437    ast_cli_register(&cli_show_agents);
02438    ast_cli_register(&cli_agent_logoff);
02439    /* Read in the config */
02440    read_agent_config();
02441    if (persistent_agents)
02442       reload_agents();
02443    return 0;
02444 }

static int login_exec struct ast_channel chan,
void *  data
[static]
 

Called by the AgentLogin application (from the dial plan).

Parameters:
chan 
data 
Returns:
See also:
callback_login_exec(), agentmonitoroutgoing_exec(), load_module().

Definition at line 2117 of file chan_agent.c.

References __login_exec().

Referenced by load_module().

02118 {
02119    return __login_exec(chan, data, 0);
02120 }

static int powerof unsigned int  v  )  [static]
 

Definition at line 1364 of file chan_agent.c.

01365 {
01366    int x;
01367    for (x=0;x<32;x++) {
01368       if (v & (1 << x)) return x;
01369    }
01370    return 0;
01371 }

static int read_agent_config void   )  [static]
 

Read configuration data. The file named agents.conf.

Returns:
Always 0, or so it seems.

Definition at line 1015 of file chan_agent.c.

References ackcall, add_agent(), agentgoodbye, agent_pvt::app_lock, ast_config_destroy(), ast_config_load(), ast_get_group(), ast_log(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), autologoff, beep, cfg, agent_pvt::chan, config, createlink, agent_pvt::dead, free, group, agent_pvt::lock, LOG_NOTICE, maxlogintries, moh, ast_variable::name, ast_variable::next, agent_pvt::next, agent_pvt::owner, persistent_agents, recordagentcalls, recordformat, recordformatext, savecallsin, updatecdr, urlprefix, ast_variable::value, and wrapuptime.

Referenced by load_module(), and reload().

01016 {
01017    struct ast_config *cfg;
01018    struct ast_variable *v;
01019    struct agent_pvt *p, *pl, *pn;
01020    char *general_val;
01021 
01022    group = 0;
01023    autologoff = 0;
01024    wrapuptime = 0;
01025    ackcall = 0;
01026    cfg = ast_config_load(config);
01027    if (!cfg) {
01028       ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
01029       return 0;
01030    }
01031    ast_mutex_lock(&agentlock);
01032    p = agents;
01033    while(p) {
01034       p->dead = 1;
01035       p = p->next;
01036    }
01037    strcpy(moh, "default");
01038    /* set the default recording values */
01039    recordagentcalls = 0;
01040    createlink = 0;
01041    strcpy(recordformat, "wav");
01042    strcpy(recordformatext, "wav");
01043    urlprefix[0] = '\0';
01044    savecallsin[0] = '\0';
01045 
01046    /* Read in [general] section for persistence */
01047    if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
01048       persistent_agents = ast_true(general_val);
01049 
01050    /* Read in the [agents] section */
01051    v = ast_variable_browse(cfg, "agents");
01052    while(v) {
01053       /* Create the interface list */
01054       if (!strcasecmp(v->name, "agent")) {
01055          add_agent(v->value, 0);
01056       } else if (!strcasecmp(v->name, "group")) {
01057          group = ast_get_group(v->value);
01058       } else if (!strcasecmp(v->name, "autologoff")) {
01059          autologoff = atoi(v->value);
01060          if (autologoff < 0)
01061             autologoff = 0;
01062       } else if (!strcasecmp(v->name, "ackcall")) {
01063          if (!strcasecmp(v->value, "always"))
01064             ackcall = 2;
01065          else if (ast_true(v->value))
01066             ackcall = 1;
01067          else
01068             ackcall = 0;
01069       } else if (!strcasecmp(v->name, "wrapuptime")) {
01070          wrapuptime = atoi(v->value);
01071          if (wrapuptime < 0)
01072             wrapuptime = 0;
01073       } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
01074          maxlogintries = atoi(v->value);
01075          if (maxlogintries < 0)
01076             maxlogintries = 0;
01077       } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
01078          strcpy(agentgoodbye,v->value);
01079       } else if (!strcasecmp(v->name, "musiconhold")) {
01080          ast_copy_string(moh, v->value, sizeof(moh));
01081       } else if (!strcasecmp(v->name, "updatecdr")) {
01082          if (ast_true(v->value))
01083             updatecdr = 1;
01084          else
01085             updatecdr = 0;
01086       } else if (!strcasecmp(v->name, "recordagentcalls")) {
01087          recordagentcalls = ast_true(v->value);
01088       } else if (!strcasecmp(v->name, "createlink")) {
01089          createlink = ast_true(v->value);
01090       } else if (!strcasecmp(v->name, "recordformat")) {
01091          ast_copy_string(recordformat, v->value, sizeof(recordformat));
01092          if (!strcasecmp(v->value, "wav49"))
01093             strcpy(recordformatext, "WAV");
01094          else
01095             ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
01096       } else if (!strcasecmp(v->name, "urlprefix")) {
01097          ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
01098          if (urlprefix[strlen(urlprefix) - 1] != '/')
01099             strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
01100       } else if (!strcasecmp(v->name, "savecallsin")) {
01101          if (v->value[0] == '/')
01102             ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
01103          else
01104             snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
01105          if (savecallsin[strlen(savecallsin) - 1] != '/')
01106             strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
01107       } else if (!strcasecmp(v->name, "custom_beep")) {
01108          ast_copy_string(beep, v->value, sizeof(beep));
01109       }
01110       v = v->next;
01111    }
01112    p = agents;
01113    pl = NULL;
01114    while(p) {
01115       pn = p->next;
01116       if (p->dead) {
01117          /* Unlink */
01118          if (pl)
01119             pl->next = p->next;
01120          else
01121             agents = p->next;
01122          /* Destroy if  appropriate */
01123          if (!p->owner) {
01124             if (!p->chan) {
01125                ast_mutex_destroy(&p->lock);
01126                ast_mutex_destroy(&p->app_lock);
01127                free(p);
01128             } else {
01129                /* Cause them to hang up */
01130                ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01131             }
01132          }
01133       } else
01134          pl = p;
01135       p = pn;
01136    }
01137    ast_mutex_unlock(&agentlock);
01138    ast_config_destroy(cfg);
01139    return 0;
01140 }

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.

Returns:
The return value is not used.

Definition at line 2446 of file chan_agent.c.

References persistent_agents, read_agent_config(), and reload_agents().

02447 {
02448    read_agent_config();
02449    if (persistent_agents)
02450       reload_agents();
02451    return 0;
02452 }

static void reload_agents void   )  [static]
 

Reload the persistent agents from astdb.

Definition at line 2312 of file chan_agent.c.

References agent_pvt::agent, ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), ast_device_state_changed(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_db_entry::key, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::next, ast_db_entry::next, option_debug, pa_family, parse(), set_agentbycallerid(), and strsep().

Referenced by load_module(), and reload().

02313 {
02314    char *agent_num;
02315    struct ast_db_entry *db_tree;
02316    struct ast_db_entry *entry;
02317    struct agent_pvt *cur_agent;
02318    char agent_data[256];
02319    char *parse;
02320    char *agent_chan;
02321    char *agent_callerid;
02322 
02323    db_tree = ast_db_gettree(pa_family, NULL);
02324 
02325    ast_mutex_lock(&agentlock);
02326    for (entry = db_tree; entry; entry = entry->next) {
02327       agent_num = entry->key + strlen(pa_family) + 2;
02328       cur_agent = agents;
02329       while (cur_agent) {
02330          ast_mutex_lock(&cur_agent->lock);
02331          if (strcmp(agent_num, cur_agent->agent) == 0)
02332             break;
02333          ast_mutex_unlock(&cur_agent->lock);
02334          cur_agent = cur_agent->next;
02335       }
02336       if (!cur_agent) {
02337          ast_db_del(pa_family, agent_num);
02338          continue;
02339       } else
02340          ast_mutex_unlock(&cur_agent->lock);
02341       if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
02342          if (option_debug)
02343             ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
02344          parse = agent_data;
02345          agent_chan = strsep(&parse, ";");
02346          agent_callerid = strsep(&parse, ";");
02347          ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
02348          if (agent_callerid) {
02349             ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
02350             set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
02351          } else
02352             cur_agent->logincallerid[0] = '\0';
02353          if (cur_agent->loginstart == 0)
02354             time(&cur_agent->loginstart);
02355          ast_device_state_changed("Agent/%s", cur_agent->agent);  
02356       }
02357    }
02358    ast_mutex_unlock(&agentlock);
02359    if (db_tree) {
02360       ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
02361       ast_db_freetree(db_tree);
02362    }
02363 }

static void set_agentbycallerid const char *  callerid,
const char *  agent
[static]
 

Definition at line 717 of file chan_agent.c.

References AST_MAX_BUF, ast_strlen_zero(), GETAGENTBYCALLERID, and pbx_builtin_setvar_helper().

Referenced by __login_exec(), agent_hangup(), agent_logoff(), and reload_agents().

00718 {
00719    char buf[AST_MAX_BUF];
00720 
00721    /* if there is no Caller ID, nothing to do */
00722    if (ast_strlen_zero(callerid))
00723       return;
00724 
00725    snprintf(buf, sizeof(buf), "%s_%s",GETAGENTBYCALLERID, callerid);
00726    pbx_builtin_setvar_helper(NULL, buf, agent);
00727 }

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

Returns:
Zero on success, or non-zero on error.

Definition at line 2454 of file chan_agent.c.

References app, app2, app3, ast_channel_unregister(), ast_cli_unregister(), ast_log(), ast_manager_unregister(), ast_mutex_lock(), ast_mutex_unlock(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_unregister_application(), LOG_WARNING, agent_pvt::next, and agent_pvt::owner.

02455 {
02456    struct agent_pvt *p;
02457    /* First, take us out of the channel loop */
02458    /* Unregister CLI application */
02459    ast_cli_unregister(&cli_show_agents);
02460    ast_cli_unregister(&cli_agent_logoff);
02461    /* Unregister dialplan applications */
02462    ast_unregister_application(app);
02463    ast_unregister_application(app2);
02464    ast_unregister_application(app3);
02465    /* Unregister manager command */
02466    ast_manager_unregister("Agents");
02467    ast_manager_unregister("AgentLogoff");
02468    ast_manager_unregister("AgentCallbackLogin");
02469    /* Unregister channel */
02470    ast_channel_unregister(&agent_tech);
02471    if (!ast_mutex_lock(&agentlock)) {
02472       /* Hangup all interfaces if they have an owner */
02473       p = agents;
02474       while(p) {
02475          if (p->owner)
02476             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02477          p = p->next;
02478       }
02479       agents = NULL;
02480       ast_mutex_unlock(&agentlock);
02481    } else {
02482       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
02483       return -1;
02484    }     
02485    return 0;
02486 }

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.

Returns:
The module's usecount.

Definition at line 2488 of file chan_agent.c.

References usecnt.

02489 {
02490    return usecnt;
02491 }


Variable Documentation

int ackcall [static]
 

Definition at line 156 of file chan_agent.c.

Referenced by add_agent(), and read_agent_config().

char agent_logoff_usage[] [static]
 

Initial value:

"Usage: agent logoff <channel> [soft]\n"
"       Sets an agent as no longer logged in.\n"
"       If 'soft' is specified, do not hangup existing calls.\n"

Definition at line 1645 of file chan_agent.c.

const struct ast_channel_tech agent_tech [static]
 

Definition at line 256 of file chan_agent.c.

char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye" [static]
 

Definition at line 159 of file chan_agent.c.

Referenced by __login_exec(), and read_agent_config().

struct agent_pvt* agents = NULL [static]
 

Holds the list of agents (loaded form agents.conf).

Definition at line 208 of file chan_agent.c.

const char app[] = "AgentLogin" [static]
 

Definition at line 77 of file chan_agent.c.

Referenced by __build_step(), action_originate(), app_exec(), conf_run(), dial_exec_full(), exec_exec(), execif_exec(), feature_exec_app(), fillin_process(), handle_context_add_extension(), handle_exec(), load_config(), load_module(), page_exec(), pbx_extension_helper(), realtime_exec(), and unload_module().

const char app2[] = "AgentCallbackLogin" [static]
 

Definition at line 78 of file chan_agent.c.

Referenced by load_module(), and unload_module().

const char app3[] = "AgentMonitorOutgoing" [static]
 

Definition at line 79 of file chan_agent.c.

Referenced by load_module(), and unload_module().

int autologoff [static]
 

Definition at line 154 of file chan_agent.c.

Referenced by add_agent(), and read_agent_config().

char beep[AST_MAX_BUF] = "beep" [static]
 

Definition at line 174 of file chan_agent.c.

Referenced by agent_call(), check_availability(), check_beep(), and read_agent_config().

const char channeltype[] = "Agent" [static]
 

Definition at line 73 of file chan_agent.c.

Referenced by agent_new(), ast_iax2_new(), func_header_read(), function_sipchaninfo_read(), iax2_bridge(), iax2_prov_app(), load_module(), register_peer_exten(), reload_config(), set_config(), sip_dtmfmode(), sip_getheader(), and sip_new().

struct ast_cli_entry cli_agent_logoff [static]
 

Initial value:

 {
   { "agent", "logoff", NULL }, agent_logoff_cmd, 
   "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd }

Definition at line 1654 of file chan_agent.c.

struct ast_cli_entry cli_show_agents [static]
 

Initial value:

 {
   { "show", "agents", NULL }, agents_show, 
   "Show status of agents", show_agents_usage, NULL }

Definition at line 1650 of file chan_agent.c.

const char config[] = "agents.conf" [static]
 

Definition at line 75 of file chan_agent.c.

int createlink = 0 [static]
 

Definition at line 170 of file chan_agent.c.

Referenced by read_agent_config().

const char desc[] = "Agent Proxy Channel" [static]
 

Definition at line 72 of file chan_agent.c.

Referenced by description(), load_module(), odbc_load_module(), process_my_load_module(), and tds_load_module().

const char descrip[] [static]
 

Definition at line 85 of file chan_agent.c.

Referenced by load_module().

const char descrip2[] [static]
 

Definition at line 94 of file chan_agent.c.

Referenced by load_module().

const char descrip3[] [static]
 

Definition at line 102 of file chan_agent.c.

Referenced by load_module().

ast_group_t group [static]
 

Definition at line 153 of file chan_agent.c.

Referenced by add_agent(), ast_app_group_set_channel(), ast_get_group(), ast_makesocket(), chanspy_exec(), get_group(), group_count_exec(), group_count_function_read(), group_function_read(), group_match_count_exec(), group_match_count_function_read(), load_module(), main(), misdn_request(), modem_request(), read_agent_config(), and vpb_request().

LOCAL_USER_DECL
 

Definition at line 1659 of file chan_agent.c.

const char mandescr_agent_callback_login[] [static]
 

Definition at line 130 of file chan_agent.c.

Referenced by load_module().

const char mandescr_agent_logoff[] [static]
 

Initial value:

"Description: Sets an agent as no longer logged in.\n"
"Variables: (Names marked with * are required)\n"
"  *Agent: Agent ID of the agent to log off\n"
"  Soft: Set to 'true' to not hangup existing calls\n"

Definition at line 124 of file chan_agent.c.

Referenced by load_module().

const char mandescr_agents[] [static]
 

Initial value:

"Description: Will list info about all possible agents.\n"
"Variables: NONE\n"

Definition at line 120 of file chan_agent.c.

Referenced by load_module().

int maxlogintries = 3 [static]
 

Definition at line 158 of file chan_agent.c.

Referenced by __login_exec(), and read_agent_config().

char moh[80] = "default" [static]
 

Definition at line 139 of file chan_agent.c.

Referenced by add_agent(), agents_show(), ast_moh_destroy(), dial_exec_full(), get_mohbyname(), init_classes(), moh_generate(), moh_release(), mohalloc(), monmp3thread(), and read_agent_config().

const char pa_family[] = "/Agents" [static]
 

Persistent Agents astdb family

Definition at line 146 of file chan_agent.c.

Referenced by dump_agents(), and reload_agents().

int persistent_agents = 0 [static]
 

queues.conf [general] option

Definition at line 150 of file chan_agent.c.

Referenced by __login_exec(), action_agent_callback_login(), agent_hangup(), agent_logoff(), load_module(), read_agent_config(), and reload().

int recordagentcalls = 0 [static]
 

Definition at line 167 of file chan_agent.c.

Referenced by agent_call(), agent_read(), and read_agent_config().

char recordformat[AST_MAX_BUF] = "" [static]
 

Definition at line 168 of file chan_agent.c.

Referenced by __agent_start_monitoring(), and read_agent_config().

char recordformatext[AST_MAX_BUF] = "" [static]
 

Definition at line 169 of file chan_agent.c.

Referenced by __agent_start_monitoring(), and read_agent_config().

char savecallsin[AST_MAX_BUF] = "" [static]
 

Definition at line 172 of file chan_agent.c.

Referenced by __agent_start_monitoring(), and read_agent_config().

char show_agents_usage[] [static]
 

Initial value:

 
"Usage: show agents\n"
"       Provides summary information on agents.\n"

Definition at line 1641 of file chan_agent.c.

STANDARD_LOCAL_USER
 

Definition at line 1658 of file chan_agent.c.

const char synopsis[] = "Call agent login" [static]
 

Definition at line 81 of file chan_agent.c.

Referenced by description(), function_enum(), handle_show_application(), handle_show_function(), load_module(), and load_pbx().

const char synopsis2[] = "Call agent callback login" [static]
 

Definition at line 82 of file chan_agent.c.

Referenced by load_module().

const char synopsis3[] = "Record agent's outgoing call" [static]
 

Definition at line 83 of file chan_agent.c.

Referenced by load_module().

const char tdesc[] = "Call Agent Proxy Channel" [static]
 

Definition at line 74 of file chan_agent.c.

Referenced by description(), load_module(), and rpt_tele_thread().

int updatecdr = 0 [static]
 

Definition at line 173 of file chan_agent.c.

Referenced by __login_exec(), and read_agent_config().

char urlprefix[AST_MAX_BUF] = "" [static]
 

Definition at line 171 of file chan_agent.c.

Referenced by __agent_start_monitoring(), read_agent_config(), and start_monitor_exec().

int usecnt = 0 [static]
 

Definition at line 161 of file chan_agent.c.

Referenced by __oh323_new(), agent_hangup(), agent_new(), alsa_hangup(), alsa_new(), aopen_decusecnt(), aopen_incusecnt(), ast_iax2_new(), ast_modem_new(), bestdata_decusecnt(), bestdata_incusecnt(), features_new(), i4l_decusecnt(), i4l_incusecnt(), iax2_predestroy(), local_hangup(), local_new(), mgcp_hangup(), mgcp_new(), modem_hangup(), nbs_new(), oh323_hangup(), oss_hangup(), oss_new(), phone_check_exception(), phone_hangup(), phone_new(), sip_hangup(), sip_new(), skinny_new(), usecount(), zt_hangup(), and zt_new().

int wrapuptime [static]
 

Definition at line 155 of file chan_agent.c.

Referenced by add_agent(), and read_agent_config().


Generated on Sun Aug 6 15:05:46 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2