Thu Dec 17 23:51:33 2009

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 force_inline int powerof (unsigned int d)
static int read_agent_config (void)
static int reload (void)
static void reload_agents (void)
 Reload the persistent agents from astdb.
static void set_agentbycallerid (const char *callerid, const char *agent)
 store/clear the global variable that stores agentid based on the callerid
static int unload_module (void)

Variables

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

Definition at line 147 of file chan_agent.c.

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

#define AST_MAX_FILENAME_LEN   256

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

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

Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().

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

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 1947 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, 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_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_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, context, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), EVENT_FLAG_AGENT, free, agent_pvt::inherited_devicestate, ast_channel::language, agent_pvt::lastdisc, agent_pvt::list, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, ast_channel::name, option_debug, option_verbose, agent_pvt::owner, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, set_agentbycallerid(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

Referenced by callback_exec(), and login_exec().

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

static void __reg_module ( void   )  [static]

Definition at line 2884 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

Definition at line 2884 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 2444 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::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), option_verbose, agent_pvt::pending, s, VERBOSE_PREFIX_2, and agent_pvt::wrapuptime.

Referenced by load_module().

02445 {
02446    const char *agent = astman_get_header(m, "Agent");
02447    const char *exten = astman_get_header(m, "Exten");
02448    const char *context = astman_get_header(m, "Context");
02449    const char *wrapuptime_s = astman_get_header(m, "WrapupTime");
02450    const char *ackcall_s = astman_get_header(m, "AckCall");
02451    struct agent_pvt *p;
02452    int login_state = 0;
02453 
02454    callback_deprecated();
02455 
02456    if (ast_strlen_zero(agent)) {
02457       astman_send_error(s, m, "No agent specified");
02458       return 0;
02459    }
02460 
02461    if (ast_strlen_zero(exten)) {
02462       astman_send_error(s, m, "No extension specified");
02463       return 0;
02464    }
02465 
02466    AST_LIST_LOCK(&agents);
02467    AST_LIST_TRAVERSE(&agents, p, list) {
02468       if (strcmp(p->agent, agent) || p->pending) 
02469          continue;
02470       if (p->chan) {
02471          login_state = 2; /* already logged in (and on the phone)*/
02472          break;
02473       }
02474       ast_mutex_lock(&p->lock);
02475       login_state = 1; /* Successful Login */
02476       
02477       if (ast_strlen_zero(context))
02478          ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
02479       else
02480          snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
02481 
02482       if (!ast_strlen_zero(wrapuptime_s)) {
02483          p->wrapuptime = atoi(wrapuptime_s);
02484          if (p->wrapuptime < 0)
02485             p->wrapuptime = 0;
02486       }
02487 
02488       if (!strcasecmp(ackcall_s, "always"))
02489          p->ackcall = 2;
02490       else if (ast_true(ackcall_s))
02491          p->ackcall = 1;
02492       else
02493          p->ackcall = 0;
02494 
02495       if (p->loginstart == 0)
02496          time(&p->loginstart);
02497       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
02498                "Agent: %s\r\n"
02499                "Loginchan: %s\r\n",
02500                p->agent, p->loginchan);
02501       ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
02502       if (option_verbose > 1)
02503          ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
02504       ast_device_state_changed("Agent/%s", p->agent);
02505       ast_mutex_unlock(&p->lock);
02506       if (persistent_agents)
02507          dump_agents();
02508    }
02509    AST_LIST_UNLOCK(&agents);
02510 
02511    if (login_state == 1)
02512       astman_send_ack(s, m, "Agent logged in");
02513    else if (login_state == 0)
02514       astman_send_error(s, m, "No such agent");
02515    else if (login_state == 2)
02516       astman_send_error(s, m, "Agent already logged in");
02517 
02518    return 0;
02519 }

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

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

Referenced by load_module().

01736 {
01737    const char *agent = astman_get_header(m, "Agent");
01738    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01739    int soft;
01740    int ret; /* return value of agent_logoff */
01741 
01742    if (ast_strlen_zero(agent)) {
01743       astman_send_error(s, m, "No agent specified");
01744       return 0;
01745    }
01746 
01747    soft = ast_true(soft_s) ? 1 : 0;
01748    ret = agent_logoff(agent, soft);
01749    if (ret == 0)
01750       astman_send_ack(s, m, "Agent logged out");
01751    else
01752       astman_send_error(s, m, "No such agent");
01753 
01754    return 0;
01755 }

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 1548 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::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, ast_channel::name, agent_pvt::name, agent_pvt::owner, s, S_OR, and username.

Referenced by load_module().

01549 {
01550    const char *id = astman_get_header(m,"ActionID");
01551    char idText[256] = "";
01552    char chanbuf[256];
01553    struct agent_pvt *p;
01554    char *username = NULL;
01555    char *loginChan = NULL;
01556    char *talkingtoChan = NULL;
01557    char *status = NULL;
01558 
01559    if (!ast_strlen_zero(id))
01560       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
01561    astman_send_ack(s, m, "Agents will follow");
01562    AST_LIST_LOCK(&agents);
01563    AST_LIST_TRAVERSE(&agents, p, list) {
01564          ast_mutex_lock(&p->lock);
01565 
01566       /* Status Values:
01567          AGENT_LOGGEDOFF - Agent isn't logged in
01568          AGENT_IDLE      - Agent is logged in, and waiting for call
01569          AGENT_ONCALL    - Agent is logged in, and on a call
01570          AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
01571 
01572       username = S_OR(p->name, "None");
01573 
01574       /* Set a default status. It 'should' get changed. */
01575       status = "AGENT_UNKNOWN";
01576 
01577       if (!ast_strlen_zero(p->loginchan) && !p->chan) {
01578          loginChan = p->loginchan;
01579          talkingtoChan = "n/a";
01580          status = "AGENT_IDLE";
01581          if (p->acknowledged) {
01582             snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
01583             loginChan = chanbuf;
01584          }
01585       } else if (p->chan) {
01586          loginChan = ast_strdupa(p->chan->name);
01587          if (p->owner && p->owner->_bridge) {
01588             if (ast_bridged_channel(p->owner)) {
01589                talkingtoChan = ast_strdupa(S_OR(ast_bridged_channel(p->owner)->cid.cid_num, ""));
01590             } else {
01591                talkingtoChan = "n/a";
01592             }
01593                status = "AGENT_ONCALL";
01594          } else {
01595                talkingtoChan = "n/a";
01596                status = "AGENT_IDLE";
01597          }
01598       } else {
01599          loginChan = "n/a";
01600          talkingtoChan = "n/a";
01601          status = "AGENT_LOGGEDOFF";
01602       }
01603 
01604       astman_append(s, "Event: Agents\r\n"
01605          "Agent: %s\r\n"
01606          "Name: %s\r\n"
01607          "Status: %s\r\n"
01608          "LoggedInChan: %s\r\n"
01609          "LoggedInTime: %d\r\n"
01610          "TalkingTo: %s\r\n"
01611          "%s"
01612          "\r\n",
01613          p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText);
01614       ast_mutex_unlock(&p->lock);
01615    }
01616    AST_LIST_UNLOCK(&agents);
01617    astman_append(s, "Event: AgentsComplete\r\n"
01618       "%s"
01619       "\r\n",idText);
01620    return 0;
01621 }

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

