Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:03 2007

Asterisk developer's documentation :: Codename Pineapple


chan_agent.c File Reference


Detailed Description

Implementation of Agents (proxy channel).

Author:
Mark Spencer <markster@digium.com>
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.

#include "asterisk.h"
#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/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 "asterisk/stringfields.h"

Include dependency graph for chan_agent.c:

Go to the source code of this file.

Data Structures

struct  agent_pvt
 Structure representing an agent. More...

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)
 Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX.
#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_logoff (struct mansession *s, const struct message *m)
static int action_agents (struct mansession *s, const 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)
 Part of PBX channel interface.
static int agent_digit_begin (struct ast_channel *ast, char digit)
static int agent_digit_end (struct ast_channel *ast, char digit, unsigned int duration)
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, const void *data, size_t datalen)
static int agent_logoff (const char *agent, int soft)
static int agent_logoff_cmd (int fd, int argc, char **argv)
static void agent_logoff_maintenance (struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand)
static struct ast_channelagent_new (struct agent_pvt *p, int state)
 Create new agent channel.
static struct ast_frameagent_read (struct ast_channel *ast)
static struct ast_channelagent_request (const char *type, int format, void *data, int *cause)
 Part of the Asterisk PBX interface.
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 int agent_write (struct ast_channel *ast, struct ast_frame *f)
static int agentmonitoroutgoing_exec (struct ast_channel *chan, void *data)
 Called by the AgentMonitorOutgoing application (from the dial plan).
static int agents_show (int fd, int argc, char **argv)
static int agents_show_online (int fd, int argc, char **argv)
static int allow_multiple_login (char *chan, char *context)
static AST_LIST_HEAD_STATIC (agents, agent_pvt)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Agent Proxy Channel",.load=load_module,.unload=unload_module,.reload=reload,)
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 (const char *line, const char *word, int pos, int state)
static void dump_agents (void)
 Dump AgentCallbackLogin agents to the ASTdb database for persistence.
static struct agent_pvtfind_agent (char *agentid)
static int function_agent (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int load_module (void)
 Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other things it registers applications, cli commands and reads the cofiguration file.
static int login_exec (struct ast_channel *chan, void *data)
static force_inline int powerof (unsigned int d)
static int read_agent_config (void)
static int reload (void)
static void reload_agents (void)
 Reload the persistent agents from astdb.
static void set_agentbycallerid (const char *callerid, const char *agent)
 store/clear the global variable that stores agentid based on the callerid
static int unload_module (void)

Variables

static int ackcall
ast_custom_function agent_function
static const char agent_logoff_usage []
static const struct ast_channel_tech agent_tech
 Channel interface description for PBX integration.
static char agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye"
static const char app [] = "AgentLogin"
static const char app3 [] = "AgentMonitorOutgoing"
static int autologoff
static int autologoffunavail = 0
static char beep [AST_MAX_BUF] = "beep"
static struct ast_cli_entry cli_agents []
static const char config [] = "agents.conf"
static const char descrip []
static const char descrip3 []
static int endcall
static ast_group_t group
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 int multiplelogin = 1
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 const char show_agents_online_usage []
static const char show_agents_usage []
static const char synopsis [] = "Call agent 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 wrapuptime


Define Documentation

#define AST_MAX_AGENT   80
 

Agent ID or Password max length

Definition at line 133 of file chan_agent.c.

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

#define AST_MAX_BUF   256
 

Definition at line 134 of file chan_agent.c.

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

#define AST_MAX_FILENAME_LEN   256
 

Definition at line 135 of file chan_agent.c.

Referenced by __login_exec().

#define CHECK_FORMATS ast,
 ) 
 

Definition at line 194 of file chan_agent.c.

Referenced by agent_read(), and agent_write().

#define CLEANUP ast,
 ) 
 

Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX.

Definition at line 217 of file chan_agent.c.

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

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"
 

Definition at line 162 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 138 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 393 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, and ast_channel::monitor.

Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().

00394 {
00395    char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
00396    char filename[AST_MAX_BUF];
00397    int res = -1;
00398    if (!p)
00399       return -1;
00400    if (!ast->monitor) {
00401       snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
00402       /* substitute . for - */
00403       if ((pointer = strchr(filename, '.')))
00404          *pointer = '-';
00405       snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
00406       ast_monitor_start(ast, recordformat, tmp, needlock);
00407       ast_monitor_setjoinfiles(ast, 1);
00408       snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
00409 #if 0
00410       ast_verbose("name is %s, link is %s\n",tmp, tmp2);
00411 #endif
00412       if (!ast->cdr)
00413          ast->cdr = ast_cdr_alloc();
00414       ast_cdr_setuserfield(ast, tmp2);
00415       res = 0;
00416    } else
00417       ast_log(LOG_ERROR, "Recording already started on that call.\n");
00418    return res;
00419 }

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

References ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), agent_logoff_maintenance(), allow_multiple_login(), agent_pvt::app_lock, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), AST_CONTROL_HOLD, AST_DECLARE_APP_ARGS, ast_device_state_changed(), AST_DIGIT_ANY, ast_exists_extension(), ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, AST_MAX_FILENAME_LEN, ast_module_user_add, 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, ast_module_user::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, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event, agent_pvt::moh, option_debug, option_verbose, agent_pvt::owner, agent_pvt::owning_app, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, set_agentbycallerid(), strsep(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

Referenced by login_exec().

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

static int action_agent_logoff struct mansession s,
const 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 1553 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().

01554 {
01555    const char *agent = astman_get_header(m, "Agent");
01556    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01557    int soft;
01558    int ret; /* return value of agent_logoff */
01559 
01560    if (ast_strlen_zero(agent)) {
01561       astman_send_error(s, m, "No agent specified");
01562       return 0;
01563    }
01564 
01565    soft = ast_true(soft_s) ? 1 : 0;
01566    ret = agent_logoff(agent, soft);
01567    if (ret == 0)
01568       astman_send_ack(s, m, "Agent logged out");
01569    else
01570       astman_send_error(s, m, "No such agent");
01571 
01572    return 0;
01573 }

static int action_agents struct mansession s,
const 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 1392 of file chan_agent.c.

References ast_channel::_bridge, agent_pvt::acknowledged, agent_pvt::agent, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), astman_append(), 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, agent_pvt::name, agent_pvt::owner, s, and S_OR.

Referenced by load_module().

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

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

