Wed Feb 11 12:00:09 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 = "f450f61f60e761b3aa089ebed76ca8a5" , .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 210 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 231 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 454 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().

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

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

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

static void __reg_module ( void   )  [static]

Definition at line 2870 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

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

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

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

01722 {
01723    const char *agent = astman_get_header(m, "Agent");
01724    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01725    int soft;
01726    int ret; /* return value of agent_logoff */
01727 
01728    if (ast_strlen_zero(agent)) {
01729       astman_send_error(s, m, "No agent specified");
01730       return 0;
01731    }
01732 
01733    soft = ast_true(soft_s) ? 1 : 0;
01734    ret = agent_logoff(agent, soft);
01735    if (ret == 0)
01736       astman_send_ack(s, m, "Agent logged out");
01737    else
01738       astman_send_error(s, m, "No such agent");
01739 
01740    return 0;
01741 }

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

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

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

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

static int agent_ack_sleep ( void *  data  )  [static]

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

00978 {
00979    struct agent_pvt *p;
00980    int res=0;
00981    int to = 1000;
00982    struct ast_frame *f;
00983 
00984    /* Wait a second and look for something */
00985 
00986    p = (struct agent_pvt *) data;
00987    if (!p->chan) 
00988       return -1;
00989 
00990    for(;;) {
00991       to = ast_waitfor(p->chan, to);
00992       if (to < 0) 
00993          return -1;
00994       if (!to) 
00995          return 0;
00996       f = ast_read(p->chan);
00997       if (!f) 
00998          return -1;
00999       if (f->frametype == AST_FRAME_DTMF)
01000          res = f->subclass;
01001       else
01002          res = 0;
01003       ast_frfree(f);
01004       ast_mutex_lock(&p->lock);
01005       if (!p->app_sleep_cond) {
01006          ast_mutex_unlock(&p->lock);
01007          return 0;
01008       } else if (res == '#') {
01009          ast_mutex_unlock(&p->lock);
01010          return 1;
01011       }
01012       ast_mutex_unlock(&p->lock);
01013       res = 0;
01014    }
01015    return res;
01016 }

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 448 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00449 {
00450    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00451    return -1;
00452 }

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

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

01019 {
01020    struct agent_pvt *p = bridge->tech_pvt;
01021    struct ast_channel *ret = NULL;
01022 
01023    if (p) {
01024       if (chan == p->chan)
01025          ret = bridge->_bridge;
01026       else if (chan == bridge->_bridge)
01027          ret = p->chan;
01028    }
01029 
01030    if (option_debug)
01031       ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
01032    return ret;
01033 }

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

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

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

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

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

static int agent_cont_sleep ( void *  data  )  [static]

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

00957 {
00958    struct agent_pvt *p;
00959    int res;
00960 
00961    p = (struct agent_pvt *)data;
00962 
00963    ast_mutex_lock(&p->lock);
00964    res = p->app_sleep_cond;
00965    if (p->lastdisc.tv_sec) {
00966       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
00967          res = 1;
00968    }
00969    ast_mutex_unlock(&p->lock);
00970 
00971    if(option_debug > 4 && !res )
00972       ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
00973 
00974    return res;
00975 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

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

02652 {
02653    struct agent_pvt *p;
02654    char *s;
02655    ast_group_t groupmatch;
02656    int groupoff;
02657    int waitforagent=0;
02658    int res = AST_DEVICE_INVALID;
02659    
02660    s = data;
02661    if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
02662       groupmatch = (1 << groupoff);
02663    else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
02664       groupmatch = (1 << groupoff);
02665       waitforagent = 1;
02666    } else 
02667       groupmatch = 0;
02668 
02669    /* Check actual logged in agents first */
02670    AST_LIST_LOCK(&agents);
02671    AST_LIST_TRAVERSE(&agents, p, list) {
02672       ast_mutex_lock(&p->lock);
02673       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02674          if (p->owner) {
02675             if (res != AST_DEVICE_INUSE)
02676                res = AST_DEVICE_BUSY;
02677          } else if (p->inherited_devicestate > -1) {
02678             res = p->inherited_devicestate;
02679          } else {
02680             if (res == AST_DEVICE_BUSY)
02681                res = AST_DEVICE_INUSE;
02682             if (p->chan || !ast_strlen_zero(p->loginchan)) {
02683                if (res == AST_DEVICE_INVALID)
02684                   res = AST_DEVICE_UNKNOWN;
02685             } else if (res == AST_DEVICE_INVALID)  
02686                res = AST_DEVICE_UNAVAILABLE;
02687          }
02688          if (!strcmp(data, p->agent)) {
02689             ast_mutex_unlock(&p->lock);
02690             break;
02691          }
02692       }
02693       ast_mutex_unlock(&p->lock);
02694    }
02695    AST_LIST_UNLOCK(&agents);
02696    return res;
02697 }

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

