Thu May 14 14:49:27 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 213 of file chan_agent.c.

Referenced by agent_read(), and agent_write().

#define CLEANUP ( ast,
 ) 

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

Definition at line 234 of file chan_agent.c.

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

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"

Definition at line 175 of file chan_agent.c.

Referenced by agentmonitoroutgoing_exec(), and set_agentbycallerid().

#define PA_MAX_LEN   2048

The maximum length of each persistent member agent database entry

Definition at line 151 of file chan_agent.c.


Function Documentation

static int __agent_start_monitoring ( struct ast_channel ast,
struct agent_pvt p,
int  needlock 
) [static]

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

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

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

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

static void __reg_module ( void   )  [static]

Definition at line 2873 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

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

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

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

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

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

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

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

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

static int agent_ack_sleep ( void *  data  )  [static]

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

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

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 451 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

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

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

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

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

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

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

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

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

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

static int agent_cont_sleep ( void *  data  )  [static]

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

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

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

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

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

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

Definition at line 290 of file chan_agent.c.

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

Referenced by load_module(), and unload_module().

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

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

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

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

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

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

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

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

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

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

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

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

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

static int agent_hangup ( struct ast_channel ast  )  [static]

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

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

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

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

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

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

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

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

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

Definition at line 1698 of file chan_agent.c.

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

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

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

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

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

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

Create new agent channel.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 826 of file chan_agent.c.

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

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

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

Definition at line 485 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 1402 of file chan_agent.c.

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

Referenced by __login_exec().

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

static void callback_deprecated ( void   )  [static]

Definition at line 2397 of file chan_agent.c.

References ast_log(), depwarning, and LOG_WARNING.

Referenced by action_agent_callback_login(), and callback_exec().

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

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

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

Referenced by load_module().

02419 {
02420    callback_deprecated();
02421 
02422    return __login_exec(chan, data, 1);
02423 }

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

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

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

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

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

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

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

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

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

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

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

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

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

Note:
This function expects the agent list to be locked

Definition at line 2705 of file chan_agent.c.

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

Referenced by function_agent().

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

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

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

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

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

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

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

References __login_exec(), and ast_module_user::chan.

Referenced by load_module().

02393 {
02394    return __login_exec(chan, data, 0);
02395 }

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

Definition at line 1519 of file chan_agent.c.

01520 {
01521    int x = ffs(d);
01522 
01523    if (x)
01524       return x - 1;
01525 
01526    return 0;
01527 }

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

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

static int reload ( void   )  [static]

Definition at line 2830 of file chan_agent.c.

References read_agent_config(), and reload_agents().

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

02831 {
02832    read_agent_config();
02833    if (persistent_agents)
02834       reload_agents();
02835    return 0;
02836 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

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

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

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

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

static int unload_module ( void   )  [static]

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

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


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 2873 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 2774 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 1900 of file chan_agent.c.

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

Definition at line 266 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 2873 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 1915 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 1905 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 1910 of file chan_agent.c.

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

Definition at line 80 of file chan_agent.c.

Referenced by add_features_datastores(), app_exec(), ast_bridge_call(), ast_category_append(), ast_category_browse(), ast_category_exist(), ast_category_get(), ast_category_root(), ast_channel_bridge(), ast_config_new(), ast_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(), set_bridge_features_on_config(), and set_config_flags().

const char descrip[] [static]

Definition at line 90 of file chan_agent.c.

Referenced by aji_handle_presence(), and load_module().

const char descrip2[] [static]

Definition at line 99 of file chan_agent.c.

Referenced by load_module().

const char descrip3[] [static]

Definition at line 107 of file chan_agent.c.

int endcall [static]

Definition at line 160 of file chan_agent.c.

ast_group_t group [static]

Definition at line 156 of file chan_agent.c.

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

const char mandescr_agent_callback_login[] [static]

Definition at line 135 of file chan_agent.c.

const char mandescr_agent_logoff[] [static]

Initial value:

"Description: Sets an agent as no longer logged in.\n"
"Variables: (Names marked with * are required)\n"
"  *Agent: Agent ID of the agent to log off\n"
"  Soft: Set to 'true' to not hangup existing calls\n"

Definition at line 129 of file chan_agent.c.

const char mandescr_agents[] [static]

Initial value:

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

Definition at line 125 of file chan_agent.c.

int maxlogintries = 3 [static]

Definition at line 164 of file chan_agent.c.

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

Definition at line 144 of file chan_agent.c.

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

int multiplelogin = 1 [static]

Definition at line 161 of file chan_agent.c.

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

Persistent Agents astdb family

Definition at line 150 of file chan_agent.c.

int persistent_agents = 0 [static]

queues.conf [general] option

Definition at line 153 of file chan_agent.c.

int recordagentcalls = 0 [static]

Definition at line 167 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 168 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 169 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

Definition at line 171 of file chan_agent.c.

char show_agents_online_usage[] [static]

Initial value:

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

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

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

Definition at line 86 of file chan_agent.c.

Referenced by load_module().

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

Definition at line 87 of file chan_agent.c.

Referenced by load_module().

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

Definition at line 88 of file chan_agent.c.

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

Definition at line 79 of file chan_agent.c.

int updatecdr = 0 [static]

Definition at line 172 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 170 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 158 of file chan_agent.c.


Generated on Thu May 14 14:49:28 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7