References agent_pvt::ackcall, agent_pvt::agent, AST_APP_ARG, ast_calloc, AST_DECLARE_APP_ARGS, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_init(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::lastdisc, LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, and agent_pvt::wrapuptime.

Referenced by agent_request(), and read_agent_config().

00278 {
00279    char *parse;
00280    AST_DECLARE_APP_ARGS(args,
00281       AST_APP_ARG(agt);
00282       AST_APP_ARG(password);
00283       AST_APP_ARG(name);
00284    );
00285    char *password = NULL;
00286    char *name = NULL;
00287    char *agt = NULL;
00288    struct agent_pvt *p;
00289 
00290    parse = ast_strdupa(agent);
00291 
00292    /* Extract username (agt), password and name from agent (args). */
00293    AST_NONSTANDARD_APP_ARGS(args, parse, ',');
00294 
00295    if(args.argc == 0) {
00296       ast_log(LOG_WARNING, "A blank agent line!\n");
00297       return NULL;
00298    }
00299 
00300    if(ast_strlen_zero(args.agt) ) {
00301       ast_log(LOG_WARNING, "An agent line with no agentid!\n");
00302       return NULL;
00303    } else
00304       agt = args.agt;
00305 
00306    if(!ast_strlen_zero(args.password)) {
00307       password = args.password;
00308       while (*password && *password < 33) password++;
00309    }
00310    if(!ast_strlen_zero(args.name)) {
00311       name = args.name;
00312       while (*name && *name < 33) name++;
00313    }
00314    
00315    /* Are we searching for the agent here ? To see if it exists already ? */
00316    AST_LIST_TRAVERSE(&agents, p, list) {
00317       if (!pending && !strcmp(p->agent, agt))
00318          break;
00319    }
00320    if (!p) {
00321       // Build the agent.
00322       if (!(p = ast_calloc(1, sizeof(*p))))
00323          return NULL;
00324       ast_copy_string(p->agent, agt, sizeof(p->agent));
00325       ast_mutex_init(&p->lock);
00326       ast_mutex_init(&p->app_lock);
00327       p->owning_app = (pthread_t) -1;
00328       p->app_sleep_cond = 1;
00329       p->group = group;
00330       p->pending = pending;
00331       AST_LIST_INSERT_TAIL(&agents, p, list);
00332    }
00333    
00334    ast_copy_string(p->password, password ? password : "", sizeof(p->password));
00335    ast_copy_string(p->name, name ? name : "", sizeof(p->name));
00336    ast_copy_string(p->moh, moh, sizeof(p->moh));
00337    p->ackcall = ackcall;
00338    p->autologoff = autologoff;
00339 
00340    /* If someone reduces the wrapuptime and reloads, we want it
00341     * to change the wrapuptime immediately on all calls */
00342    if (p->wrapuptime > wrapuptime) {
00343       struct timeval now = ast_tvnow();
00344       /* XXX check what is this exactly */
00345 
00346       /* We won't be pedantic and check the tv_usec val */
00347       if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
00348          p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
00349          p->lastdisc.tv_usec = now.tv_usec;
00350       }
00351    }
00352    p->wrapuptime = wrapuptime;
00353 
00354    if (pending)
00355       p->dead = 1;
00356    else
00357       p->dead = 0;
00358    return p;
00359 }

static int agent_ack_sleep void *  data  )  [static]
 

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

00841 {
00842    struct agent_pvt *p;
00843    int res=0;
00844    int to = 1000;
00845    struct ast_frame *f;
00846 
00847    /* Wait a second and look for something */
00848 
00849    p = (struct agent_pvt *) data;
00850    if (!p->chan) 
00851       return -1;
00852 
00853    for(;;) {
00854       to = ast_waitfor(p->chan, to);
00855       if (to < 0) 
00856          return -1;
00857       if (!to) 
00858          return 0;
00859       f = ast_read(p->chan);
00860       if (!f) 
00861          return -1;
00862       if (f->frametype == AST_FRAME_DTMF)
00863          res = f->subclass;
00864       else
00865          res = 0;
00866       ast_frfree(f);
00867       ast_mutex_lock(&p->lock);
00868       if (!p->app_sleep_cond) {
00869          ast_mutex_unlock(&p->lock);
00870          return 0;
00871       } else if (res == '#') {
00872          ast_mutex_unlock(&p->lock);
00873          return 1;
00874       }
00875       ast_mutex_unlock(&p->lock);
00876       res = 0;
00877    }
00878    return res;
00879 }

static int agent_answer struct ast_channel ast  )  [static]
 

Definition at line 387 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00388 {
00389    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00390    return -1;
00391 }

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

Definition at line 881 of file chan_agent.c.

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

00882 {
00883    struct agent_pvt *p = bridge->tech_pvt;
00884    struct ast_channel *ret = NULL;
00885 
00886    if (p) {
00887       if (chan == p->chan)
00888          ret = bridge->_bridge;
00889       else if (chan == bridge->_bridge)
00890          ret = p->chan;
00891    }
00892 
00893    if (option_debug)
00894       ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
00895    return ret;
00896 }

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

Definition at line 623 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, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::loginchan, ast_channel::nativeformats, option_debug, option_verbose, agent_pvt::pending, agent_pvt::start, ast_channel::tech_pvt, and VERBOSE_PREFIX_3.

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

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 367 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::chan, agent_pvt::dead, free, agent_pvt::lock, agent_pvt::owner, and ast_channel::tech_pvt.

Referenced by check_availability().

00368 {
00369    struct ast_channel *chan = p->owner;
00370    p->owner = NULL;
00371    chan->tech_pvt = NULL;
00372    p->app_sleep_cond = 1;
00373    /* Release ownership of the agent to other threads (presumably running the login app). */
00374    ast_mutex_unlock(&p->app_lock);
00375    if (chan)
00376       ast_channel_free(chan);
00377    if (p->dead) {
00378       ast_mutex_destroy(&p->lock);
00379       ast_mutex_destroy(&p->app_lock);
00380       free(p);
00381         }
00382    return 0;
00383 }

static int agent_cont_sleep void *  data  )  [static]
 

Definition at line 819 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, option_debug, and agent_pvt::wrapuptime.

Referenced by __login_exec().

00820 {
00821    struct agent_pvt *p;
00822    int res;
00823 
00824    p = (struct agent_pvt *)data;
00825 
00826    ast_mutex_lock(&p->lock);
00827    res = p->app_sleep_cond;
00828    if (p->lastdisc.tv_sec) {
00829       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) 
00830          res = 1;
00831    }
00832    ast_mutex_unlock(&p->lock);
00833 
00834    if (option_debug > 4 && !res)
00835       ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
00836 
00837    return res;
00838 }

static int agent_devicestate void *  data  )  [static]
 

Part of PBX channel interface.

Definition at line 2329 of file chan_agent.c.

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