Definition at line 287 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(), agent_pvt::chan, agent_pvt::inherited_devicestate, agent_pvt::list, agent_pvt::lock, and ast_channel::name.

Referenced by load_module(), and unload_module().

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

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

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

00688 {
00689    struct agent_pvt *p = ast->tech_pvt;
00690    ast_mutex_lock(&p->lock);
00691    if (p->chan) {
00692       ast_senddigit_begin(p->chan, digit);
00693    }
00694    ast_mutex_unlock(&p->lock);
00695    return 0;
00696 }

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

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

00699 {
00700    struct agent_pvt *p = ast->tech_pvt;
00701    ast_mutex_lock(&p->lock);
00702    if (p->chan) {
00703       ast_senddigit_end(p->chan, digit, duration);
00704    }
00705    ast_mutex_unlock(&p->lock);
00706    return 0;
00707 }

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

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

00655 {
00656    struct agent_pvt *p = newchan->tech_pvt;
00657    ast_mutex_lock(&p->lock);
00658    if (p->owner != oldchan) {
00659       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00660       ast_mutex_unlock(&p->lock);
00661       return -1;
00662    }
00663    p->owner = newchan;
00664    ast_mutex_unlock(&p->lock);
00665    return 0;
00666 }

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

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

00808 {
00809    struct agent_pvt *p = NULL;
00810    struct ast_channel *base = chan;
00811 
00812    /* chan is locked by the calling function */
00813    if (!chan || !chan->tech_pvt) {
00814       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);
00815       return NULL;
00816    }
00817    p = chan->tech_pvt;
00818    if (p->chan) 
00819       base = p->chan;
00820    return base;
00821 }

static int agent_hangup ( struct ast_channel ast  )  [static]

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

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

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

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

00669 {
00670    struct agent_pvt *p = ast->tech_pvt;
00671    int res = -1;
00672    ast_mutex_lock(&p->lock);
00673    if (p->chan && !ast_check_hangup(p->chan)) {
00674       while (ast_channel_trylock(p->chan)) {
00675          ast_channel_unlock(ast);
00676          usleep(1);
00677          ast_channel_lock(ast);
00678       }
00679       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00680       ast_channel_unlock(p->chan);
00681    } else
00682       res = 0;
00683    ast_mutex_unlock(&p->lock);
00684    return res;
00685 }

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

Definition at line 1649 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(), and agent_logoff_cmd().

