Thu Oct 11 06:42:57 2012

Asterisk developer's documentation


chan_agent.c File Reference

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

#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...
struct  agents

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 void __reg_module (void)
static void __unreg_module (void)
static int action_agent_callback_login (struct mansession *s, const struct message *m)
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_devicestate_cb (const char *dev, int state, void *data)
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 struct ast_channelagent_get_base_channel (struct ast_channel *chan)
 return the channel or base channel if one exists. This function assumes the channel it is called on is already locked
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_set_base_channel (struct ast_channel *chan, struct ast_channel *base)
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 void callback_deprecated (void)
static int callback_exec (struct ast_channel *chan, void *data)
static int check_availability (struct agent_pvt *newlyavailable, int needlock)
static int check_beep (struct agent_pvt *newlyavailable, int needlock)
static char * complete_agent_logoff_cmd (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, 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 struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Agent Proxy Channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static int ackcall
struct ast_custom_function agent_function
static char agent_logoff_usage []
static 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 app2 [] = "AgentCallbackLogin"
static const char app3 [] = "AgentMonitorOutgoing"
static const struct
ast_module_info
ast_module_info = &__mod_info
static int autologoff
static int autologoffunavail = 0
static char beep [AST_MAX_BUF] = "beep"
static struct ast_cli_entry cli_agents []
static struct ast_cli_entry cli_show_agents_deprecated
static struct ast_cli_entry cli_show_agents_online_deprecated
static const char config [] = "agents.conf"
static const char descrip []
static const char descrip2 []
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 char show_agents_online_usage []
static char show_agents_usage []
static const char synopsis [] = "Call agent login"
static const char synopsis2 [] = "Call agent callback login"
static const char synopsis3 [] = "Record agent's outgoing call"
static const char tdesc [] = "Call Agent Proxy Channel"
static int updatecdr = 0
static char urlprefix [AST_MAX_BUF] = ""
static int wrapuptime


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.


Define Documentation

#define AST_MAX_AGENT   80

Agent ID or Password max length

Definition at line 146 of file chan_agent.c.

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

#define AST_MAX_BUF   256

#define AST_MAX_FILENAME_LEN   256

Definition at line 148 of file chan_agent.c.

Referenced by __login_exec().

#define CHECK_FORMATS ( ast,
 ) 

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

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

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"

Definition at line 175 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 151 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 463 of file chan_agent.c.

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

Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().

00464 {
00465    char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
00466    char filename[AST_MAX_BUF];
00467    int res = -1;
00468    if (!p)
00469       return -1;
00470    if (!ast->monitor) {
00471       snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
00472       /* substitute . for - */
00473       if ((pointer = strchr(filename, '.')))
00474          *pointer = '-';
00475       snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
00476       ast_monitor_start(ast, recordformat, tmp, needlock);
00477       ast_monitor_setjoinfiles(ast, 1);
00478       snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
00479 #if 0
00480       ast_verbose("name is %s, link is %s\n",tmp, tmp2);
00481 #endif
00482       if (!ast->cdr)
00483          ast->cdr = ast_cdr_alloc();
00484       ast_cdr_setuserfield(ast, tmp2);
00485       res = 0;
00486    } else
00487       ast_log(LOG_ERROR, "Recording already started on that call.\n");
00488    return res;
00489 }

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 1989 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_complete_cond, agent_pvt::app_lock_flag, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_signal(), ast_cond_wait(), AST_CONTROL_HOLD, ast_copy_string(), 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_module_user_remove, 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_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_tv(), ast_tvdiff_ms(), ast_tvnow(), ast_verbose(), ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, context, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), EVENT_FLAG_AGENT, ast_channel::exten, free, agent_pvt::inherited_devicestate, ast_channel::language, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, ast_channel::name, ast_channel::nativeformats, option_debug, option_verbose, agent_pvt::owner, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), agent_pvt::pending, ast_channel::priority, ast_channel::readformat, S_OR, set_agentbycallerid(), ast_channel::uniqueid, VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, agent_pvt::wrapuptime, and ast_channel::writeformat.

Referenced by callback_exec(), and login_exec().

01990 {
01991    int res=0;
01992    int tries = 0;
01993    int max_login_tries = maxlogintries;
01994    struct agent_pvt *p;
01995    struct ast_module_user *u;
01996    int login_state = 0;
01997    char user[AST_MAX_AGENT] = "";
01998    char pass[AST_MAX_AGENT];
01999    char agent[AST_MAX_AGENT] = "";
02000    char xpass[AST_MAX_AGENT] = "";
02001    char *errmsg;
02002    char *parse;
02003    AST_DECLARE_APP_ARGS(args,
02004               AST_APP_ARG(agent_id);
02005               AST_APP_ARG(options);
02006               AST_APP_ARG(extension);
02007       );
02008    const char *tmpoptions = NULL;
02009    char *context = NULL;
02010    int play_announcement = 1;
02011    char agent_goodbye[AST_MAX_FILENAME_LEN];
02012    int update_cdr = updatecdr;
02013    char *filename = "agent-loginok";
02014    char tmpchan[AST_MAX_BUF] = "";
02015 
02016    u = ast_module_user_add(chan);
02017 
02018    parse = ast_strdupa(data);
02019 
02020    AST_STANDARD_APP_ARGS(args, parse);
02021 
02022    ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
02023 
02024    ast_channel_lock(chan);
02025    /* Set Channel Specific Login Overrides */
02026    if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
02027       max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
02028       if (max_login_tries < 0)
02029          max_login_tries = 0;
02030       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
02031       if (option_verbose > 2)
02032          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);
02033    }
02034    if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
02035       if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
02036          update_cdr = 1;
02037       else
02038          update_cdr = 0;
02039       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
02040       if (option_verbose > 2)
02041          ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
02042    }
02043    if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
02044       strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
02045       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
02046       if (option_verbose > 2)
02047          ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
02048    }
02049    ast_channel_unlock(chan);
02050    /* End Channel Specific Login Overrides */
02051    
02052    if (callbackmode && args.extension) {
02053       parse = args.extension;
02054       args.extension = strsep(&parse, "@");
02055       context = parse;
02056    }
02057 
02058    if (!ast_strlen_zero(args.options)) {
02059       if (strchr(args.options, 's')) {
02060          play_announcement = 0;
02061       }
02062    }
02063 
02064    if (chan->_state != AST_STATE_UP)
02065       res = ast_answer(chan);
02066    if (!res) {
02067       if (!ast_strlen_zero(args.agent_id))
02068          ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
02069       else
02070          res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
02071    }
02072    while (!res && (max_login_tries==0 || tries < max_login_tries)) {
02073       tries++;
02074       /* Check for password */
02075       AST_LIST_LOCK(&agents);
02076       AST_LIST_TRAVERSE(&agents, p, list) {
02077          if (!strcmp(p->agent, user) && !p->pending)
02078             ast_copy_string(xpass, p->password, sizeof(xpass));
02079       }
02080       AST_LIST_UNLOCK(&agents);
02081       if (!res) {
02082          if (!ast_strlen_zero(xpass))
02083             res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
02084          else
02085             pass[0] = '\0';
02086       }
02087       errmsg = "agent-incorrect";
02088 
02089 #if 0
02090       ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
02091 #endif      
02092 
02093       /* Check again for accuracy */
02094       AST_LIST_LOCK(&agents);
02095       AST_LIST_TRAVERSE(&agents, p, list) {
02096          int unlock_channel = 1;
02097          ast_channel_lock(chan);
02098          ast_mutex_lock(&p->lock);
02099          if (!strcmp(p->agent, user) &&
02100              !strcmp(p->password, pass) && !p->pending) {
02101             login_state = 1; /* Successful Login */
02102 
02103             /* Ensure we can't be gotten until we're done */
02104             gettimeofday(&p->lastdisc, NULL);
02105             p->lastdisc.tv_sec++;
02106 
02107             /* Set Channel Specific Agent Overrides */
02108             if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
02109                if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
02110                   p->ackcall = 2;
02111                else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
02112                   p->ackcall = 1;
02113                else
02114                   p->ackcall = 0;
02115                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
02116                if (option_verbose > 2)
02117                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
02118             } else {
02119                p->ackcall = ackcall;
02120             }
02121             if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
02122                p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
02123                if (p->autologoff < 0)
02124                   p->autologoff = 0;
02125                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
02126                if (option_verbose > 2)
02127                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
02128             } else {
02129                p->autologoff = autologoff;
02130             }
02131             if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
02132                p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
02133                if (p->wrapuptime < 0)
02134                   p->wrapuptime = 0;
02135                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
02136                if (option_verbose > 2)
02137                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
02138             } else {
02139                p->wrapuptime = wrapuptime;
02140             }
02141             ast_channel_unlock(chan);
02142             unlock_channel = 0;
02143             /* End Channel Specific Agent Overrides */
02144             if (!p->chan) {
02145                char last_loginchan[80] = "";
02146                long logintime;
02147                snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
02148 
02149                if (callbackmode) {
02150                   int pos = 0;
02151                   /* Retrieve login chan */
02152                   for (;;) {
02153                      if (!ast_strlen_zero(args.extension)) {
02154                         ast_copy_string(tmpchan, args.extension, sizeof(tmpchan));
02155                         res = 0;
02156                      } else
02157                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
02158                      if (ast_strlen_zero(tmpchan) )
02159                         break;
02160                      if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) {
02161                         if(!allow_multiple_login(tmpchan,context) ) {
02162                            args.extension = NULL;
02163                            pos = 0;
02164                         } else
02165                            break;
02166                      }
02167                      if (args.extension) {
02168                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent);
02169                         args.extension = NULL;
02170                         pos = 0;
02171                      } else {
02172                         ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent);
02173                         res = ast_streamfile(chan, "invalid", chan->language);
02174                         if (!res)
02175                            res = ast_waitstream(chan, AST_DIGIT_ANY);
02176                         if (res > 0) {
02177                            tmpchan[0] = res;
02178                            tmpchan[1] = '\0';
02179                            pos = 1;
02180                         } else {
02181                            tmpchan[0] = '\0';
02182                            pos = 0;
02183                         }
02184                      }
02185                   }
02186                   args.extension = tmpchan;
02187                   if (!res) {
02188                      set_agentbycallerid(p->logincallerid, NULL);
02189                      if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
02190                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
02191                      else {
02192                         ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
02193                         ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
02194                      }
02195                      p->acknowledged = 0;
02196                      if (ast_strlen_zero(p->loginchan)) {
02197                         login_state = 2;
02198                         filename = "agent-loggedoff";
02199                      } else {
02200                         if (chan->cid.cid_num) {
02201                            ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
02202                            set_agentbycallerid(p->logincallerid, p->agent);
02203                         } else
02204                            p->logincallerid[0] = '\0';
02205                      }
02206 
02207                      if(update_cdr && chan->cdr)
02208                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02209 
02210                   }
02211                } else {
02212                   p->loginchan[0] = '\0';
02213                   p->logincallerid[0] = '\0';
02214                   p->acknowledged = 0;
02215                }
02216                ast_mutex_unlock(&p->lock);
02217                AST_LIST_UNLOCK(&agents);
02218                if( !res && play_announcement==1 )
02219                   res = ast_streamfile(chan, filename, chan->language);
02220                if (!res)
02221                   ast_waitstream(chan, "");
02222                AST_LIST_LOCK(&agents);
02223                ast_mutex_lock(&p->lock);
02224                if (!res) {
02225                   res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
02226                   if (res)
02227                      ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
02228                }
02229                if (!res) {
02230                   res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
02231                   if (res)
02232                      ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
02233                }
02234                /* Check once more just in case */
02235                if (p->chan)
02236                   res = -1;
02237                if (callbackmode && !res) {
02238                   /* Just say goodbye and be done with it */
02239                   if (!ast_strlen_zero(p->loginchan)) {
02240                      if (p->loginstart == 0)
02241                         time(&p->loginstart);
02242                      manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
02243                               "Agent: %s\r\n"
02244                               "Loginchan: %s\r\n"
02245                               "Uniqueid: %s\r\n",
02246                               p->agent, p->loginchan, chan->uniqueid);
02247                      ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
02248                      if (option_verbose > 1)
02249                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
02250                      ast_device_state_changed("Agent/%s", p->agent);
02251                      if (persistent_agents)
02252                         dump_agents();
02253                   } else {
02254                      logintime = time(NULL) - p->loginstart;
02255                      p->loginstart = 0;
02256 
02257                      agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL);
02258                      if (option_verbose > 1)
02259                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
02260                   }
02261                   AST_LIST_UNLOCK(&agents);
02262                   if (!res)
02263                      res = ast_safe_sleep(chan, 500);
02264                   ast_mutex_unlock(&p->lock);
02265                } else if (!res) {
02266                   ast_indicate_data(chan, AST_CONTROL_HOLD, 
02267                      S_OR(p->moh, NULL), 
02268                      !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
02269                   if (p->loginstart == 0)
02270                      time(&p->loginstart);
02271                   manager_event(EVENT_FLAG_AGENT, "Agentlogin",
02272                            "Agent: %s\r\n"
02273                            "Channel: %s\r\n"
02274                            "Uniqueid: %s\r\n",
02275                            p->agent, chan->name, chan->uniqueid);
02276                   if (update_cdr && chan->cdr)
02277                      snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02278                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
02279                   if (option_verbose > 1)
02280                      ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
02281                             ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
02282                   /* Login this channel and wait for it to go away */
02283                   p->chan = chan;
02284                   if (p->ackcall > 1)
02285                      check_beep(p, 0);
02286                   else
02287                      check_availability(p, 0);
02288                   ast_mutex_unlock(&p->lock);
02289                   AST_LIST_UNLOCK(&agents);
02290                   ast_device_state_changed("Agent/%s", p->agent);
02291                   while (res >= 0) {
02292                      ast_mutex_lock(&p->lock);
02293                      if (p->deferlogoff && p->chan) {
02294                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
02295                         p->deferlogoff = 0;
02296                      }
02297                      if (p->chan != chan)
02298                         res = -1;
02299                      ast_mutex_unlock(&p->lock);
02300                      /* Yield here so other interested threads can kick in. */
02301                      sched_yield();
02302                      if (res)
02303                         break;
02304 
02305                      AST_LIST_LOCK(&agents);
02306                      ast_mutex_lock(&p->lock);
02307                      if (p->lastdisc.tv_sec) {
02308                         if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
02309                            if (option_debug)
02310                               ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
02311                            p->lastdisc = ast_tv(0, 0);
02312                            ast_device_state_changed("Agent/%s", p->agent);
02313                            if (p->ackcall > 1)
02314                               check_beep(p, 0);
02315                            else
02316                               check_availability(p, 0);
02317                         }
02318                      }
02319                      ast_mutex_unlock(&p->lock);
02320                      AST_LIST_UNLOCK(&agents);
02321 
02322                      /* Synchronize channel ownership between call to agent and itself. */
02323                      ast_mutex_lock(&p->lock);
02324                      if (p->app_lock_flag == 1) {
02325                         ast_cond_signal(&p->login_wait_cond);
02326                         ast_cond_wait(&p->app_complete_cond, &p->lock);
02327                      }
02328                      ast_mutex_unlock(&p->lock);
02329 
02330                      if (p->ackcall > 1) 
02331                         res = agent_ack_sleep(p);
02332                      else
02333                         res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
02334                      if ((p->ackcall > 1)  && (res == 1)) {
02335                         AST_LIST_LOCK(&agents);
02336                         ast_mutex_lock(&p->lock);
02337                         check_availability(p, 0);
02338                         ast_mutex_unlock(&p->lock);
02339                         AST_LIST_UNLOCK(&agents);
02340                         res = 0;
02341                      }
02342                      sched_yield();
02343                   }
02344                   ast_mutex_lock(&p->lock);
02345                   /* Log us off if appropriate */
02346                   if (p->chan == chan) {
02347                      p->chan = NULL;
02348                      p->inherited_devicestate = -1;
02349                   }
02350 
02351                   /* Synchronize channel ownership between call to agent and itself. */
02352                   if (p->app_lock_flag == 1) {
02353                      ast_cond_signal(&p->login_wait_cond);
02354                      ast_cond_wait(&p->app_complete_cond, &p->lock);
02355                   }
02356 
02357                   if (res && p->owner)
02358                      ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
02359 
02360                   p->acknowledged = 0;
02361                   logintime = time(NULL) - p->loginstart;
02362                   p->loginstart = 0;
02363                   ast_mutex_unlock(&p->lock);
02364                   manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
02365                            "Agent: %s\r\n"
02366                            "Logintime: %ld\r\n"
02367                            "Uniqueid: %s\r\n",
02368                            p->agent, logintime, chan->uniqueid);
02369                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
02370                   if (option_verbose > 1)
02371                      ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
02372                   /* If there is no owner, go ahead and kill it now */
02373                   ast_device_state_changed("Agent/%s", p->agent);
02374                   if (p->dead && !p->owner) {
02375                      ast_mutex_destroy(&p->lock);
02376                      ast_cond_destroy(&p->app_complete_cond);
02377                      ast_cond_destroy(&p->login_wait_cond);
02378                      free(p);
02379                   }
02380                }
02381                else {
02382                   ast_mutex_unlock(&p->lock);
02383                   p = NULL;
02384                }
02385                res = -1;
02386             } else {
02387                ast_mutex_unlock(&p->lock);
02388                errmsg = "agent-alreadyon";
02389                p = NULL;
02390             }
02391             break;
02392          }
02393          ast_mutex_unlock(&p->lock);
02394          if (unlock_channel) {
02395             ast_channel_unlock(chan);
02396          }
02397       }
02398       if (!p)
02399          AST_LIST_UNLOCK(&agents);
02400 
02401       if (!res && (max_login_tries==0 || tries < max_login_tries))
02402          res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
02403    }
02404       
02405    if (!res)
02406       res = ast_safe_sleep(chan, 500);
02407 
02408    /* AgentLogin() exit */
02409    if (!callbackmode) {
02410       ast_module_user_remove(u);
02411       return -1;
02412    } else { /* AgentCallbackLogin() exit*/
02413       /* Set variables */
02414       if (login_state > 0) {
02415          pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
02416          if (login_state==1) {
02417             pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
02418             pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension);
02419          } else 
02420             pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
02421       } else {
02422          pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
02423       }
02424       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
02425          ast_module_user_remove(u);
02426          return 0;
02427       }
02428       /* Do we need to play agent-goodbye now that we will be hanging up? */
02429       if (play_announcement) {
02430          if (!res)
02431             res = ast_safe_sleep(chan, 1000);
02432          res = ast_streamfile(chan, agent_goodbye, chan->language);
02433          if (!res)
02434             res = ast_waitstream(chan, "");
02435          if (!res)
02436             res = ast_safe_sleep(chan, 1000);
02437       }
02438    }
02439 
02440    ast_module_user_remove(u);
02441    
02442    /* We should never get here if next priority exists when in callbackmode */
02443    return -1;
02444 }