02330 {
02331    struct agent_pvt *p;
02332    char *s;
02333    ast_group_t groupmatch;
02334    int groupoff;
02335    int waitforagent=0;
02336    int res = AST_DEVICE_INVALID;
02337    
02338    s = data;
02339    if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
02340       groupmatch = (1 << groupoff);
02341    else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
02342       groupmatch = (1 << groupoff);
02343       waitforagent = 1;
02344    } else 
02345       groupmatch = 0;
02346 
02347    /* Check actual logged in agents first */
02348    AST_LIST_LOCK(&agents);
02349    AST_LIST_TRAVERSE(&agents, p, list) {
02350       ast_mutex_lock(&p->lock);
02351       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02352          if (p->owner) {
02353             if (res != AST_DEVICE_INUSE)
02354                res = AST_DEVICE_BUSY;
02355          } else {
02356             if (res == AST_DEVICE_BUSY)
02357                res = AST_DEVICE_INUSE;
02358             if (p->chan || !ast_strlen_zero(p->loginchan)) {
02359                if (res == AST_DEVICE_INVALID)
02360                   res = AST_DEVICE_UNKNOWN;
02361             } else if (res == AST_DEVICE_INVALID)  
02362                res = AST_DEVICE_UNAVAILABLE;
02363          }
02364          if (!strcmp(data, p->agent)) {
02365             ast_mutex_unlock(&p->lock);
02366             break;
02367          }
02368       }
02369       ast_mutex_unlock(&p->lock);
02370    }
02371    AST_LIST_UNLOCK(&agents);
02372    return res;
02373 }

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

Definition at line 603 of file chan_agent.c.

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

00604 {
00605    struct agent_pvt *p = ast->tech_pvt;
00606    int res = -1;
00607    ast_mutex_lock(&p->lock);
00608    ast_senddigit_begin(p->chan, digit);
00609    ast_mutex_unlock(&p->lock);
00610    return res;
00611 }

static int agent_digit_end struct ast_channel ast,
char  digit,
unsigned int  duration
[static]
 

Definition at line 613 of file chan_agent.c.

References ast_mutex_lock(), ast_mutex_unlock(), ast_senddigit_end(), 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    ast_senddigit_end(p->chan, digit, duration);
00619    ast_mutex_unlock(&p->lock);
00620    return res;
00621 }

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

Definition at line 576 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.

00577 {
00578    struct agent_pvt *p = newchan->tech_pvt;
00579    ast_mutex_lock(&p->lock);
00580    if (p->owner != oldchan) {
00581       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00582       ast_mutex_unlock(&p->lock);
00583       return -1;
00584    }
00585    p->owner = newchan;
00586    ast_mutex_unlock(&p->lock);
00587    return 0;
00588 }

static int agent_hangup struct ast_channel ast  )  [static]
 

Definition at line 718 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::abouttograb, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff_maintenance(), agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_channel_lock, ast_channel_unlock, AST_CONTROL_HOLD, ast_device_state_changed(), ast_hangup(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), 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, free, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::moh, agent_pvt::name, option_debug, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, agent_pvt::start, ast_channel::tech_pvt, and agent_pvt::wrapuptime.

00719 {
00720    struct agent_pvt *p = ast->tech_pvt;
00721    int howlong = 0;
00722    const char *status;
00723    ast_mutex_lock(&p->lock);
00724    p->owner = NULL;
00725    ast->tech_pvt = NULL;
00726    p->app_sleep_cond = 1;
00727    p->acknowledged = 0;
00728 
00729    /* if they really are hung up then set start to 0 so the test
00730     * later if we're called on an already downed channel
00731     * doesn't cause an agent to be logged out like when
00732     * agent_request() is followed immediately by agent_hangup()
00733     * as in apps/app_chanisavail.c:chanavail_exec()
00734     */
00735 
00736    if (option_debug)
00737       ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
00738    if (p->start && (ast->_state != AST_STATE_UP)) {
00739       howlong = time(NULL) - p->start;
00740       p->start = 0;
00741    } else if (ast->_state == AST_STATE_RESERVED) 
00742       howlong = 0;
00743    else
00744       p->start = 0; 
00745    if (p->chan) {
00746       p->chan->_bridge = NULL;
00747       /* If they're dead, go ahead and hang up on the agent now */
00748       if (!ast_strlen_zero(p->loginchan)) {
00749          /* Store last disconnect time */
00750          if (p->wrapuptime)
00751             p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00752          else
00753             p->lastdisc = ast_tv(0,0);
00754          if (p->chan) {
00755             status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00756             if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00757                long logintime = time(NULL) - p->loginstart;
00758                p->loginstart = 0;
00759                ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
00760                agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00761             }
00762             /* Recognize the hangup and pass it along immediately */
00763             ast_hangup(p->chan);
00764             p->chan = NULL;
00765          }
00766          if (option_debug)
00767             ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
00768          if (howlong  && p->autologoff && (howlong > p->autologoff)) {
00769             long logintime = time(NULL) - p->loginstart;
00770             p->loginstart = 0;
00771             ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00772             agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
00773          }
00774       } else if (p->dead) {
00775          ast_channel_lock(p->chan);
00776          ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00777          ast_channel_unlock(p->chan);
00778       } else if (p->loginstart) {
00779          ast_channel_lock(p->chan);
00780          ast_indicate_data(p->chan, AST_CONTROL_HOLD, 
00781             S_OR(p->moh, NULL),
00782             !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
00783          ast_channel_unlock(p->chan);
00784       }
00785    }
00786    ast_mutex_unlock(&p->lock);
00787    /* Only register a device state change if the agent is still logged in */
00788    if (p->loginstart)
00789       ast_device_state_changed("Agent/%s", p->agent);
00790 
00791    if (p->pending) {
00792       AST_LIST_LOCK(&agents);
00793       AST_LIST_REMOVE(&agents, p, list);
00794       AST_LIST_UNLOCK(&agents);
00795    }
00796    if (p->abouttograb) {
00797       /* Let the "about to grab" thread know this isn't valid anymore, and let it
00798          kill it later */
00799       p->abouttograb = 0;
00800    } else if (p->dead) {
00801       ast_mutex_destroy(&p->lock);
00802       ast_mutex_destroy(&p->app_lock);
00803       free(p);
00804    } else {
00805       if (p->chan) {
00806          /* Not dead -- check availability now */
00807          ast_mutex_lock(&p->lock);
00808          /* Store last disconnect time */
00809          p->lastdisc = ast_tvnow();
00810          ast_mutex_unlock(&p->lock);
00811       }
00812       /* Release ownership of the agent to other threads (presumably running the login app). */
00813       if (ast_strlen_zero(p->loginchan))
00814          ast_mutex_unlock(&p->app_lock);
00815    }
00816    return 0;
00817 }

static int agent_indicate struct ast_channel ast,
int  condition,
const void *  data,
size_t  datalen
[static]
 

Definition at line 590 of file chan_agent.c.

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