01650 {
01651    struct agent_pvt *p;
01652    long logintime;
01653    int ret = -1; /* Return -1 if no agent if found */
01654 
01655    AST_LIST_LOCK(&agents);
01656    AST_LIST_TRAVERSE(&agents, p, list) {
01657       if (!strcasecmp(p->agent, agent)) {
01658          ret = 0;
01659          if (p->owner || p->chan) {
01660             if (!soft) {
01661                ast_mutex_lock(&p->lock);
01662 
01663                while (p->owner && ast_channel_trylock(p->owner)) {
01664                   DEADLOCK_AVOIDANCE(&p->lock);
01665                }
01666                if (p->owner) {
01667                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01668                   ast_channel_unlock(p->owner);
01669                }
01670 
01671                while (p->chan && ast_channel_trylock(p->chan)) {
01672                   DEADLOCK_AVOIDANCE(&p->lock);
01673                }
01674                if (p->chan) {
01675                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01676                   ast_channel_unlock(p->chan);
01677                }
01678 
01679                ast_mutex_unlock(&p->lock);
01680             } else
01681                p->deferlogoff = 1;
01682          } else {
01683             logintime = time(NULL) - p->loginstart;
01684             p->loginstart = 0;
01685             agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
01686          }
01687          break;
01688       }
01689    }
01690    AST_LIST_UNLOCK(&agents);
01691 
01692    return ret;
01693 }

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

Definition at line 1695 of file chan_agent.c.

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

01696 {
01697    int ret;
01698    char *agent;
01699 
01700    if (argc < 3 || argc > 4)
01701       return RESULT_SHOWUSAGE;
01702    if (argc == 4 && strcasecmp(argv[3], "soft"))
01703       return RESULT_SHOWUSAGE;
01704 
01705    agent = argv[2] + 6;
01706    ret = agent_logoff(agent, argc == 4);
01707    if (ret == 0)
01708       ast_cli(fd, "Logging out %s\n", agent);
01709 
01710    return RESULT_SUCCESS;
01711 }

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

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

01610 {
01611    char *tmp = NULL;
01612    char agent[AST_MAX_AGENT];
01613 
01614    if (!ast_strlen_zero(logcommand))
01615       tmp = logcommand;
01616    else
01617       tmp = ast_strdupa("");
01618 
01619    snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01620 
01621    if (!ast_strlen_zero(uniqueid)) {
01622       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01623             "Agent: %s\r\n"
01624             "Reason: %s\r\n"
01625             "Loginchan: %s\r\n"
01626             "Logintime: %ld\r\n"
01627             "Uniqueid: %s\r\n", 
01628             p->agent, tmp, loginchan, logintime, uniqueid);
01629    } else {
01630       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01631             "Agent: %s\r\n"
01632             "Reason: %s\r\n"
01633             "Loginchan: %s\r\n"
01634             "Logintime: %ld\r\n",
01635             p->agent, tmp, loginchan, logintime);
01636    }
01637 
01638    ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
01639    set_agentbycallerid(p->logincallerid, NULL);
01640    p->loginchan[0] ='\0';
01641    p->logincallerid[0] = '\0';
01642    p->inherited_devicestate = -1;
01643    ast_device_state_changed("Agent/%s", p->agent);
01644    if (persistent_agents)
01645       dump_agents(); 
01646 
01647 }

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

Create new agent channel.

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

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

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

Definition at line 487 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, AST_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, dump_agents(), 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.

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

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

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

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

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

00608 {
00609    struct agent_pvt *p = ast->tech_pvt;
00610    int res = -1;
00611    ast_mutex_lock(&p->lock);
00612    if (p->chan) 
00613       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00614    ast_mutex_unlock(&p->lock);
00615    return res;
00616 }

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

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

00619 {
00620    struct agent_pvt *p = ast->tech_pvt;
00621    int res = -1;
00622    ast_mutex_lock(&p->lock);
00623    if (p->chan) 
00624       res = ast_sendtext(p->chan, text);
00625    ast_mutex_unlock(&p->lock);
00626    return res;
00627 }

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

Definition at line 823 of file chan_agent.c.

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

00824 {
00825    struct agent_pvt *p = NULL;
00826    
00827    if (!chan || !base) {
00828       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00829       return -1;
00830    }
00831    p = chan->tech_pvt;
00832    if (!p) {
00833       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00834       return -1;
00835    }
00836    p->chan = base;
00837    return 0;
00838 }

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

