Sat Nov 1 06:28:51 2008

Asterisk developer's documentation


chan_agent.c File Reference

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

#include "asterisk.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
#include "asterisk/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/features.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/stringfields.h"

Include dependency graph for chan_agent.c:

Go to the source code of this file.

Data Structures

struct  agent_pvt
 Structure representing an agent. More...

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 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 AST_LIST_HEAD_STATIC (agents, agent_pvt)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Agent Proxy Channel",.load=load_module,.unload=unload_module,.reload=reload,)
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 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 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().

#define CHECK_FORMATS ( ast,
 ) 

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

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

Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().

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

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 1918 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_lock, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, AST_CONTROL_HOLD, 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_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, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, option_debug, option_verbose, agent_pvt::owner, agent_pvt::owning_app, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, set_agentbycallerid(), strsep(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

Referenced by callback_exec(), and login_exec().

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