Adds an agent to the global list of agents.

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

Definition at line 338 of file chan_agent.c.

References agent_pvt::ackcall, agent_pvt::agent, 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::lastdisc, agent_pvt::list, LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, 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_mutex_init(&p->app_lock);
00388       ast_cond_init(&p->app_complete_cond, NULL);
00389       p->app_lock_flag = 0;
00390       p->app_sleep_cond = 1;
00391       p->group = group;
00392       p->pending = pending;
00393       p->inherited_devicestate = -1;
00394       AST_LIST_INSERT_TAIL(&agents, p, list);
00395    }
00396    
00397    ast_copy_string(p->password, password ? password : "", sizeof(p->password));
00398    ast_copy_string(p->name, name ? name : "", sizeof(p->name));
00399    ast_copy_string(p->moh, moh, sizeof(p->moh));
00400    p->ackcall = ackcall;
00401    p->autologoff = autologoff;
00402 
00403    /* If someone reduces the wrapuptime and reloads, we want it
00404     * to change the wrapuptime immediately on all calls */
00405    if (p->wrapuptime > wrapuptime) {
00406       struct timeval now = ast_tvnow();
00407       /* XXX check what is this exactly */
00408 
00409       /* We won't be pedantic and check the tv_usec val */
00410       if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
00411          p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
00412          p->lastdisc.tv_usec = now.tv_usec;
00413       }
00414    }
00415    p->wrapuptime = wrapuptime;
00416 
00417    if (pending)
00418       p->dead = 1;
00419    else
00420       p->dead = 0;
00421    return p;
00422 }

static int agent_ack_sleep ( void *  data  )  [static]

Definition at line 991 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, and agent_pvt::lock.

Referenced by __login_exec().

00992 {
00993    struct agent_pvt *p;
00994    int res=0;
00995    int to = 1000;
00996    struct ast_frame *f;
00997 
00998    /* Wait a second and look for something */
00999 
01000    p = (struct agent_pvt *) data;
01001    if (!p->chan) 
01002       return -1;
01003 
01004    for(;;) {
01005       to = ast_waitfor(p->chan, to);
01006       if (to < 0) 
01007          return -1;
01008       if (!to) 
01009          return 0;
01010       f = ast_read(p->chan);
01011       if (!f) 
01012          return -1;
01013       if (f->frametype == AST_FRAME_DTMF)
01014          res = f->subclass;
01015       else
01016          res = 0;
01017       ast_frfree(f);
01018       ast_mutex_lock(&p->lock);
01019       if (!p->app_sleep_cond) {
01020          ast_mutex_unlock(&p->lock);
01021          return 0;
01022       } else if (res == '#') {
01023          ast_mutex_unlock(&p->lock);
01024          return 1;
01025       }
01026       ast_mutex_unlock(&p->lock);
01027       res = 0;
01028    }
01029    return res;
01030 }

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 452 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00453 {
00454    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00455    return -1;
00456 }

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

Definition at line 1032 of file chan_agent.c.

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

01033 {
01034    struct agent_pvt *p = bridge->tech_pvt;
01035    struct ast_channel *ret = NULL;
01036 
01037    if (p) {
01038       if (chan == p->chan)
01039          ret = bridge->_bridge;
01040       else if (chan == bridge->_bridge)
01041          ret = p->chan;
01042    }
01043 
01044    if (option_debug)
01045       ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
01046    return ret;
01047 }

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

Definition at line 723 of file chan_agent.c.

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

00724 {
00725    struct agent_pvt *p = ast->tech_pvt;
00726    int res = -1;
00727    int newstate=0;
00728    ast_mutex_lock(&p->lock);
00729    p->acknowledged = 0;
00730    if (!p->chan) {
00731       if (p->pending) {
00732          ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
00733          newstate = AST_STATE_DIALING;
00734          res = 0;
00735       } else {
00736          ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
00737          res = -1;
00738       }
00739       ast_mutex_unlock(&p->lock);
00740       if (newstate)
00741          ast_setstate(ast, newstate);
00742       return res;
00743    } else if (!ast_strlen_zero(p->loginchan)) {
00744       time(&p->start);
00745       /* Call on this agent */
00746       if (option_verbose > 2)
00747          ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
00748       ast_set_callerid(p->chan,
00749          ast->cid.cid_num, ast->cid.cid_name, NULL);
00750       ast_channel_inherit_variables(ast, p->chan);
00751       res = ast_call(p->chan, p->loginchan, 0);
00752       CLEANUP(ast,p);
00753       ast_mutex_unlock(&p->lock);
00754       return res;
00755    }
00756    if (option_verbose > 2)
00757       ast_verbose(VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
00758    if (option_debug > 2)
00759       ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
00760    res = ast_streamfile(p->chan, beep, p->chan->language);
00761    if (option_debug > 2)
00762       ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res);
00763    if (!res) {
00764       res = ast_waitstream(p->chan, "");
00765       if (option_debug > 2)
00766          ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res);
00767    }
00768    if (!res) {
00769       res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
00770       if (option_debug > 2)
00771          ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res);
00772       if (res)
00773          ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00774    } else {
00775       /* Agent hung-up */
00776       p->chan = NULL;
00777       p->inherited_devicestate = -1;
00778       ast_device_state_changed("Agent/%s", p->agent);
00779    }
00780 
00781    if (!res) {
00782       res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
00783       if (option_debug > 2)
00784          ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res);
00785       if (res)
00786          ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00787    }
00788    if(!res) {
00789       /* Call is immediately up, or might need ack */
00790       if (p->ackcall > 1)
00791          newstate = AST_STATE_RINGING;
00792       else {
00793          newstate = AST_STATE_UP;
00794          if (recordagentcalls)
00795             agent_start_monitoring(ast, 0);
00796          p->acknowledged = 1;
00797       }
00798       res = 0;
00799    }
00800    CLEANUP(ast, p);
00801    ast_mutex_unlock(&p->lock);
00802    if (newstate)
00803       ast_setstate(ast, newstate);
00804    return res;
00805 }

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, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_free(), ast_cond_destroy, ast_cond_signal, ast_mutex_destroy, agent_pvt::chan, agent_pvt::dead, free, agent_pvt::lock, agent_pvt::owner, and ast_channel::tech_pvt.