Definition at line 482 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00483 {
00484    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00485 }

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

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

00630 {
00631    struct agent_pvt *p = ast->tech_pvt;
00632    int res = -1;
00633    CHECK_FORMATS(ast, p);
00634    ast_mutex_lock(&p->lock);
00635    if (!p->chan) 
00636       res = 0;
00637    else {
00638       if ((f->frametype != AST_FRAME_VOICE) ||
00639           (f->frametype != AST_FRAME_VIDEO) ||
00640           (f->subclass == p->chan->writeformat)) {
00641          res = ast_write(p->chan, f);
00642       } else {
00643          ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00644             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00645             ast->name, p->chan->name);
00646          res = 0;
00647       }
00648    }
00649    CLEANUP(ast, p);
00650    ast_mutex_unlock(&p->lock);
00651    return res;
00652 }

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

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

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

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

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

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

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

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

Definition at line 1399 of file chan_agent.c.

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

Referenced by __login_exec().

01400 {
01401    struct agent_pvt *p;
01402    char loginchan[80];
01403 
01404    if (multiplelogin) {
01405       return 1;
01406    }
01407    if (!chan) {
01408       return 0;
01409    }
01410 
01411    snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default"));
01412    
01413    AST_LIST_TRAVERSE(&agents, p, list) {
01414       if(!strcasecmp(loginchan, p->loginchan))
01415          return 0;
01416    }
01417    return -1;
01418 }

static void callback_deprecated ( void   )  [static]

Definition at line 2394 of file chan_agent.c.

References ast_log(), depwarning, and LOG_WARNING.

Referenced by action_agent_callback_login(), and callback_exec().

02395 {
02396    static int depwarning = 0;
02397 
02398    if (!depwarning) {
02399       depwarning = 1;
02400 
02401       ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n");
02402       ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n");
02403       ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n");
02404    }
02405 }

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

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

Referenced by load_module().

02416 {
02417    callback_deprecated();
02418 
02419    return __login_exec(chan, data, 1);
02420 }

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

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

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

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

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

01359 {
01360    struct agent_pvt *p;
01361    int res=0;
01362 
01363    ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
01364    if (needlock)
01365       AST_LIST_LOCK(&agents);
01366    AST_LIST_TRAVERSE(&agents, p, list) {
01367       if (p == newlyavailable) {
01368          continue;
01369       }
01370       ast_mutex_lock(&p->lock);
01371       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01372          if (option_debug)
01373             ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01374          ast_mutex_unlock(&p->lock);
01375          break;
01376       }
01377       ast_mutex_unlock(&p->lock);
01378    }
01379    if (needlock)
01380       AST_LIST_UNLOCK(&agents);
01381    if (p) {
01382       ast_mutex_unlock(&newlyavailable->lock);
01383       if (option_debug > 2)
01384          ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01385       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01386       if (option_debug > 2)
01387          ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
01388       if (!res) {
01389          res = ast_waitstream(newlyavailable->chan, "");
01390          if (option_debug)
01391             ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
01392       }
01393       ast_mutex_lock(&newlyavailable->lock);
01394    }
01395    return res;
01396 }

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

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

01744 {
01745    char *ret = NULL;
01746 
01747    if (pos == 2) {
01748       struct agent_pvt *p;
01749       char name[AST_MAX_AGENT];
01750       int which = 0, len = strlen(word);
01751 
01752       AST_LIST_LOCK(&agents);
01753       AST_LIST_TRAVERSE(&agents, p, list) {
01754          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01755          if (!strncasecmp(word, name, len) && ++which > state) {
01756             ret = ast_strdup(name);
01757             break;
01758          }
01759       }
01760       AST_LIST_UNLOCK(&agents);
01761    } else if (pos == 3 && state == 0) 
01762       return ast_strdup("soft");
01763    
01764    return ret;
01765 }

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

