Thu May 24 14:21:49 2007

Asterisk developer's documentation


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.

Data Structures

struct  agent_pvt

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 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, and ast_channel::uniqueid.

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 1681 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, agents, 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, ast_channel::cdr, agent_pvt::chan, localuser::chan, ast_cdr::channel, check_availability(), check_beep(), ast_channel::cid, ast_callerid::cid_num, context, agent_pvt::dead, dump_agents(), EVENT_FLAG_AGENT, free, ast_channel::language, 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(), 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().

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

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 2156 of file chan_agent.c.

References agent_pvt::ackcall, agent_pvt::agent, agents, 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, s, VERBOSE_PREFIX_2, and agent_pvt::wrapuptime.

Referenced by load_module().

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

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 1536 of file chan_agent.c.

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

Referenced by load_module().

01537 {
01538    char *agent = astman_get_header(m, "Agent");
01539    char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01540    int soft;
01541    int ret; /* return value of agent_logoff */
01542 
01543    if (ast_strlen_zero(agent)) {
01544       astman_send_error(s, m, "No agent specified");
01545       return 0;
01546    }
01547 
01548    if (ast_true(soft_s))
01549       soft = 1;
01550    else
01551       soft = 0;
01552 
01553    ret = agent_logoff(agent, soft);
01554    if (ret == 0)
01555       astman_send_ack(s, m, "Agent logged out");
01556    else
01557       astman_send_error(s, m, "No such agent");
01558 
01559    return 0;
01560 }

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 1394 of file chan_agent.c.

References ast_channel::_bridge, agent_pvt::acknowledged, agent_pvt::agent, agents, 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, s, and username.

Referenced by load_module().

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

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 agent_pvt::ackcall, agent_pvt::agent, agents, ast_app_separate_args(), ast_log(), ast_mutex_init(), ast_strdupa, agent_pvt::autologoff, agent_pvt::dead, agent_pvt::lastdisc, LOG_WARNING, malloc, agent_pvt::moh, agent_pvt::name, name, agent_pvt::next, agent_pvt::password, password, 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 858 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().

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

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

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

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(), 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, 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 agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_channel_free(), ast_mutex_destroy(), ast_mutex_unlock(), agent_pvt::dead, free, agent_pvt::lock, agent_pvt::owner, 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 837 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().

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

static int agent_devicestate ( void *  data  )  [static]

Definition at line 2379 of file chan_agent.c.

References agent_pvt::agent, agents, 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.

02380 {
02381    struct agent_pvt *p;
02382    char *s;
02383    ast_group_t groupmatch;
02384    int groupoff;
02385    int waitforagent=0;
02386    int res = AST_DEVICE_INVALID;
02387    
02388    s = data;
02389    if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
02390       groupmatch = (1 << groupoff);
02391    } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
02392       groupmatch = (1 << groupoff);
02393       waitforagent = 1;
02394    } else {
02395       groupmatch = 0;
02396    }
02397 
02398    /* Check actual logged in agents first */
02399    ast_mutex_lock(&agentlock);
02400    p = agents;
02401    while(p) {
02402       ast_mutex_lock(&p->lock);
02403       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02404          if (p->owner) {
02405             if (res != AST_DEVICE_INUSE)
02406                res = AST_DEVICE_BUSY;
02407          } else {
02408             if (res == AST_DEVICE_BUSY)
02409                res = AST_DEVICE_INUSE;
02410             if (p->chan || !ast_strlen_zero(p->loginchan)) {
02411                if (res == AST_DEVICE_INVALID)
02412                   res = AST_DEVICE_UNKNOWN;
02413             } else if (res == AST_DEVICE_INVALID)  
02414                res = AST_DEVICE_UNAVAILABLE;
02415          }
02416          if (!strcmp(data, p->agent)) {
02417             ast_mutex_unlock(&p->lock);
02418             break;
02419          }
02420       }
02421       ast_mutex_unlock(&p->lock);
02422       p = p->next;
02423    }
02424    ast_mutex_unlock(&agentlock);
02425    return res;
02426 }

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, set_agentbycallerid(), agent_pvt::start, ast_channel::tech_pvt, ast_channel::uniqueid, 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       if (ast_strlen_zero(p->loginchan))
00832          ast_mutex_unlock(&p->app_lock);
00833    }
00834    return 0;
00835 }

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 1471 of file chan_agent.c.

References agent_pvt::agent, agents, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agent_pvt::chan, agent_pvt::next, and agent_pvt::owner.

Referenced by action_agent_logoff(), and agent_logoff_cmd().