Referenced by check_availability().

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

static int agent_cont_sleep ( void *  data  )  [static]

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

00971 {
00972    struct agent_pvt *p;
00973    int res;
00974 
00975    p = (struct agent_pvt *)data;
00976 
00977    ast_mutex_lock(&p->lock);
00978    res = p->app_sleep_cond;
00979    if (p->lastdisc.tv_sec) {
00980       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
00981          res = 1;
00982    }
00983    ast_mutex_unlock(&p->lock);
00984 
00985    if(option_debug > 4 && !res )
00986       ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
00987 
00988    return res;
00989 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

Definition at line 2665 of file chan_agent.c.

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

02666 {
02667    struct agent_pvt *p;
02668    char *s;
02669    ast_group_t groupmatch;
02670    int groupoff;
02671    int waitforagent=0;
02672    int res = AST_DEVICE_INVALID;
02673    
02674    s = data;
02675    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1))
02676       groupmatch = (1 << groupoff);
02677    else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
02678       groupmatch = (1 << groupoff);
02679       waitforagent = 1;
02680    } else 
02681       groupmatch = 0;
02682 
02683    /* Check actual logged in agents first */
02684    AST_LIST_LOCK(&agents);
02685    AST_LIST_TRAVERSE(&agents, p, list) {
02686       ast_mutex_lock(&p->lock);
02687       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02688          if (p->owner) {
02689             if (res != AST_DEVICE_INUSE)
02690                res = AST_DEVICE_BUSY;
02691          } else if (p->inherited_devicestate > -1) {
02692             res = p->inherited_devicestate;
02693          } else {
02694             if (res == AST_DEVICE_BUSY)
02695                res = AST_DEVICE_INUSE;
02696             if (p->chan || !ast_strlen_zero(p->loginchan)) {
02697                if (res == AST_DEVICE_INVALID)
02698                   res = AST_DEVICE_UNKNOWN;
02699             } else if (res == AST_DEVICE_INVALID)  
02700                res = AST_DEVICE_UNAVAILABLE;
02701          }
02702          if (!strcmp(data, p->agent)) {
02703             ast_mutex_unlock(&p->lock);
02704             break;
02705          }
02706       }
02707       ast_mutex_unlock(&p->lock);
02708    }
02709    AST_LIST_UNLOCK(&agents);
02710    return res;
02711 }

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::list, agent_pvt::lock, agent_pvt::loginchan, and ast_channel::name.

Referenced by load_module(), and unload_module().

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

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

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

00702 {
00703    struct agent_pvt *p = ast->tech_pvt;
00704    ast_mutex_lock(&p->lock);
00705    if (p->chan) {
00706       ast_senddigit_begin(p->chan, digit);
00707    }
00708    ast_mutex_unlock(&p->lock);
00709    return 0;
00710 }

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

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

00713 {
00714    struct agent_pvt *p = ast->tech_pvt;
00715    ast_mutex_lock(&p->lock);
00716    if (p->chan) {
00717       ast_senddigit_end(p->chan, digit, duration);
00718    }
00719    ast_mutex_unlock(&p->lock);
00720    return 0;
00721 }

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

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

00669 {
00670    struct agent_pvt *p = newchan->tech_pvt;
00671    ast_mutex_lock(&p->lock);
00672    if (p->owner != oldchan) {
00673       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00674       ast_mutex_unlock(&p->lock);
00675       return -1;
00676    }
00677    p->owner = newchan;
00678    ast_mutex_unlock(&p->lock);
00679    return 0;
00680 }

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

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

Definition at line 821 of file chan_agent.c.

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

00822 {
00823    struct agent_pvt *p = NULL;
00824    struct ast_channel *base = chan;
00825 
00826    /* chan is locked by the calling function */
00827    if (!chan || !chan->tech_pvt) {
00828       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);
00829       return NULL;
00830    }
00831    p = chan->tech_pvt;
00832    if (p->chan) 
00833       base = p->chan;
00834    return base;
00835 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 854 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, 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::list, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::moh, agent_pvt::name, option_debug, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, agent_pvt::start, ast_channel::tech_pvt, ast_channel::uniqueid, and agent_pvt::wrapuptime.

00855 {
00856    struct agent_pvt *p = ast->tech_pvt;
00857    int howlong = 0;
00858    const char *status;
00859    ast_mutex_lock(&p->lock);
00860    p->owner = NULL;
00861    ast->tech_pvt = NULL;
00862    p->app_sleep_cond = 1;
00863    p->acknowledged = 0;
00864 
00865    /* if they really are hung up then set start to 0 so the test
00866     * later if we're called on an already downed channel
00867     * doesn't cause an agent to be logged out like when
00868     * agent_request() is followed immediately by agent_hangup()
00869     * as in apps/app_chanisavail.c:chanavail_exec()
00870     */
00871 
00872    if (option_debug)
00873       ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
00874    if (p->start && (ast->_state != AST_STATE_UP)) {
00875       howlong = time(NULL) - p->start;
00876       p->start = 0;
00877    } else if (ast->_state == AST_STATE_RESERVED) 
00878       howlong = 0;
00879    else
00880       p->start = 0; 
00881    if (p->chan) {
00882       p->chan->_bridge = NULL;
00883       /* If they're dead, go ahead and hang up on the agent now */
00884       if (!ast_strlen_zero(p->loginchan)) {
00885          /* Store last disconnect time */
00886          if (p->wrapuptime)
00887             p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00888          else
00889             p->lastdisc = ast_tv(0,0);
00890          if (p->chan) {
00891             status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00892             if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00893                long logintime = time(NULL) - p->loginstart;
00894                p->loginstart = 0;
00895                ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
00896                agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00897             }
00898             /* Recognize the hangup and pass it along immediately */
00899             ast_hangup(p->chan);
00900             p->chan = NULL;
00901             p->inherited_devicestate = -1;
00902             ast_device_state_changed("Agent/%s", p->agent);
00903          }
00904          ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
00905          if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) {
00906             long logintime = time(NULL) - p->loginstart;
00907             p->loginstart = 0;
00908             if (!p->deferlogoff)
00909                ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00910             p->deferlogoff = 0;
00911             agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
00912             if (persistent_agents)
00913                dump_agents();
00914          }
00915       } else if (p->dead) {
00916          ast_channel_lock(p->chan);
00917          ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00918          ast_channel_unlock(p->chan);
00919       } else if (p->loginstart) {
00920          ast_channel_lock(p->chan);
00921          ast_indicate_data(p->chan, AST_CONTROL_HOLD, 
00922             S_OR(p->moh, NULL),
00923             !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
00924          ast_channel_unlock(p->chan);
00925       }
00926    }
00927    ast_mutex_unlock(&p->lock);
00928 
00929    /* Only register a device state change if the agent is still logged in */
00930    if (!p->loginstart) {
00931       p->loginchan[0] = '\0';
00932       p->logincallerid[0] = '\0';
00933       if (persistent_agents)
00934          dump_agents();
00935    } else {
00936       ast_device_state_changed("Agent/%s", p->agent);
00937    }
00938 
00939    if (p->pending) {
00940       AST_LIST_LOCK(&agents);
00941       AST_LIST_REMOVE(&agents, p, list);
00942       AST_LIST_UNLOCK(&agents);
00943    }
00944    if (p->abouttograb) {
00945       /* Let the "about to grab" thread know this isn't valid anymore, and let it
00946          kill it later */
00947       p->abouttograb = 0;
00948    } else if (p->dead) {
00949       ast_mutex_destroy(&p->lock);
00950       ast_mutex_destroy(&p->app_lock);
00951       ast_cond_destroy(&p->app_complete_cond);
00952       free(p);
00953    } else {
00954       if (p->chan) {
00955          /* Not dead -- check availability now */
00956          ast_mutex_lock(&p->lock);
00957          /* Store last disconnect time */
00958          p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00959          ast_mutex_unlock(&p->lock);
00960       }
00961       /* Release ownership of the agent to other threads (presumably running the login app). */
00962       if (ast_strlen_zero(p->loginchan)) {
00963          p->app_lock_flag = 0;
00964          ast_cond_signal(&p->app_complete_cond);
00965       }
00966    }
00967    return 0;
00968 }

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