00591 {
00592    struct agent_pvt *p = ast->tech_pvt;
00593    int res = -1;
00594    ast_mutex_lock(&p->lock);
00595    if (p->chan)
00596       res = ast_indicate_data(p->chan, condition, data, datalen);
00597    else
00598       res = 0;
00599    ast_mutex_unlock(&p->lock);
00600    return res;
00601 }

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

Definition at line 1502 of file chan_agent.c.

References agent_pvt::agent, agent_logoff_maintenance(), AST_LIST_TRAVERSE, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agent_pvt::chan, agent_pvt::loginchan, agent_pvt::loginstart, and agent_pvt::owner.

Referenced by action_agent_logoff(), and agent_logoff_cmd().

01503 {
01504    struct agent_pvt *p;
01505    long logintime;
01506    int ret = -1; /* Return -1 if no agent if found */
01507 
01508    AST_LIST_TRAVERSE(&agents, p, list) {
01509       if (!strcasecmp(p->agent, agent)) {
01510          if (!soft) {
01511             if (p->owner)
01512                ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01513             if (p->chan) 
01514                ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01515          }
01516          ret = 0; /* found an agent => return 0 */
01517          logintime = time(NULL) - p->loginstart;
01518          p->loginstart = 0;
01519          agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
01520          break;
01521       }
01522    }
01523 
01524    return ret;
01525 }

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

Definition at line 1527 of file chan_agent.c.

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

01528 {
01529    int ret;
01530    char *agent;
01531 
01532    if (argc < 3 || argc > 4)
01533       return RESULT_SHOWUSAGE;
01534    if (argc == 4 && strcasecmp(argv[3], "soft"))
01535       return RESULT_SHOWUSAGE;
01536 
01537    agent = argv[2] + 6;
01538    ret = agent_logoff(agent, argc == 4);
01539    if (ret == 0)
01540       ast_cli(fd, "Logging out %s\n", agent);
01541 
01542    return RESULT_SUCCESS;
01543 }

static void agent_logoff_maintenance struct agent_pvt p,
char *  loginchan,
long  logintime,
const char *  uniqueid,
char *  logcommand
[static]
 

Definition at line 1463 of file chan_agent.c.

References agent_pvt::agent, ast_device_state_changed(), AST_MAX_AGENT, ast_queue_log(), ast_strdupa, ast_strlen_zero(), dump_agents(), EVENT_FLAG_AGENT, agent_pvt::logincallerid, agent_pvt::loginchan, manager_event, and set_agentbycallerid().

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

01464 {
01465    char *tmp = NULL;
01466    char agent[AST_MAX_AGENT];
01467 
01468    if (!ast_strlen_zero(logcommand))
01469       tmp = logcommand;
01470    else
01471       tmp = ast_strdupa("");
01472 
01473    snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01474 
01475    if (!ast_strlen_zero(uniqueid)) {
01476       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01477             "Agent: %s\r\n"
01478             "Reason: %s\r\n"
01479             "Loginchan: %s\r\n"
01480             "Logintime: %ld\r\n"
01481             "Uniqueid: %s\r\n", 
01482             p->agent, tmp, loginchan, logintime, uniqueid);
01483    } else {
01484       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01485             "Agent: %s\r\n"
01486             "Reason: %s\r\n"
01487             "Loginchan: %s\r\n"
01488             "Logintime: %ld\r\n",
01489             p->agent, tmp, loginchan, logintime);
01490    }
01491 
01492    ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
01493    set_agentbycallerid(p->logincallerid, NULL);
01494    p->loginchan[0] ='\0';
01495    p->logincallerid[0] = '\0';
01496    ast_device_state_changed("Agent/%s", p->agent);
01497    if (persistent_agents)
01498       dump_agents(); 
01499 
01500 }

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

Create new agent channel.

Definition at line 899 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_CONTROL_UNHOLD, AST_FLAG_BLOCKING, AST_FORMAT_SLINEAR, ast_indicate(), ast_log(), ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_null_frame, ast_queue_frame(), ast_random(), ast_string_field_set, ast_strlen_zero(), ast_test_flag, agent_pvt::chan, ast_channel::context, CRASH, ast_channel::exten, language, agent_pvt::lock, LOG_ERROR, LOG_WARNING, agent_pvt::loginchan, 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, and ast_channel::writeformat.

Referenced by agent_request(), and check_availability().

00900 {
00901    struct ast_channel *tmp;
00902 #if 0
00903    if (!p->chan) {
00904       ast_log(LOG_WARNING, "No channel? :(\n");
00905       return NULL;
00906    }
00907 #endif   
00908    if (p->pending)
00909       tmp = ast_channel_alloc(0, state, 0, 0, "Agent/P%s-%d", p->agent, ast_random() & 0xffff);
00910    else
00911       tmp = ast_channel_alloc(0, state, 0, 0, "Agent/%s", p->agent);
00912    if (!tmp) {
00913       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
00914       return NULL;
00915    }
00916 
00917    tmp->tech = &agent_tech;
00918    if (p->chan) {
00919       tmp->nativeformats = p->chan->nativeformats;
00920       tmp->writeformat = p->chan->writeformat;
00921       tmp->rawwriteformat = p->chan->writeformat;
00922       tmp->readformat = p->chan->readformat;
00923       tmp->rawreadformat = p->chan->readformat;
00924       ast_string_field_set(tmp, language, p->chan->language);
00925       ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
00926       ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
00927       /* XXX Is this really all we copy form the originating channel?? */
00928    } else {
00929       tmp->nativeformats = AST_FORMAT_SLINEAR;
00930       tmp->writeformat = AST_FORMAT_SLINEAR;
00931       tmp->rawwriteformat = AST_FORMAT_SLINEAR;
00932       tmp->readformat = AST_FORMAT_SLINEAR;
00933       tmp->rawreadformat = AST_FORMAT_SLINEAR;
00934    }
00935    /* Safe, agentlock already held */
00936    tmp->tech_pvt = p;
00937    p->owner = tmp;
00938    tmp->priority = 1;
00939    /* Wake up and wait for other applications (by definition the login app)
00940     * to release this channel). Takes ownership of the agent channel
00941     * to this thread only.
00942     * For signalling the other thread, ast_queue_frame is used until we
00943     * can safely use signals for this purpose. The pselect() needs to be
00944     * implemented in the kernel for this.
00945     */
00946    p->app_sleep_cond = 0;
00947    if(ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock)) {
00948       if (p->chan) {
00949          ast_queue_frame(p->chan, &ast_null_frame);
00950          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
00951          ast_mutex_lock(&p->app_lock);
00952          ast_mutex_lock(&p->lock);
00953       } else {
00954          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
00955          p->owner = NULL;
00956          tmp->tech_pvt = NULL;
00957          p->app_sleep_cond = 1;
00958          ast_channel_free( tmp );
00959          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
00960          ast_mutex_unlock(&p->app_lock);
00961          return NULL;
00962       }
00963    } else if (!ast_strlen_zero(p->loginchan)) {
00964       if (p->chan)
00965          ast_queue_frame(p->chan, &ast_null_frame);
00966       if (!p->chan) {
00967          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
00968          p->owner = NULL;
00969          tmp->tech_pvt = NULL;
00970          p->app_sleep_cond = 1;
00971          ast_channel_free( tmp );
00972          ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
00973          return NULL;
00974       }  
00975    }
00976       ast_indicate(p->chan, AST_CONTROL_UNHOLD);
00977    p->owning_app = pthread_self();
00978    /* After the above step, there should not be any blockers. */
00979    if (p->chan) {
00980       if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
00981          ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
00982          CRASH;
00983       }
00984    }
00985    return tmp;
00986 }

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