static void __reg_module ( void   )  [static]

Definition at line 2937 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

Definition at line 2937 of file chan_agent.c.

static int action_agent_callback_login ( struct mansession s,
const struct message m 
) [static]

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

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

Definition at line 2495 of file chan_agent.c.

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

Referenced by load_module().

02496 {
02497    const char *agent = astman_get_header(m, "Agent");
02498    const char *exten = astman_get_header(m, "Exten");
02499    const char *context = astman_get_header(m, "Context");
02500    const char *wrapuptime_s = astman_get_header(m, "WrapupTime");
02501    const char *ackcall_s = astman_get_header(m, "AckCall");
02502    struct agent_pvt *p;
02503    int login_state = 0;
02504 
02505    callback_deprecated();
02506 
02507    if (ast_strlen_zero(agent)) {
02508       astman_send_error(s, m, "No agent specified");
02509       return 0;
02510    }
02511 
02512    if (ast_strlen_zero(exten)) {
02513       astman_send_error(s, m, "No extension specified");
02514       return 0;
02515    }
02516 
02517    AST_LIST_LOCK(&agents);
02518    AST_LIST_TRAVERSE(&agents, p, list) {
02519       if (strcmp(p->agent, agent) || p->pending) 
02520          continue;
02521       if (p->chan) {
02522          login_state = 2; /* already logged in (and on the phone)*/
02523          break;
02524       }
02525       ast_mutex_lock(&p->lock);
02526       login_state = 1; /* Successful Login */
02527       
02528       if (ast_strlen_zero(context))
02529          ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
02530       else
02531          snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
02532 
02533       if (!ast_strlen_zero(wrapuptime_s)) {
02534          p->wrapuptime = atoi(wrapuptime_s);
02535          if (p->wrapuptime < 0)
02536             p->wrapuptime = 0;
02537       }
02538 
02539       if (!strcasecmp(ackcall_s, "always"))
02540          p->ackcall = 2;
02541       else if (ast_true(ackcall_s))
02542          p->ackcall = 1;
02543       else
02544          p->ackcall = 0;
02545 
02546       if (p->loginstart == 0)
02547          time(&p->loginstart);
02548       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
02549                "Agent: %s\r\n"
02550                "Loginchan: %s\r\n",
02551                p->agent, p->loginchan);
02552       ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
02553       if (option_verbose > 1)
02554          ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
02555       ast_device_state_changed("Agent/%s", p->agent);
02556       ast_mutex_unlock(&p->lock);
02557       if (persistent_agents)
02558          dump_agents();
02559    }
02560    AST_LIST_UNLOCK(&agents);
02561 
02562    if (login_state == 1)
02563       astman_send_ack(s, m, "Agent logged in");
02564    else if (login_state == 0)
02565       astman_send_error(s, m, "No such agent");
02566    else if (login_state == 2)
02567       astman_send_error(s, m, "Agent already logged in");
02568 
02569    return 0;
02570 }

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

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

Referenced by load_module().

01778 {
01779    const char *agent = astman_get_header(m, "Agent");
01780    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01781    int soft;
01782    int ret; /* return value of agent_logoff */
01783 
01784    if (ast_strlen_zero(agent)) {
01785       astman_send_error(s, m, "No agent specified");
01786       return 0;
01787    }
01788 
01789    soft = ast_true(soft_s) ? 1 : 0;
01790    ret = agent_logoff(agent, soft);
01791    if (ret == 0)
01792       astman_send_ack(s, m, "Agent logged out");
01793    else
01794       astman_send_error(s, m, "No such agent");
01795 
01796    return 0;
01797 }

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

References ast_channel::_bridge, agent_pvt::acknowledged, agent_pvt::agent, ast_bridged_channel(), 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, ast_channel::name, agent_pvt::name, agent_pvt::owner, S_OR, and username.

Referenced by load_module().