Definition at line 682 of file chan_agent.c.

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

00683 {
00684    struct agent_pvt *p = ast->tech_pvt;
00685    int res = -1;
00686    ast_mutex_lock(&p->lock);
00687    if (p->chan && !ast_check_hangup(p->chan)) {
00688       while (ast_channel_trylock(p->chan)) {
00689          ast_channel_unlock(ast);
00690          usleep(1);
00691          ast_channel_lock(ast);
00692       }
00693       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00694       ast_channel_unlock(p->chan);
00695    } else
00696       res = 0;
00697    ast_mutex_unlock(&p->lock);
00698    return res;
00699 }

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

Definition at line 1663 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::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, and agent_pvt::owner.

Referenced by action_agent_logoff(), agent_logoff_cmd(), and agent_read().

01664 {
01665    struct agent_pvt *p;
01666    long logintime;
01667    int ret = -1; /* Return -1 if no agent if found */
01668 
01669    AST_LIST_LOCK(&agents);
01670    AST_LIST_TRAVERSE(&agents, p, list) {
01671       if (!strcasecmp(p->agent, agent)) {
01672          ret = 0;
01673          if (p->owner || p->chan) {
01674             if (!soft) {
01675                ast_mutex_lock(&p->lock);
01676 
01677                while (p->owner && ast_channel_trylock(p->owner)) {
01678                   DEADLOCK_AVOIDANCE(&p->lock);
01679                }
01680                if (p->owner) {
01681                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01682                   ast_channel_unlock(p->owner);
01683                }
01684 
01685                while (p->chan && ast_channel_trylock(p->chan)) {
01686                   DEADLOCK_AVOIDANCE(&p->lock);
01687                }
01688                if (p->chan) {
01689                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01690                   ast_channel_unlock(p->chan);
01691                }
01692 
01693                ast_mutex_unlock(&p->lock);
01694             } else
01695                p->deferlogoff = 1;
01696          } else {
01697             logintime = time(NULL) - p->loginstart;
01698             p->loginstart = 0;
01699             agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
01700          }
01701          break;
01702       }
01703    }
01704    AST_LIST_UNLOCK(&agents);
01705 
01706    return ret;
01707 }

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

Definition at line 1709 of file chan_agent.c.

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

01710 {
01711    int ret;
01712    char *agent;
01713 
01714    if (argc < 3 || argc > 4)
01715       return RESULT_SHOWUSAGE;
01716    if (argc == 4 && strcasecmp(argv[3], "soft"))
01717       return RESULT_SHOWUSAGE;
01718 
01719    agent = argv[2] + 6;
01720    ret = agent_logoff(agent, argc == 4);
01721    if (ret == 0)
01722       ast_cli(fd, "Logging out %s\n", agent);
01723 
01724    return RESULT_SUCCESS;
01725 }

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

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

01624 {
01625    char *tmp = NULL;
01626    char agent[AST_MAX_AGENT];
01627 
01628    if (!ast_strlen_zero(logcommand))
01629       tmp = logcommand;
01630    else
01631       tmp = ast_strdupa("");
01632 
01633    snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01634 
01635    if (!ast_strlen_zero(uniqueid)) {
01636       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01637             "Agent: %s\r\n"
01638             "Reason: %s\r\n"
01639             "Loginchan: %s\r\n"
01640             "Logintime: %ld\r\n"
01641             "Uniqueid: %s\r\n", 
01642             p->agent, tmp, loginchan, logintime, uniqueid);
01643    } else {
01644       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01645             "Agent: %s\r\n"
01646             "Reason: %s\r\n"
01647             "Loginchan: %s\r\n"
01648             "Logintime: %ld\r\n",
01649             p->agent, tmp, loginchan, logintime);
01650    }
01651 
01652    ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
01653    set_agentbycallerid(p->logincallerid, NULL);
01654    p->loginchan[0] ='\0';
01655    p->logincallerid[0] = '\0';
01656    p->inherited_devicestate = -1;
01657    ast_device_state_changed("Agent/%s", p->agent);
01658    if (persistent_agents)
01659       dump_agents();
01660 
01661 }

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

Create new agent channel.

Definition at line 1050 of file chan_agent.c.