01472 {
01473    struct agent_pvt *p;
01474    long logintime;
01475    int ret = -1; /* Return -1 if no agent if found */
01476 
01477    for (p=agents; p; p=p->next) {
01478       if (!strcasecmp(p->agent, agent)) {
01479          if (!soft) {
01480             if (p->owner) {
01481                ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01482             }
01483             if (p->chan) {
01484                ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01485             }
01486          }
01487          ret = 0; /* found an agent => return 0 */
01488          logintime = time(NULL) - p->loginstart;
01489          p->loginstart = 0;
01490          
01491          manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01492                   "Agent: %s\r\n"
01493                   "Loginchan: %s\r\n"
01494                   "Logintime: %ld\r\n",
01495                   p->agent, p->loginchan, logintime);
01496          ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
01497          set_agentbycallerid(p->logincallerid, NULL);
01498          p->loginchan[0] = '\0';
01499          p->logincallerid[0] = '\0';
01500          ast_device_state_changed("Agent/%s", p->agent);
01501          if (persistent_agents)
01502             dump_agents();
01503          break;
01504       }
01505    }
01506 
01507    return ret;
01508 }

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

Definition at line 1510 of file chan_agent.c.

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

01511 {
01512    int ret;
01513    char *agent;
01514 
01515    if (argc < 3 || argc > 4)
01516       return RESULT_SHOWUSAGE;
01517    if (argc == 4 && strcasecmp(argv[3], "soft"))
01518       return RESULT_SHOWUSAGE;
01519 
01520    agent = argv[2] + 6;
01521    ret = agent_logoff(agent, argc == 4);
01522    if (ret == 0)
01523       ast_cli(fd, "Logging out %s\n", agent);
01524 
01525    return RESULT_SUCCESS;
01526 }

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

Definition at line 925 of file chan_agent.c.

References agent_pvt::agent, agent_tech, 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_strlen_zero(), ast_test_flag, ast_update_use_count(), agent_pvt::chan, ast_channel::context, CRASH, ast_channel::exten, ast_channel::language, agent_pvt::lock, LOG_ERROR, LOG_WARNING, agent_pvt::loginchan, 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_lock, and ast_channel::writeformat.

Referenced by agent_request(), and check_availability().

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

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, 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 1275 of file chan_agent.c.

References add_agent(), agent_pvt::agent, agent_new(), agents, 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.

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

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::agent, agents, and 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 2241 of file chan_agent.c.

References __agent_start_monitoring(), agent_pvt::agent, agents, ast_exists_extension(), ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), ast_channel::cdr, agent_pvt::chan, 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().

02242 {
02243    int exitifnoagentid = 0;
02244    int nowarnings = 0;
02245    int changeoutgoing = 0;
02246    int res = 0;
02247    char agent[AST_MAX_AGENT], *tmp;
02248 
02249    if (data) {
02250       if (strchr(data, 'd'))
02251          exitifnoagentid = 1;
02252       if (strchr(data, 'n'))
02253          nowarnings = 1;
02254       if (strchr(data, 'c'))
02255          changeoutgoing = 1;
02256    }
02257    if (chan->cid.cid_num) {
02258       char agentvar[AST_MAX_BUF];
02259       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02260       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02261          struct agent_pvt *p = agents;
02262          ast_copy_string(agent, tmp, sizeof(agent));
02263          ast_mutex_lock(&agentlock);
02264          while (p) {
02265             if (!strcasecmp(p->agent, tmp)) {
02266                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02267                __agent_start_monitoring(chan, p, 1);
02268                break;
02269             }
02270             p = p->next;
02271          }
02272          ast_mutex_unlock(&agentlock);
02273          
02274       } else {
02275          res = -1;
02276          if (!nowarnings)
02277             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);
02278       }
02279    } else {
02280       res = -1;
02281       if (!nowarnings)
02282          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");
02283    }
02284    /* check if there is n + 101 priority */
02285    if (res) {
02286       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
02287          chan->priority+=100;
02288          if (option_verbose > 2)
02289             ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
02290       }
02291       else if (exitifnoagentid)
02292          return res;
02293    }
02294    return 0;
02295 }

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

Show agents in cli.

Definition at line 1586 of file chan_agent.c.

References agent_pvt::acknowledged, agent_pvt::agent, agents, 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.

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

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 2143 of file chan_agent.c.

References __login_exec(), and localuser::chan.

Referenced by load_module().

02144 {
02145    return __login_exec(chan, data, 1);
02146 }

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

Definition at line 1155 of file chan_agent.c.

References agent_pvt::abouttograb, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_cleanup(), agent_new(), agents, 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(), 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().

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

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

Definition at line 1231 of file chan_agent.c.