01591 {
01592    const char *id = astman_get_header(m,"ActionID");
01593    char idText[256] = "";
01594    char chanbuf[256];
01595    struct agent_pvt *p;
01596    char *username = NULL;
01597    char *loginChan = NULL;
01598    char *talkingtoChan = NULL;
01599    char *status = NULL;
01600 
01601    if (!ast_strlen_zero(id))
01602       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
01603    astman_send_ack(s, m, "Agents will follow");
01604    AST_LIST_LOCK(&agents);
01605    AST_LIST_TRAVERSE(&agents, p, list) {
01606          ast_mutex_lock(&p->lock);
01607 
01608       /* Status Values:
01609          AGENT_LOGGEDOFF - Agent isn't logged in
01610          AGENT_IDLE      - Agent is logged in, and waiting for call
01611          AGENT_ONCALL    - Agent is logged in, and on a call
01612          AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
01613 
01614       username = S_OR(p->name, "None");
01615 
01616       /* Set a default status. It 'should' get changed. */
01617       status = "AGENT_UNKNOWN";
01618 
01619       if (!ast_strlen_zero(p->loginchan) && !p->chan) {
01620          loginChan = p->loginchan;
01621          talkingtoChan = "n/a";
01622          status = "AGENT_IDLE";
01623          if (p->acknowledged) {
01624             snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
01625             loginChan = chanbuf;
01626          }
01627       } else if (p->chan) {
01628          loginChan = ast_strdupa(p->chan->name);
01629          if (p->owner && p->owner->_bridge) {
01630             if (ast_bridged_channel(p->owner)) {
01631                talkingtoChan = ast_strdupa(S_OR(ast_bridged_channel(p->owner)->cid.cid_num, ""));
01632             } else {
01633                talkingtoChan = "n/a";
01634             }
01635                status = "AGENT_ONCALL";
01636          } else {
01637                talkingtoChan = "n/a";
01638                status = "AGENT_IDLE";
01639          }
01640       } else {
01641          loginChan = "n/a";
01642          talkingtoChan = "n/a";
01643          status = "AGENT_LOGGEDOFF";
01644       }
01645 
01646       astman_append(s, "Event: Agents\r\n"
01647          "Agent: %s\r\n"
01648          "Name: %s\r\n"
01649          "Status: %s\r\n"
01650          "LoggedInChan: %s\r\n"
01651          "LoggedInTime: %d\r\n"
01652          "TalkingTo: %s\r\n"
01653          "%s"
01654          "\r\n",
01655          p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText);
01656       ast_mutex_unlock(&p->lock);
01657    }
01658    AST_LIST_UNLOCK(&agents);
01659    astman_append(s, "Event: AgentsComplete\r\n"
01660       "%s"
01661       "\r\n",idText);
01662    return 0;
01663 }

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

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

References agent_pvt::ackcall, agent_pvt::agent, agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, AST_APP_ARG, ast_calloc, ast_cond_init(), ast_copy_string(), 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(), ast_tvnow(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::group, agent_pvt::inherited_devicestate, agent_pvt::lastdisc, agent_pvt::lock, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, agent_pvt::pending, and agent_pvt::wrapuptime.

Referenced by agent_request(), and read_agent_config().

00339 {
00340    char *parse;
00341    AST_DECLARE_APP_ARGS(args,
00342       AST_APP_ARG(agt);
00343       AST_APP_ARG(password);
00344       AST_APP_ARG(name);
00345    );
00346    char *password = NULL;
00347    char *name = NULL;
00348    char *agt = NULL;
00349    struct agent_pvt *p;
00350 
00351    parse = ast_strdupa(agent);
00352 
00353    /* Extract username (agt), password and name from agent (args). */
00354    AST_NONSTANDARD_APP_ARGS(args, parse, ',');
00355 
00356    if(args.argc == 0) {
00357       ast_log(LOG_WARNING, "A blank agent line!\n");
00358       return NULL;
00359    }
00360 
00361    if(ast_strlen_zero(args.agt) ) {
00362       ast_log(LOG_WARNING, "An agent line with no agentid!\n");
00363       return NULL;
00364    } else
00365       agt = args.agt;
00366 
00367    if(!ast_strlen_zero(args.password)) {
00368       password = args.password;
00369       while (*password && *password < 33) password++;
00370    }
00371    if(!ast_strlen_zero(args.name)) {
00372       name = args.name;
00373       while (*name && *name < 33) name++;
00374    }
00375    
00376    /* Are we searching for the agent here ? To see if it exists already ? */
00377    AST_LIST_TRAVERSE(&agents, p, list) {
00378       if (!pending && !strcmp(p->agent, agt))
00379          break;
00380    }
00381    if (!p) {
00382       // Build the agent.
00383       if (!(p = ast_calloc(1, sizeof(*p))))
00384          return NULL;
00385       ast_copy_string(p->agent, agt, sizeof(p->agent));
00386       ast_mutex_init(&p->lock);
00387       ast_cond_init(&p->app_complete_cond, NULL);
00388       ast_cond_init(&p->login_wait_cond, NULL);
00389       p->app_lock_flag = 0;
00390       p->app_sleep_cond = 1;
00391       p->group = group;
00392       p->pending = pending;
00393       p->inherited_devicestate = -1;
00394       AST_LIST_INSERT_TAIL(&agents, p, list);
00395    }
00396    
00397    ast_copy_string(p->password, password ? password : "", sizeof(p->password));
00398    ast_copy_string(p->name, name ? name : "", sizeof(p->name));
00399    ast_copy_string(p->moh, moh, sizeof(p->moh));
00400    p->ackcall = ackcall;
00401    p->autologoff = autologoff;
00402 
00403    /* If someone reduces the wrapuptime and reloads, we want it
00404     * to change the wrapuptime immediately on all calls */
00405    if (p->wrapuptime > wrapuptime) {
00406       struct timeval now = ast_tvnow();
00407       /* XXX check what is this exactly */
00408 
00409       /* We won't be pedantic and check the tv_usec val */
00410       if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
00411          p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
00412          p->lastdisc.tv_usec = now.tv_usec;
00413       }
00414    }
00415    p->wrapuptime = wrapuptime;
00416 
00417    if (pending)
00418       p->dead = 1;
00419    else
00420       p->dead = 0;
00421    return p;
00422 }

static int agent_ack_sleep ( void *  data  )  [static]

Definition at line 1037 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, f, ast_frame::frametype, agent_pvt::lock, and ast_frame::subclass.

Referenced by __login_exec().

01038 {
01039    struct agent_pvt *p;
01040    int res=0;
01041    int to = 1000;
01042    struct ast_frame *f;
01043 
01044    /* Wait a second and look for something */
01045 
01046    p = (struct agent_pvt *) data;
01047    if (!p->chan) 
01048       return -1;
01049 
01050    for(;;) {
01051       to = ast_waitfor(p->chan, to);
01052       if (to < 0) 
01053          return -1;
01054       if (!to) 
01055          return 0;
01056       f = ast_read(p->chan);
01057       if (!f) 
01058          return -1;
01059       if (f->frametype == AST_FRAME_DTMF)
01060          res = f->subclass;
01061       else
01062          res = 0;
01063       ast_frfree(f);
01064       ast_mutex_lock(&p->lock);
01065       if (!p->app_sleep_cond) {
01066          ast_mutex_unlock(&p->lock);
01067          return 0;
01068       } else if (res == '#') {
01069          ast_mutex_unlock(&p->lock);
01070          return 1;
01071       }
01072       ast_mutex_unlock(&p->lock);
01073       res = 0;
01074    }
01075    return res;
01076 }

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 457 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00458 {
00459    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00460    return -1;
00461 }

static struct ast_channel * agent_bridgedchannel ( struct ast_channel chan,
struct ast_channel bridge 
) [static, read]

Definition at line 1078 of file chan_agent.c.

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

01079 {
01080    struct agent_pvt *p = bridge->tech_pvt;
01081    struct ast_channel *ret = NULL;
01082 
01083    if (p) {
01084       if (chan == p->chan)
01085          ret = bridge->_bridge;
01086       else if (chan == bridge->_bridge)
01087          ret = p->chan;
01088    }
01089 
01090    if (option_debug)
01091       ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
01092    return ret;
01093 }

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

Definition at line 754 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_device_state_changed(), 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::inherited_devicestate, ast_channel::language, agent_pvt::lock, LOG_DEBUG, LOG_WARNING, agent_pvt::loginchan, ast_channel::name, ast_channel::nativeformats, option_debug, option_verbose, agent_pvt::pending, agent_pvt::start, ast_channel::tech_pvt, and VERBOSE_PREFIX_3.

00755 {
00756    struct agent_pvt *p = ast->tech_pvt;
00757    int res = -1;
00758    int newstate=0;
00759    struct ast_channel *chan;
00760 
00761    ast_mutex_lock(&p->lock);
00762    p->acknowledged = 0;
00763 
00764    if (p->pending) {
00765       ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
00766       ast_mutex_unlock(&p->lock);
00767       ast_setstate(ast, AST_STATE_DIALING);
00768       return 0;
00769    }
00770 
00771    if (!p->chan) {
00772       ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
00773       ast_mutex_unlock(&p->lock);
00774       return res;
00775    }
00776 
00777    if (!ast_strlen_zero(p->loginchan)) {
00778       time(&p->start);
00779       /* Call on this agent */
00780       if (option_verbose > 2)
00781          ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
00782       ast_set_callerid(p->chan,
00783          ast->cid.cid_num, ast->cid.cid_name, NULL);
00784       ast_channel_inherit_variables(ast, p->chan);
00785       res = ast_call(p->chan, p->loginchan, 0);
00786       CLEANUP(ast,p);
00787       ast_mutex_unlock(&p->lock);
00788       return res;
00789    }
00790    if (option_verbose > 2)
00791       ast_verbose(VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
00792    if (option_debug > 2)
00793       ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
00794 
00795    chan = p->chan;
00796    ast_mutex_unlock(&p->lock);
00797 
00798    res = ast_streamfile(chan, beep, chan->language);
00799    if (option_debug > 2)
00800       ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res);
00801    if (!res) {
00802       res = ast_waitstream(chan, "");
00803       if (option_debug > 2)
00804          ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res);
00805    }
00806 
00807    ast_mutex_lock(&p->lock);
00808    if (!p->chan) {
00809       /* chan went away while we were streaming, this shouldn't be possible */
00810       res = -1;
00811    }
00812 
00813    if (!res) {
00814       res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
00815       if (option_debug > 2)
00816          ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res);
00817       if (res)
00818          ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00819    } else {
00820       /* Agent hung-up */
00821       p->chan = NULL;
00822       p->inherited_devicestate = -1;
00823       ast_device_state_changed("Agent/%s", p->agent);
00824    }
00825 
00826    if (!res) {
00827       res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
00828       if (option_debug > 2)
00829          ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res);
00830       if (res)
00831          ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00832    }
00833    if(!res) {
00834       /* Call is immediately up, or might need ack */
00835       if (p->ackcall > 1)
00836          newstate = AST_STATE_RINGING;
00837       else {
00838          newstate = AST_STATE_UP;
00839          if (recordagentcalls)
00840             agent_start_monitoring(ast, 0);
00841          p->acknowledged = 1;
00842       }
00843       res = 0;
00844    }
00845    CLEANUP(ast, p);
00846    ast_mutex_unlock(&p->lock);
00847    if (newstate)
00848       ast_setstate(ast, newstate);
00849    return res;
00850 }

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

References agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_free(), ast_cond_destroy(), ast_cond_signal(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::dead, free, agent_pvt::lock, agent_pvt::login_wait_cond, agent_pvt::owner, and ast_channel::tech_pvt.

Referenced by check_availability().

00431 {
00432    struct ast_channel *chan = NULL;
00433    ast_mutex_lock(&p->lock);
00434    chan = p->owner;
00435    p->owner = NULL;
00436    chan->tech_pvt = NULL;
00437    /* Release ownership of the agent to other threads (presumably running the login app). */
00438    p->app_sleep_cond = 1;
00439    p->app_lock_flag = 0;
00440    ast_cond_signal(&p->app_complete_cond);
00441    if (chan)
00442       ast_channel_free(chan);
00443    if (p->dead) {
00444       ast_mutex_unlock(&p->lock);
00445       ast_mutex_destroy(&p->lock);
00446       ast_cond_destroy(&p->app_complete_cond);
00447       ast_cond_destroy(&p->login_wait_cond);
00448       free(p);
00449         } else {
00450       ast_mutex_unlock(&p->lock);
00451    }
00452    return 0;
00453 }

static int agent_cont_sleep ( void *  data  )  [static]

Definition at line 1016 of file chan_agent.c.

References agent_pvt::app_sleep_cond, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_tvdiff_ms(), ast_tvnow(), agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, and option_debug.

Referenced by __login_exec().

01017 {
01018    struct agent_pvt *p;
01019    int res;
01020 
01021    p = (struct agent_pvt *)data;
01022 
01023    ast_mutex_lock(&p->lock);
01024    res = p->app_sleep_cond;
01025    if (p->lastdisc.tv_sec) {
01026       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
01027          res = 1;
01028    }
01029    ast_mutex_unlock(&p->lock);
01030 
01031    if(option_debug > 4 && !res )
01032       ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
01033 
01034    return res;
01035 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

Definition at line 2716 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::inherited_devicestate, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.

02717 {
02718    struct agent_pvt *p;
02719    char *s;
02720    ast_group_t groupmatch;
02721    int groupoff;
02722    int waitforagent=0;
02723    int res = AST_DEVICE_INVALID;
02724    
02725    s = data;
02726    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1))
02727       groupmatch = (1 << groupoff);
02728    else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
02729       groupmatch = (1 << groupoff);
02730       waitforagent = 1;
02731    } else 
02732       groupmatch = 0;
02733 
02734    /* Check actual logged in agents first */
02735    AST_LIST_LOCK(&agents);
02736    AST_LIST_TRAVERSE(&agents, p, list) {
02737       ast_mutex_lock(&p->lock);
02738       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02739          if (p->owner) {
02740             if (res != AST_DEVICE_INUSE)
02741                res = AST_DEVICE_BUSY;
02742          } else if (p->inherited_devicestate > -1) {
02743             res = p->inherited_devicestate;
02744          } else {
02745             if (res == AST_DEVICE_BUSY)
02746                res = AST_DEVICE_INUSE;
02747             if (p->chan || !ast_strlen_zero(p->loginchan)) {
02748                if (res == AST_DEVICE_INVALID)
02749                   res = AST_DEVICE_UNKNOWN;
02750             } else if (res == AST_DEVICE_INVALID)  
02751                res = AST_DEVICE_UNAVAILABLE;
02752          }
02753          if (!strcmp(data, p->agent)) {
02754             ast_mutex_unlock(&p->lock);
02755             break;
02756          }
02757       }
02758       ast_mutex_unlock(&p->lock);
02759    }
02760    AST_LIST_UNLOCK(&agents);
02761    return res;
02762 }

static int agent_devicestate_cb ( const char *  dev,
int  state,
void *  data 
) [static]

Definition at line 291 of file chan_agent.c.

References agent_pvt::agent, AST_CHANNEL_NAME, ast_copy_string(), ast_device_state_changed(), AST_LIST_TRAVERSE, AST_LIST_TRYLOCK, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), agent_pvt::chan, agent_pvt::inherited_devicestate, agent_pvt::lock, agent_pvt::loginchan, and ast_channel::name.

Referenced by load_module(), and unload_module().

00292 {
00293    int res, i;
00294    struct agent_pvt *p;
00295    char basename[AST_CHANNEL_NAME], *tmp;
00296 
00297    /* Skip Agent status */
00298    if (!strncasecmp(dev, "Agent/", 6)) {
00299       return 0;
00300    }
00301 
00302    /* Try to be safe, but don't deadlock */
00303    for (i = 0; i < 10; i++) {
00304       if ((res = AST_LIST_TRYLOCK(&agents)) == 0) {
00305          break;
00306       }
00307    }
00308    if (res) {
00309       return -1;
00310    }
00311 
00312    AST_LIST_TRAVERSE(&agents, p, list) {
00313       ast_mutex_lock(&p->lock);
00314       if (p->chan && !ast_strlen_zero(p->loginchan)) {
00315          ast_copy_string(basename, p->chan->name, sizeof(basename));
00316          if ((tmp = strrchr(basename, '-'))) {
00317             *tmp = '\0';
00318          }
00319          if (strcasecmp(p->chan->name, dev) == 0 || strcasecmp(basename, dev) == 0) {
00320             p->inherited_devicestate = state;
00321             ast_device_state_changed("Agent/%s", p->agent);
00322          }
00323       }
00324       ast_mutex_unlock(&p->lock);
00325    }
00326    AST_LIST_UNLOCK(&agents);
00327    return 0;
00328 }

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

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

00733 {
00734    struct agent_pvt *p = ast->tech_pvt;
00735    ast_mutex_lock(&p->lock);
00736    if (p->chan) {
00737       ast_senddigit_begin(p->chan, digit);
00738    }
00739    ast_mutex_unlock(&p->lock);
00740    return 0;
00741 }

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

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

00744 {
00745    struct agent_pvt *p = ast->tech_pvt;
00746    ast_mutex_lock(&p->lock);
00747    if (p->chan) {
00748       ast_senddigit_end(p->chan, digit, duration);
00749    }
00750    ast_mutex_unlock(&p->lock);
00751    return 0;
00752 }

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

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

00695 {
00696    struct agent_pvt *p = newchan->tech_pvt;
00697    ast_mutex_lock(&p->lock);
00698    if (p->owner != oldchan) {
00699       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00700       ast_mutex_unlock(&p->lock);
00701       return -1;
00702    }
00703    p->owner = newchan;
00704    ast_mutex_unlock(&p->lock);
00705    return 0;
00706 }

struct ast_channel * agent_get_base_channel ( struct ast_channel chan  )  [static, read]

return the channel or base channel if one exists. This function assumes the channel it is called on is already locked

Definition at line 866 of file chan_agent.c.

References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.

00867 {
00868    struct agent_pvt *p = NULL;
00869    struct ast_channel *base = chan;
00870 
00871    /* chan is locked by the calling function */
00872    if (!chan || !chan->tech_pvt) {
00873       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) with a tech_pvt (0x%ld) to get a base channel.\n", (long)chan, (chan)?(long)chan->tech_pvt:(long)NULL);
00874       return NULL;
00875    }
00876    p = chan->tech_pvt;
00877    if (p->chan) 
00878       base = p->chan;
00879    return base;
00880 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 899 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_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_signal(), 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_samp2tv(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_state2str(), AST_STATE_RESERVED, AST_STATE_UP, ast_strlen_zero(), ast_tv(), ast_tvadd(), ast_tvnow(), agent_pvt::autologoff, agent_pvt::chan, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), free, agent_pvt::inherited_devicestate, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::login_wait_cond, agent_pvt::logincallerid, 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, ast_channel::uniqueid, and agent_pvt::wrapuptime.

Referenced by agent_request().

00900 {
00901    struct agent_pvt *p = ast->tech_pvt;
00902    int howlong = 0;
00903    const char *status;
00904    ast_mutex_lock(&p->lock);
00905    p->owner = NULL;
00906    ast->tech_pvt = NULL;
00907    p->app_sleep_cond = 1;
00908    p->acknowledged = 0;
00909 
00910    /* Release ownership of the agent to other threads (presumably running the login app). */
00911    if (ast_strlen_zero(p->loginchan)) {
00912       p->app_lock_flag = 0;
00913       ast_cond_signal(&p->app_complete_cond);
00914    }
00915 
00916    /* if they really are hung up then set start to 0 so the test
00917     * later if we're called on an already downed channel
00918     * doesn't cause an agent to be logged out like when
00919     * agent_request() is followed immediately by agent_hangup()
00920     * as in apps/app_chanisavail.c:chanavail_exec()
00921     */
00922 
00923    if (option_debug)
00924       ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
00925    if (p->start && (ast->_state != AST_STATE_UP)) {
00926       howlong = time(NULL) - p->start;
00927       p->start = 0;
00928    } else if (ast->_state == AST_STATE_RESERVED) 
00929       howlong = 0;
00930    else
00931       p->start = 0; 
00932    if (p->chan) {
00933       p->chan->_bridge = NULL;
00934       /* If they're dead, go ahead and hang up on the agent now */
00935       if (!ast_strlen_zero(p->loginchan)) {
00936          /* Store last disconnect time */
00937          if (p->wrapuptime)
00938             p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00939          else
00940             p->lastdisc = ast_tv(0,0);
00941          if (p->chan) {
00942             status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00943             if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00944                long logintime = time(NULL) - p->loginstart;
00945                p->loginstart = 0;
00946                ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
00947                agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00948             }
00949             /* Recognize the hangup and pass it along immediately */
00950             ast_hangup(p->chan);
00951             p->chan = NULL;
00952             p->inherited_devicestate = -1;
00953             ast_device_state_changed("Agent/%s", p->agent);
00954          }
00955          ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
00956          if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) {
00957             long logintime = time(NULL) - p->loginstart;
00958             p->loginstart = 0;
00959             if (!p->deferlogoff)
00960                ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00961             p->deferlogoff = 0;
00962             agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
00963             if (persistent_agents)
00964                dump_agents();
00965          }
00966       } else if (p->dead) {
00967          ast_channel_lock(p->chan);
00968          ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00969          ast_channel_unlock(p->chan);
00970       } else if (p->loginstart) {
00971          ast_channel_lock(p->chan);
00972          ast_indicate_data(p->chan, AST_CONTROL_HOLD, 
00973             S_OR(p->moh, NULL),
00974             !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
00975          ast_channel_unlock(p->chan);
00976       }
00977    }
00978    ast_mutex_unlock(&p->lock);
00979 
00980    /* Only register a device state change if the agent is still logged in */
00981    if (!p->loginstart) {
00982       p->loginchan[0] = '\0';
00983       p->logincallerid[0] = '\0';
00984       if (persistent_agents)
00985          dump_agents();
00986    } else {
00987       ast_device_state_changed("Agent/%s", p->agent);
00988    }
00989 
00990    if (p->pending) {
00991       AST_LIST_LOCK(&agents);
00992       AST_LIST_REMOVE(&agents, p, list);
00993       AST_LIST_UNLOCK(&agents);
00994    }
00995    if (p->abouttograb) {
00996       /* Let the "about to grab" thread know this isn't valid anymore, and let it
00997          kill it later */
00998       p->abouttograb = 0;
00999    } else if (p->dead) {
01000       ast_mutex_destroy(&p->lock);
01001       ast_cond_destroy(&p->app_complete_cond);
01002       ast_cond_destroy(&p->login_wait_cond);
01003       free(p);
01004    } else {
01005       if (p->chan) {
01006          /* Not dead -- check availability now */
01007          ast_mutex_lock(&p->lock);
01008          /* Store last disconnect time */
01009          p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
01010          ast_mutex_unlock(&p->lock);
01011       }
01012    }
01013    return 0;
01014 }

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

Definition at line 708 of file chan_agent.c.

References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, ast_channel_tech::indicate, agent_pvt::lock, LOG_ERROR, ast_channel::tech, and ast_channel::tech_pvt.

00709 {
00710    struct agent_pvt *p = ast->tech_pvt;
00711    int res = -1;
00712    ast_mutex_lock(&p->lock);
00713    if (p->chan && !ast_check_hangup(p->chan)) {
00714       while (ast_channel_trylock(p->chan)) {
00715          int res;
00716          if ((res = ast_channel_unlock(ast))) {
00717             ast_log(LOG_ERROR, "chan_agent bug! Channel was not locked upon entry to agent_indicate: %s\n", strerror(res));
00718             ast_mutex_unlock(&p->lock);
00719             return -1;
00720          }
00721          usleep(1);
00722          ast_channel_lock(ast);
00723       }
00724       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00725       ast_channel_unlock(p->chan);
00726    } else
00727       res = 0;
00728    ast_mutex_unlock(&p->lock);
00729    return res;
00730 }

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

Definition at line 1705 of file chan_agent.c.

References agent_pvt::agent, agent_logoff_maintenance(), ast_channel_trylock, ast_channel_unlock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agent_pvt::chan, DEADLOCK_AVOIDANCE, agent_pvt::deferlogoff, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, and agent_pvt::owner.