References agent_pvt::agent, agent_tech, agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_atomic_fetchadd_int(), ast_channel_alloc(), ast_channel_free(), ast_cond_signal, AST_CONTROL_UNHOLD, ast_copy_string(), AST_FORMAT_SLINEAR, ast_indicate(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_null_frame, ast_queue_frame(), ast_random(), ast_string_field_set, ast_strlen_zero(), ast_update_use_count(), agent_pvt::chan, ast_channel::context, ast_channel::exten, ast_channel::language, language, agent_pvt::lock, LOG_WARNING, agent_pvt::loginchan, 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().

01051 {
01052    struct ast_channel *tmp;
01053    int alreadylocked;
01054 #if 0
01055    if (!p->chan) {
01056       ast_log(LOG_WARNING, "No channel? :(\n");
01057       return NULL;
01058    }
01059 #endif   
01060    if (p->pending)
01061       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);
01062    else
01063       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent);
01064    if (!tmp) {
01065       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
01066       return NULL;
01067    }
01068 
01069    tmp->tech = &agent_tech;
01070    if (p->chan) {
01071       tmp->nativeformats = p->chan->nativeformats;
01072       tmp->writeformat = p->chan->writeformat;
01073       tmp->rawwriteformat = p->chan->writeformat;
01074       tmp->readformat = p->chan->readformat;
01075       tmp->rawreadformat = p->chan->readformat;
01076       ast_string_field_set(tmp, language, p->chan->language);
01077       ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
01078       ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
01079       /* XXX Is this really all we copy form the originating channel?? */
01080    } else {
01081       tmp->nativeformats = AST_FORMAT_SLINEAR;
01082       tmp->writeformat = AST_FORMAT_SLINEAR;
01083       tmp->rawwriteformat = AST_FORMAT_SLINEAR;
01084       tmp->readformat = AST_FORMAT_SLINEAR;
01085       tmp->rawreadformat = AST_FORMAT_SLINEAR;
01086    }
01087    /* Safe, agentlock already held */
01088    tmp->tech_pvt = p;
01089    p->owner = tmp;
01090    /* XXX: this needs fixing */
01091 #if 0
01092    ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1);
01093 #endif
01094    ast_update_use_count();
01095    tmp->priority = 1;
01096    /* Wake up and wait for other applications (by definition the login app)
01097     * to release this channel). Takes ownership of the agent channel
01098     * to this thread only.
01099     * For signalling the other thread, ast_queue_frame is used until we
01100     * can safely use signals for this purpose. The pselect() needs to be
01101     * implemented in the kernel for this.
01102     */
01103    p->app_sleep_cond = 0;
01104 
01105    alreadylocked = p->app_lock_flag;
01106    p->app_lock_flag = 1;
01107 
01108    if(ast_strlen_zero(p->loginchan) && alreadylocked) {
01109       if (p->chan) {
01110          ast_queue_frame(p->chan, &ast_null_frame);
01111          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01112          p->app_lock_flag = 1;
01113          ast_mutex_lock(&p->lock);
01114       } else {
01115          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
01116          p->owner = NULL;
01117          tmp->tech_pvt = NULL;
01118          p->app_sleep_cond = 1;
01119          ast_channel_free( tmp );
01120          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01121          p->app_lock_flag = 0;
01122          ast_cond_signal(&p->app_complete_cond);
01123          return NULL;
01124       }
01125    } else if (!ast_strlen_zero(p->loginchan)) {
01126       if (p->chan)
01127          ast_queue_frame(p->chan, &ast_null_frame);
01128       if (!p->chan) {
01129          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
01130          p->owner = NULL;
01131          tmp->tech_pvt = NULL;
01132          p->app_sleep_cond = 1;
01133          ast_channel_free( tmp );
01134          ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
01135          return NULL;
01136       }  
01137    } 
01138    if (p->chan)
01139       ast_indicate(p->chan, AST_CONTROL_UNHOLD);
01140    return tmp;
01141 }

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

Definition at line 491 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff(), agent_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, 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_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_tvnow(), ast_verbose(), agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, f, ast_channel::fdno, agent_pvt::inherited_devicestate, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, ast_channel::name, option_verbose, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::start, ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, ast_channel::uniqueid, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

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

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

Part of the Asterisk PBX interface.

Definition at line 1435 of file chan_agent.c.

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

01436 {
01437    struct agent_pvt *p;
01438    struct ast_channel *chan = NULL;
01439    char *s;
01440    ast_group_t groupmatch;
01441    int groupoff;
01442    int waitforagent=0;
01443    int hasagent = 0;
01444    struct timeval tv;
01445 
01446    s = data;
01447    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01448       groupmatch = (1 << groupoff);
01449    } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01450       groupmatch = (1 << groupoff);
01451       waitforagent = 1;
01452    } else 
01453       groupmatch = 0;
01454 
01455    /* Check actual logged in agents first */
01456    AST_LIST_LOCK(&agents);
01457    AST_LIST_TRAVERSE(&agents, p, list) {
01458       ast_mutex_lock(&p->lock);
01459       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
01460           ast_strlen_zero(p->loginchan)) {
01461          if (p->chan)
01462             hasagent++;
01463          tv = ast_tvnow();
01464          if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
01465             p->lastdisc = ast_tv(0, 0);
01466             /* Agent must be registered, but not have any active call, and not be in a waiting state */
01467             if (!p->owner && p->chan) {
01468                /* Fixed agent */
01469                chan = agent_new(p, AST_STATE_DOWN);
01470             }
01471             if (chan) {
01472                ast_mutex_unlock(&p->lock);
01473                break;
01474             }
01475          }
01476       }
01477       ast_mutex_unlock(&p->lock);
01478    }
01479    if (!p) {
01480       AST_LIST_TRAVERSE(&agents, p, list) {
01481          ast_mutex_lock(&p->lock);
01482          if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01483             if (p->chan || !ast_strlen_zero(p->loginchan))
01484                hasagent++;
01485             tv = ast_tvnow();
01486 #if 0
01487             ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
01488 #endif
01489             if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
01490                p->lastdisc = ast_tv(0, 0);
01491                /* Agent must be registered, but not have any active call, and not be in a waiting state */
01492                if (!p->owner && p->chan) {
01493                   /* Could still get a fixed agent */
01494                   chan = agent_new(p, AST_STATE_DOWN);
01495                } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
01496                   /* Adjustable agent */
01497                   p->chan = ast_request("Local", format, p->loginchan, cause);
01498                   if (p->chan)
01499                      chan = agent_new(p, AST_STATE_DOWN);
01500                }
01501                if (chan) {
01502                   ast_mutex_unlock(&p->lock);
01503                   break;
01504                }
01505             }
01506          }
01507          ast_mutex_unlock(&p->lock);
01508       }
01509    }
01510 
01511    if (!chan && waitforagent) {
01512       /* No agent available -- but we're requesting to wait for one.
01513          Allocate a place holder */
01514       if (hasagent) {
01515          if (option_debug)
01516             ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
01517          p = add_agent(data, 1);
01518          p->group = groupmatch;
01519          chan = agent_new(p, AST_STATE_DOWN);
01520          if (!chan) 
01521             ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
01522       } else
01523          ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
01524    }
01525    *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
01526    AST_LIST_UNLOCK(&agents);
01527    return chan;
01528 }

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

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

00622 {
00623    struct agent_pvt *p = ast->tech_pvt;
00624    int res = -1;
00625    ast_mutex_lock(&p->lock);
00626    if (p->chan) 
00627       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00628    ast_mutex_unlock(&p->lock);
00629    return res;
00630 }

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

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

