Fri Jan 31 13:16:32 2014

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"

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 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 = "361d7bb937402d51e4658efb5b4d76e4" , .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(), and ael2_semantic_check().

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

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 1985 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, 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::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(), strsep(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, agent_pvt::wrapuptime, and ast_channel::writeformat.

Referenced by callback_exec(), and login_exec().

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

static void __reg_module ( void   )  [static]

Definition at line 2938 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

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

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

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

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

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 1585 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, agent_pvt::name, agent_pvt::owner, S_OR, and username.

Referenced by load_module().

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

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       memcpy(&p->group, group, sizeof(p->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, 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, agent_pvt::lock, LOG_DEBUG, LOG_WARNING, agent_pvt::loginchan, ast_channel::nativeformats, option_debug, option_verbose, agent_pvt::pending, agent_pvt::start, ast_channel::tech_pvt, and VERBOSE_PREFIX_3.

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 2712 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_get_group(), ast_have_common_group(), ast_is_empty_group(), 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.

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

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, and agent_pvt::loginchan.

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

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

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

Definition at line 1746 of file chan_agent.c.

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

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

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

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

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

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

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, 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_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 2576 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().

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

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 1821 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_print_group(), 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, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, RESULT_SHOWUSAGE, RESULT_SUCCESS, and username.

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

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

Definition at line 1887 of file chan_agent.c.

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

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

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

References ast_log(), depwarning, and LOG_WARNING.

Referenced by action_agent_callback_login(), and callback_exec().

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

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

References __login_exec(), and callback_deprecated().

Referenced by load_module().

02477 {
02478    callback_deprecated();
02479 
02480    return __login_exec(chan, data, 1);
02481 }

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_have_common_group(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_waitstream(), agent_pvt::chan, ast_channel::context, agent_pvt::group, agent_pvt::lock, LOG_DEBUG, option_debug, agent_pvt::owner, and agent_pvt::pending.

Referenced by __login_exec().

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 && ast_have_common_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_have_common_group(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_streamfile(), ast_waitstream(), agent_pvt::chan, agent_pvt::group, agent_pvt::lock, LOG_DEBUG, option_debug, agent_pvt::owner, and agent_pvt::pending.

Referenced by __login_exec().

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 && ast_have_common_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 1794 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.

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

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

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

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

static struct agent_pvt* find_agent ( char *  agentid  )  [static, read]
Note:
This function expects the agent list to be locked

Definition at line 2768 of file chan_agent.c.

References agent_pvt::agent, and AST_LIST_TRAVERSE.

Referenced by function_agent().

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

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

Definition at line 2780 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, agent_pvt::name, parse(), and agent_pvt::password.

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

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

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

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

References __login_exec().

Referenced by load_module().

02451 {
02452    return __login_exec(chan, data, 0);
02453 }

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    memset(group, 0, sizeof(group));
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          ast_get_group(&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 2895 of file chan_agent.c.

References read_agent_config(), and reload_agents().

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

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

Definition at line 2660 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(), set_agentbycallerid(), and strsep().

Referenced by load_module(), and reload().

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

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

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


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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 2938 of file chan_agent.c.

int ackcall [static]

Definition at line 159 of file chan_agent.c.

Definition at line 2839 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 1949 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 2938 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 1964 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 1954 of file chan_agent.c.

Initial value:
 {
   { "show", "agents", "online" },
   agents_show_online, NULL,
   NULL, NULL }

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

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

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

Definition at line 86 of file chan_agent.c.

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 31 Jan 2014 for Asterisk - the Open Source PBX by  doxygen 1.6.1