Definition at line 426 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, AST_CONTROL_ANSWER, ast_copy_flags, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree(), ast_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_read(), AST_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_verbose(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, ast_channel::fdno, ast_frame::frametype, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, option_debug, option_verbose, pbx_builtin_getvar_helper(), ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

00427 {
00428    struct agent_pvt *p = ast->tech_pvt;
00429    struct ast_frame *f = NULL;
00430    static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00431    const char *status;
00432    ast_mutex_lock(&p->lock); 
00433    CHECK_FORMATS(ast, p);
00434    if (p->chan) {
00435       ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
00436       p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
00437       f = ast_read(p->chan);
00438    } else
00439       f = &ast_null_frame;
00440    if (!f) {
00441       /* If there's a channel, hang it up (if it's on a callback) make it NULL */
00442       if (p->chan) {
00443          p->chan->_bridge = NULL;
00444          /* Note that we don't hangup if it's not a callback because Asterisk will do it
00445             for us when the PBX instance that called login finishes */
00446          if (!ast_strlen_zero(p->loginchan)) {
00447             if (p->chan && option_debug)
00448                ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
00449 
00450             status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00451             if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00452                long logintime = time(NULL) - p->loginstart;
00453                p->loginstart = 0;
00454                ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name);
00455                agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00456             }
00457             ast_hangup(p->chan);
00458             if (p->wrapuptime && p->acknowledged)
00459                p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00460          }
00461          p->chan = NULL;
00462          p->acknowledged = 0;
00463       }
00464    } else {
00465       /* if acknowledgement is not required, and the channel is up, we may have missed
00466          an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
00467       if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP))
00468          p->acknowledged = 1;
00469       switch (f->frametype) {
00470       case AST_FRAME_CONTROL:
00471          if (f->subclass == AST_CONTROL_ANSWER) {
00472             if (p->ackcall) {
00473                if (option_verbose > 2)
00474                   ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
00475                /* Don't pass answer along */
00476                ast_frfree(f);
00477                f = &ast_null_frame;
00478             } else {
00479                p->acknowledged = 1;
00480                /* Use the builtin answer frame for the 
00481                   recording start check below. */
00482                ast_frfree(f);
00483                f = &answer_frame;
00484             }
00485          }
00486          break;
00487       case AST_FRAME_DTMF_BEGIN:
00488       case AST_FRAME_DTMF_END:
00489          if (!p->acknowledged && (f->subclass == '#')) {
00490             if (option_verbose > 2)
00491                ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
00492             p->acknowledged = 1;
00493             ast_frfree(f);
00494             f = &answer_frame;
00495          } else if (f->subclass == '*' && endcall) {
00496             /* terminates call */
00497             ast_frfree(f);
00498             f = NULL;
00499          }
00500          break;
00501       case AST_FRAME_VOICE:
00502       case AST_FRAME_VIDEO:
00503          /* don't pass voice or video until the call is acknowledged */
00504          if (!p->acknowledged) {
00505             ast_frfree(f);
00506             f = &ast_null_frame;
00507          }
00508       default:
00509          /* pass everything else on through */
00510          break;
00511       }
00512    }
00513 
00514    CLEANUP(ast,p);
00515    if (p->chan && !p->chan->_bridge) {
00516       if (strcasecmp(p->chan->tech->type, "Local")) {
00517          p->chan->_bridge = ast;
00518          if (p->chan && option_debug)
00519             ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
00520       }
00521    }
00522    ast_mutex_unlock(&p->lock);
00523    if (recordagentcalls && f == &answer_frame)
00524       agent_start_monitoring(ast,0);
00525    return f;
00526 }

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

Part of the Asterisk PBX interface.

Definition at line 1279 of file chan_agent.c.

References add_agent(), agent_pvt::agent, agent_new(), AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, 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, option_debug, agent_pvt::owner, agent_pvt::pending, and s.

01280 {
01281    struct agent_pvt *p;
01282    struct ast_channel *chan = NULL;
01283    char *s;
01284    ast_group_t groupmatch;
01285    int groupoff;
01286    int waitforagent=0;
01287    int hasagent = 0;
01288    struct timeval tv;
01289 
01290    s = data;
01291    if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
01292       groupmatch = (1 << groupoff);
01293    } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
01294       groupmatch = (1 << groupoff);
01295       waitforagent = 1;
01296    } else 
01297       groupmatch = 0;
01298 
01299    /* Check actual logged in agents first */
01300    AST_LIST_LOCK(&agents);
01301    AST_LIST_TRAVERSE(&agents, p, list) {
01302       ast_mutex_lock(&p->lock);
01303       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
01304           ast_strlen_zero(p->loginchan)) {
01305          if (p->chan)
01306             hasagent++;
01307          if (!p->lastdisc.tv_sec) {
01308             /* Agent must be registered, but not have any active call, and not be in a waiting state */
01309             if (!p->owner && p->chan) {
01310                /* Fixed agent */
01311                chan = agent_new(p, AST_STATE_DOWN);
01312             }
01313             if (chan) {
01314                ast_mutex_unlock(&p->lock);
01315                break;
01316             }
01317          }
01318       }
01319       ast_mutex_unlock(&p->lock);
01320    }
01321    if (!p) {
01322       AST_LIST_TRAVERSE(&agents, p, list) {
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       }
01351    }
01352 
01353    if (!chan && waitforagent) {
01354       /* No agent available -- but we're requesting to wait for one.
01355          Allocate a place holder */
01356       if (hasagent) {
01357          if (option_debug)
01358             ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
01359          p = add_agent(data, 1);
01360          p->group = groupmatch;
01361          chan = agent_new(p, AST_STATE_DOWN);
01362          if (!chan) 
01363             ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
01364       } else {
01365          if (option_debug)
01366             ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
01367       }
01368    }
01369    *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
01370    AST_LIST_UNLOCK(&agents);
01371    return chan;
01372 }

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