00633 {
00634    struct agent_pvt *p = ast->tech_pvt;
00635    int res = -1;
00636    ast_mutex_lock(&p->lock);
00637    if (p->chan) 
00638       res = ast_sendtext(p->chan, text);
00639    ast_mutex_unlock(&p->lock);
00640    return res;
00641 }

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

Definition at line 837 of file chan_agent.c.

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

00838 {
00839    struct agent_pvt *p = NULL;
00840    
00841    if (!chan || !base) {
00842       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00843       return -1;
00844    }
00845    p = chan->tech_pvt;
00846    if (!p) {
00847       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00848       return -1;
00849    }
00850    p->chan = base;
00851    return 0;
00852 }

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

Definition at line 486 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00487 {
00488    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00489 }

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

Definition at line 643 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, f, agent_pvt::lock, LOG_DEBUG, ast_channel::name, ast_channel::tech_pvt, and ast_channel::writeformat.

00644 {
00645    struct agent_pvt *p = ast->tech_pvt;
00646    int res = -1;
00647    CHECK_FORMATS(ast, p);
00648    ast_mutex_lock(&p->lock);
00649    if (!p->chan) 
00650       res = 0;
00651    else {
00652       if ((f->frametype != AST_FRAME_VOICE) ||
00653           (f->frametype != AST_FRAME_VIDEO) ||
00654           (f->subclass == p->chan->writeformat)) {
00655          res = ast_write(p->chan, f);
00656       } else {
00657          ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00658             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00659             ast->name, p->chan->name);
00660          res = 0;
00661       }
00662    }
00663    CLEANUP(ast, p);
00664    ast_mutex_unlock(&p->lock);
00665    return res;
00666 }

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 2529 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, agent_pvt::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, GETAGENTBYCALLERID, agent_pvt::list, LOG_WARNING, option_verbose, pbx_builtin_getvar_helper(), and VERBOSE_PREFIX_3.

Referenced by load_module().

02530 {
02531    int exitifnoagentid = 0;
02532    int nowarnings = 0;
02533    int changeoutgoing = 0;
02534    int res = 0;
02535    char agent[AST_MAX_AGENT];
02536 
02537    if (data) {
02538       if (strchr(data, 'd'))
02539          exitifnoagentid = 1;
02540       if (strchr(data, 'n'))
02541          nowarnings = 1;
02542       if (strchr(data, 'c'))
02543          changeoutgoing = 1;
02544    }
02545    if (chan->cid.cid_num) {
02546       const char *tmp;
02547       char agentvar[AST_MAX_BUF];
02548       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02549       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02550          struct agent_pvt *p;
02551          ast_copy_string(agent, tmp, sizeof(agent));
02552          AST_LIST_LOCK(&agents);
02553          AST_LIST_TRAVERSE(&agents, p, list) {
02554             if (!strcasecmp(p->agent, tmp)) {
02555                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02556                __agent_start_monitoring(chan, p, 1);
02557                break;
02558             }
02559          }
02560          AST_LIST_UNLOCK(&agents);
02561          
02562       } else {
02563          res = -1;
02564          if (!nowarnings)
02565             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);
02566       }
02567    } else {
02568       res = -1;
02569       if (!nowarnings)
02570          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");
02571    }
02572    /* check if there is n + 101 priority */
02573    /*! \todo XXX Needs to check option priorityjump etc etc */
02574    if (res) {
02575       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
02576          chan->priority+=100;
02577          if (option_verbose > 2)
02578             ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
02579       } else if (exitifnoagentid)
02580          return res;
02581    }
02582    return 0;
02583 }

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

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

01785 {
01786    struct agent_pvt *p;
01787    char username[AST_MAX_BUF];
01788    char location[AST_MAX_BUF] = "";
01789    char talkingto[AST_MAX_BUF] = "";
01790    char moh[AST_MAX_BUF];
01791    int count_agents = 0;      /*!< Number of agents configured */
01792    int online_agents = 0;     /*!< Number of online agents */
01793    int offline_agents = 0;    /*!< Number of offline agents */
01794    if (argc != 2)
01795       return RESULT_SHOWUSAGE;
01796    AST_LIST_LOCK(&agents);
01797    AST_LIST_TRAVERSE(&agents, p, list) {
01798       ast_mutex_lock(&p->lock);
01799       if (p->pending) {
01800          if (p->group)
01801             ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
01802          else
01803             ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
01804       } else {
01805          if (!ast_strlen_zero(p->name))
01806             snprintf(username, sizeof(username), "(%s) ", p->name);
01807          else
01808             username[0] = '\0';
01809          if (p->chan) {
01810             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01811             if (p->owner && ast_bridged_channel(p->owner))
01812                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01813              else 
01814                strcpy(talkingto, " is idle");
01815             online_agents++;
01816          } else if (!ast_strlen_zero(p->loginchan)) {
01817             if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
01818                snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01819             else 
01820                snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
01821             talkingto[0] = '\0';
01822             online_agents++;
01823             if (p->acknowledged)
01824                strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01825          } else {
01826             strcpy(location, "not logged in");
01827             talkingto[0] = '\0';
01828             offline_agents++;
01829          }
01830          if (!ast_strlen_zero(p->moh))
01831             snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01832          ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
01833             username, location, talkingto, moh);
01834          count_agents++;
01835       }
01836       ast_mutex_unlock(&p->lock);
01837    }
01838    AST_LIST_UNLOCK(&agents);
01839    if ( !count_agents ) 
01840       ast_cli(fd, "No Agents are configured in %s\n",config);
01841    else 
01842       ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01843    ast_cli(fd, "\n");
01844                    
01845    return RESULT_SUCCESS;
01846 }

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

Definition at line 1849 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::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, RESULT_SHOWUSAGE, RESULT_SUCCESS, and username.

01850 {
01851    struct agent_pvt *p;
01852    char username[AST_MAX_BUF];
01853    char location[AST_MAX_BUF] = "";
01854    char talkingto[AST_MAX_BUF] = "";
01855    char moh[AST_MAX_BUF];
01856    int count_agents = 0;           /* Number of agents configured */
01857    int online_agents = 0;          /* Number of online agents */
01858    int agent_status = 0;           /* 0 means offline, 1 means online */
01859    if (argc != 3)
01860       return RESULT_SHOWUSAGE;
01861    AST_LIST_LOCK(&agents);
01862    AST_LIST_TRAVERSE(&agents, p, list) {
01863       agent_status = 0;       /* reset it to offline */
01864       ast_mutex_lock(&p->lock);
01865       if (!ast_strlen_zero(p->name))
01866          snprintf(username, sizeof(username), "(%s) ", p->name);
01867       else
01868          username[0] = '\0';
01869       if (p->chan) {
01870          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01871          if (p->owner && ast_bridged_channel(p->owner)) 
01872             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01873          else 
01874             strcpy(talkingto, " is idle");
01875          agent_status = 1;
01876          online_agents++;
01877       } else if (!ast_strlen_zero(p->loginchan)) {
01878          snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01879          talkingto[0] = '\0';
01880          agent_status = 1;
01881          online_agents++;
01882          if (p->acknowledged)
01883             strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01884       }
01885       if (!ast_strlen_zero(p->moh))
01886          snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01887       if (agent_status)
01888          ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh);
01889       count_agents++;
01890       ast_mutex_unlock(&p->lock);
01891    }
01892    AST_LIST_UNLOCK(&agents);
01893    if (!count_agents) 
01894       ast_cli(fd, "No Agents are configured in %s\n", config);
01895    else
01896       ast_cli(fd, "%d agents online\n", online_agents);
01897    ast_cli(fd, "\n");
01898    return RESULT_SUCCESS;
01899 }

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