Referenced by action_agent_logoff(), and agent_logoff_cmd().

01706 {
01707    struct agent_pvt *p;
01708    long logintime;
01709    int ret = -1; /* Return -1 if no agent if found */
01710 
01711    AST_LIST_LOCK(&agents);
01712    AST_LIST_TRAVERSE(&agents, p, list) {
01713       if (!strcasecmp(p->agent, agent)) {
01714          ret = 0;
01715          if (p->owner || p->chan) {
01716             if (!soft) {
01717                ast_mutex_lock(&p->lock);
01718 
01719                while (p->owner && ast_channel_trylock(p->owner)) {
01720                   DEADLOCK_AVOIDANCE(&p->lock);
01721                }
01722                if (p->owner) {
01723                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01724                   ast_channel_unlock(p->owner);
01725                }
01726 
01727                while (p->chan && ast_channel_trylock(p->chan)) {
01728                   DEADLOCK_AVOIDANCE(&p->lock);
01729                }
01730                if (p->chan) {
01731                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01732                   ast_channel_unlock(p->chan);
01733                }
01734 
01735                ast_mutex_unlock(&p->lock);
01736             } else
01737                p->deferlogoff = 1;
01738          } else {
01739             logintime = time(NULL) - p->loginstart;
01740             p->loginstart = 0;
01741             agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
01742          }
01743          break;
01744       }
01745    }
01746    AST_LIST_UNLOCK(&agents);
01747 
01748    return ret;
01749 }

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

Definition at line 1751 of file chan_agent.c.

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

01752 {
01753    int ret;
01754    char *agent;
01755 
01756    if (argc < 3 || argc > 4)
01757       return RESULT_SHOWUSAGE;
01758    if (argc == 4 && strcasecmp(argv[3], "soft"))
01759       return RESULT_SHOWUSAGE;
01760 
01761    agent = argv[2] + 6;
01762    ret = agent_logoff(agent, argc == 4);
01763    if (ret == 0)
01764       ast_cli(fd, "Logging out %s\n", agent);
01765 
01766    return RESULT_SUCCESS;
01767 }

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

Definition at line 1665 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::inherited_devicestate, agent_pvt::logincallerid, agent_pvt::loginchan, manager_event(), and set_agentbycallerid().

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

01666 {
01667    char *tmp = NULL;
01668    char agent[AST_MAX_AGENT];
01669 
01670    if (!ast_strlen_zero(logcommand))
01671       tmp = logcommand;
01672    else
01673       tmp = ast_strdupa("");
01674 
01675    snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01676 
01677    if (!ast_strlen_zero(uniqueid)) {
01678       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01679             "Agent: %s\r\n"
01680             "Reason: %s\r\n"
01681             "Loginchan: %s\r\n"
01682             "Logintime: %ld\r\n"
01683             "Uniqueid: %s\r\n", 
01684             p->agent, tmp, loginchan, logintime, uniqueid);
01685    } else {
01686       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01687             "Agent: %s\r\n"
01688             "Reason: %s\r\n"
01689             "Loginchan: %s\r\n"
01690             "Logintime: %ld\r\n",
01691             p->agent, tmp, loginchan, logintime);
01692    }
01693 
01694    ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
01695    set_agentbycallerid(p->logincallerid, NULL);
01696    p->loginchan[0] ='\0';
01697    p->logincallerid[0] = '\0';
01698    p->inherited_devicestate = -1;
01699    ast_device_state_changed("Agent/%s", p->agent);
01700    if (persistent_agents)
01701       dump_agents();
01702 
01703 }

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

Create new agent channel.

Definition at line 1096 of file chan_agent.c.

References agent_pvt::agent, agent_tech, ast_atomic_fetchadd_int(), ast_channel_alloc(), ast_copy_string(), AST_FORMAT_SLINEAR, ast_log(), ast_random(), ast_string_field_set, ast_update_use_count(), agent_pvt::chan, ast_channel::context, ast_channel::exten, ast_channel::language, language, LOG_WARNING, ast_channel::nativeformats, agent_pvt::owner, 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().

01097 {
01098    struct ast_channel *tmp;
01099 #if 0
01100    if (!p->chan) {
01101       ast_log(LOG_WARNING, "No channel? :(\n");
01102       return NULL;
01103    }
01104 #endif   
01105    if (p->pending)
01106       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/P%s-%d", p->agent, (int) ast_random() & 0xffff);
01107    else
01108       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent);
01109    if (!tmp) {
01110       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
01111       return NULL;
01112    }
01113 
01114    tmp->tech = &agent_tech;
01115    if (p->chan) {
01116       tmp->nativeformats = p->chan->nativeformats;
01117       tmp->writeformat = p->chan->writeformat;
01118       tmp->rawwriteformat = p->chan->writeformat;
01119       tmp->readformat = p->chan->readformat;
01120       tmp->rawreadformat = p->chan->readformat;
01121       ast_string_field_set(tmp, language, p->chan->language);
01122       ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
01123       ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
01124       /* XXX Is this really all we copy form the originating channel?? */
01125    } else {
01126       tmp->nativeformats = AST_FORMAT_SLINEAR;
01127       tmp->writeformat = AST_FORMAT_SLINEAR;
01128       tmp->rawwriteformat = AST_FORMAT_SLINEAR;
01129       tmp->readformat = AST_FORMAT_SLINEAR;
01130       tmp->rawreadformat = AST_FORMAT_SLINEAR;
01131    }
01132    /* Safe, agentlock already held */
01133    tmp->tech_pvt = p;
01134    p->owner = tmp;
01135    /* XXX: this needs fixing */
01136 #if 0
01137    ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1);
01138 #endif
01139    ast_update_use_count();
01140    tmp->priority = 1;
01141    return tmp;
01142 }

static struct ast_frame * agent_read ( struct ast_channel ast  )  [static, read]

Definition at line 496 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, ast_channel_trylock, ast_channel_unlock, AST_CONTROL_ANSWER, ast_copy_flags, ast_device_state_changed(), 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_samp2tv(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_tvnow(), ast_verbose(), agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, DEADLOCK_AVOIDANCE, f, ast_channel::fdno, ast_frame::frametype, agent_pvt::inherited_devicestate, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, ast_channel::name, option_verbose, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::start, ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, ast_channel::uniqueid, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

00497 {
00498    struct agent_pvt *p = ast->tech_pvt;
00499    struct ast_frame *f = NULL;
00500    static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00501    const char *status;
00502    int cur_time = time(NULL);
00503    ast_mutex_lock(&p->lock);
00504    CHECK_FORMATS(ast, p);
00505    if (!p->start) {
00506       p->start = cur_time;
00507    }
00508    if (p->chan) {
00509       ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
00510       p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
00511       f = ast_read(p->chan);
00512    } else
00513       f = &ast_null_frame;
00514    if (!f) {
00515       /* If there's a channel, hang it up (if it's on a callback) make it NULL */
00516       if (p->chan) {
00517          p->chan->_bridge = NULL;
00518          /* Note that we don't hangup if it's not a callback because Asterisk will do it
00519             for us when the PBX instance that called login finishes */
00520          if (!ast_strlen_zero(p->loginchan)) {
00521             if (p->chan)
00522                ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
00523             if (p->owner->_state != AST_STATE_UP) {
00524                int howlong = cur_time - p->start;
00525                if (p->autologoff && howlong >= p->autologoff) {
00526                   p->loginstart = 0;
00527                      ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00528                   agent_logoff_maintenance(p, p->loginchan, (cur_time = p->loginstart), ast->uniqueid, "Autologoff");
00529                }
00530             }
00531             status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00532             if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00533                long logintime = cur_time - p->loginstart;
00534                p->loginstart = 0;
00535                ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name);
00536                agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00537             }
00538             ast_hangup(p->chan);
00539             if (p->wrapuptime && p->acknowledged)
00540                p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00541          }
00542          p->chan = NULL;
00543          p->inherited_devicestate = -1;
00544          ast_device_state_changed("Agent/%s", p->agent);
00545          p->acknowledged = 0;
00546       }
00547    } else {
00548       /* if acknowledgement is not required, and the channel is up, we may have missed
00549          an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
00550       if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) {
00551          p->acknowledged = 1;
00552       }
00553       if (!p->acknowledged) {
00554          int howlong = cur_time - p->start;
00555          if (p->autologoff && (howlong >= p->autologoff)) {
00556             ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00557             agent_logoff_maintenance(p, p->loginchan, (cur_time - p->loginstart), ast->uniqueid, "Autologoff");
00558             if (p->owner || p->chan) {
00559                while (p->owner && ast_channel_trylock(p->owner)) {
00560                   DEADLOCK_AVOIDANCE(&p->lock);
00561                }
00562                if (p->owner) {
00563                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
00564                   ast_channel_unlock(p->owner);
00565                }
00566 
00567                while (p->chan && ast_channel_trylock(p->chan)) {
00568                   DEADLOCK_AVOIDANCE(&p->lock);
00569                }
00570                if (p->chan) {
00571                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00572                   ast_channel_unlock(p->chan);
00573                }
00574             } else {
00575                long logintime;
00576                logintime = time(NULL) - p->loginstart;
00577                p->loginstart = 0;
00578                agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
00579             }
00580          }
00581       }
00582       switch (f->frametype) {
00583       case AST_FRAME_CONTROL:
00584          if (f->subclass == AST_CONTROL_ANSWER) {
00585             if (p->ackcall) {
00586                if (option_verbose > 2)
00587                   ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
00588                /* Don't pass answer along */
00589                ast_frfree(f);
00590                f = &ast_null_frame;
00591             } else {
00592                p->acknowledged = 1;
00593                /* Use the builtin answer frame for the 
00594                   recording start check below. */
00595                ast_frfree(f);
00596                f = &answer_frame;
00597             }
00598          }
00599          break;
00600       case AST_FRAME_DTMF_BEGIN:
00601          /*ignore DTMF begin's as it can cause issues with queue announce files*/
00602          if((!p->acknowledged && f->subclass == '#') || (f->subclass == '*' && endcall)){
00603             ast_frfree(f);
00604             f = &ast_null_frame;
00605          }
00606          break;
00607       case AST_FRAME_DTMF_END:
00608          if (!p->acknowledged && (f->subclass == '#')) {
00609             if (option_verbose > 2)
00610                ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
00611             p->acknowledged = 1;
00612             ast_frfree(f);
00613             f = &answer_frame;
00614          } else if (f->subclass == '*' && endcall) {
00615             /* terminates call */
00616             ast_frfree(f);
00617             f = NULL;
00618          }
00619          break;
00620       case AST_FRAME_VOICE:
00621       case AST_FRAME_VIDEO:
00622          /* don't pass voice or video until the call is acknowledged */
00623          if (!p->acknowledged) {
00624             ast_frfree(f);
00625             f = &ast_null_frame;
00626          }
00627       default:
00628          /* pass everything else on through */
00629          break;
00630       }
00631    }
00632 
00633    CLEANUP(ast,p);
00634    if (p->chan && !p->chan->_bridge) {
00635       if (strcasecmp(p->chan->tech->type, "Local")) {
00636          p->chan->_bridge = ast;
00637          if (p->chan)
00638             ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
00639       }
00640    }
00641    ast_mutex_unlock(&p->lock);
00642    if (recordagentcalls && f == &answer_frame)
00643       agent_start_monitoring(ast,0);
00644    return f;
00645 }

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

Part of the Asterisk PBX interface.

Definition at line 1436 of file chan_agent.c.