Definition at line 528 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.

00529 {
00530    struct agent_pvt *p = ast->tech_pvt;
00531    int res = -1;
00532    ast_mutex_lock(&p->lock);
00533    if (p->chan) 
00534       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00535    ast_mutex_unlock(&p->lock);
00536    return res;
00537 }

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

Definition at line 539 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.

00540 {
00541    struct agent_pvt *p = ast->tech_pvt;
00542    int res = -1;
00543    ast_mutex_lock(&p->lock);
00544    if (p->chan) 
00545       res = ast_sendtext(p->chan, text);
00546    ast_mutex_unlock(&p->lock);
00547    return res;
00548 }

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

Definition at line 421 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00422 {
00423    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00424 }

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

Definition at line 550 of file chan_agent.c.

References AST_FRAME_VIDEO, 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, option_debug, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.

00551 {
00552    struct agent_pvt *p = ast->tech_pvt;
00553    int res = -1;
00554    CHECK_FORMATS(ast, p);
00555    ast_mutex_lock(&p->lock);
00556    if (!p->chan) 
00557       res = 0;
00558    else {
00559       if ((f->frametype != AST_FRAME_VOICE) ||
00560           (f->frametype != AST_FRAME_VIDEO) ||
00561           (f->subclass == p->chan->writeformat)) {
00562          res = ast_write(p->chan, f);
00563       } else {
00564          if (option_debug)
00565             ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00566                f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00567                ast->name, p->chan->name);
00568          res = 0;
00569       }
00570    }
00571    CLEANUP(ast, p);
00572    ast_mutex_unlock(&p->lock);
00573    return res;
00574 }

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().
Todo:
XXX Needs to check option priorityjump etc etc

Definition at line 2193 of file chan_agent.c.

References __agent_start_monitoring(), agent_pvt::agent, ast_exists_extension(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_verbose(), ast_channel::cdr, agent_pvt::chan, ast_module_user::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, GETAGENTBYCALLERID, LOG_WARNING, option_verbose, pbx_builtin_getvar_helper(), and VERBOSE_PREFIX_3.

Referenced by load_module().

02194 {
02195    int exitifnoagentid = 0;
02196    int nowarnings = 0;
02197    int changeoutgoing = 0;
02198    int res = 0;
02199    char agent[AST_MAX_AGENT];
02200 
02201    if (data) {
02202       if (strchr(data, 'd'))
02203          exitifnoagentid = 1;
02204       if (strchr(data, 'n'))
02205          nowarnings = 1;
02206       if (strchr(data, 'c'))
02207          changeoutgoing = 1;
02208    }
02209    if (chan->cid.cid_num) {
02210       const char *tmp;
02211       char agentvar[AST_MAX_BUF];
02212       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02213       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02214          struct agent_pvt *p;
02215          ast_copy_string(agent, tmp, sizeof(agent));
02216          AST_LIST_LOCK(&agents);
02217          AST_LIST_TRAVERSE(&agents, p, list) {
02218             if (!strcasecmp(p->agent, tmp)) {
02219                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02220                __agent_start_monitoring(chan, p, 1);
02221                break;
02222             }
02223          }
02224          AST_LIST_UNLOCK(&agents);
02225          
02226       } else {
02227          res = -1;
02228          if (!nowarnings)
02229             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);
02230       }
02231    } else {
02232       res = -1;
02233       if (!nowarnings)
02234          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");
02235    }
02236    /* check if there is n + 101 priority */
02237    /*! \todo XXX Needs to check option priorityjump etc etc */
02238    if (res) {
02239       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
02240          chan->priority+=100;
02241          if (option_verbose > 2)
02242             ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
02243       } else if (exitifnoagentid)
02244          return res;
02245    }
02246    return 0;
02247 }

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

Show agents in cli.

< Number of agents configured

< Number of online agents

< Number of offline agents

Definition at line 1596 of file chan_agent.c.

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

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

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

Definition at line 1661 of file chan_agent.c.

References agent_pvt::acknowledged, agent_pvt::agent, ast_bridged_channel(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), agent_pvt::chan, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01662 {
01663    struct agent_pvt *p;
01664    char username[AST_MAX_BUF];
01665    char location[AST_MAX_BUF] = "";
01666    char talkingto[AST_MAX_BUF] = "";
01667    char moh[AST_MAX_BUF];
01668    int count_agents = 0;           /* Number of agents configured */
01669    int online_agents = 0;          /* Number of online agents */
01670    int agent_status = 0;           /* 0 means offline, 1 means online */
01671    if (argc != 3)
01672       return RESULT_SHOWUSAGE;
01673    AST_LIST_LOCK(&agents);
01674    AST_LIST_TRAVERSE(&agents, p, list) {
01675       agent_status = 0;       /* reset it to offline */
01676       ast_mutex_lock(&p->lock);
01677       if (!ast_strlen_zero(p->name))
01678          snprintf(username, sizeof(username), "(%s) ", p->name);
01679       else
01680          username[0] = '\0';
01681       if (p->chan) {
01682          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01683          if (p->owner && ast_bridged_channel(p->owner)) 
01684             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01685          else 
01686             strcpy(talkingto, " is idle");
01687          agent_status = 1;
01688          online_agents++;
01689       } else if (!ast_strlen_zero(p->loginchan)) {
01690          snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01691          talkingto[0] = '\0';
01692          agent_status = 1;
01693          online_agents++;
01694          if (p->acknowledged)
01695             strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01696       }
01697       if (!ast_strlen_zero(p->moh))
01698          snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01699       if (agent_status)
01700          ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh);
01701       count_agents++;
01702       ast_mutex_unlock(&p->lock);
01703    }
01704    AST_LIST_UNLOCK(&agents);
01705    if (!count_agents) 
01706       ast_cli(fd, "No Agents are configured in %s\n", config);
01707    else
01708       ast_cli(fd, "%d agents online\n", online_agents);
01709    ast_cli(fd, "\n");
01710    return RESULT_SUCCESS;
01711 }

static int allow_multiple_login char *  chan,
char *  context
[static]
 

Definition at line 1259 of file chan_agent.c.

References AST_LIST_TRAVERSE, agent_pvt::loginchan, and S_OR.

Referenced by __login_exec().

01260 {
01261    struct agent_pvt *p;
01262    char loginchan[80];
01263 
01264    if(multiplelogin)
01265       return 1;
01266    if(!chan) 
01267       return 0;
01268 
01269    snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default"));
01270    
01271    AST_LIST_TRAVERSE(&agents, p, list) {
01272       if(!strcasecmp(chan, p->loginchan))
01273          return 0;
01274    }
01275    return -1;
01276 }