Definition at line 1413 of file chan_agent.c.

References AST_LIST_TRAVERSE, agent_pvt::list, agent_pvt::loginchan, and S_OR.

Referenced by __login_exec().

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

static void callback_deprecated ( void   )  [static]

Definition at line 2408 of file chan_agent.c.

References ast_log(), depwarning, and LOG_WARNING.

Referenced by action_agent_callback_login(), and callback_exec().

02409 {
02410    static int depwarning = 0;
02411 
02412    if (!depwarning) {
02413       depwarning = 1;
02414 
02415       ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n");
02416       ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n");
02417       ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n");
02418    }
02419 }

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

References __login_exec(), callback_deprecated(), and ast_module_user::chan.

Referenced by load_module().

02430 {
02431    callback_deprecated();
02432 
02433    return __login_exec(chan, data, 1);
02434 }

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

Definition at line 1299 of file chan_agent.c.

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

Referenced by __login_exec().

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

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

Definition at line 1372 of file chan_agent.c.

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

Referenced by __login_exec().

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

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

Definition at line 1757 of file chan_agent.c.

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

01758 {
01759    char *ret = NULL;
01760 
01761    if (pos == 2) {
01762       struct agent_pvt *p;
01763       char name[AST_MAX_AGENT];
01764       int which = 0, len = strlen(word);
01765 
01766       AST_LIST_LOCK(&agents);
01767       AST_LIST_TRAVERSE(&agents, p, list) {
01768          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01769          if (!strncasecmp(word, name, len) && ++which > state) {
01770             ret = ast_strdup(name);
01771             break;
01772          }
01773       }
01774       AST_LIST_UNLOCK(&agents);
01775    } else if (pos == 3 && state == 0) 
01776       return ast_strdup("soft");
01777    
01778    return ret;
01779 }

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

Definition at line 2588 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, agent_pvt::list, 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().

02589 {
02590    struct agent_pvt *cur_agent = NULL;
02591    char buf[256];
02592 
02593    AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02594       if (cur_agent->chan)
02595          continue;
02596 
02597       if (!ast_strlen_zero(cur_agent->loginchan)) {
02598          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02599          if (ast_db_put(pa_family, cur_agent->agent, buf))
02600             ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
02601          else if (option_debug)
02602             ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02603       } else {
02604          /* Delete -  no agent or there is an error */
02605          ast_db_del(pa_family, cur_agent->agent);
02606       }
02607    }
02608 }

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

Note:
This function expects the agent list to be locked

Definition at line 2716 of file chan_agent.c.

References agent_pvt::agent, AST_LIST_TRAVERSE, and agent_pvt::list.

Referenced by function_agent().

02717 {
02718    struct agent_pvt *cur;
02719 
02720    AST_LIST_TRAVERSE(&agents, cur, list) {
02721       if (!strcmp(cur->agent, agentid))
02722          break;   
02723    }
02724 
02725    return cur; 
02726 }

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

Definition at line 2728 of file chan_agent.c.

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

02729 {
02730    char *parse;    
02731    AST_DECLARE_APP_ARGS(args,
02732       AST_APP_ARG(agentid);
02733       AST_APP_ARG(item);
02734    );
02735    char *tmp;
02736    struct agent_pvt *agent;
02737 
02738    buf[0] = '\0';
02739 
02740    if (ast_strlen_zero(data)) {
02741       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02742       return -1;
02743    }
02744 
02745    parse = ast_strdupa(data);
02746 
02747    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02748    if (!args.item)
02749       args.item = "status";
02750 
02751    AST_LIST_LOCK(&agents);
02752 
02753    if (!(agent = find_agent(args.agentid))) {
02754       AST_LIST_UNLOCK(&agents);
02755       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02756       return -1;
02757    }
02758 
02759    if (!strcasecmp(args.item, "status")) {
02760       char *status = "LOGGEDOUT";
02761       if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
02762          status = "LOGGEDIN"; 
02763       ast_copy_string(buf, status, len);
02764    } else if (!strcasecmp(args.item, "password")) 
02765       ast_copy_string(buf, agent->password, len);
02766    else if (!strcasecmp(args.item, "name"))
02767       ast_copy_string(buf, agent->name, len);
02768    else if (!strcasecmp(args.item, "mohclass"))
02769       ast_copy_string(buf, agent->moh, len);
02770    else if (!strcasecmp(args.item, "channel")) {
02771       if (agent->chan) {
02772          ast_copy_string(buf, agent->chan->name, len);
02773          tmp = strrchr(buf, '-');
02774          if (tmp)
02775             *tmp = '\0';
02776       } 
02777    } else if (!strcasecmp(args.item, "exten"))
02778       ast_copy_string(buf, agent->loginchan, len); 
02779 
02780    AST_LIST_UNLOCK(&agents);
02781 
02782    return 0;
02783 }

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

02809 {
02810    /* Make sure we can register our agent channel type */
02811    if (ast_channel_register(&agent_tech)) {
02812       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02813       return -1;
02814    }
02815    /* Read in the config */
02816    if (!read_agent_config())
02817       return AST_MODULE_LOAD_DECLINE;
02818    if (persistent_agents)
02819       reload_agents();
02820    /* Dialplan applications */
02821    ast_register_application(app, login_exec, synopsis, descrip);
02822    ast_register_application(app2, callback_exec, synopsis2, descrip2);
02823    ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
02824 
02825    /* Manager commands */
02826    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02827    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02828    ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
02829 
02830    /* CLI Commands */
02831    ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02832 
02833    /* Dialplan Functions */
02834    ast_custom_function_register(&agent_function);
02835 
02836    ast_devstate_add(agent_devicestate_cb, NULL);
02837 
02838    return 0;
02839 }

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

References __login_exec(), and ast_module_user::chan.

Referenced by load_module().

02404 {
02405    return __login_exec(chan, data, 0);
02406 }

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

Definition at line 1530 of file chan_agent.c.