References agent_pvt::abouttograb, agent_pvt::agent, agents, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_streamfile(), ast_waitstream(), 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().

01232 {
01233    struct agent_pvt *p;
01234    int res=0;
01235 
01236    ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
01237    if (needlock)
01238       ast_mutex_lock(&agentlock);
01239    p = agents;
01240    while(p) {
01241       if (p == newlyavailable) {
01242          p = p->next;
01243          continue;
01244       }
01245       ast_mutex_lock(&p->lock);
01246       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01247          if (option_debug)
01248             ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01249          ast_mutex_unlock(&p->lock);
01250          break;
01251       }
01252       ast_mutex_unlock(&p->lock);
01253       p = p->next;
01254    }
01255    if (needlock)
01256       ast_mutex_unlock(&agentlock);
01257    if (p) {
01258       ast_mutex_unlock(&newlyavailable->lock);
01259       if (option_debug > 2)
01260          ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01261       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01262       if (option_debug > 2)
01263          ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
01264       if (!res) {
01265          res = ast_waitstream(newlyavailable->chan, "");
01266          if (option_debug)
01267             ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
01268       }
01269       ast_mutex_lock(&newlyavailable->lock);
01270    }
01271    return res;
01272 }

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

Definition at line 1562 of file chan_agent.c.

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

01563 {
01564    struct agent_pvt *p;
01565    char name[AST_MAX_AGENT];
01566    int which = 0;
01567 
01568    if (pos == 2) {
01569       for (p=agents; p; p=p->next) {
01570          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01571          if (!strncasecmp(word, name, strlen(word))) {
01572             if (++which > state) {
01573                return strdup(name);
01574             }
01575          }
01576       }
01577    } else if (pos == 3 && state == 0) {
01578       return strdup("soft");
01579    }
01580    return NULL;
01581 }

char* description ( void   ) 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 2511 of file chan_agent.c.

References desc.

02512 {
02513    return (char *) desc;
02514 }

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the database for persistence

Definition at line 2300 of file chan_agent.c.

References agent_pvt::agent, agents, 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(), and agent_hangup().

02301 {
02302    struct agent_pvt *cur_agent = NULL;
02303    char buf[256];
02304 
02305    for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
02306       if (cur_agent->chan)
02307          continue;
02308 
02309       if (!ast_strlen_zero(cur_agent->loginchan)) {
02310          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02311          if (ast_db_put(pa_family, cur_agent->agent, buf))
02312             ast_log(LOG_WARNING, "failed to create persistent entry!\n");
02313          else if (option_debug)
02314             ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02315       } else {
02316          /* Delete -  no agent or there is an error */
02317          ast_db_del(pa_family, cur_agent->agent);
02318       }
02319    }
02320 }

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 2506 of file chan_agent.c.

References ASTERISK_GPL_KEY.

02507 {
02508    return ASTERISK_GPL_KEY;
02509 }

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 2434 of file chan_agent.c.

References action_agent_callback_login(), action_agent_logoff(), action_agents(), agent_tech, agentmonitoroutgoing_exec(), app, app2, app3, ast_channel_register(), ast_cli_register(), ast_log(), ast_manager_register2(), ast_register_application(), callback_exec(), channeltype, cli_agent_logoff, cli_show_agents, 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.

02435 {
02436    /* Make sure we can register our agent channel type */
02437    if (ast_channel_register(&agent_tech)) {
02438       ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
02439       return -1;
02440    }
02441    /* Dialplan applications */
02442    ast_register_application(app, login_exec, synopsis, descrip);
02443    ast_register_application(app2, callback_exec, synopsis2, descrip2);
02444    ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
02445    /* Manager commands */
02446    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02447    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02448    ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
02449    /* CLI Application */
02450    ast_cli_register(&cli_show_agents);
02451    ast_cli_register(&cli_agent_logoff);
02452    /* Read in the config */
02453    read_agent_config();
02454    if (persistent_agents)
02455       reload_agents();
02456    return 0;
02457 }

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 2130 of file chan_agent.c.

References __login_exec(), and localuser::chan.

Referenced by load_module().

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

static int powerof ( unsigned int  v  )  [static]

Definition at line 1377 of file chan_agent.c.

01378 {
01379    int x;
01380    for (x=0;x<32;x++) {
01381       if (v & (1 << x)) return x;
01382    }
01383    return 0;
01384 }

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 1028 of file chan_agent.c.

References add_agent(), agents, 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(), cfg, agent_pvt::chan, agent_pvt::dead, free, agent_pvt::lock, LOG_NOTICE, ast_variable::name, ast_variable::next, agent_pvt::next, agent_pvt::owner, and ast_variable::value.