static AST_LIST_HEAD_STATIC agents  ,
agent_pvt 
[static]
 

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

AST_MODULE_INFO ASTERISK_GPL_KEY  ,
AST_MODFLAG_DEFAULT  ,
"Agent Proxy Channel"  ,
load = load_module,
unload = unload_module,
reload = reload
 

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

Definition at line 1143 of file chan_agent.c.

References agent_pvt::abouttograb, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_cleanup(), agent_new(), ast_channel_masquerade(), AST_FLAG_ZOMBIE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, 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, agent_pvt::lock, LOG_DEBUG, option_debug, agent_pvt::owner, and agent_pvt::pending.

Referenced by __login_exec().

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

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

Definition at line 1217 of file chan_agent.c.

References agent_pvt::abouttograb, agent_pvt::agent, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_streamfile(), ast_waitstream(), agent_pvt::chan, agent_pvt::group, agent_pvt::lock, LOG_DEBUG, option_debug, agent_pvt::owner, and agent_pvt::pending.

Referenced by __login_exec().

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

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

Definition at line 1575 of file chan_agent.c.

References agent_pvt::agent, AST_LIST_TRAVERSE, AST_MAX_AGENT, ast_strdup, len, and name.

01576 {
01577    if (pos == 2) {
01578       struct agent_pvt *p;
01579       char name[AST_MAX_AGENT];
01580       int which = 0, len = strlen(word);
01581 
01582       AST_LIST_TRAVERSE(&agents, p, list) {
01583          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01584          if (!strncasecmp(word, name, len) && ++which > state)
01585             return ast_strdup(name);
01586       }
01587    } else if (pos == 3 && state == 0) 
01588       return ast_strdup("soft");
01589    
01590    return NULL;
01591 }

static void dump_agents void   )  [static]
 

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

Definition at line 2252 of file chan_agent.c.

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

Referenced by __login_exec(), and agent_logoff_maintenance().

02253 {
02254    struct agent_pvt *cur_agent = NULL;
02255    char buf[256];
02256 
02257    AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02258       if (cur_agent->chan)
02259          continue;
02260 
02261       if (!ast_strlen_zero(cur_agent->loginchan)) {
02262          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02263          if (ast_db_put(pa_family, cur_agent->agent, buf))
02264             ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
02265          else if (option_debug)
02266             ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02267       } else {
02268          /* Delete -  no agent or there is an error */
02269          ast_db_del(pa_family, cur_agent->agent);
02270       }
02271    }
02272 }

static struct agent_pvt* find_agent char *  agentid  )  [static]
 

Definition at line 2375 of file chan_agent.c.

References agent_pvt::agent, and AST_LIST_TRAVERSE.

Referenced by function_agent().

02376 {
02377    struct agent_pvt *cur;
02378 
02379    AST_LIST_TRAVERSE(&agents, cur, list) {
02380       if (!strcmp(cur->agent, agentid))
02381          break;   
02382    }
02383 
02384    return cur; 
02385 }

static int function_agent struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len
[static]
 

Definition at line 2387 of file chan_agent.c.

References agent_pvt::agent, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), find_agent(), LOG_WARNING, and parse().

02388 {
02389    char *parse;    
02390    AST_DECLARE_APP_ARGS(args,
02391       AST_APP_ARG(agentid);
02392       AST_APP_ARG(item);
02393    );
02394    char *tmp;
02395    struct agent_pvt *agent;
02396 
02397    buf[0] = '\0';
02398 
02399    if (ast_strlen_zero(data)) {
02400       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02401       return -1;
02402    }
02403 
02404    parse = ast_strdupa(data);
02405 
02406    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02407    if (!args.item)
02408       args.item = "status";
02409 
02410    if (!(agent = find_agent(args.agentid))) {
02411       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02412       return -1;
02413    }
02414 
02415    if (!strcasecmp(args.item, "status")) {
02416       char *status = "LOGGEDOUT";
02417       if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
02418          status = "LOGGEDIN"; 
02419       ast_copy_string(buf, status, len);
02420    } else if (!strcasecmp(args.item, "password")) 
02421       ast_copy_string(buf, agent->password, len);
02422    else if (!strcasecmp(args.item, "name"))
02423       ast_copy_string(buf, agent->name, len);
02424    else if (!strcasecmp(args.item, "mohclass"))
02425       ast_copy_string(buf, agent->moh, len);
02426    else if (!strcasecmp(args.item, "channel")) {
02427       if (agent->chan) {
02428          ast_copy_string(buf, agent->chan->name, len);
02429          tmp = strrchr(buf, '-');
02430          if (tmp)
02431             *tmp = '\0';
02432       } 
02433    } else if (!strcasecmp(args.item, "exten"))
02434       ast_copy_string(buf, agent->loginchan, len); 
02435 
02436    return 0;
02437 }

static int load_module void   )  [static]
 

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other things it registers applications, cli commands and reads the cofiguration file.

Returns:
int Always 0.

Definition at line 2462 of file chan_agent.c.

References action_agent_logoff(), action_agents(), agent_function, agent_tech, agentmonitoroutgoing_exec(), ast_channel_register(), ast_cli_register_multiple(), ast_custom_function_register(), ast_log(), ast_manager_register2(), AST_MODULE_LOAD_DECLINE, ast_register_application(), cli_agents, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), read_agent_config(), and reload_agents().

02463 {
02464    /* Make sure we can register our agent channel type */
02465    if (ast_channel_register(&agent_tech)) {
02466       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02467       return -1;
02468    }
02469    /* Read in the config */
02470    if (!read_agent_config())
02471       return AST_MODULE_LOAD_DECLINE;
02472    if (persistent_agents)
02473       reload_agents();
02474    /* Dialplan applications */
02475    ast_register_application(app, login_exec, synopsis, descrip);
02476    ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
02477 
02478    /* Manager commands */
02479    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02480    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02481 
02482    /* CLI Commands */
02483    ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02484 
02485    /* Dialplan Functions */
02486    ast_custom_function_register(&agent_function);
02487 
02488    return 0;
02489 }

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

References __login_exec(), and ast_module_user::chan.

Referenced by load_module().

02181 {
02182    return __login_exec(chan, data, 0);
02183 }

static force_inline int powerof unsigned int  d  )  [static]
 

Definition at line 1374 of file chan_agent.c.

01375 {
01376    int x = ffs(d);
01377 
01378    if (x)
01379       return x - 1;
01380 
01381    return 0;
01382 }

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

References add_agent(), agent_pvt::app_lock, ast_category_browse(), ast_config_destroy(), ast_config_load(), ast_get_group(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), agent_pvt::chan, agent_pvt::dead, free, agent_pvt::lock, LOG_NOTICE, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.

Referenced by load_module(), and reload().

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