Definition at line 2574 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(), agent_logoff_maintenance(), and agent_read().

02575 {
02576    struct agent_pvt *cur_agent = NULL;
02577    char buf[256];
02578 
02579    AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02580       if (cur_agent->chan)
02581          continue;
02582 
02583       if (!ast_strlen_zero(cur_agent->loginchan)) {
02584          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02585          if (ast_db_put(pa_family, cur_agent->agent, buf))
02586             ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
02587          else if (option_debug)
02588             ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02589       } else {
02590          /* Delete -  no agent or there is an error */
02591          ast_db_del(pa_family, cur_agent->agent);
02592       }
02593    }
02594 }

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

Note:
This function expects the agent list to be locked

Definition at line 2702 of file chan_agent.c.

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

Referenced by function_agent().

02703 {
02704    struct agent_pvt *cur;
02705 
02706    AST_LIST_TRAVERSE(&agents, cur, list) {
02707       if (!strcmp(cur->agent, agentid))
02708          break;   
02709    }
02710 
02711    return cur; 
02712 }

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

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

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

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

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

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

References __login_exec(), and ast_module_user::chan.

Referenced by load_module().

02390 {
02391    return __login_exec(chan, data, 0);
02392 }

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

Definition at line 1516 of file chan_agent.c.

01517 {
01518    int x = ffs(d);
01519 
01520    if (x)
01521       return x - 1;
01522 
01523    return 0;
01524 }

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

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

static int reload ( void   )  [static]

Definition at line 2827 of file chan_agent.c.

References read_agent_config(), and reload_agents().

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

02828 {
02829    read_agent_config();
02830    if (persistent_agents)
02831       reload_agents();
02832    return 0;
02833 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

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

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

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

00795 {
00796    char buf[AST_MAX_BUF];
00797 
00798    /* if there is no Caller ID, nothing to do */
00799    if (ast_strlen_zero(callerid))
00800       return;
00801 
00802    snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00803    pbx_builtin_setvar_helper(NULL, buf, agent);
00804 }

static int unload_module ( void   )  [static]

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

02836 {
02837    struct agent_pvt *p;
02838    /* First, take us out of the channel loop */
02839    ast_channel_unregister(&agent_tech);
02840    /* Delete devicestate subscription */
02841    ast_devstate_del(agent_devicestate_cb, NULL);
02842    /* Unregister dialplan functions */
02843    ast_custom_function_unregister(&agent_function);   
02844    /* Unregister CLI commands */
02845    ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02846    /* Unregister dialplan applications */
02847    ast_unregister_application(app);
02848    ast_unregister_application(app2);
02849    ast_unregister_application(app3);
02850    /* Unregister manager command */
02851    ast_manager_unregister("Agents");
02852    ast_manager_unregister("AgentLogoff");
02853    ast_manager_unregister("AgentCallbackLogin");
02854    /* Unregister channel */
02855    AST_LIST_LOCK(&agents);
02856    /* Hangup all interfaces if they have an owner */
02857    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02858       if (p->owner)
02859          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02860       free(p);
02861    }
02862    AST_LIST_UNLOCK(&agents);
02863    return 0;
02864 }


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

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

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

Definition at line 263 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(), try_calling(), 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 2870 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 1912 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 1902 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 1907 of file chan_agent.c.

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

Definition at line 80 of file chan_agent.c.

Referenced by 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_feature_interpret(), ast_generic_bridge(), ast_readconfig(), ast_variable_browse(), ast_variable_next(), ast_variable_retrieve(), builtin_atxfer(), category_get(), do_atxfer(), do_reload(), load_module(), load_odbc_config(), misdn_cfg_init(), park_exec(), parse_config(), pbx_load_module(), read_config_maps(), reload(), reload_config(), and set_config_flags().

const char descrip[] [static]

Definition at line 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 1893 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 1889 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 Wed Feb 11 12:00:09 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7