References add_agent(), agent_pvt::agent, agent_hangup(), agent_new(), agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_cond_signal(), ast_cond_wait(), AST_CONTROL_UNHOLD, ast_indicate(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_queue_frame(), ast_request(), AST_STATE_DOWN, ast_strlen_zero(), ast_tv(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::loginchan, option_debug, agent_pvt::owner, agent_pvt::pending, and s.

01437 {
01438    struct agent_pvt *p;
01439    struct ast_channel *chan = NULL;
01440    char *s;
01441    ast_group_t groupmatch;
01442    int groupoff;
01443    int waitforagent=0;
01444    int hasagent = 0;
01445    struct timeval tv;
01446 
01447    s = data;
01448    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01449       groupmatch = (1 << groupoff);
01450    } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01451       groupmatch = (1 << groupoff);
01452       waitforagent = 1;
01453    } else 
01454       groupmatch = 0;
01455 
01456    /* Check actual logged in agents first */
01457    AST_LIST_LOCK(&agents);
01458    AST_LIST_TRAVERSE(&agents, p, list) {
01459       ast_mutex_lock(&p->lock);
01460       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
01461           ast_strlen_zero(p->loginchan)) {
01462          if (p->chan)
01463             hasagent++;
01464          tv = ast_tvnow();
01465          if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
01466             p->lastdisc = ast_tv(0, 0);
01467             /* Agent must be registered, but not have any active call, and not be in a waiting state */
01468             if (!p->owner && p->chan) {
01469                /* Fixed agent */
01470                chan = agent_new(p, AST_STATE_DOWN);
01471             }
01472             if (chan) {
01473                ast_mutex_unlock(&p->lock);
01474                break;
01475             }
01476          }
01477       }
01478       ast_mutex_unlock(&p->lock);
01479    }
01480    if (!p) {
01481       AST_LIST_TRAVERSE(&agents, p, list) {
01482          ast_mutex_lock(&p->lock);
01483          if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01484             if (p->chan || !ast_strlen_zero(p->loginchan))
01485                hasagent++;
01486             tv = ast_tvnow();
01487 #if 0
01488             ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
01489 #endif
01490             if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
01491                p->lastdisc = ast_tv(0, 0);
01492                /* Agent must be registered, but not have any active call, and not be in a waiting state */
01493                if (!p->owner && p->chan) {
01494                   /* Could still get a fixed agent */
01495                   chan = agent_new(p, AST_STATE_DOWN);
01496                } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
01497                   /* Adjustable agent */
01498                   p->chan = ast_request("Local", format, p->loginchan, cause);
01499                   if (p->chan)
01500                      chan = agent_new(p, AST_STATE_DOWN);
01501                }
01502                if (chan) {
01503                   ast_mutex_unlock(&p->lock);
01504                   break;
01505                }
01506             }
01507          }
01508          ast_mutex_unlock(&p->lock);
01509       }
01510    }
01511 
01512    if (!chan && waitforagent) {
01513       /* No agent available -- but we're requesting to wait for one.
01514          Allocate a place holder */
01515       if (hasagent) {
01516          if (option_debug)
01517             ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
01518          p = add_agent(data, 1);
01519          p->group = groupmatch;
01520          chan = agent_new(p, AST_STATE_DOWN);
01521          if (!chan) 
01522             ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
01523       } else
01524          ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
01525    }
01526    *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
01527    AST_LIST_UNLOCK(&agents);
01528 
01529    if (chan) {
01530       ast_mutex_lock(&p->lock);
01531       if (p->pending) {
01532          ast_mutex_unlock(&p->lock);
01533          return chan;
01534       }
01535 
01536       if (!p->chan) {
01537          ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
01538          *cause = AST_CAUSE_UNREGISTERED;
01539          ast_mutex_unlock(&p->lock);
01540          agent_hangup(chan);
01541          return NULL;
01542       }
01543 
01544       /* when not in callback mode we need to take control of the channel
01545        * from the login app thread */
01546       if(ast_strlen_zero(p->loginchan)) {
01547          p->app_sleep_cond = 0;
01548          p->app_lock_flag = 1;
01549 
01550          ast_queue_frame(p->chan, &ast_null_frame);
01551          ast_cond_wait(&p->login_wait_cond, &p->lock);
01552 
01553          if (!p->chan) {
01554             ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
01555             p->app_sleep_cond = 1;
01556             p->app_lock_flag = 0;
01557             ast_cond_signal(&p->app_complete_cond);
01558             ast_mutex_unlock(&p->lock);
01559             *cause = AST_CAUSE_UNREGISTERED;
01560             agent_hangup(chan);
01561             return NULL;
01562          }
01563 
01564          ast_indicate(p->chan, AST_CONTROL_UNHOLD);
01565       }
01566       ast_mutex_unlock(&p->lock);
01567    }
01568 
01569    return chan;
01570 }

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

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

00648 {
00649    struct agent_pvt *p = ast->tech_pvt;
00650    int res = -1;
00651    ast_mutex_lock(&p->lock);
00652    if (p->chan) 
00653       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00654    ast_mutex_unlock(&p->lock);
00655    return res;
00656 }

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

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

00659 {
00660    struct agent_pvt *p = ast->tech_pvt;
00661    int res = -1;
00662    ast_mutex_lock(&p->lock);
00663    if (p->chan) 
00664       res = ast_sendtext(p->chan, text);
00665    ast_mutex_unlock(&p->lock);
00666    return res;
00667 }

int agent_set_base_channel ( struct ast_channel chan,
struct ast_channel base 
) [static]

Definition at line 882 of file chan_agent.c.

References ast_log(), agent_pvt::chan, LOG_ERROR, ast_channel::name, and ast_channel::tech_pvt.

00883 {
00884    struct agent_pvt *p = NULL;
00885    
00886    if (!chan || !base) {
00887       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00888       return -1;
00889    }
00890    p = chan->tech_pvt;
00891    if (!p) {
00892       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00893       return -1;
00894    }
00895    p->chan = base;
00896    return 0;
00897 }

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

Definition at line 491 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00492 {
00493    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00494 }

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

Definition at line 669 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, ast_channel::name, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.

00670 {
00671    struct agent_pvt *p = ast->tech_pvt;
00672    int res = -1;
00673    CHECK_FORMATS(ast, p);
00674    ast_mutex_lock(&p->lock);
00675    if (!p->chan) 
00676       res = 0;
00677    else {
00678       if ((f->frametype != AST_FRAME_VOICE) ||
00679           (f->frametype != AST_FRAME_VIDEO) ||
00680           (f->subclass == p->chan->writeformat)) {
00681          res = ast_write(p->chan, f);
00682       } else {
00683          ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00684             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00685             ast->name, p->chan->name);
00686          res = 0;
00687       }
00688    }
00689    CLEANUP(ast, p);
00690    ast_mutex_unlock(&p->lock);
00691    return res;
00692 }

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

References __agent_start_monitoring(), agent_pvt::agent, ast_copy_string(), 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, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, GETAGENTBYCALLERID, LOG_WARNING, option_verbose, pbx_builtin_getvar_helper(), ast_channel::priority, and VERBOSE_PREFIX_3.

Referenced by load_module().

02581 {
02582    int exitifnoagentid = 0;
02583    int nowarnings = 0;
02584    int changeoutgoing = 0;
02585    int res = 0;
02586    char agent[AST_MAX_AGENT];
02587 
02588    if (data) {
02589       if (strchr(data, 'd'))
02590          exitifnoagentid = 1;
02591       if (strchr(data, 'n'))
02592          nowarnings = 1;
02593       if (strchr(data, 'c'))
02594          changeoutgoing = 1;
02595    }
02596    if (chan->cid.cid_num) {
02597       const char *tmp;
02598       char agentvar[AST_MAX_BUF];
02599       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02600       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02601          struct agent_pvt *p;
02602          ast_copy_string(agent, tmp, sizeof(agent));
02603          AST_LIST_LOCK(&agents);
02604          AST_LIST_TRAVERSE(&agents, p, list) {
02605             if (!strcasecmp(p->agent, tmp)) {
02606                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02607                __agent_start_monitoring(chan, p, 1);
02608                break;
02609             }
02610          }
02611          AST_LIST_UNLOCK(&agents);
02612          
02613       } else {
02614          res = -1;
02615          if (!nowarnings)
02616             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);
02617       }
02618    } else {
02619       res = -1;
02620       if (!nowarnings)
02621          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");
02622    }
02623    /* check if there is n + 101 priority */
02624    /*! \todo XXX Needs to check option priorityjump etc etc */
02625    if (res) {
02626       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
02627          chan->priority+=100;
02628          if (option_verbose > 2)
02629             ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
02630       } else if (exitifnoagentid)
02631          return res;
02632    }
02633    return 0;
02634 }

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 1826 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(), ast_tvdiff_ms(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, powerof(), RESULT_SHOWUSAGE, RESULT_SUCCESS, and username.

01827 {
01828    struct agent_pvt *p;
01829    char username[AST_MAX_BUF];
01830    char location[AST_MAX_BUF] = "";
01831    char talkingto[AST_MAX_BUF] = "";
01832    char moh[AST_MAX_BUF];
01833    int count_agents = 0;      /*!< Number of agents configured */
01834    int online_agents = 0;     /*!< Number of online agents */
01835    int offline_agents = 0;    /*!< Number of offline agents */
01836    if (argc != 2)
01837       return RESULT_SHOWUSAGE;
01838    AST_LIST_LOCK(&agents);
01839    AST_LIST_TRAVERSE(&agents, p, list) {
01840       ast_mutex_lock(&p->lock);
01841       if (p->pending) {
01842          if (p->group)
01843             ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
01844          else
01845             ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
01846       } else {
01847          if (!ast_strlen_zero(p->name))
01848             snprintf(username, sizeof(username), "(%s) ", p->name);
01849          else
01850             username[0] = '\0';
01851          if (p->chan) {
01852             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01853             if (p->owner && ast_bridged_channel(p->owner))
01854                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01855              else 
01856                strcpy(talkingto, " is idle");
01857             online_agents++;
01858          } else if (!ast_strlen_zero(p->loginchan)) {
01859             if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
01860                snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01861             else 
01862                snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
01863             talkingto[0] = '\0';
01864             online_agents++;
01865             if (p->acknowledged)
01866                strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01867          } else {
01868             strcpy(location, "not logged in");
01869             talkingto[0] = '\0';
01870             offline_agents++;
01871          }
01872          if (!ast_strlen_zero(p->moh))
01873             snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01874          ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
01875             username, location, talkingto, moh);
01876          count_agents++;
01877       }
01878       ast_mutex_unlock(&p->lock);
01879    }
01880    AST_LIST_UNLOCK(&agents);
01881    if ( !count_agents ) 
01882       ast_cli(fd, "No Agents are configured in %s\n",config);
01883    else 
01884       ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01885    ast_cli(fd, "\n");
01886                    
01887    return RESULT_SUCCESS;
01888 }

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

Definition at line 1891 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, ast_channel::name, agent_pvt::name, agent_pvt::owner, RESULT_SHOWUSAGE, RESULT_SUCCESS, and username.

01892 {
01893    struct agent_pvt *p;
01894    char username[AST_MAX_BUF];
01895    char location[AST_MAX_BUF] = "";
01896    char talkingto[AST_MAX_BUF] = "";
01897    char moh[AST_MAX_BUF];
01898    int count_agents = 0;           /* Number of agents configured */
01899    int online_agents = 0;          /* Number of online agents */
01900    int agent_status = 0;           /* 0 means offline, 1 means online */
01901    if (argc != 3)
01902       return RESULT_SHOWUSAGE;
01903    AST_LIST_LOCK(&agents);
01904    AST_LIST_TRAVERSE(&agents, p, list) {
01905       agent_status = 0;       /* reset it to offline */
01906       ast_mutex_lock(&p->lock);
01907       if (!ast_strlen_zero(p->name))
01908          snprintf(username, sizeof(username), "(%s) ", p->name);
01909       else
01910          username[0] = '\0';
01911       if (p->chan) {
01912          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01913          if (p->owner && ast_bridged_channel(p->owner)) 
01914             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01915          else 
01916             strcpy(talkingto, " is idle");
01917          agent_status = 1;
01918          online_agents++;
01919       } else if (!ast_strlen_zero(p->loginchan)) {
01920          snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01921          talkingto[0] = '\0';
01922          agent_status = 1;
01923          online_agents++;
01924          if (p->acknowledged)
01925             strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01926       }
01927       if (!ast_strlen_zero(p->moh))
01928          snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01929       if (agent_status)
01930          ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh);
01931       count_agents++;
01932       ast_mutex_unlock(&p->lock);
01933    }
01934    AST_LIST_UNLOCK(&agents);
01935    if (!count_agents) 
01936       ast_cli(fd, "No Agents are configured in %s\n", config);
01937    else
01938       ast_cli(fd, "%d agents online\n", online_agents);
01939    ast_cli(fd, "\n");
01940    return RESULT_SUCCESS;
01941 }

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