static int reload void   )  [static]
 

Definition at line 2491 of file chan_agent.c.

References read_agent_config(), and reload_agents().

02492 {
02493    read_agent_config();
02494    if (persistent_agents)
02495       reload_agents();
02496    return 0;
02497 }

static void reload_agents void   )  [static]
 

Reload the persistent agents from astdb.

Definition at line 2277 of file chan_agent.c.

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

Referenced by load_module(), and reload().

02278 {
02279    char *agent_num;
02280    struct ast_db_entry *db_tree;
02281    struct ast_db_entry *entry;
02282    struct agent_pvt *cur_agent;
02283    char agent_data[256];
02284    char *parse;
02285    char *agent_chan;
02286    char *agent_callerid;
02287 
02288    db_tree = ast_db_gettree(pa_family, NULL);
02289 
02290    AST_LIST_LOCK(&agents);
02291    for (entry = db_tree; entry; entry = entry->next) {
02292       agent_num = entry->key + strlen(pa_family) + 2;
02293       AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02294          ast_mutex_lock(&cur_agent->lock);
02295          if (strcmp(agent_num, cur_agent->agent) == 0)
02296             break;
02297          ast_mutex_unlock(&cur_agent->lock);
02298       }
02299       if (!cur_agent) {
02300          ast_db_del(pa_family, agent_num);
02301          continue;
02302       } else
02303          ast_mutex_unlock(&cur_agent->lock);
02304       if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
02305          if (option_debug)
02306             ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
02307          parse = agent_data;
02308          agent_chan = strsep(&parse, ";");
02309          agent_callerid = strsep(&parse, ";");
02310          ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
02311          if (agent_callerid) {
02312             ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
02313             set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
02314          } else
02315             cur_agent->logincallerid[0] = '\0';
02316          if (cur_agent->loginstart == 0)
02317             time(&cur_agent->loginstart);
02318          ast_device_state_changed("Agent/%s", cur_agent->agent);  
02319       }
02320    }
02321    AST_LIST_UNLOCK(&agents);
02322    if (db_tree) {
02323       ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
02324       ast_db_freetree(db_tree);
02325    }
02326 }

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

store/clear the global variable that stores agentid based on the callerid

Definition at line 706 of file chan_agent.c.

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

Referenced by __login_exec(), agent_logoff_maintenance(), and reload_agents().

00707 {
00708    char buf[AST_MAX_BUF];
00709 
00710    /* if there is no Caller ID, nothing to do */
00711    if (ast_strlen_zero(callerid))
00712       return;
00713 
00714    snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00715    pbx_builtin_setvar_helper(NULL, buf, agent);
00716 }

static int unload_module void   )  [static]
 

Definition at line 2499 of file chan_agent.c.

References agent_function, agent_tech, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_manager_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_unregister_application(), cli_agents, free, and agent_pvt::owner.

02500 {
02501    struct agent_pvt *p;
02502    /* First, take us out of the channel loop */
02503    ast_channel_unregister(&agent_tech);
02504    /* Unregister dialplan functions */
02505    ast_custom_function_unregister(&agent_function);   
02506    /* Unregister CLI commands */
02507    ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02508    /* Unregister dialplan applications */
02509    ast_unregister_application(app);
02510    ast_unregister_application(app3);
02511    /* Unregister manager command */
02512    ast_manager_unregister("Agents");
02513    ast_manager_unregister("AgentLogoff");
02514    /* Unregister channel */
02515    AST_LIST_LOCK(&agents);
02516    /* Hangup all interfaces if they have an owner */
02517    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02518       if (p->owner)
02519          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02520       free(p);
02521    }
02522    AST_LIST_UNLOCK(&agents);
02523    AST_LIST_HEAD_DESTROY(&agents);
02524    return 0;
02525 }


Variable Documentation

int ackcall [static]
 

Definition at line 146 of file chan_agent.c.

struct ast_custom_function agent_function
 

Definition at line 2439 of file chan_agent.c.

Referenced by load_module(), and unload_module().

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

const struct ast_channel_tech agent_tech [static]
 

Channel interface description for PBX integration.

Definition at line 247 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 152 of file chan_agent.c.

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

Definition at line 79 of file chan_agent.c.

Referenced by action_originate(), add_extensions(), answer_exec_enable(), ast_pbx_run_app(), async_wait(), check_app_args(), check_pval_item(), feature_exec_app(), handle_context_add_extension(), handle_exec(), load_module(), pbx_builtin_execiftime(), pbx_exec(), pbx_extension_helper(), realtime_exec(), unload_module(), and unreference_cached_app().

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

Definition at line 80 of file chan_agent.c.

int autologoff [static]
 

Definition at line 144 of file chan_agent.c.

int autologoffunavail = 0 [static]
 

Definition at line 149 of file chan_agent.c.

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

Definition at line 160 of file chan_agent.c.

struct ast_cli_entry cli_agents[] [static]
 

Definition at line 1728 of file chan_agent.c.

Referenced by load_module(), and unload_module().

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

Definition at line 77 of file chan_agent.c.

Referenced by ast_bridge_call(), ast_category_append(), ast_category_browse(), ast_category_exist(), ast_category_get(), ast_channel_bridge(), ast_config_new(), ast_feature_interpret(), ast_generic_bridge(), ast_readconfig(), ast_variable_browse(), ast_variable_retrieve(), builtin_atxfer(), category_get(), do_reload(), handle_save_dialplan(), load_module(), load_odbc_config(), misdn_cfg_init(), park_exec(), parse_config(), pbx_load_module(), read_config_maps(), reload(), reload_config(), and set_config_flags().

const char descrip[] [static]
 

Definition at line 85 of file chan_agent.c.

Referenced by aji_handle_presence(), and load_module().

const char descrip3[] [static]
 

Definition at line 94 of file chan_agent.c.

int endcall [static]
 

Definition at line 147 of file chan_agent.c.

ast_group_t group [static]
 

Definition at line 143 of file chan_agent.c.

Referenced by ast_app_group_set_channel(), ast_get_group(), ast_makesocket(), and misdn_request().

const char mandescr_agent_callback_login[] [static]
 

Definition at line 122 of file chan_agent.c.

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

const char mandescr_agents[] [static]
 

Initial value:

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

Definition at line 112 of file chan_agent.c.

int maxlogintries = 3 [static]
 

Definition at line 151 of file chan_agent.c.

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

Definition at line 131 of file chan_agent.c.

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

int multiplelogin = 1 [static]
 

Definition at line 148 of file chan_agent.c.

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

Persistent Agents astdb family

Definition at line 137 of file chan_agent.c.

int persistent_agents = 0 [static]
 

queues.conf [general] option

Definition at line 140 of file chan_agent.c.

int recorda