01531 {
01532    int x = ffs(d);
01533 
01534    if (x)
01535       return x - 1;
01536 
01537    return 0;
01538 }

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

References add_agent(), agent_pvt::app_complete_cond, agent_pvt::app_lock, 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::list, agent_pvt::lock, LOG_NOTICE, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.

Referenced by load_module(), and reload().

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

static int reload ( void   )  [static]

Definition at line 2841 of file chan_agent.c.

References read_agent_config(), and reload_agents().

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

02842 {
02843    read_agent_config();
02844    if (persistent_agents)
02845       reload_agents();
02846    return 0;
02847 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

Definition at line 2613 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::list, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, ast_db_entry::next, option_debug, parse(), and set_agentbycallerid().

Referenced by load_module(), and reload().

02614 {
02615    char *agent_num;
02616    struct ast_db_entry *db_tree;
02617    struct ast_db_entry *entry;
02618    struct agent_pvt *cur_agent;
02619    char agent_data[256];
02620    char *parse;
02621    char *agent_chan;
02622    char *agent_callerid;
02623 
02624    db_tree = ast_db_gettree(pa_family, NULL);
02625 
02626    AST_LIST_LOCK(&agents);
02627    for (entry = db_tree; entry; entry = entry->next) {
02628       agent_num = entry->key + strlen(pa_family) + 2;
02629       AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02630          ast_mutex_lock(&cur_agent->lock);
02631          if (strcmp(agent_num, cur_agent->agent) == 0)
02632             break;
02633          ast_mutex_unlock(&cur_agent->lock);
02634       }
02635       if (!cur_agent) {
02636          ast_db_del(pa_family, agent_num);
02637          continue;
02638       } else
02639          ast_mutex_unlock(&cur_agent->lock);
02640       if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
02641          if (option_debug)
02642             ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
02643          parse = agent_data;
02644          agent_chan = strsep(&parse, ";");
02645          agent_callerid = strsep(&parse, ";");
02646          ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
02647          if (agent_callerid) {
02648             ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
02649             set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
02650          } else
02651             cur_agent->logincallerid[0] = '\0';
02652          if (cur_agent->loginstart == 0)
02653             time(&cur_agent->loginstart);
02654          ast_device_state_changed("Agent/%s", cur_agent->agent);  
02655       }
02656    }
02657    AST_LIST_UNLOCK(&agents);
02658    if (db_tree) {
02659       ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
02660       ast_db_freetree(db_tree);
02661    }
02662 }

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

00809 {
00810    char buf[AST_MAX_BUF];
00811 
00812    /* if there is no Caller ID, nothing to do */
00813    if (ast_strlen_zero(callerid))
00814       return;
00815 
00816    snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00817    pbx_builtin_setvar_helper(NULL, buf, agent);
00818 }

static int unload_module ( void   )  [static]

Definition at line 2849 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, agent_pvt::list, and agent_pvt::owner.

Referenced by load_module().

02850 {
02851    struct agent_pvt *p;
02852    /* First, take us out of the channel loop */
02853    ast_channel_unregister(&agent_tech);
02854    /* Delete devicestate subscription */
02855    ast_devstate_del(agent_devicestate_cb, NULL);
02856    /* Unregister dialplan functions */
02857    ast_custom_function_unregister(&agent_function);   
02858    /* Unregister CLI commands */
02859    ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02860    /* Unregister dialplan applications */
02861    ast_unregister_application(app);
02862    ast_unregister_application(app2);
02863    ast_unregister_application(app3);
02864    /* Unregister manager command */
02865    ast_manager_unregister("Agents");
02866    ast_manager_unregister("AgentLogoff");
02867    ast_manager_unregister("AgentCallbackLogin");
02868    /* Unregister channel */
02869    AST_LIST_LOCK(&agents);
02870    /* Hangup all interfaces if they have an owner */
02871    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02872       if (p->owner)
02873          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02874       free(p);
02875    }
02876    AST_LIST_UNLOCK(&agents);
02877    return 0;
02878 }


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

Definition at line 2884 of file chan_agent.c.

int ackcall [static]

Definition at line 159 of file chan_agent.c.

struct ast_custom_function agent_function

Definition at line 2785 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 1911 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]

Definition at line 82 of file chan_agent.c.

Referenced by action_originate(), add_extensions(), ael2_semantic_check(), answer_exec_enable(), ast_pbx_run_app(), async_wait(), check_app_args(), check_pval_item(), conf_run(), exec_exec(), execif_exec(), feature_exec_app(), forward_message(), handle_context_add_extension(), handle_context_add_extension_deprecated(), handle_exec(), load_module(), page_exec(), pbx_builtin_execiftime(), pbx_exec(), pbx_extension_helper(), realtime_exec(), tryexec_exec(), and unload_module().

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

Referenced by load_module(), and unload_module().

struct ast_cli_entry cli_show_agents_deprecated [static]

Initial value:

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

Definition at line 1916 of file chan_agent.c.

struct ast_cli_entry cli_show_agents_online_deprecated [static]

Initial value:

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

Definition at line 1921 of file chan_agent.c.

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

Definition at line 80 of file chan_agent.c.

Referenced by add_features_datastores(), app_exec(), ast_bridge_call(), ast_category_append(), ast_category_browse(), ast_category_exist(), ast_category_get(), ast_category_root(), ast_channel_bridge(), ast_config_new(), ast_generic_bridge(), ast_readconfig(), ast_variable_browse(), ast_variable_next(), ast_variable_retrieve(), builtin_atxfer(), category_get(), do_atxfer(), do_reload(), feature_interpret(), feature_interpret_helper(), load_module(), load_odbc_config(), misdn_cfg_init(), park_exec(), parse_config(), pbx_load_module(), read_config_maps(), reload(), reload_config(), set_bridge_features_on_config(), and set_config_flags().

const char descrip[] [static]

Definition at line 90 of file chan_agent.c.

Referenced by aji_handle_presence(), and load_module().

const char descrip2[] [static]

Definition at line 99 of file chan_agent.c.

Referenced by load_module().

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]

Definition at line 156 of file chan_agent.c.

Referenced by ast_app_group_set_channel(), ast_get_group(), ast_makesocket(), common_exec(), group_count_function_read(), group_match_count_function_read(), main(), misdn_check_l2l1(), and misdn_request().

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

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

Definition at line 86 of file chan_agent.c.

Referenced by load_module().

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

Definition at line 87 of file chan_agent.c.

Referenced by load_module().

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

Definition at line 88 of file chan_agent.c.

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

Definition at line 79 of file chan_agent.c.

int updatecdr = 0 [static]

Definition at line 172 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 170 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 158 of file chan_agent.c.


Generated on Thu Dec 17 23:51:33 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7