Referenced by load_module(), and reload().

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

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 2459 of file chan_agent.c.

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

02460 {
02461    read_agent_config();
02462    if (persistent_agents)
02463       reload_agents();
02464    return 0;
02465 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

Definition at line 2325 of file chan_agent.c.

References agent_pvt::agent, agents, 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().

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

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(), 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 2467 of file chan_agent.c.

References agent_tech, agents, 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(), cli_agent_logoff, cli_show_agents, LOG_WARNING, agent_pvt::next, and agent_pvt::owner.

02468 {
02469    struct agent_pvt *p;
02470    /* First, take us out of the channel loop */
02471    /* Unregister CLI application */
02472    ast_cli_unregister(&cli_show_agents);
02473    ast_cli_unregister(&cli_agent_logoff);
02474    /* Unregister dialplan applications */
02475    ast_unregister_application(app);
02476    ast_unregister_application(app2);
02477    ast_unregister_application(app3);
02478    /* Unregister manager command */
02479    ast_manager_unregister("Agents");
02480    ast_manager_unregister("AgentLogoff");
02481    ast_manager_unregister("AgentCallbackLogin");
02482    /* Unregister channel */
02483    ast_channel_unregister(&agent_tech);
02484    if (!ast_mutex_lock(&agentlock)) {
02485       /* Hangup all interfaces if they have an owner */
02486       p = agents;
02487       while(p) {
02488          if (p->owner)
02489             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02490          p = p->next;
02491       }
02492       agents = NULL;
02493       ast_mutex_unlock(&agentlock);
02494    } else {
02495       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
02496       return -1;
02497    }     
02498    return 0;
02499 }

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 2501 of file chan_agent.c.

References usecnt.

02502 {
02503    return usecnt;
02504 }


Variable Documentation

int ackcall [static]

Definition at line 156 of file chan_agent.c.

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 1658 of file chan_agent.c.

struct ast_channel_tech agent_tech [static]

Definition at line 256 of file chan_agent.c.

Referenced by agent_new(), load_module(), and unload_module().

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

Definition at line 159 of file chan_agent.c.

Referenced by __login_exec().

struct agent_pvt* agents = NULL [static]

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

Definition at line 208 of file chan_agent.c.

Referenced by __login_exec(), action_agent_callback_login(), action_agents(), add_agent(), agent_devicestate(), agent_logoff(), agent_request(), agent_unlink(), agentmonitoroutgoing_exec(), agents_show(), check_availability(), check_beep(), complete_agent_logoff_cmd(), dump_agents(), read_agent_config(), reload_agents(), and unload_module().

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

Definition at line 77 of file chan_agent.c.

Referenced by __build_step(), action_originate(), ast_pbx_run_app(), async_wait(), conf_run(), dial_exec_full(), exec_exec(), execif_exec(), feature_exec_app(), fillin_process(), forward_message(), handle_context_add_extension(), handle_exec(), load_config(), load_module(), page_exec(), pbx_builtin_execiftime(), pbx_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.

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

Definition at line 174 of file chan_agent.c.

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

Definition at line 73 of file chan_agent.c.

Referenced by func_header_read(), function_sipchaninfo_read(), load_module(), reload_config(), sip_dtmfmode(), and sip_getheader().

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 1667 of file chan_agent.c.

Referenced by load_module(), and unload_module().

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 1663 of file chan_agent.c.

Referenced by load_module(), and unload_module().

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.

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

Definition at line 72 of file chan_agent.c.

Referenced by ast_cause2str(), ast_codec2str(), and description().

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 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(), and vpb_request().

LOCAL_USER_DECL

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

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

Definition at line 139 of file chan_agent.c.

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

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(), load_module(), and reload().

int recordagentcalls = 0 [static]

Definition at line 167 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 168 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 169 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

Definition at line 172 of file chan_agent.c.

char show_agents_usage[] [static]

Initial value:

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

Definition at line 1654 of file chan_agent.c.

STANDARD_LOCAL_USER

Definition at line 1671 of file chan_agent.c.

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

Definition at line 81 of file chan_agent.c.

Referenced by 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().

int updatecdr = 0 [static]

Definition at line 173 of file chan_agent.c.

Referenced by __login_exec().

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 171 of file chan_agent.c.

Referenced by start_monitor_exec().

int usecnt = 0 [static]

Definition at line 161 of file chan_agent.c.

Referenced by mgcp_hangup(), mgcp_new(), and usecount().

int wrapuptime [static]

Definition at line 155 of file chan_agent.c.


Generated on Thu May 24 14:21:49 2007 for Asterisk - the Open Source PBX by  doxygen 1.4.7