Definition at line 1414 of file chan_agent.c.

References AST_LIST_TRAVERSE, agent_pvt::loginchan, and S_OR.

Referenced by __login_exec().

01415 {
01416    struct agent_pvt *p;
01417    char loginchan[80];
01418 
01419    if (multiplelogin) {
01420       return 1;
01421    }
01422    if (!chan) {
01423       return 0;
01424    }
01425 
01426    snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default"));
01427    
01428    AST_LIST_TRAVERSE(&agents, p, list) {
01429       if(!strcasecmp(loginchan, p->loginchan))
01430          return 0;
01431    }
01432    return -1;
01433 }

static void callback_deprecated ( void   )  [static]

Definition at line 2459 of file chan_agent.c.

References ast_log(), depwarning, and LOG_WARNING.

Referenced by action_agent_callback_login(), and callback_exec().

02460 {
02461    static int depwarning = 0;
02462 
02463    if (!depwarning) {
02464       depwarning = 1;
02465 
02466       ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n");
02467       ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n");
02468       ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n");
02469    }
02470 }

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

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

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

Definition at line 2480 of file chan_agent.c.

References __login_exec(), and callback_deprecated().

Referenced by load_module().

02481 {
02482    callback_deprecated();
02483 
02484    return __login_exec(chan, data, 1);
02485 }

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

Definition at line 1300 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_copy_string(), 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, ast_channel::language, agent_pvt::lock, LOG_DEBUG, ast_channel::name, option_debug, agent_pvt::owner, and agent_pvt::pending.

Referenced by __login_exec().

01301 {
01302    struct ast_channel *chan=NULL, *parent=NULL;
01303    struct agent_pvt *p;
01304    int res;
01305 
01306    if (option_debug)
01307       ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
01308    if (needlock)
01309       AST_LIST_LOCK(&agents);
01310    AST_LIST_TRAVERSE(&agents, p, list) {
01311       if (p == newlyavailable) {
01312          continue;
01313       }
01314       ast_mutex_lock(&p->lock);
01315       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01316          if (option_debug)
01317             ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01318          /* We found a pending call, time to merge */
01319          chan = agent_new(newlyavailable, AST_STATE_DOWN);
01320          parent = p->owner;
01321          p->abouttograb = 1;
01322          ast_mutex_unlock(&p->lock);
01323          break;
01324       }
01325       ast_mutex_unlock(&p->lock);
01326    }
01327    if (needlock)
01328       AST_LIST_UNLOCK(&agents);
01329    if (parent && chan)  {
01330       if (newlyavailable->ackcall > 1) {
01331          /* Don't do beep here */
01332          res = 0;
01333       } else {
01334          if (option_debug > 2)
01335             ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01336          res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01337          if (option_debug > 2)
01338             ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
01339          if (!res) {
01340             res = ast_waitstream(newlyavailable->chan, "");
01341             ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
01342          }
01343       }
01344       if (!res) {
01345          /* Note -- parent may have disappeared */
01346          if (p->abouttograb) {
01347             newlyavailable->acknowledged = 1;
01348             /* Safe -- agent lock already held */
01349             ast_setstate(parent, AST_STATE_UP);
01350             ast_setstate(chan, AST_STATE_UP);
01351             ast_copy_string(parent->context, chan->context, sizeof(parent->context));
01352             /* Go ahead and mark the channel as a zombie so that masquerade will
01353                destroy it for us, and we need not call ast_hangup */
01354             ast_mutex_lock(&parent->lock);
01355             ast_set_flag(chan, AST_FLAG_ZOMBIE);
01356             ast_channel_masquerade(parent, chan);
01357             ast_mutex_unlock(&parent->lock);
01358             p->abouttograb = 0;
01359          } else {
01360             if (option_debug)
01361                ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
01362             agent_cleanup(newlyavailable);
01363          }
01364       } else {
01365          if (option_debug)
01366             ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
01367          agent_cleanup(newlyavailable);
01368       }
01369    }
01370    return 0;
01371 }

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

Definition at line 1373 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, ast_channel::language, agent_pvt::lock, LOG_DEBUG, ast_channel::name, option_debug, agent_pvt::owner, and agent_pvt::pending.

Referenced by __login_exec().

01374 {
01375    struct agent_pvt *p;
01376    int res=0;
01377 
01378    ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
01379    if (needlock)
01380       AST_LIST_LOCK(&agents);
01381    AST_LIST_TRAVERSE(&agents, p, list) {
01382       if (p == newlyavailable) {
01383          continue;
01384       }
01385       ast_mutex_lock(&p->lock);
01386       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01387          if (option_debug)
01388             ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01389          ast_mutex_unlock(&p->lock);
01390          break;
01391       }
01392       ast_mutex_unlock(&p->lock);
01393    }
01394    if (needlock)
01395       AST_LIST_UNLOCK(&agents);
01396    if (p) {
01397       ast_mutex_unlock(&newlyavailable->lock);
01398       if (option_debug > 2)
01399          ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01400       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01401       if (option_debug > 2)
01402          ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
01403       if (!res) {
01404          res = ast_waitstream(newlyavailable->chan, "");
01405          if (option_debug)
01406             ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
01407       }
01408       ast_mutex_lock(&newlyavailable->lock);
01409    }
01410    return res;
01411 }

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

Definition at line 1799 of file chan_agent.c.

References agent_pvt::agent, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_AGENT, ast_strdup, len(), and agent_pvt::name.

01800 {
01801    char *ret = NULL;
01802 
01803    if (pos == 2) {
01804       struct agent_pvt *p;
01805       char name[AST_MAX_AGENT];
01806       int which = 0, len = strlen(word);
01807 
01808       AST_LIST_LOCK(&agents);
01809       AST_LIST_TRAVERSE(&agents, p, list) {
01810          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01811          if (!strncasecmp(word, name, len) && ++which > state) {
01812             ret = ast_strdup(name);
01813             break;
01814          }
01815       }
01816       AST_LIST_UNLOCK(&agents);
01817    } else if (pos == 3 && state == 0) 
01818       return ast_strdup("soft");
01819    
01820    return ret;
01821 }

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

Definition at line 2639 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(), action_agent_callback_login(), agent_hangup(), and agent_logoff_maintenance().

02640 {
02641    struct agent_pvt *cur_agent = NULL;
02642    char buf[256];
02643 
02644    AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02645       if (cur_agent->chan)
02646          continue;
02647 
02648       if (!ast_strlen_zero(cur_agent->loginchan)) {
02649          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02650          if (ast_db_put(pa_family, cur_agent->agent, buf))
02651             ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
02652          else if (option_debug)
02653             ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02654       } else {
02655          /* Delete -  no agent or there is an error */
02656          ast_db_del(pa_family, cur_agent->agent);
02657       }
02658    }
02659 }

static struct agent_pvt* find_agent ( char *  agentid  )  [static, read]

Note:
This function expects the agent list to be locked

Definition at line 2767 of file chan_agent.c.

References agent_pvt::agent, and AST_LIST_TRAVERSE.

Referenced by function_agent().

02768 {
02769    struct agent_pvt *cur;
02770 
02771    AST_LIST_TRAVERSE(&agents, cur, list) {
02772       if (!strcmp(cur->agent, agentid))
02773          break;   
02774    }
02775 
02776    return cur; 
02777 }

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

Definition at line 2779 of file chan_agent.c.

References agent_pvt::agent, AST_APP_ARG, ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), agent_pvt::chan, find_agent(), LOG_WARNING, agent_pvt::loginchan, agent_pvt::moh, ast_channel::name, agent_pvt::name, parse(), and agent_pvt::password.

02780 {
02781    char *parse;    
02782    AST_DECLARE_APP_ARGS(args,
02783       AST_APP_ARG(agentid);
02784       AST_APP_ARG(item);
02785    );
02786    char *tmp;
02787    struct agent_pvt *agent;
02788 
02789    buf[0] = '\0';
02790 
02791    if (ast_strlen_zero(data)) {
02792       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02793       return -1;
02794    }
02795 
02796    parse = ast_strdupa(data);
02797 
02798    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02799    if (!args.item)
02800       args.item = "status";
02801 
02802    AST_LIST_LOCK(&agents);
02803 
02804    if (!(agent = find_agent(args.agentid))) {
02805       AST_LIST_UNLOCK(&agents);
02806       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02807       return -1;
02808    }
02809 
02810    if (!strcasecmp(args.item, "status")) {
02811       char *status = "LOGGEDOUT";
02812       if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
02813          status = "LOGGEDIN"; 
02814       ast_copy_string(buf, status, len);
02815    } else if (!strcasecmp(args.item, "password")) 
02816       ast_copy_string(buf, agent->password, len);
02817    else if (!strcasecmp(args.item, "name"))
02818       ast_copy_string(buf, agent->name, len);
02819    else if (!strcasecmp(args.item, "mohclass"))
02820       ast_copy_string(buf, agent->moh, len);
02821    else if (!strcasecmp(args.item, "channel")) {
02822       if (agent->chan) {
02823          ast_channel_lock(agent->chan);
02824          ast_copy_string(buf, agent->chan->name, len);
02825          ast_channel_unlock(agent->chan);
02826          tmp = strrchr(buf, '-');
02827          if (tmp)
02828             *tmp = '\0';
02829       } 
02830    } else if (!strcasecmp(args.item, "exten"))
02831       ast_copy_string(buf, agent->loginchan, len); 
02832 
02833    AST_LIST_UNLOCK(&agents);
02834 
02835    return 0;
02836 }

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

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

02862 {
02863    /* Make sure we can register our agent channel type */
02864    if (ast_channel_register(&agent_tech)) {
02865       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02866       return -1;
02867    }
02868    /* Read in the config */
02869    if (!read_agent_config())
02870       return AST_MODULE_LOAD_DECLINE;
02871    if (persistent_agents)
02872       reload_agents();
02873    /* Dialplan applications */
02874    ast_register_application(app, login_exec, synopsis, descrip);
02875    ast_register_application(app2, callback_exec, synopsis2, descrip2);
02876    ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
02877 
02878    /* Manager commands */
02879    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02880    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02881    ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
02882 
02883    /* CLI Commands */
02884    ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02885 
02886    /* Dialplan Functions */
02887    ast_custom_function_register(&agent_function);
02888 
02889    ast_devstate_add(agent_devicestate_cb, NULL);
02890 
02891    return 0;
02892 }

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

References __login_exec().

Referenced by load_module().

02455 {
02456    return __login_exec(chan, data, 0);
02457 }

static force_inline int powerof ( unsigned int  d  )  [static]

Definition at line 1572 of file chan_agent.c.

01573 {
01574    int x = ffs(d);
01575 
01576    if (x)
01577       return x - 1;
01578 
01579    return 0;
01580 }

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

References add_agent(), agent_pvt::app_complete_cond, ast_category_browse(), ast_cond_destroy(), ast_config_destroy(), ast_config_load(), ast_copy_string(), 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, agent_pvt::login_wait_cond, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.

Referenced by load_module(), and reload().

01151 {
01152    struct ast_config *cfg;
01153    struct ast_config *ucfg;
01154    struct ast_variable *v;
01155    struct agent_pvt *p;
01156    const char *general_val;
01157    const char *catname;
01158    const char *hasagent;
01159    int genhasagent;
01160 
01161    group = 0;
01162    autologoff = 0;
01163    wrapuptime = 0;
01164    ackcall = 0;
01165    endcall = 1;
01166    cfg = ast_config_load(config);
01167    if (!cfg) {
01168       ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
01169       return 0;
01170    }
01171    AST_LIST_LOCK(&agents);
01172    AST_LIST_TRAVERSE(&agents, p, list) {
01173       p->dead = 1;
01174    }
01175    strcpy(moh, "default");
01176    /* set the default recording values */
01177    recordagentcalls = 0;
01178    strcpy(recordformat, "wav");
01179    strcpy(recordformatext, "wav");
01180    urlprefix[0] = '\0';
01181    savecallsin[0] = '\0';
01182 
01183    /* Read in [general] section for persistence */
01184    if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
01185       persistent_agents = ast_true(general_val);
01186    multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
01187 
01188    /* Read in the [agents] section */
01189    v = ast_variable_browse(cfg, "agents");
01190    while(v) {
01191       /* Create the interface list */
01192       if (!strcasecmp(v->name, "agent")) {
01193          add_agent(v->value, 0);
01194       } else if (!strcasecmp(v->name, "group")) {
01195          group = ast_get_group(v->value);
01196       } else if (!strcasecmp(v->name, "autologoff")) {
01197          autologoff = atoi(v->value);
01198          if (autologoff < 0)
01199             autologoff = 0;
01200       } else if (!strcasecmp(v->name, "ackcall")) {
01201          if (!strcasecmp(v->value, "always"))
01202             ackcall = 2;
01203          else if (ast_true(v->value))
01204             ackcall = 1;
01205          else
01206             ackcall = 0;
01207       } else if (!strcasecmp(v->name, "endcall")) {
01208          endcall = ast_true(v->value);
01209       } else if (!strcasecmp(v->name, "wrapuptime")) {
01210          wrapuptime = atoi(v->value);
01211          if (wrapuptime < 0)
01212             wrapuptime = 0;
01213       } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
01214          maxlogintries = atoi(v->value);
01215          if (maxlogintries < 0)
01216             maxlogintries = 0;
01217       } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
01218          strcpy(agentgoodbye,v->value);
01219       } else if (!strcasecmp(v->name, "musiconhold")) {
01220          ast_copy_string(moh, v->value, sizeof(moh));
01221       } else if (!strcasecmp(v->name, "updatecdr")) {
01222          if (ast_true(v->value))
01223             updatecdr = 1;
01224          else
01225             updatecdr = 0;
01226       } else if (!strcasecmp(v->name, "autologoffunavail")) {
01227          if (ast_true(v->value))
01228             autologoffunavail = 1;
01229          else
01230             autologoffunavail = 0;
01231       } else if (!strcasecmp(v->name, "recordagentcalls")) {
01232          recordagentcalls = ast_true(v->value);
01233       } else if (!strcasecmp(v->name, "recordformat")) {
01234          ast_copy_string(recordformat, v->value, sizeof(recordformat));
01235          if (!strcasecmp(v->value, "wav49"))
01236             strcpy(recordformatext, "WAV");
01237          else
01238             ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
01239       } else if (!strcasecmp(v->name, "urlprefix")) {
01240          ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
01241          if (urlprefix[strlen(urlprefix) - 1] != '/')
01242             strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
01243       } else if (!strcasecmp(v->name, "savecallsin")) {
01244          if (v->value[0] == '/')
01245             ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
01246          else
01247             snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
01248          if (savecallsin[strlen(savecallsin) - 1] != '/')
01249             strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
01250       } else if (!strcasecmp(v->name, "custom_beep")) {
01251          ast_copy_string(beep, v->value, sizeof(beep));
01252       }
01253       v = v->next;
01254    }
01255    if ((ucfg = ast_config_load("users.conf"))) {
01256       genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
01257       catname = ast_category_browse(ucfg, NULL);
01258       while(catname) {
01259          if (strcasecmp(catname, "general")) {
01260             hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
01261             if (ast_true(hasagent) || (!hasagent && genhasagent)) {
01262                char tmp[256];
01263                const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
01264                const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
01265                if (!fullname)
01266                   fullname = "";
01267                if (!secret)
01268                   secret = "";
01269                snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
01270                add_agent(tmp, 0);
01271             }
01272          }
01273          catname = ast_category_browse(ucfg, catname);
01274       }
01275       ast_config_destroy(ucfg);
01276    }
01277    AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
01278       if (p->dead) {
01279          AST_LIST_REMOVE_CURRENT(&agents, list);
01280          /* Destroy if  appropriate */
01281          if (!p->owner) {
01282             if (!p->chan) {
01283                ast_mutex_destroy(&p->lock);
01284                ast_cond_destroy(&p->app_complete_cond);
01285                ast_cond_destroy(&p->login_wait_cond);
01286                free(p);
01287             } else {
01288                /* Cause them to hang up */
01289                ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01290             }
01291          }
01292       }
01293    }
01294    AST_LIST_TRAVERSE_SAFE_END
01295    AST_LIST_UNLOCK(&agents);
01296    ast_config_destroy(cfg);
01297    return 1;
01298 }

static int reload ( void   )  [static]

Definition at line 2894 of file chan_agent.c.

References read_agent_config(), and reload_agents().

Referenced by moh_cli(), reload(), rpt_do_reload(), and show_console().

02895 {
02896    read_agent_config();
02897    if (persistent_agents)
02898       reload_agents();
02899    return 0;
02900 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

Definition at line 2664 of file chan_agent.c.

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

Referenced by load_module(), and reload().

02665 {
02666    char *agent_num;
02667    struct ast_db_entry *db_tree;
02668    struct ast_db_entry *entry;
02669    struct agent_pvt *cur_agent;
02670    char agent_data[256];
02671    char *parse;
02672    char *agent_chan;
02673    char *agent_callerid;
02674 
02675    db_tree = ast_db_gettree(pa_family, NULL);
02676 
02677    AST_LIST_LOCK(&agents);
02678    for (entry = db_tree; entry; entry = entry->next) {
02679       agent_num = entry->key + strlen(pa_family) + 2;
02680       AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02681          ast_mutex_lock(&cur_agent->lock);
02682          if (strcmp(agent_num, cur_agent->agent) == 0)
02683             break;
02684          ast_mutex_unlock(&cur_agent->lock);
02685       }
02686       if (!cur_agent) {
02687          ast_db_del(pa_family, agent_num);
02688          continue;
02689       } else
02690          ast_mutex_unlock(&cur_agent->lock);
02691       if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
02692          if (option_debug)
02693             ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
02694          parse = agent_data;
02695          agent_chan = strsep(&parse, ";");
02696          agent_callerid = strsep(&parse, ";");
02697          ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
02698          if (agent_callerid) {
02699             ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
02700             set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
02701          } else
02702             cur_agent->logincallerid[0] = '\0';
02703          if (cur_agent->loginstart == 0)
02704             time(&cur_agent->loginstart);
02705          ast_device_state_changed("Agent/%s", cur_agent->agent);  
02706       }
02707    }
02708    AST_LIST_UNLOCK(&agents);
02709    if (db_tree) {
02710       ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
02711       ast_db_freetree(db_tree);
02712    }
02713 }

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

00854 {
00855    char buf[AST_MAX_BUF];
00856 
00857    /* if there is no Caller ID, nothing to do */
00858    if (ast_strlen_zero(callerid))
00859       return;
00860 
00861    snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00862    pbx_builtin_setvar_helper(NULL, buf, agent);
00863 }

static int unload_module ( void   )  [static]

Definition at line 2902 of file chan_agent.c.

References agent_devicestate_cb(), agent_function, agent_tech, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_devstate_del(), 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.

Referenced by load_module().

02903 {
02904    struct agent_pvt *p;
02905    /* First, take us out of the channel loop */
02906    ast_channel_unregister(&agent_tech);
02907    /* Delete devicestate subscription */
02908    ast_devstate_del(agent_devicestate_cb, NULL);
02909    /* Unregister dialplan functions */
02910    ast_custom_function_unregister(&agent_function);   
02911    /* Unregister CLI commands */
02912    ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02913    /* Unregister dialplan applications */
02914    ast_unregister_application(app);
02915    ast_unregister_application(app2);
02916    ast_unregister_application(app3);
02917    /* Unregister manager command */
02918    ast_manager_unregister("Agents");
02919    ast_manager_unregister("AgentLogoff");
02920    ast_manager_unregister("AgentCallbackLogin");
02921    /* Unregister channel */
02922    AST_LIST_LOCK(&agents);
02923    /* Hangup all interfaces if they have an owner */
02924    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02925       if (p->owner)
02926          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02927       free(p);
02928    }
02929    AST_LIST_UNLOCK(&agents);
02930    return 0;
02931 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Agent Proxy Channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 2937 of file chan_agent.c.

int ackcall [static]

Definition at line 159 of file chan_agent.c.

Definition at line 2838 of file chan_agent.c.

Referenced by load_module(), and unload_module().

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

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

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

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

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

Definition at line 83 of file chan_agent.c.

Referenced by _macro_exec().

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

Definition at line 84 of file chan_agent.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2937 of file chan_agent.c.

int autologoff [static]

Definition at line 157 of file chan_agent.c.

int autologoffunavail = 0 [static]

Definition at line 162 of file chan_agent.c.

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

Definition at line 173 of file chan_agent.c.

struct ast_cli_entry cli_agents[] [static]

Definition at line 1968 of file chan_agent.c.

Referenced by load_module(), and unload_module().

Initial value:

 {
   { "show", "agents", NULL },
   agents_show, NULL,
   NULL, NULL }

Definition at line 1958 of file chan_agent.c.

Initial value:

 {
   { "show", "agents", "online" },
   agents_show_online, NULL,
   NULL, NULL }

Definition at line 1963 of file chan_agent.c.

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

const char descrip[] [static]

Definition at line 90 of file chan_agent.c.

Referenced by aji_handle_presence(), and load_module().

const char descrip2[] [static]

Definition at line 99 of file chan_agent.c.

const char descrip3[] [static]

Definition at line 107 of file chan_agent.c.

int endcall [static]

Definition at line 160 of file chan_agent.c.

ast_group_t group [static]

const char mandescr_agent_callback_login[] [static]

Definition at line 135 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 129 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 125 of file chan_agent.c.

int maxlogintries = 3 [static]

Definition at line 164 of file chan_agent.c.

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

Definition at line 144 of file chan_agent.c.

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

int multiplelogin = 1 [static]

Definition at line 161 of file chan_agent.c.

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

Persistent Agents astdb family

Definition at line 150 of file chan_agent.c.

int persistent_agents = 0 [static]

queues.conf [general] option

Definition at line 153 of file chan_agent.c.

int recordagentcalls = 0 [static]

Definition at line 167 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 168 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 169 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

Definition at line 171 of file chan_agent.c.

char show_agents_online_usage[] [static]

Initial value:

"Usage: agent show online\n"
"  Provides a list of all online agents.\n"

Definition at line 1949 of file chan_agent.c.

char show_agents_usage[] [static]

Initial value:

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

Definition at line 1945 of file chan_agent.c.

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

Definition at line 86 of file chan_agent.c.

Referenced by load_module().

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

Definition at line 87 of file chan_agent.c.

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

Definition at line 88 of file chan_agent.c.

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

Definition at line 79 of file chan_agent.c.

int updatecdr = 0 [static]

Definition at line 172 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 170 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 158 of file chan_agent.c.


Generated on Thu Oct 11 06:42:58 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6