2002-09-02 15:20:28 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
2002-09-02 15:20:28 +00:00
*
2006-02-12 04:28:58 +00:00
* Copyright ( C ) 1999 - 2006 , Digium , Inc .
2002-09-02 15:20:28 +00:00
*
2004-08-11 19:02:46 +00:00
* Mark Spencer < markster @ digium . com >
2002-09-02 15:20:28 +00:00
*
2005-09-14 20:46:50 +00:00
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
2002-09-02 15:20:28 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
2002-09-02 15:20:28 +00:00
*/
2005-09-14 20:46:50 +00:00
2005-10-24 20:12:06 +00:00
/*! \file
2005-12-30 21:18:06 +00:00
*
2005-11-06 15:09:47 +00:00
* \ brief Implementation of Agents ( proxy channel )
2005-09-14 20:46:50 +00:00
*
2005-12-30 21:18:06 +00:00
* \ author Mark Spencer < markster @ digium . com >
*
2005-10-24 20:12:06 +00:00
* This file is the implementation of Agents modules .
2005-11-06 15:09:47 +00:00
* It is a dynamic module that is loaded by Asterisk .
* \ par See also
* \ arg \ ref Config_agent
*
* \ ingroup channel_drivers
2005-09-07 20:44:57 +00:00
*/
2002-09-02 15:20:28 +00:00
# include <stdio.h>
# include <string.h>
2005-06-06 21:09:59 +00:00
# include <errno.h>
# include <unistd.h>
2005-06-07 17:06:33 +00:00
# include <sys/socket.h>
2005-06-06 21:09:59 +00:00
# include <stdlib.h>
# include <fcntl.h>
# include <netdb.h>
2005-06-07 17:06:33 +00:00
# include <netinet/in.h>
2005-06-06 21:09:59 +00:00
# include <arpa/inet.h>
# include <sys/signal.h>
# include "asterisk.h"
2005-06-06 22:12:19 +00:00
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2005-06-06 21:09:59 +00:00
2005-04-21 06:02:45 +00:00
# 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/lock.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"
2005-07-08 21:14:34 +00:00
# include "asterisk/devicestate.h"
2005-11-08 04:02:35 +00:00
# include "asterisk/monitor.h"
2006-02-01 23:05:28 +00:00
# include "asterisk/stringfields.h"
2002-09-02 15:20:28 +00:00
2005-03-04 06:47:24 +00:00
static const char desc [ ] = " Agent Proxy Channel " ;
static const char tdesc [ ] = " Call Agent Proxy Channel " ;
static const char config [ ] = " agents.conf " ;
2002-09-02 15:20:28 +00:00
2005-03-04 06:47:24 +00:00
static const char app [ ] = " AgentLogin " ;
static const char app2 [ ] = " AgentCallbackLogin " ;
static const char app3 [ ] = " AgentMonitorOutgoing " ;
2002-09-02 15:20:28 +00:00
2005-03-04 06:47:24 +00:00
static const char synopsis [ ] = " Call agent login " ;
static const char synopsis2 [ ] = " Call agent callback login " ;
static const char synopsis3 [ ] = " Record agent's outgoing call " ;
2002-09-02 15:20:28 +00:00
2005-03-04 06:47:24 +00:00
static const char descrip [ ] =
2002-12-06 16:22:19 +00:00
" AgentLogin([AgentNo][|options]): \n "
2002-09-02 15:20:28 +00:00
" Asks the agent to login to the system. Always returns -1. While \n "
" logged in, the agent can receive calls and will hear a 'beep' \n "
2004-12-31 00:58:44 +00:00
" when a new call comes in. The agent can dump the call by pressing \n "
2002-12-06 16:22:19 +00:00
" the star key. \n "
" The option string may contain zero or more of the following characters: \n "
2004-10-24 13:24:16 +00:00
" 's' -- silent login - do not announce the login ok segment after agent logged in/off \n " ;
2002-09-02 15:20:28 +00:00
2005-03-04 06:47:24 +00:00
static const char descrip2 [ ] =
2005-10-26 16:16:05 +00:00
" AgentCallbackLogin([AgentNo][|[options][|[exten]@context]]): \n "
2004-10-24 13:24:16 +00:00
" Asks the agent to login to the system with callback. \n "
2003-07-14 02:31:56 +00:00
" The agent's callback extension is called (optionally with the specified \n "
2004-12-31 00:58:44 +00:00
" context). \n "
2004-10-24 13:24:16 +00:00
" The option string may contain zero or more of the following characters: \n "
" 's' -- silent login - do not announce the login ok segment agent logged in/off \n " ;
2005-03-04 06:47:24 +00:00
static const char descrip3 [ ] =
2004-02-05 21:13:17 +00:00
" AgentMonitorOutgoing([options]): \n "
2004-12-31 00:58:44 +00:00
" Tries to figure out the id of the agent who is placing outgoing call based on \n "
2006-01-13 06:11:41 +00:00
" comparison of the callerid of the current interface and the global variable \n "
2004-12-31 00:58:44 +00:00
" placed by the AgentCallbackLogin application. That's why it should be used only \n "
" with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n "
" instead of Monitor application. That have to be configured in the agents.conf file. \n "
" \n Return value: \n "
" Normally the app returns 0 unless the options are passed. Also if the callerid or \n "
" the agentid are not specified it'll look for n+101 priority. \n "
" \n Options: \n "
" 'd' - make the app return -1 if there is an error condition and there is \n "
" no extension n+101 \n "
2004-12-10 17:37:20 +00:00
" 'c' - change the CDR so that the source of the call is 'Agent/agent_id' \n "
2004-12-31 00:58:44 +00:00
" 'n' - don't generate the warnings when there is no callerid or the \n "
" agentid is not known. \n "
" It's handy if you want to have one context for agent and non-agent calls. \n " ;
2004-02-05 21:13:17 +00:00
2005-03-04 06:47:24 +00:00
static const char mandescr_agents [ ] =
2004-12-01 05:00:29 +00:00
" Description: Will list info about all possible agents. \n "
" Variables: NONE \n " ;
2005-08-26 20:24:16 +00:00
static const char mandescr_agent_logoff [ ] =
" 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 " ;
static const char mandescr_agent_callback_login [ ] =
" Description: Sets an agent as logged in with callback. \n "
" Variables: (Names marked with * are required) \n "
" *Agent: Agent ID of the agent to login \n "
2005-12-21 19:44:51 +00:00
" *Exten: Extension to use for callback \n "
2005-08-26 20:24:16 +00:00
" Context: Context to use for callback \n "
" AckCall: Set to 'true' to require an acknowledgement by '#' when agent is called back \n "
" WrapupTime: the minimum amount of time after disconnecting before the caller can receive a new call \n " ;
2002-09-02 15:20:28 +00:00
static char moh [ 80 ] = " default " ;
2005-09-07 20:44:57 +00:00
# define AST_MAX_AGENT 80 /**< Agent ID or Password max length */
2004-02-03 16:57:00 +00:00
# define AST_MAX_BUF 256
2004-10-24 13:24:16 +00:00
# define AST_MAX_FILENAME_LEN 256
2002-09-02 15:20:28 +00:00
2005-09-07 20:44:57 +00:00
/** Persistent Agents astdb family */
2005-03-04 06:47:24 +00:00
static const char pa_family [ ] = " /Agents " ;
2006-01-13 06:11:41 +00:00
/** The maximum length of each persistent member agent database entry */
2005-01-01 00:57:04 +00:00
# define PA_MAX_LEN 2048
2005-09-07 20:44:57 +00:00
/** queues.conf [general] option */
2005-01-01 00:57:04 +00:00
static int persistent_agents = 0 ;
static void dump_agents ( void ) ;
2005-01-15 21:51:38 +00:00
static ast_group_t group ;
2003-07-22 11:06:56 +00:00
static int autologoff ;
2003-07-28 14:24:10 +00:00
static int wrapuptime ;
2003-08-05 23:57:55 +00:00
static int ackcall ;
2006-01-12 19:07:18 +00:00
static int multiplelogin = 1 ;
2006-01-13 18:23:30 +00:00
static int autologoffunavail = 0 ;
2003-07-01 04:08:25 +00:00
2004-10-24 13:24:16 +00:00
static int maxlogintries = 3 ;
static char agentgoodbye [ AST_MAX_FILENAME_LEN ] = " vm-goodbye " ;
2002-09-02 15:20:28 +00:00
static int usecnt = 0 ;
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( usecnt_lock ) ;
2002-09-02 15:20:28 +00:00
2004-02-12 22:28:35 +00:00
static int recordagentcalls = 0 ;
2004-07-16 04:40:54 +00:00
static char recordformat [ AST_MAX_BUF ] = " " ;
static char recordformatext [ AST_MAX_BUF ] = " " ;
static char urlprefix [ AST_MAX_BUF ] = " " ;
static char savecallsin [ AST_MAX_BUF ] = " " ;
2004-04-03 00:41:47 +00:00
static int updatecdr = 0 ;
2004-06-28 18:40:41 +00:00
static char beep [ AST_MAX_BUF ] = " beep " ;
2004-02-03 16:57:00 +00:00
2004-02-05 21:13:17 +00:00
# define GETAGENTBYCALLERID "AGENTBYCALLERID"
2005-09-07 20:44:57 +00:00
/**
* Structure representing an agent .
*/
struct agent_pvt {
ast_mutex_t lock ; /**< Channel private lock */
int dead ; /**< Poised for destruction? */
int pending ; /**< Not a real agent -- just pending a match */
int abouttograb ; /**< About to grab */
int autologoff ; /**< Auto timeout time */
int ackcall ; /**< ackcall */
time_t loginstart ; /**< When agent first logged in (0 when logged off) */
time_t start ; /**< When call started */
struct timeval lastdisc ; /**< When last disconnected */
int wrapuptime ; /**< Wrapup time in ms */
ast_group_t group ; /**< Group memberships */
int acknowledged ; /**< Acknowledged */
char moh [ 80 ] ; /**< Which music on hold */
char agent [ AST_MAX_AGENT ] ; /**< Agent ID */
char password [ AST_MAX_AGENT ] ; /**< Password for Agent login */
2002-09-02 15:20:28 +00:00
char name [ AST_MAX_AGENT ] ;
2005-09-07 20:44:57 +00:00
ast_mutex_t app_lock ; /**< Synchronization between owning applications */
volatile pthread_t owning_app ; /**< Owning application thread id */
volatile int app_sleep_cond ; /**< Sleep condition for the login app */
struct ast_channel * owner ; /**< Agent */
char loginchan [ 80 ] ; /**< channel they logged in from */
char logincallerid [ 80 ] ; /**< Caller ID they had when they logged in */
struct ast_channel * chan ; /**< Channel we use */
2006-01-25 18:12:55 +00:00
AST_LIST_ENTRY ( agent_pvt ) list ; /**< Next Agent in the linked list. */
2005-09-07 20:44:57 +00:00
} ;
2006-01-25 18:12:55 +00:00
static AST_LIST_HEAD_STATIC ( agents , agent_pvt ) ; /**< Holds the list of agents (loaded form agents.conf). */
2002-09-02 15:20:28 +00:00
2003-08-13 17:32:44 +00:00
# define CHECK_FORMATS(ast, p) do { \
if ( p - > chan ) { \
if ( ast - > nativeformats ! = p - > chan - > nativeformats ) { \
ast_log ( LOG_DEBUG , " Native formats changing from %d to %d \n " , ast - > nativeformats , p - > chan - > nativeformats ) ; \
/* Native formats changed, reset things */ \
ast - > nativeformats = p - > chan - > nativeformats ; \
ast_log ( LOG_DEBUG , " Resetting read to %d and write to %d \n " , ast - > readformat , ast - > writeformat ) ; \
2004-04-06 22:17:32 +00:00
ast_set_read_format ( ast , ast - > readformat ) ; \
ast_set_write_format ( ast , ast - > writeformat ) ; \
2003-08-13 17:32:44 +00:00
} \
2005-03-04 06:47:24 +00:00
if ( p - > chan - > readformat ! = ast - > rawreadformat ) \
ast_set_read_format ( p - > chan , ast - > rawreadformat ) ; \
if ( p - > chan - > writeformat ! = ast - > rawwriteformat ) \
ast_set_write_format ( p - > chan , ast - > rawwriteformat ) ; \
2003-08-13 17:32:44 +00:00
} \
} while ( 0 )
2003-08-23 02:11:44 +00:00
/* 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 */
2002-09-02 15:20:28 +00:00
# define CLEANUP(ast, p) do { \
int x ; \
if ( p - > chan ) { \
2003-08-23 02:11:44 +00:00
for ( x = 0 ; x < AST_MAX_FDS ; x + + ) { \
2006-01-30 03:13:33 +00:00
if ( x ! = AST_TIMING_FD ) \
2003-08-23 02:11:44 +00:00
ast - > fds [ x ] = p - > chan - > fds [ x ] ; \
} \
2006-01-30 03:13:33 +00:00
ast - > fds [ AST_AGENT_FD ] = p - > chan - > fds [ AST_TIMING_FD ] ; \
2002-09-02 15:20:28 +00:00
} \
} while ( 0 )
2005-03-04 06:47:24 +00:00
static struct ast_channel * agent_request ( const char * type , int format , void * data , int * cause ) ;
static int agent_devicestate ( void * data ) ;
2006-02-14 23:42:36 +00:00
static void agent_logoff_maintenance ( struct agent_pvt * p , char * loginchan , long logintime , const char * uniqueid , char * logcommand ) ;
2005-03-04 06:47:24 +00:00
static int agent_digit ( struct ast_channel * ast , char digit ) ;
static int agent_call ( struct ast_channel * ast , char * dest , int timeout ) ;
static int agent_hangup ( struct ast_channel * ast ) ;
static int agent_answer ( struct ast_channel * ast ) ;
static struct ast_frame * agent_read ( struct ast_channel * ast ) ;
static int agent_write ( struct ast_channel * ast , struct ast_frame * f ) ;
2005-03-28 20:48:24 +00:00
static int agent_sendhtml ( struct ast_channel * ast , int subclass , const char * data , int datalen ) ;
2005-10-14 00:46:13 +00:00
static int agent_sendtext ( struct ast_channel * ast , const char * text ) ;
2005-03-04 06:47:24 +00:00
static int agent_indicate ( struct ast_channel * ast , int condition ) ;
static int agent_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan ) ;
static struct ast_channel * agent_bridgedchannel ( struct ast_channel * chan , struct ast_channel * bridge ) ;
2006-01-13 18:23:30 +00:00
static void set_agentbycallerid ( const char * callerid , const char * agent ) ;
2005-03-04 06:47:24 +00:00
static const struct ast_channel_tech agent_tech = {
2006-02-01 23:05:28 +00:00
. type = " Agent " ,
2005-03-04 06:47:24 +00:00
. description = tdesc ,
. capabilities = - 1 ,
. requester = agent_request ,
. devicestate = agent_devicestate ,
. send_digit = agent_digit ,
. call = agent_call ,
. hangup = agent_hangup ,
. answer = agent_answer ,
. read = agent_read ,
. write = agent_write ,
. send_html = agent_sendhtml ,
2005-10-14 00:46:13 +00:00
. send_text = agent_sendtext ,
2005-03-04 06:47:24 +00:00
. exception = agent_read ,
. indicate = agent_indicate ,
. fixup = agent_fixup ,
. bridged_channel = agent_bridgedchannel ,
} ;
2005-01-01 00:57:04 +00:00
2005-09-07 20:44:57 +00:00
/**
* Adds an agent to the global list of agents .
*
* @ param agent A string with the username , password and real name of an agent . As defined in agents . conf . Example : " 13,169,John Smith "
* @ param pending If it is pending or not .
* @ return The just created agent .
* @ sa agent_pvt , agents .
*/
2003-07-01 16:16:28 +00:00
static struct agent_pvt * add_agent ( char * agent , int pending )
2002-09-02 15:20:28 +00:00
{
2006-01-13 18:30:49 +00:00
char * parse ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( agt ) ;
AST_APP_ARG ( password ) ;
AST_APP_ARG ( name ) ;
) ;
2005-04-15 05:51:30 +00:00
char * password = NULL ;
char * name = NULL ;
char * agt = NULL ;
2006-01-25 18:12:55 +00:00
struct agent_pvt * p ;
2005-04-15 05:51:30 +00:00
2006-01-21 20:57:06 +00:00
if ( ! ( parse = ast_strdupa ( agent ) ) )
2006-01-21 17:50:04 +00:00
return NULL ;
2006-01-13 18:30:49 +00:00
/* Extract username (agt), password and name from agent (args). */
AST_NONSTANDARD_APP_ARGS ( args , parse , ' , ' ) ;
if ( args . argc = = 0 ) {
2005-04-15 05:51:30 +00:00
ast_log ( LOG_WARNING , " A blank agent line! \n " ) ;
2006-01-13 18:30:49 +00:00
return NULL ;
}
if ( ast_strlen_zero ( args . agt ) ) {
ast_log ( LOG_WARNING , " An agent line with no agentid! \n " ) ;
return NULL ;
} else
agt = args . agt ;
if ( ! ast_strlen_zero ( args . password ) ) {
password = args . password ;
while ( * password & & * password < 33 ) password + + ;
}
if ( ! ast_strlen_zero ( args . name ) ) {
name = args . name ;
while ( * name & & * name < 33 ) name + + ;
2002-09-02 15:20:28 +00:00
}
2005-04-15 05:51:30 +00:00
2006-01-13 18:30:49 +00:00
/* Are we searching for the agent here ? To see if it exists already ? */
2006-01-25 18:12:55 +00:00
AST_LIST_TRAVERSE ( & agents , p , list ) {
2005-04-15 05:51:30 +00:00
if ( ! pending & & ! strcmp ( p - > agent , agt ) )
2002-09-02 15:20:28 +00:00
break ;
}
if ( ! p ) {
2005-09-07 20:44:57 +00:00
// Build the agent.
2006-01-11 01:20:29 +00:00
if ( ! ( p = ast_calloc ( 1 , sizeof ( * p ) ) ) )
2005-04-15 05:51:30 +00:00
return NULL ;
2006-01-11 01:20:29 +00:00
ast_copy_string ( p - > agent , agt , sizeof ( p - > agent ) ) ;
ast_mutex_init ( & p - > lock ) ;
ast_mutex_init ( & p - > app_lock ) ;
p - > owning_app = ( pthread_t ) - 1 ;
p - > app_sleep_cond = 1 ;
p - > group = group ;
p - > pending = pending ;
2006-01-25 18:12:55 +00:00
AST_LIST_INSERT_TAIL ( & agents , p , list ) ;
2002-09-02 15:20:28 +00:00
}
2005-04-15 05:51:30 +00:00
2005-08-26 20:24:16 +00:00
ast_copy_string ( p - > password , password ? password : " " , sizeof ( p - > password ) ) ;
ast_copy_string ( p - > name , name ? name : " " , sizeof ( p - > name ) ) ;
ast_copy_string ( p - > moh , moh , sizeof ( p - > moh ) ) ;
2003-08-05 23:57:55 +00:00
p - > ackcall = ackcall ;
2003-07-22 11:06:56 +00:00
p - > autologoff = autologoff ;
2005-04-06 16:06:05 +00:00
/* If someone reduces the wrapuptime and reloads, we want it
* to change the wrapuptime immediately on all calls */
if ( p - > wrapuptime > wrapuptime ) {
2005-07-15 23:00:47 +00:00
struct timeval now = ast_tvnow ( ) ;
/* XXX check what is this exactly */
2005-04-06 16:06:05 +00:00
/* We won't be pedantic and check the tv_usec val */
if ( p - > lastdisc . tv_sec > ( now . tv_sec + wrapuptime / 1000 ) ) {
p - > lastdisc . tv_sec = now . tv_sec + wrapuptime / 1000 ;
p - > lastdisc . tv_usec = now . tv_usec ;
}
}
2003-07-28 14:24:10 +00:00
p - > wrapuptime = wrapuptime ;
2005-04-06 16:06:05 +00:00
2003-07-01 16:16:28 +00:00
if ( pending )
p - > dead = 1 ;
else
p - > dead = 0 ;
return p ;
2002-09-02 15:20:28 +00:00
}
2005-09-14 02:12:37 +00:00
/**
* Deletes an agent after doing some clean up .
* Further documentation : How safe is this function ? What state should the agent be to be cleaned .
* @ param p Agent to be deleted .
* @ returns Always 0.
*/
2003-07-09 22:41:51 +00:00
static int agent_cleanup ( struct agent_pvt * p )
{
struct ast_channel * chan = p - > owner ;
p - > owner = NULL ;
2005-03-04 06:47:24 +00:00
chan - > tech_pvt = NULL ;
2003-07-09 22:41:51 +00:00
p - > app_sleep_cond = 1 ;
/* Release ownership of the agent to other threads (presumably running the login app). */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > app_lock ) ;
2003-07-09 22:41:51 +00:00
if ( chan )
ast_channel_free ( chan ) ;
2004-06-22 17:42:14 +00:00
if ( p - > dead ) {
ast_mutex_destroy ( & p - > lock ) ;
ast_mutex_destroy ( & p - > app_lock ) ;
2003-07-09 22:41:51 +00:00
free ( p ) ;
2004-06-22 17:42:14 +00:00
}
2003-07-09 22:41:51 +00:00
return 0 ;
}
2003-07-01 16:16:28 +00:00
static int check_availability ( struct agent_pvt * newlyavailable , int needlock ) ;
2002-09-02 15:20:28 +00:00
static int agent_answer ( struct ast_channel * ast )
{
ast_log ( LOG_WARNING , " Huh? Agent is being asked to answer? \n " ) ;
return - 1 ;
}
2004-02-05 21:13:17 +00:00
static int __agent_start_monitoring ( struct ast_channel * ast , struct agent_pvt * p , int needlock )
2004-02-03 16:57:00 +00:00
{
char tmp [ AST_MAX_BUF ] , tmp2 [ AST_MAX_BUF ] , * pointer ;
char filename [ AST_MAX_BUF ] ;
int res = - 1 ;
if ( ! p )
return - 1 ;
if ( ! ast - > monitor ) {
snprintf ( filename , sizeof ( filename ) , " agent-%s-%s " , p - > agent , ast - > uniqueid ) ;
2004-02-10 21:14:48 +00:00
/* substitute . for - */
if ( ( pointer = strchr ( filename , ' . ' ) ) )
2004-02-03 16:57:00 +00:00
* pointer = ' - ' ;
2004-02-10 21:14:48 +00:00
snprintf ( tmp , sizeof ( tmp ) , " %s%s " , savecallsin ? savecallsin : " " , filename ) ;
2004-02-03 16:57:00 +00:00
ast_monitor_start ( ast , recordformat , tmp , needlock ) ;
ast_monitor_setjoinfiles ( ast , 1 ) ;
snprintf ( tmp2 , sizeof ( tmp2 ) , " %s%s.%s " , urlprefix ? urlprefix : " " , filename , recordformatext ) ;
#if 0
ast_verbose ( " name is %s, link is %s \n " , tmp , tmp2 ) ;
# endif
if ( ! ast - > cdr )
ast - > cdr = ast_cdr_alloc ( ) ;
ast_cdr_setuserfield ( ast , tmp2 ) ;
res = 0 ;
} else
ast_log ( LOG_ERROR , " Recording already started on that call. \n " ) ;
return res ;
}
2004-02-05 21:13:17 +00:00
static int agent_start_monitoring ( struct ast_channel * ast , int needlock )
{
2005-03-04 06:47:24 +00:00
return __agent_start_monitoring ( ast , ast - > tech_pvt , needlock ) ;
2004-02-05 21:13:17 +00:00
}
2004-12-31 00:58:44 +00:00
static struct ast_frame * agent_read ( struct ast_channel * ast )
2002-09-02 15:20:28 +00:00
{
2005-03-04 06:47:24 +00:00
struct agent_pvt * p = ast - > tech_pvt ;
2002-09-02 15:20:28 +00:00
struct ast_frame * f = NULL ;
2003-07-14 02:31:56 +00:00
static struct ast_frame answer_frame = { AST_FRAME_CONTROL , AST_CONTROL_ANSWER } ;
2006-01-13 18:23:30 +00:00
const char * status ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-08-13 17:32:44 +00:00
CHECK_FORMATS ( ast , p ) ;
2003-08-13 01:12:19 +00:00
if ( p - > chan ) {
2004-12-07 20:38:43 +00:00
ast_copy_flags ( p - > chan , ast , AST_FLAG_EXCEPTION ) ;
2006-01-30 03:13:33 +00:00
p - > chan - > fdno = ( ast - > fdno = = AST_AGENT_FD ) ? AST_TIMING_FD : ast - > fdno ;
2002-09-02 15:20:28 +00:00
f = ast_read ( p - > chan ) ;
2003-08-13 01:12:19 +00:00
} else
2006-01-31 17:18:58 +00:00
f = & ast_null_frame ;
2002-09-02 15:20:28 +00:00
if ( ! f ) {
2005-04-05 21:30:24 +00:00
/* If there's a channel, hang it up (if it's on a callback) make it NULL */
2003-07-27 04:27:18 +00:00
if ( p - > chan ) {
2005-03-22 19:10:21 +00:00
p - > chan - > _bridge = NULL ;
2003-08-27 15:59:43 +00:00
/* Note that we don't hangup if it's not a callback because Asterisk will do it
for us when the PBX instance that called login finishes */
2004-08-11 19:02:46 +00:00
if ( ! ast_strlen_zero ( p - > loginchan ) ) {
2005-02-14 23:20:01 +00:00
if ( p - > chan )
ast_log ( LOG_DEBUG , " Bridge on '%s' being cleared (2) \n " , p - > chan - > name ) ;
2006-01-13 18:23:30 +00:00
status = pbx_builtin_getvar_helper ( p - > chan , " CHANLOCALSTATUS " ) ;
if ( autologoffunavail & & status & & ! strcasecmp ( status , " CHANUNAVAIL " ) ) {
long logintime = time ( NULL ) - p - > loginstart ;
p - > loginstart = 0 ;
ast_log ( LOG_NOTICE , " Agent read: '%s' is not available now, auto logoff \n " , p - > name ) ;
2006-01-14 03:25:38 +00:00
agent_logoff_maintenance ( p , p - > loginchan , logintime , ast - > uniqueid , " Chanunavail " ) ;
2006-01-13 18:23:30 +00:00
}
2003-07-28 14:24:10 +00:00
ast_hangup ( p - > chan ) ;
2005-07-15 23:00:47 +00:00
if ( p - > wrapuptime & & p - > acknowledged )
p - > lastdisc = ast_tvadd ( ast_tvnow ( ) , ast_samp2tv ( p - > wrapuptime , 1000 ) ) ;
2004-08-11 19:02:46 +00:00
}
2002-09-02 15:20:28 +00:00
p - > chan = NULL ;
2003-08-06 01:39:42 +00:00
p - > acknowledged = 0 ;
2003-07-27 04:27:18 +00:00
}
2005-04-05 21:30:24 +00:00
} else {
/* if acknowledgement is not required, and the channel is up, we may have missed
an AST_CONTROL_ANSWER ( if there was one ) , so mark the call acknowledged anyway */
2005-10-13 16:29:49 +00:00
if ( ! p - > ackcall & & ! p - > acknowledged & & p - > chan & & ( p - > chan - > _state = = AST_STATE_UP ) )
2005-04-05 21:30:24 +00:00
p - > acknowledged = 1 ;
switch ( f - > frametype ) {
case AST_FRAME_CONTROL :
if ( f - > subclass = = AST_CONTROL_ANSWER ) {
if ( p - > ackcall ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s answered, waiting for '#' to acknowledge \n " , p - > chan - > name ) ;
/* Don't pass answer along */
ast_frfree ( f ) ;
2006-01-31 17:18:58 +00:00
f = & ast_null_frame ;
2005-04-05 21:30:24 +00:00
} else {
p - > acknowledged = 1 ;
2005-06-18 16:38:48 +00:00
/* Use the builtin answer frame for the
recording start check below . */
ast_frfree ( f ) ;
f = & answer_frame ;
2005-04-05 21:30:24 +00:00
}
}
break ;
case AST_FRAME_DTMF :
if ( ! p - > acknowledged & & ( f - > subclass = = ' # ' ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s acknowledged \n " , p - > chan - > name ) ;
p - > acknowledged = 1 ;
ast_frfree ( f ) ;
f = & answer_frame ;
} else if ( f - > subclass = = ' * ' ) {
/* terminates call */
ast_frfree ( f ) ;
f = NULL ;
}
break ;
case AST_FRAME_VOICE :
/* don't pass voice until the call is acknowledged */
if ( ! p - > acknowledged ) {
ast_frfree ( f ) ;
2006-01-31 17:18:58 +00:00
f = & ast_null_frame ;
2005-04-05 21:30:24 +00:00
}
break ;
}
}
2002-09-02 15:20:28 +00:00
CLEANUP ( ast , p ) ;
2005-02-14 23:20:01 +00:00
if ( p - > chan & & ! p - > chan - > _bridge ) {
2006-02-01 23:05:28 +00:00
if ( strcasecmp ( p - > chan - > tech - > type , " Local " ) ) {
2005-02-14 23:20:01 +00:00
p - > chan - > _bridge = ast ;
if ( p - > chan )
ast_log ( LOG_DEBUG , " Bridge on '%s' being set to '%s' (3) \n " , p - > chan - > name , p - > chan - > _bridge - > name ) ;
}
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2004-02-12 22:28:35 +00:00
if ( recordagentcalls & & f = = & answer_frame )
2004-02-03 16:57:00 +00:00
agent_start_monitoring ( ast , 0 ) ;
2002-09-02 15:20:28 +00:00
return f ;
}
2005-03-28 20:48:24 +00:00
static int agent_sendhtml ( struct ast_channel * ast , int subclass , const char * data , int datalen )
2005-02-10 06:36:09 +00:00
{
2005-03-04 06:47:24 +00:00
struct agent_pvt * p = ast - > tech_pvt ;
2005-02-10 06:36:09 +00:00
int res = - 1 ;
ast_mutex_lock ( & p - > lock ) ;
if ( p - > chan )
res = ast_channel_sendhtml ( p - > chan , subclass , data , datalen ) ;
ast_mutex_unlock ( & p - > lock ) ;
return res ;
}
2005-10-14 00:46:13 +00:00
static int agent_sendtext ( struct ast_channel * ast , const char * text )
{
struct agent_pvt * p = ast - > tech_pvt ;
int res = - 1 ;
ast_mutex_lock ( & p - > lock ) ;
if ( p - > chan )
res = ast_sendtext ( p - > chan , text ) ;
ast_mutex_unlock ( & p - > lock ) ;
return res ;
}
2002-09-02 15:20:28 +00:00
static int agent_write ( struct ast_channel * ast , struct ast_frame * f )
{
2005-03-04 06:47:24 +00:00
struct agent_pvt * p = ast - > tech_pvt ;
2002-09-02 15:20:28 +00:00
int res = - 1 ;
2003-08-13 17:32:44 +00:00
CHECK_FORMATS ( ast , p ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-08-13 01:12:19 +00:00
if ( p - > chan ) {
2003-08-13 17:32:44 +00:00
if ( ( f - > frametype ! = AST_FRAME_VOICE ) | |
2005-09-14 00:28:06 +00:00
( f - > subclass = = p - > chan - > writeformat ) ) {
2003-08-13 17:32:44 +00:00
res = ast_write ( p - > chan , f ) ;
} else {
ast_log ( LOG_DEBUG , " Dropping one incompatible voice frame on '%s' to '%s' \n " , ast - > name , p - > chan - > name ) ;
res = 0 ;
}
2003-08-13 01:12:19 +00:00
} else
2003-07-01 16:16:28 +00:00
res = 0 ;
2002-09-02 15:20:28 +00:00
CLEANUP ( ast , p ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
return res ;
}
2004-04-08 19:19:24 +00:00
static int agent_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan )
2002-09-02 15:20:28 +00:00
{
2005-03-04 06:47:24 +00:00
struct agent_pvt * p = newchan - > tech_pvt ;
2004-04-08 19:28:05 +00:00
ast_mutex_lock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
if ( p - > owner ! = oldchan ) {
ast_log ( LOG_WARNING , " old channel wasn't %p but was %p \n " , oldchan , p - > owner ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
return - 1 ;
}
p - > owner = newchan ;
2004-04-08 19:28:05 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
return 0 ;
}
static int agent_indicate ( struct ast_channel * ast , int condition )
{
2005-03-04 06:47:24 +00:00
struct agent_pvt * p = ast - > tech_pvt ;
2002-09-02 15:20:28 +00:00
int res = - 1 ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
if ( p - > chan )
res = ast_indicate ( p - > chan , condition ) ;
2003-07-01 16:16:28 +00:00
else
res = 0 ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
return res ;
}
static int agent_digit ( struct ast_channel * ast , char digit )
{
2005-03-04 06:47:24 +00:00
struct agent_pvt * p = ast - > tech_pvt ;
2002-09-02 15:20:28 +00:00
int res = - 1 ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
if ( p - > chan )
2005-03-04 06:47:24 +00:00
res = p - > chan - > tech - > send_digit ( p - > chan , digit ) ;
2003-07-01 16:16:28 +00:00
else
res = 0 ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
return res ;
}
static int agent_call ( struct ast_channel * ast , char * dest , int timeout )
{
2005-03-04 06:47:24 +00:00
struct agent_pvt * p = ast - > tech_pvt ;
2002-09-02 15:20:28 +00:00
int res = - 1 ;
2005-01-15 23:31:19 +00:00
int newstate = 0 ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-08-21 16:42:13 +00:00
p - > acknowledged = 0 ;
2003-07-01 16:16:28 +00:00
if ( ! p - > chan ) {
if ( p - > pending ) {
ast_log ( LOG_DEBUG , " Pretending to dial on pending agent \n " ) ;
2005-01-15 23:31:19 +00:00
newstate = AST_STATE_DIALING ;
2003-07-01 16:16:28 +00:00
res = 0 ;
} else {
ast_log ( LOG_NOTICE , " Whoa, they hung up between alloc and call... what are the odds of that? \n " ) ;
res = - 1 ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2005-01-15 23:31:19 +00:00
if ( newstate )
ast_setstate ( ast , newstate ) ;
2003-07-01 16:16:28 +00:00
return res ;
2004-05-09 07:51:44 +00:00
} else if ( ! ast_strlen_zero ( p - > loginchan ) ) {
2003-07-22 11:06:56 +00:00
time ( & p - > start ) ;
2003-07-14 02:31:56 +00:00
/* Call on this agent */
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " outgoing agentcall, to agent '%s', on '%s' \n " , p - > agent , p - > chan - > name ) ;
2004-10-02 00:58:31 +00:00
if ( p - > chan - > cid . cid_num )
free ( p - > chan - > cid . cid_num ) ;
2006-01-11 01:20:29 +00:00
p - > chan - > cid . cid_num = ast_strdup ( ast - > cid . cid_num ) ;
2004-10-02 00:58:31 +00:00
if ( p - > chan - > cid . cid_name )
free ( p - > chan - > cid . cid_name ) ;
2006-01-11 01:20:29 +00:00
p - > chan - > cid . cid_name = ast_strdup ( ast - > cid . cid_name ) ;
2005-02-07 22:24:11 +00:00
ast_channel_inherit_variables ( ast , p - > chan ) ;
2003-07-14 02:31:56 +00:00
res = ast_call ( p - > chan , p - > loginchan , 0 ) ;
CLEANUP ( ast , p ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-07-14 02:31:56 +00:00
return res ;
2003-07-01 16:16:28 +00:00
}
2003-03-20 17:21:54 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " agent_call, call to agent '%s' call on '%s' \n " , p - > agent , p - > chan - > name ) ;
ast_log ( LOG_DEBUG , " Playing beep, lang '%s' \n " , p - > chan - > language ) ;
2004-06-28 18:40:41 +00:00
res = ast_streamfile ( p - > chan , beep , p - > chan - > language ) ;
2003-03-20 17:21:54 +00:00
ast_log ( LOG_DEBUG , " Played beep, result '%d' \n " , res ) ;
if ( ! res ) {
2002-09-02 15:20:28 +00:00
res = ast_waitstream ( p - > chan , " " ) ;
2003-03-20 17:21:54 +00:00
ast_log ( LOG_DEBUG , " Waited for stream, result '%d' \n " , res ) ;
}
2002-09-02 15:20:28 +00:00
if ( ! res ) {
2004-04-06 22:17:32 +00:00
res = ast_set_read_format ( p - > chan , ast_best_codec ( p - > chan - > nativeformats ) ) ;
2003-03-20 17:21:54 +00:00
ast_log ( LOG_DEBUG , " Set read format, result '%d' \n " , res ) ;
2002-09-02 15:20:28 +00:00
if ( res )
2003-08-16 05:10:35 +00:00
ast_log ( LOG_WARNING , " Unable to set read format to %s \n " , ast_getformatname ( ast_best_codec ( p - > chan - > nativeformats ) ) ) ;
2003-07-01 16:16:28 +00:00
} else {
2004-12-19 21:13:41 +00:00
/* Agent hung-up */
2003-03-20 17:21:54 +00:00
p - > chan = NULL ;
}
2002-09-02 15:20:28 +00:00
if ( ! res ) {
2004-04-06 22:17:32 +00:00
ast_set_write_format ( p - > chan , ast_best_codec ( p - > chan - > nativeformats ) ) ;
2003-03-20 17:21:54 +00:00
ast_log ( LOG_DEBUG , " Set write format, result '%d' \n " , res ) ;
2002-09-02 15:20:28 +00:00
if ( res )
2003-08-16 05:10:35 +00:00
ast_log ( LOG_WARNING , " Unable to set write format to %s \n " , ast_getformatname ( ast_best_codec ( p - > chan - > nativeformats ) ) ) ;
2002-09-02 15:20:28 +00:00
}
2003-03-20 17:21:54 +00:00
if ( ! res )
{
2003-08-21 16:42:13 +00:00
/* Call is immediately up, or might need ack */
if ( p - > ackcall > 1 )
2005-01-15 23:31:19 +00:00
newstate = AST_STATE_RINGING ;
2003-08-21 16:42:13 +00:00
else {
2005-01-15 23:31:19 +00:00
newstate = AST_STATE_UP ;
2004-02-12 22:28:35 +00:00
if ( recordagentcalls )
agent_start_monitoring ( ast , 0 ) ;
2003-08-21 16:42:13 +00:00
p - > acknowledged = 1 ;
}
res = 0 ;
2003-03-20 17:21:54 +00:00
}
2002-12-06 16:22:19 +00:00
CLEANUP ( ast , p ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2005-01-15 23:31:19 +00:00
if ( newstate )
ast_setstate ( ast , newstate ) ;
2002-09-02 15:20:28 +00:00
return res ;
}
2005-07-06 01:29:15 +00:00
/* store/clear the global variable that stores agentid based on the callerid */
2005-09-14 00:39:05 +00:00
static void set_agentbycallerid ( const char * callerid , const char * agent )
2005-07-06 01:29:15 +00:00
{
char buf [ AST_MAX_BUF ] ;
/* if there is no Caller ID, nothing to do */
2005-10-27 02:19:37 +00:00
if ( ast_strlen_zero ( callerid ) )
2005-07-06 01:29:15 +00:00
return ;
2005-09-14 00:39:05 +00:00
snprintf ( buf , sizeof ( buf ) , " %s_%s " , GETAGENTBYCALLERID , callerid ) ;
pbx_builtin_setvar_helper ( NULL , buf , agent ) ;
2005-07-06 01:29:15 +00:00
}
2002-09-02 15:20:28 +00:00
static int agent_hangup ( struct ast_channel * ast )
{
2005-03-04 06:47:24 +00:00
struct agent_pvt * p = ast - > tech_pvt ;
2003-07-22 11:06:56 +00:00
int howlong = 0 ;
2006-01-13 18:23:30 +00:00
const char * status ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
p - > owner = NULL ;
2005-03-04 06:47:24 +00:00
ast - > tech_pvt = NULL ;
2002-12-06 16:22:19 +00:00
p - > app_sleep_cond = 1 ;
2003-08-21 16:42:13 +00:00
p - > acknowledged = 0 ;
2004-10-16 15:01:59 +00:00
/* if they really are hung up then set start to 0 so the test
* later if we ' re called on an already downed channel
* doesn ' t cause an agent to be logged out like when
* agent_request ( ) is followed immediately by agent_hangup ( )
* as in apps / app_chanisavail . c : chanavail_exec ( )
*/
2004-12-11 04:46:49 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
usecnt - - ;
ast_mutex_unlock ( & usecnt_lock ) ;
2004-10-16 15:01:59 +00:00
ast_log ( LOG_DEBUG , " Hangup called for state %s \n " , ast_state2str ( ast - > _state ) ) ;
if ( p - > start & & ( ast - > _state ! = AST_STATE_UP ) ) {
2003-07-22 11:06:56 +00:00
howlong = time ( NULL ) - p - > start ;
2004-10-16 15:01:59 +00:00
p - > start = 0 ;
} else if ( ast - > _state = = AST_STATE_RESERVED ) {
howlong = 0 ;
} else
p - > start = 0 ;
2002-09-02 15:20:28 +00:00
if ( p - > chan ) {
2005-03-22 19:10:21 +00:00
p - > chan - > _bridge = NULL ;
2002-09-02 15:20:28 +00:00
/* If they're dead, go ahead and hang up on the agent now */
2004-05-09 07:51:44 +00:00
if ( ! ast_strlen_zero ( p - > loginchan ) ) {
2004-08-01 02:39:32 +00:00
/* Store last disconnect time */
2005-10-05 21:27:38 +00:00
if ( p - > wrapuptime )
2005-07-15 23:00:47 +00:00
p - > lastdisc = ast_tvadd ( ast_tvnow ( ) , ast_samp2tv ( p - > wrapuptime , 1000 ) ) ;
else
p - > lastdisc = ast_tv ( 0 , 0 ) ;
2003-07-14 02:31:56 +00:00
if ( p - > chan ) {
2006-01-13 18:23:30 +00:00
status = pbx_builtin_getvar_helper ( p - > chan , " CHANLOCALSTATUS " ) ;
if ( autologoffunavail & & status & & ! strcasecmp ( status , " CHANUNAVAIL " ) ) {
long logintime = time ( NULL ) - p - > loginstart ;
p - > loginstart = 0 ;
ast_log ( LOG_NOTICE , " Agent hangup: '%s' is not available now, auto logoff \n " , p - > name ) ;
2006-01-14 03:25:38 +00:00
agent_logoff_maintenance ( p , p - > loginchan , logintime , ast - > uniqueid , " Chanunavail " ) ;
2006-01-13 18:23:30 +00:00
}
2003-07-14 02:31:56 +00:00
/* Recognize the hangup and pass it along immediately */
ast_hangup ( p - > chan ) ;
p - > chan = NULL ;
}
2003-07-27 04:27:18 +00:00
ast_log ( LOG_DEBUG , " Hungup, howlong is %d, autologoff is %d \n " , howlong , p - > autologoff ) ;
2003-07-22 11:06:56 +00:00
if ( howlong & & p - > autologoff & & ( howlong > p - > autologoff ) ) {
2004-06-03 17:33:35 +00:00
long logintime = time ( NULL ) - p - > loginstart ;
p - > loginstart = 0 ;
2003-07-22 11:06:56 +00:00
ast_log ( LOG_NOTICE , " Agent '%s' didn't answer/confirm within %d seconds (waited %d) \n " , p - > name , p - > autologoff , howlong ) ;
2006-01-14 03:25:38 +00:00
agent_logoff_maintenance ( p , p - > loginchan , logintime , ast - > uniqueid , " Autologoff " ) ;
2003-07-22 11:06:56 +00:00
}
2003-07-14 02:31:56 +00:00
} else if ( p - > dead ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > chan - > lock ) ;
2002-09-02 15:20:28 +00:00
ast_softhangup ( p - > chan , AST_SOFTHANGUP_EXPLICIT ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > chan - > lock ) ;
2003-07-14 02:31:56 +00:00
} else {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > chan - > lock ) ;
2003-07-14 02:31:56 +00:00
ast_moh_start ( p - > chan , p - > moh ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > chan - > lock ) ;
2003-07-14 02:31:56 +00:00
}
2003-07-01 16:16:28 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2005-05-26 20:24:56 +00:00
ast_device_state_changed ( " Agent/%s " , p - > agent ) ;
2002-12-06 16:22:19 +00:00
2003-07-01 16:16:28 +00:00
if ( p - > pending ) {
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
AST_LIST_REMOVE ( & agents , p , list ) ;
AST_LIST_UNLOCK ( & agents ) ;
2003-07-01 16:16:28 +00:00
}
2003-07-09 22:41:51 +00:00
if ( p - > abouttograb ) {
/* Let the "about to grab" thread know this isn't valid anymore, and let it
kill it later */
p - > abouttograb = 0 ;
} else if ( p - > dead ) {
2004-06-22 17:42:14 +00:00
ast_mutex_destroy ( & p - > lock ) ;
ast_mutex_destroy ( & p - > app_lock ) ;
2003-07-01 16:16:28 +00:00
free ( p ) ;
2003-08-27 15:59:43 +00:00
} else {
if ( p - > chan ) {
/* Not dead -- check availability now */
ast_mutex_lock ( & p - > lock ) ;
/* Store last disconnect time */
2005-07-15 23:00:47 +00:00
p - > lastdisc = ast_tvnow ( ) ;
2003-08-27 15:59:43 +00:00
ast_mutex_unlock ( & p - > lock ) ;
}
2003-08-26 03:50:01 +00:00
/* Release ownership of the agent to other threads (presumably running the login app). */
ast_mutex_unlock ( & p - > app_lock ) ;
2003-07-01 16:16:28 +00:00
}
2002-09-02 15:20:28 +00:00
return 0 ;
}
2002-12-06 16:22:19 +00:00
static int agent_cont_sleep ( void * data )
{
struct agent_pvt * p ;
int res ;
p = ( struct agent_pvt * ) data ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2002-12-06 16:22:19 +00:00
res = p - > app_sleep_cond ;
2003-07-28 14:24:10 +00:00
if ( p - > lastdisc . tv_sec ) {
2005-07-15 23:00:47 +00:00
if ( ast_tvdiff_ms ( ast_tvnow ( ) , p - > lastdisc ) > p - > wrapuptime )
2003-07-28 14:24:10 +00:00
res = 1 ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-07-01 16:16:28 +00:00
#if 0
2002-12-06 16:22:19 +00:00
if ( ! res )
ast_log ( LOG_DEBUG , " agent_cont_sleep() returning %d \n " , res ) ;
2003-07-01 16:16:28 +00:00
# endif
2002-12-06 16:22:19 +00:00
return res ;
}
2003-08-26 00:36:03 +00:00
static int agent_ack_sleep ( void * data )
{
struct agent_pvt * p ;
2003-08-26 03:50:01 +00:00
int res = 0 ;
2003-08-26 00:36:03 +00:00
int to = 1000 ;
2003-08-26 18:50:46 +00:00
struct ast_frame * f ;
2003-08-26 00:36:03 +00:00
/* Wait a second and look for something */
p = ( struct agent_pvt * ) data ;
if ( p - > chan ) {
for ( ; ; ) {
to = ast_waitfor ( p - > chan , to ) ;
if ( to < 0 ) {
res = - 1 ;
break ;
}
if ( ! to ) {
res = 0 ;
break ;
}
2003-08-26 18:50:46 +00:00
f = ast_read ( p - > chan ) ;
if ( ! f ) {
res = - 1 ;
break ;
}
if ( f - > frametype = = AST_FRAME_DTMF )
res = f - > subclass ;
else
res = 0 ;
ast_frfree ( f ) ;
2003-08-26 00:36:03 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-08-26 04:53:49 +00:00
if ( ! p - > app_sleep_cond ) {
2003-08-26 00:36:03 +00:00
ast_mutex_unlock ( & p - > lock ) ;
res = 0 ;
break ;
} else if ( res = = ' # ' ) {
ast_mutex_unlock ( & p - > lock ) ;
2003-08-26 04:53:49 +00:00
res = 1 ;
2003-08-26 00:36:03 +00:00
break ;
}
ast_mutex_unlock ( & p - > lock ) ;
res = 0 ;
}
} else
res = - 1 ;
return res ;
}
2004-10-23 12:19:47 +00:00
static struct ast_channel * agent_bridgedchannel ( struct ast_channel * chan , struct ast_channel * bridge )
{
Merged revisions 7265-7266,7268-7275 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.2
........
r7265 | oej | 2005-12-01 17:18:14 -0600 (Thu, 01 Dec 2005) | 2 lines
Changing bug report address to the Asterisk issue tracker
........
r7266 | kpfleming | 2005-12-01 17:18:29 -0600 (Thu, 01 Dec 2005) | 3 lines
Makefile 'update' target now supports updating from Subversion repositories (issue #5875)
remove support for 'patches' subdirectory, it's no longer useful
........
r7268 | kpfleming | 2005-12-01 17:34:58 -0600 (Thu, 01 Dec 2005) | 2 lines
ensure channel's scheduling context is freed (issue #5788)
........
r7269 | kpfleming | 2005-12-01 17:49:44 -0600 (Thu, 01 Dec 2005) | 2 lines
don't block waiting for the Festival server forever when it goes away (issue #5882)
........
r7270 | kpfleming | 2005-12-01 18:26:12 -0600 (Thu, 01 Dec 2005) | 2 lines
allow variables to exist on both 'halves' of the Local channel (issue #5810)
........
r7271 | kpfleming | 2005-12-01 18:28:48 -0600 (Thu, 01 Dec 2005) | 2 lines
protect agent_bridgedchannel() from segfaulting when there is no bridged channel (issue #5879)
........
r7272 | kpfleming | 2005-12-01 18:39:00 -0600 (Thu, 01 Dec 2005) | 3 lines
properly handle password changes when mailbox is last line of config file and not followed by a newline (issue #5870)
reformat password changing code to conform to coding guidelines (issue #5870)
........
r7273 | kpfleming | 2005-12-01 18:42:40 -0600 (Thu, 01 Dec 2005) | 2 lines
allow previous context-searching behavior to be used if desired (issue #5899)
........
r7274 | kpfleming | 2005-12-01 18:51:15 -0600 (Thu, 01 Dec 2005) | 2 lines
inherit channel variables into channels created by Page() application (issue #5888)
........
r7275 | oej | 2005-12-01 18:52:13 -0600 (Thu, 01 Dec 2005) | 2 lines
Bug #5907. Improve SIP INFO DTMF debugging output. (1.2 & Trunk)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@7276 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-12-02 01:01:11 +00:00
struct agent_pvt * p = bridge - > tech_pvt ;
2004-10-23 12:19:47 +00:00
struct ast_channel * ret = NULL ;
Merged revisions 7265-7266,7268-7275 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.2
........
r7265 | oej | 2005-12-01 17:18:14 -0600 (Thu, 01 Dec 2005) | 2 lines
Changing bug report address to the Asterisk issue tracker
........
r7266 | kpfleming | 2005-12-01 17:18:29 -0600 (Thu, 01 Dec 2005) | 3 lines
Makefile 'update' target now supports updating from Subversion repositories (issue #5875)
remove support for 'patches' subdirectory, it's no longer useful
........
r7268 | kpfleming | 2005-12-01 17:34:58 -0600 (Thu, 01 Dec 2005) | 2 lines
ensure channel's scheduling context is freed (issue #5788)
........
r7269 | kpfleming | 2005-12-01 17:49:44 -0600 (Thu, 01 Dec 2005) | 2 lines
don't block waiting for the Festival server forever when it goes away (issue #5882)
........
r7270 | kpfleming | 2005-12-01 18:26:12 -0600 (Thu, 01 Dec 2005) | 2 lines
allow variables to exist on both 'halves' of the Local channel (issue #5810)
........
r7271 | kpfleming | 2005-12-01 18:28:48 -0600 (Thu, 01 Dec 2005) | 2 lines
protect agent_bridgedchannel() from segfaulting when there is no bridged channel (issue #5879)
........
r7272 | kpfleming | 2005-12-01 18:39:00 -0600 (Thu, 01 Dec 2005) | 3 lines
properly handle password changes when mailbox is last line of config file and not followed by a newline (issue #5870)
reformat password changing code to conform to coding guidelines (issue #5870)
........
r7273 | kpfleming | 2005-12-01 18:42:40 -0600 (Thu, 01 Dec 2005) | 2 lines
allow previous context-searching behavior to be used if desired (issue #5899)
........
r7274 | kpfleming | 2005-12-01 18:51:15 -0600 (Thu, 01 Dec 2005) | 2 lines
inherit channel variables into channels created by Page() application (issue #5888)
........
r7275 | oej | 2005-12-01 18:52:13 -0600 (Thu, 01 Dec 2005) | 2 lines
Bug #5907. Improve SIP INFO DTMF debugging output. (1.2 & Trunk)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@7276 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-12-02 01:01:11 +00:00
if ( p ) {
if ( chan = = p - > chan )
ret = bridge - > _bridge ;
else if ( chan = = bridge - > _bridge )
ret = p - > chan ;
}
2005-02-01 07:09:56 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Asked for bridged channel on '%s'/'%s', returning '%s' \n " , chan - > name , bridge - > name , ret ? ret - > name : " <none> " ) ;
return ret ;
2004-10-23 12:19:47 +00:00
}
2006-01-20 00:18:42 +00:00
/*! \brief Create new agent channel ---*/
2002-09-02 15:20:28 +00:00
static struct ast_channel * agent_new ( struct agent_pvt * p , int state )
{
struct ast_channel * tmp ;
2003-07-01 16:16:28 +00:00
#if 0
2002-09-02 15:20:28 +00:00
if ( ! p - > chan ) {
ast_log ( LOG_WARNING , " No channel? :( \n " ) ;
return NULL ;
}
2003-07-01 16:16:28 +00:00
# endif
2002-09-02 15:20:28 +00:00
tmp = ast_channel_alloc ( 0 ) ;
if ( tmp ) {
2005-03-04 06:47:24 +00:00
tmp - > tech = & agent_tech ;
2003-07-01 16:16:28 +00:00
if ( p - > chan ) {
tmp - > nativeformats = p - > chan - > nativeformats ;
tmp - > writeformat = p - > chan - > writeformat ;
2005-03-04 06:47:24 +00:00
tmp - > rawwriteformat = p - > chan - > writeformat ;
2003-07-01 16:16:28 +00:00
tmp - > readformat = p - > chan - > readformat ;
2005-03-04 06:47:24 +00:00
tmp - > rawreadformat = p - > chan - > readformat ;
2006-02-01 23:05:28 +00:00
ast_string_field_set ( tmp , language , p - > chan - > language ) ;
2005-08-26 20:24:16 +00:00
ast_copy_string ( tmp - > context , p - > chan - > context , sizeof ( tmp - > context ) ) ;
ast_copy_string ( tmp - > exten , p - > chan - > exten , sizeof ( tmp - > exten ) ) ;
2003-07-01 16:16:28 +00:00
} else {
tmp - > nativeformats = AST_FORMAT_SLINEAR ;
tmp - > writeformat = AST_FORMAT_SLINEAR ;
2005-03-04 06:47:24 +00:00
tmp - > rawwriteformat = AST_FORMAT_SLINEAR ;
2003-07-01 16:16:28 +00:00
tmp - > readformat = AST_FORMAT_SLINEAR ;
2005-03-04 06:47:24 +00:00
tmp - > rawreadformat = AST_FORMAT_SLINEAR ;
2003-07-01 16:16:28 +00:00
}
if ( p - > pending )
2006-02-01 23:05:28 +00:00
ast_string_field_build ( tmp , name , " Agent/P%s-%d " , p - > agent , rand ( ) & 0xffff ) ;
2003-07-01 16:16:28 +00:00
else
2006-02-01 23:05:28 +00:00
ast_string_field_build ( tmp , name , " Agent/%s " , p - > agent ) ;
2005-01-15 23:31:19 +00:00
/* Safe, agentlock already held */
2002-09-02 15:20:28 +00:00
ast_setstate ( tmp , state ) ;
2005-03-04 06:47:24 +00:00
tmp - > tech_pvt = p ;
2002-09-02 15:20:28 +00:00
p - > owner = tmp ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
2002-09-02 15:20:28 +00:00
usecnt + + ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & usecnt_lock ) ;
2002-09-02 15:20:28 +00:00
ast_update_use_count ( ) ;
tmp - > priority = 1 ;
2002-12-06 16:22:19 +00:00
/* Wake up and wait for other applications (by definition the login app)
* to release this channel ) . Takes ownership of the agent channel
* to this thread only .
* For signalling the other thread , ast_queue_frame is used until we
* can safely use signals for this purpose . The pselect ( ) needs to be
* implemented in the kernel for this .
*/
p - > app_sleep_cond = 0 ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_trylock ( & p - > app_lock ) )
2002-12-06 16:22:19 +00:00
{
2003-07-08 18:50:02 +00:00
if ( p - > chan ) {
2006-01-31 17:18:58 +00:00
ast_queue_frame ( p - > chan , & ast_null_frame ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ; /* For other thread to read the condition. */
ast_mutex_lock ( & p - > app_lock ) ;
ast_mutex_lock ( & p - > lock ) ;
2003-07-08 18:50:02 +00:00
}
2003-03-20 17:21:54 +00:00
if ( ! p - > chan )
{
ast_log ( LOG_WARNING , " Agent disconnected while we were connecting the call \n " ) ;
p - > owner = NULL ;
2005-03-04 06:47:24 +00:00
tmp - > tech_pvt = NULL ;
2003-03-20 17:21:54 +00:00
p - > app_sleep_cond = 1 ;
ast_channel_free ( tmp ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ; /* For other thread to read the condition. */
ast_mutex_unlock ( & p - > app_lock ) ;
2003-03-20 17:21:54 +00:00
return NULL ;
}
2002-12-06 16:22:19 +00:00
}
p - > owning_app = pthread_self ( ) ;
/* After the above step, there should not be any blockers. */
2003-07-01 16:16:28 +00:00
if ( p - > chan ) {
2004-12-07 20:38:43 +00:00
if ( ast_test_flag ( p - > chan , AST_FLAG_BLOCKING ) ) {
2003-07-01 16:16:28 +00:00
ast_log ( LOG_ERROR , " A blocker exists after agent channel ownership acquired \n " ) ;
CRASH ;
}
ast_moh_stop ( p - > chan ) ;
2002-09-02 15:20:28 +00:00
}
} else
2004-12-31 00:58:44 +00:00
ast_log ( LOG_WARNING , " Unable to allocate agent channel structure \n " ) ;
2002-09-02 15:20:28 +00:00
return tmp ;
}
2005-09-07 20:44:57 +00:00
/**
* Read configuration data . The file named agents . conf .
*
* @ returns Always 0 , or so it seems .
*/
2002-09-02 15:20:28 +00:00
static int read_agent_config ( void )
{
struct ast_config * cfg ;
struct ast_variable * v ;
2006-01-25 18:12:55 +00:00
struct agent_pvt * p ;
2005-01-01 00:57:04 +00:00
char * general_val ;
2004-12-31 00:58:44 +00:00
2003-07-01 04:08:25 +00:00
group = 0 ;
2003-07-22 11:06:56 +00:00
autologoff = 0 ;
2003-07-28 14:24:10 +00:00
wrapuptime = 0 ;
2005-02-14 23:20:01 +00:00
ackcall = 0 ;
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( config ) ;
2002-09-02 15:20:28 +00:00
if ( ! cfg ) {
ast_log ( LOG_NOTICE , " No agent configuration found -- agent support disabled \n " ) ;
return 0 ;
}
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
AST_LIST_TRAVERSE ( & agents , p , list ) {
2002-09-02 15:20:28 +00:00
p - > dead = 1 ;
}
2005-08-26 20:24:16 +00:00
strcpy ( moh , " default " ) ;
2004-02-03 16:57:00 +00:00
/* set the default recording values */
recordagentcalls = 0 ;
2005-08-26 20:24:16 +00:00
strcpy ( recordformat , " wav " ) ;
strcpy ( recordformatext , " wav " ) ;
2004-07-16 04:40:54 +00:00
urlprefix [ 0 ] = ' \0 ' ;
savecallsin [ 0 ] = ' \0 ' ;
2004-02-03 16:57:00 +00:00
2006-01-13 06:11:41 +00:00
/* Read in [general] section for persistence */
2005-01-01 00:57:04 +00:00
if ( ( general_val = ast_variable_retrieve ( cfg , " general " , " persistentagents " ) ) )
persistent_agents = ast_true ( general_val ) ;
2006-01-12 19:07:18 +00:00
if ( ast_false ( ast_variable_retrieve ( cfg , " general " , " multiplelogin " ) ) )
multiplelogin = 0 ;
2006-01-13 06:43:27 +00:00
if ( ast_true ( ast_variable_retrieve ( cfg , " general " , " multiplelogin " ) ) )
multiplelogin = 1 ;
2005-01-01 00:57:04 +00:00
/* Read in the [agents] section */
2002-09-02 15:20:28 +00:00
v = ast_variable_browse ( cfg , " agents " ) ;
while ( v ) {
/* Create the interface list */
if ( ! strcasecmp ( v - > name , " agent " ) ) {
2003-07-01 16:16:28 +00:00
add_agent ( v - > value , 0 ) ;
2003-07-01 04:08:25 +00:00
} else if ( ! strcasecmp ( v - > name , " group " ) ) {
group = ast_get_group ( v - > value ) ;
2003-07-22 11:06:56 +00:00
} else if ( ! strcasecmp ( v - > name , " autologoff " ) ) {
autologoff = atoi ( v - > value ) ;
if ( autologoff < 0 )
autologoff = 0 ;
2003-08-05 23:57:55 +00:00
} else if ( ! strcasecmp ( v - > name , " ackcall " ) ) {
2003-08-21 16:42:13 +00:00
if ( ! strcasecmp ( v - > value , " always " ) )
ackcall = 2 ;
else if ( ast_true ( v - > value ) )
2004-12-31 00:58:44 +00:00
ackcall = 1 ;
2003-08-21 16:42:13 +00:00
else
ackcall = 0 ;
2003-07-28 14:24:10 +00:00
} else if ( ! strcasecmp ( v - > name , " wrapuptime " ) ) {
wrapuptime = atoi ( v - > value ) ;
if ( wrapuptime < 0 )
wrapuptime = 0 ;
2004-10-24 13:24:16 +00:00
} else if ( ! strcasecmp ( v - > name , " maxlogintries " ) & & ! ast_strlen_zero ( v - > value ) ) {
maxlogintries = atoi ( v - > value ) ;
if ( maxlogintries < 0 )
maxlogintries = 0 ;
} else if ( ! strcasecmp ( v - > name , " goodbye " ) & & ! ast_strlen_zero ( v - > value ) ) {
strcpy ( agentgoodbye , v - > value ) ;
2002-09-02 15:20:28 +00:00
} else if ( ! strcasecmp ( v - > name , " musiconhold " ) ) {
2005-08-26 20:24:16 +00:00
ast_copy_string ( moh , v - > value , sizeof ( moh ) ) ;
2004-04-03 00:41:47 +00:00
} else if ( ! strcasecmp ( v - > name , " updatecdr " ) ) {
2004-10-24 13:24:16 +00:00
if ( ast_true ( v - > value ) )
updatecdr = 1 ;
else
updatecdr = 0 ;
2006-01-13 18:23:30 +00:00
} else if ( ! strcasecmp ( v - > name , " autologoffunavail " ) ) {
if ( ast_true ( v - > value ) )
autologoffunavail = 1 ;
else
autologoffunavail = 0 ;
2004-02-03 16:57:00 +00:00
} else if ( ! strcasecmp ( v - > name , " recordagentcalls " ) ) {
recordagentcalls = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " recordformat " ) ) {
2005-08-26 20:24:16 +00:00
ast_copy_string ( recordformat , v - > value , sizeof ( recordformat ) ) ;
2004-02-03 16:57:00 +00:00
if ( ! strcasecmp ( v - > value , " wav49 " ) )
2005-08-26 20:24:16 +00:00
strcpy ( recordformatext , " WAV " ) ;
2004-02-03 16:57:00 +00:00
else
2005-08-26 20:24:16 +00:00
ast_copy_string ( recordformatext , v - > value , sizeof ( recordformatext ) ) ;
2004-02-03 16:57:00 +00:00
} else if ( ! strcasecmp ( v - > name , " urlprefix " ) ) {
2005-08-26 20:24:16 +00:00
ast_copy_string ( urlprefix , v - > value , sizeof ( urlprefix ) ) ;
2004-02-03 16:57:00 +00:00
if ( urlprefix [ strlen ( urlprefix ) - 1 ] ! = ' / ' )
2004-07-16 04:40:54 +00:00
strncat ( urlprefix , " / " , sizeof ( urlprefix ) - strlen ( urlprefix ) - 1 ) ;
2004-02-03 16:57:00 +00:00
} else if ( ! strcasecmp ( v - > name , " savecallsin " ) ) {
if ( v - > value [ 0 ] = = ' / ' )
2005-08-26 20:24:16 +00:00
ast_copy_string ( savecallsin , v - > value , sizeof ( savecallsin ) ) ;
2004-02-03 16:57:00 +00:00
else
snprintf ( savecallsin , sizeof ( savecallsin ) - 2 , " /%s " , v - > value ) ;
if ( savecallsin [ strlen ( savecallsin ) - 1 ] ! = ' / ' )
2004-07-16 04:40:54 +00:00
strncat ( savecallsin , " / " , sizeof ( savecallsin ) - strlen ( savecallsin ) - 1 ) ;
2004-06-28 18:40:41 +00:00
} else if ( ! strcasecmp ( v - > name , " custom_beep " ) ) {
2005-08-26 20:24:16 +00:00
ast_copy_string ( beep , v - > value , sizeof ( beep ) ) ;
2002-09-02 15:20:28 +00:00
}
v = v - > next ;
}
2006-01-25 18:12:55 +00:00
AST_LIST_TRAVERSE_SAFE_BEGIN ( & agents , p , list ) {
2002-09-02 15:20:28 +00:00
if ( p - > dead ) {
2006-01-25 18:12:55 +00:00
AST_LIST_REMOVE_CURRENT ( & agents , list ) ;
2002-09-02 15:20:28 +00:00
/* Destroy if appropriate */
if ( ! p - > owner ) {
if ( ! p - > chan ) {
2004-06-22 17:42:14 +00:00
ast_mutex_destroy ( & p - > lock ) ;
ast_mutex_destroy ( & p - > app_lock ) ;
2002-09-02 15:20:28 +00:00
free ( p ) ;
} else {
/* Cause them to hang up */
ast_softhangup ( p - > chan , AST_SOFTHANGUP_EXPLICIT ) ;
}
}
2006-01-25 18:12:55 +00:00
}
2002-09-02 15:20:28 +00:00
}
2006-01-25 18:12:55 +00:00
AST_LIST_TRAVERSE_SAFE_END
AST_LIST_UNLOCK ( & agents ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2002-09-02 15:20:28 +00:00
return 0 ;
}
2003-07-01 16:16:28 +00:00
static int check_availability ( struct agent_pvt * newlyavailable , int needlock )
{
struct ast_channel * chan = NULL , * parent = NULL ;
struct agent_pvt * p ;
int res ;
2004-12-31 00:58:44 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Checking availability of '%s' \n " , newlyavailable - > agent ) ;
2003-07-01 16:16:28 +00:00
if ( needlock )
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
AST_LIST_TRAVERSE ( & agents , p , list ) {
2003-07-01 16:16:28 +00:00
if ( p = = newlyavailable ) {
continue ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-07-16 02:25:53 +00:00
if ( ! p - > abouttograb & & p - > pending & & ( ( p - > group & & ( newlyavailable - > group & p - > group ) ) | | ! strcmp ( p - > agent , newlyavailable - > agent ) ) ) {
2004-12-31 00:58:44 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Call '%s' looks like a winner for agent '%s' \n " , p - > owner - > name , newlyavailable - > agent ) ;
2003-07-01 16:16:28 +00:00
/* We found a pending call, time to merge */
2003-08-19 21:35:33 +00:00
chan = agent_new ( newlyavailable , AST_STATE_DOWN ) ;
2003-07-01 16:16:28 +00:00
parent = p - > owner ;
2003-07-09 22:41:51 +00:00
p - > abouttograb = 1 ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-07-01 16:16:28 +00:00
break ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-07-01 16:16:28 +00:00
}
if ( needlock )
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2003-07-01 16:16:28 +00:00
if ( parent & & chan ) {
2003-09-04 04:03:47 +00:00
if ( newlyavailable - > ackcall > 1 ) {
2003-08-26 00:36:03 +00:00
/* Don't do beep here */
res = 0 ;
} else {
2004-12-31 00:58:44 +00:00
if ( option_debug > 2 )
ast_log ( LOG_DEBUG , " Playing beep, lang '%s' \n " , newlyavailable - > chan - > language ) ;
2004-06-28 18:40:41 +00:00
res = ast_streamfile ( newlyavailable - > chan , beep , newlyavailable - > chan - > language ) ;
2004-12-31 00:58:44 +00:00
if ( option_debug > 2 )
ast_log ( LOG_DEBUG , " Played beep, result '%d' \n " , res ) ;
2003-08-26 00:36:03 +00:00
if ( ! res ) {
res = ast_waitstream ( newlyavailable - > chan , " " ) ;
ast_log ( LOG_DEBUG , " Waited for stream, result '%d' \n " , res ) ;
}
2003-07-01 16:16:28 +00:00
}
if ( ! res ) {
2003-07-09 22:41:51 +00:00
/* Note -- parent may have disappeared */
if ( p - > abouttograb ) {
2003-09-06 20:13:09 +00:00
newlyavailable - > acknowledged = 1 ;
2005-01-15 23:31:19 +00:00
/* Safe -- agent lock already held */
2003-07-09 22:41:51 +00:00
ast_setstate ( parent , AST_STATE_UP ) ;
ast_setstate ( chan , AST_STATE_UP ) ;
2005-08-26 20:24:16 +00:00
ast_copy_string ( parent - > context , chan - > context , sizeof ( parent - > context ) ) ;
2003-07-14 03:45:53 +00:00
/* Go ahead and mark the channel as a zombie so that masquerade will
destroy it for us , and we need not call ast_hangup */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & parent - > lock ) ;
2004-12-07 20:38:43 +00:00
ast_set_flag ( chan , AST_FLAG_ZOMBIE ) ;
2003-07-09 22:41:51 +00:00
ast_channel_masquerade ( parent , chan ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & parent - > lock ) ;
2003-07-09 22:41:51 +00:00
p - > abouttograb = 0 ;
} else {
2004-12-31 00:58:44 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Sneaky, parent disappeared in the mean time... \n " ) ;
2003-07-09 22:41:51 +00:00
agent_cleanup ( newlyavailable ) ;
}
2003-07-01 16:16:28 +00:00
} else {
2004-12-31 00:58:44 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Ugh... Agent hung up at exactly the wrong time \n " ) ;
2003-07-09 22:41:51 +00:00
agent_cleanup ( newlyavailable ) ;
2003-07-01 16:16:28 +00:00
}
}
return 0 ;
}
2003-08-26 00:36:03 +00:00
static int check_beep ( struct agent_pvt * newlyavailable , int needlock )
{
struct agent_pvt * p ;
2003-08-26 03:17:00 +00:00
int res = 0 ;
2004-12-31 00:58:44 +00:00
2003-08-26 00:36:03 +00:00
ast_log ( LOG_DEBUG , " Checking beep availability of '%s' \n " , newlyavailable - > agent ) ;
if ( needlock )
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
AST_LIST_TRAVERSE ( & agents , p , list ) {
2003-08-26 00:36:03 +00:00
if ( p = = newlyavailable ) {
continue ;
}
ast_mutex_lock ( & p - > lock ) ;
if ( ! p - > abouttograb & & p - > pending & & ( ( p - > group & & ( newlyavailable - > group & p - > group ) ) | | ! strcmp ( p - > agent , newlyavailable - > agent ) ) ) {
2004-12-31 00:58:44 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Call '%s' looks like a would-be winner for agent '%s' \n " , p - > owner - > name , newlyavailable - > agent ) ;
2003-08-26 00:36:03 +00:00
ast_mutex_unlock ( & p - > lock ) ;
break ;
}
ast_mutex_unlock ( & p - > lock ) ;
}
if ( needlock )
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2003-08-26 00:36:03 +00:00
if ( p ) {
2003-08-26 04:08:12 +00:00
ast_mutex_unlock ( & newlyavailable - > lock ) ;
2004-12-31 00:58:44 +00:00
if ( option_debug > 2 )
ast_log ( LOG_DEBUG , " Playing beep, lang '%s' \n " , newlyavailable - > chan - > language ) ;
2004-06-28 18:40:41 +00:00
res = ast_streamfile ( newlyavailable - > chan , beep , newlyavailable - > chan - > language ) ;
2004-12-31 00:58:44 +00:00
if ( option_debug > 2 )
ast_log ( LOG_DEBUG , " Played beep, result '%d' \n " , res ) ;
2003-08-26 00:36:03 +00:00
if ( ! res ) {
res = ast_waitstream ( newlyavailable - > chan , " " ) ;
2004-12-31 00:58:44 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Waited for stream, result '%d' \n " , res ) ;
2003-08-26 00:36:03 +00:00
}
2003-08-26 04:08:12 +00:00
ast_mutex_lock ( & newlyavailable - > lock ) ;
2003-08-26 00:36:03 +00:00
}
return res ;
}
2006-01-13 06:11:41 +00:00
/* return 1 if multiple login is fine, 0 if it is not and we find a match, -1 if multiplelogin is not allowed and we don't find a match. */
2006-01-12 19:07:18 +00:00
static int allow_multiple_login ( char * chan , char * context )
{
struct agent_pvt * p ;
char loginchan [ 80 ] ;
if ( multiplelogin )
return 1 ;
if ( ! chan )
return 0 ;
2006-03-26 16:08:42 +00:00
snprintf ( loginchan , sizeof ( loginchan ) , " %s@%s " , chan , S_OR ( context , " default " ) ) ;
2006-01-12 19:07:18 +00:00
2006-01-25 18:12:55 +00:00
AST_LIST_TRAVERSE ( & agents , p , list ) {
2006-01-12 19:07:18 +00:00
if ( ! strcasecmp ( chan , p - > loginchan ) )
return 0 ;
}
return - 1 ;
}
2006-01-20 00:18:42 +00:00
/*! \brief Part of the Asterisk PBX interface ---*/
2004-10-26 22:25:43 +00:00
static struct ast_channel * agent_request ( const char * type , int format , void * data , int * cause )
2002-09-02 15:20:28 +00:00
{
struct agent_pvt * p ;
struct ast_channel * chan = NULL ;
2003-07-01 04:08:25 +00:00
char * s ;
2005-01-15 21:51:38 +00:00
ast_group_t groupmatch ;
2005-01-17 04:47:01 +00:00
int groupoff ;
2003-07-01 16:16:28 +00:00
int waitforagent = 0 ;
2003-08-19 01:01:00 +00:00
int hasagent = 0 ;
2004-08-11 19:02:46 +00:00
struct timeval tv ;
2004-12-31 00:58:44 +00:00
2003-07-01 04:08:25 +00:00
s = data ;
2005-01-17 04:47:01 +00:00
if ( ( s [ 0 ] = = ' @ ' ) & & ( sscanf ( s + 1 , " %d " , & groupoff ) = = 1 ) ) {
groupmatch = ( 1 < < groupoff ) ;
} else if ( ( s [ 0 ] = = ' : ' ) & & ( sscanf ( s + 1 , " %d " , & groupoff ) = = 1 ) ) {
groupmatch = ( 1 < < groupoff ) ;
2003-07-01 16:16:28 +00:00
waitforagent = 1 ;
2003-07-01 04:08:25 +00:00
} else {
groupmatch = 0 ;
}
2003-08-06 04:00:37 +00:00
/* Check actual logged in agents first */
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
AST_LIST_TRAVERSE ( & agents , p , list ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-07-28 14:24:10 +00:00
if ( ! p - > pending & & ( ( groupmatch & & ( p - > group & groupmatch ) ) | | ! strcmp ( data , p - > agent ) ) & &
2005-09-14 00:28:06 +00:00
ast_strlen_zero ( p - > loginchan ) ) {
2003-08-19 01:01:00 +00:00
if ( p - > chan )
hasagent + + ;
if ( ! p - > lastdisc . tv_sec ) {
/* Agent must be registered, but not have any active call, and not be in a waiting state */
if ( ! p - > owner & & p - > chan ) {
/* Fixed agent */
2003-07-14 02:31:56 +00:00
chan = agent_new ( p , AST_STATE_DOWN ) ;
2003-08-19 01:01:00 +00:00
}
if ( chan ) {
ast_mutex_unlock ( & p - > lock ) ;
break ;
}
2002-09-02 15:20:28 +00:00
}
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
}
2003-08-06 04:00:37 +00:00
if ( ! p ) {
2006-01-25 18:12:55 +00:00
AST_LIST_TRAVERSE ( & agents , p , list ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-08-19 01:01:00 +00:00
if ( ! p - > pending & & ( ( groupmatch & & ( p - > group & groupmatch ) ) | | ! strcmp ( data , p - > agent ) ) ) {
2004-05-09 07:51:44 +00:00
if ( p - > chan | | ! ast_strlen_zero ( p - > loginchan ) )
2003-08-19 01:01:00 +00:00
hasagent + + ;
2005-07-15 23:00:47 +00:00
tv = ast_tvnow ( ) ;
2004-08-11 19:02:46 +00:00
#if 0
ast_log ( LOG_NOTICE , " Time now: %ld, Time of lastdisc: %ld \n " , tv . tv_sec , p - > lastdisc . tv_sec ) ;
# endif
if ( ! p - > lastdisc . tv_sec | | ( tv . tv_sec > p - > lastdisc . tv_sec ) ) {
2005-07-15 23:00:47 +00:00
p - > lastdisc = ast_tv ( 0 , 0 ) ;
2003-08-19 01:01:00 +00:00
/* Agent must be registered, but not have any active call, and not be in a waiting state */
if ( ! p - > owner & & p - > chan ) {
/* Could still get a fixed agent */
2003-08-06 04:00:37 +00:00
chan = agent_new ( p , AST_STATE_DOWN ) ;
2004-05-09 07:51:44 +00:00
} else if ( ! p - > owner & & ! ast_strlen_zero ( p - > loginchan ) ) {
2003-08-19 01:01:00 +00:00
/* Adjustable agent */
2004-10-26 22:25:43 +00:00
p - > chan = ast_request ( " Local " , format , p - > loginchan , cause ) ;
2003-08-19 01:01:00 +00:00
if ( p - > chan )
chan = agent_new ( p , AST_STATE_DOWN ) ;
}
if ( chan ) {
ast_mutex_unlock ( & p - > lock ) ;
break ;
}
2003-08-06 04:00:37 +00:00
}
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-08-06 04:00:37 +00:00
}
}
2003-07-01 16:16:28 +00:00
if ( ! chan & & waitforagent ) {
/* No agent available -- but we're requesting to wait for one.
Allocate a place holder */
2003-08-19 01:01:00 +00:00
if ( hasagent ) {
2004-12-31 00:58:44 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Creating place holder for '%s' \n " , s ) ;
2003-08-19 01:01:00 +00:00
p = add_agent ( data , 1 ) ;
p - > group = groupmatch ;
chan = agent_new ( p , AST_STATE_DOWN ) ;
if ( ! chan ) {
ast_log ( LOG_WARNING , " Weird... Fix this to drop the unused pending agent \n " ) ;
}
} else
2003-08-19 01:20:29 +00:00
ast_log ( LOG_DEBUG , " Not creating place holder for '%s' since nobody logged in \n " , s ) ;
2003-07-01 16:16:28 +00:00
}
2004-10-26 22:25:43 +00:00
if ( hasagent )
* cause = AST_CAUSE_BUSY ;
else
* cause = AST_CAUSE_UNREGISTERED ;
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2002-09-02 15:20:28 +00:00
return chan ;
}
2003-07-01 16:16:28 +00:00
static int powerof ( unsigned int v )
{
int x ;
for ( x = 0 ; x < 32 ; x + + ) {
if ( v & ( 1 < < x ) ) return x ;
}
return 0 ;
}
2005-09-14 02:12:37 +00:00
/**
* Lists agents and their status to the Manager API .
* It is registered on load_module ( ) and it gets called by the manager backend .
* @ param s
* @ param m
* @ returns
* @ sa action_agent_logoff ( ) , action_agent_callback_login ( ) , load_module ( ) .
*/
2004-12-01 05:00:29 +00:00
static int action_agents ( struct mansession * s , struct message * m )
{
2005-07-15 16:21:41 +00:00
char * id = astman_get_header ( m , " ActionID " ) ;
char idText [ 256 ] = " " ;
2005-09-26 02:04:07 +00:00
char chanbuf [ 256 ] ;
2004-12-31 00:58:44 +00:00
struct agent_pvt * p ;
char * username = NULL ;
char * loginChan = NULL ;
char * talkingtoChan = NULL ;
char * status = NULL ;
2005-10-27 02:19:37 +00:00
if ( ! ast_strlen_zero ( id ) )
2005-07-15 16:21:41 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , id ) ;
astman_send_ack ( s , m , " Agents will follow " ) ;
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
AST_LIST_TRAVERSE ( & agents , p , list ) {
2004-12-31 00:58:44 +00:00
ast_mutex_lock ( & p - > lock ) ;
/* Status Values:
2005-09-14 00:28:06 +00:00
AGENT_LOGGEDOFF - Agent isn ' t logged in
AGENT_IDLE - Agent is logged in , and waiting for call
AGENT_ONCALL - Agent is logged in , and on a call
AGENT_UNKNOWN - Don ' t know anything about agent . Shouldn ' t ever get this . */
2004-12-31 00:58:44 +00:00
if ( ! ast_strlen_zero ( p - > name ) ) {
username = p - > name ;
} else {
username = " None " ;
}
/* Set a default status. It 'should' get changed. */
status = " AGENT_UNKNOWN " ;
2005-12-13 06:00:17 +00:00
if ( ! ast_strlen_zero ( p - > loginchan ) & & ! p - > chan ) {
2004-12-31 00:58:44 +00:00
loginChan = p - > loginchan ;
talkingtoChan = " n/a " ;
status = " AGENT_IDLE " ;
2005-09-26 02:04:07 +00:00
if ( p - > acknowledged ) {
snprintf ( chanbuf , sizeof ( chanbuf ) , " %s (Confirmed) " , p - > loginchan ) ;
loginChan = chanbuf ;
2004-12-31 00:58:44 +00:00
}
2005-10-13 21:59:25 +00:00
} else if ( p - > chan ) {
loginChan = ast_strdupa ( p - > chan - > name ) ;
if ( p - > owner & & p - > owner - > _bridge ) {
talkingtoChan = p - > chan - > cid . cid_num ;
status = " AGENT_ONCALL " ;
} else {
talkingtoChan = " n/a " ;
status = " AGENT_IDLE " ;
}
2004-12-31 00:58:44 +00:00
} else {
loginChan = " n/a " ;
talkingtoChan = " n/a " ;
status = " AGENT_LOGGEDOFF " ;
}
2006-03-25 23:50:09 +00:00
astman_append ( s , " Event: Agents \r \n "
2005-09-14 00:28:06 +00:00
" Agent: %s \r \n "
" Name: %s \r \n "
" Status: %s \r \n "
" LoggedInChan: %s \r \n "
2005-12-26 18:35:28 +00:00
" LoggedInTime: %d \r \n "
2005-09-14 00:28:06 +00:00
" TalkingTo: %s \r \n "
" %s "
" \r \n " ,
2005-12-26 18:35:28 +00:00
p - > agent , username , status , loginChan , ( int ) p - > loginstart , talkingtoChan , idText ) ;
2004-12-31 00:58:44 +00:00
ast_mutex_unlock ( & p - > lock ) ;
}
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " Event: AgentsComplete \r \n "
2005-09-14 00:28:06 +00:00
" %s "
" \r \n " , idText ) ;
2004-12-31 00:58:44 +00:00
return 0 ;
2004-12-01 05:00:29 +00:00
}
2006-02-14 23:42:36 +00:00
static void agent_logoff_maintenance ( struct agent_pvt * p , char * loginchan , long logintime , const char * uniqueid , char * logcommand )
2006-01-14 03:25:38 +00:00
{
char * tmp = NULL ;
char agent [ AST_MAX_AGENT ] ;
if ( ! ast_strlen_zero ( logcommand ) )
tmp = logcommand ;
else {
tmp = ast_strdupa ( " " ) ;
}
snprintf ( agent , sizeof ( agent ) , " Agent/%s " , p - > agent ) ;
if ( ! ast_strlen_zero ( uniqueid ) ) {
manager_event ( EVENT_FLAG_AGENT , " Agentcallbacklogoff " ,
" Agent: %s \r \n "
" Reason: %s \r \n "
" Loginchan: %s \r \n "
" Logintime: %ld \r \n "
" Uniqueid: %s \r \n " ,
p - > agent , tmp , loginchan , logintime , uniqueid ) ;
ast_queue_log ( " NONE " , uniqueid , agent , " AGENTCALLBACKLOGOFF " , " %s|%ld|%s " , loginchan , logintime , tmp ) ;
} else {
manager_event ( EVENT_FLAG_AGENT , " Agentcallbacklogoff " ,
" Agent: %s \r \n "
" Reason: %s \r \n "
" Loginchan: %s \r \n "
" Logintime: %ld \r \n " ,
p - > agent , tmp , loginchan , logintime ) ;
ast_queue_log ( " NONE " , " NONE " , agent , " AGENTCALLBACKLOGOFF " , " %s|%ld|%s " , loginchan , logintime , tmp ) ;
}
set_agentbycallerid ( p - > logincallerid , NULL ) ;
p - > loginchan [ 0 ] = ' \0 ' ;
p - > logincallerid [ 0 ] = ' \0 ' ;
ast_device_state_changed ( " Agent/%s " , p - > agent ) ;
if ( persistent_agents )
dump_agents ( ) ;
}
2005-08-26 20:24:16 +00:00
static int agent_logoff ( char * agent , int soft )
2005-01-30 06:55:10 +00:00
{
struct agent_pvt * p ;
2005-02-18 05:03:01 +00:00
long logintime ;
2005-08-26 20:24:16 +00:00
int ret = - 1 ; /* Return -1 if no agent if found */
2005-01-30 06:55:10 +00:00
2006-01-25 18:12:55 +00:00
AST_LIST_TRAVERSE ( & agents , p , list ) {
2005-01-30 06:55:10 +00:00
if ( ! strcasecmp ( p - > agent , agent ) ) {
2005-08-26 20:24:16 +00:00
if ( ! soft ) {
2005-01-30 06:55:10 +00:00
if ( p - > owner ) {
ast_softhangup ( p - > owner , AST_SOFTHANGUP_EXPLICIT ) ;
}
if ( p - > chan ) {
ast_softhangup ( p - > chan , AST_SOFTHANGUP_EXPLICIT ) ;
}
}
2005-08-26 20:24:16 +00:00
ret = 0 ; /* found an agent => return 0 */
2005-02-18 05:03:01 +00:00
logintime = time ( NULL ) - p - > loginstart ;
p - > loginstart = 0 ;
2006-01-14 03:25:38 +00:00
agent_logoff_maintenance ( p , p - > loginchan , logintime , NULL , " CommandLogoff " ) ;
2005-01-30 06:55:10 +00:00
break ;
}
}
2005-08-26 20:24:16 +00:00
return ret ;
}
static int agent_logoff_cmd ( int fd , int argc , char * * argv )
{
int ret ;
char * agent ;
if ( argc < 3 | | argc > 4 )
return RESULT_SHOWUSAGE ;
if ( argc = = 4 & & strcasecmp ( argv [ 3 ] , " soft " ) )
return RESULT_SHOWUSAGE ;
agent = argv [ 2 ] + 6 ;
ret = agent_logoff ( agent , argc = = 4 ) ;
if ( ret = = 0 )
ast_cli ( fd , " Logging out %s \n " , agent ) ;
2005-01-30 06:55:10 +00:00
return RESULT_SUCCESS ;
}
2005-09-14 02:12:37 +00:00
/**
* 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 .
* @ param s
* @ param m
* @ returns
* @ sa action_agents ( ) , action_agent_callback_login ( ) , load_module ( ) .
*/
2005-08-26 20:24:16 +00:00
static int action_agent_logoff ( struct mansession * s , struct message * m )
{
char * agent = astman_get_header ( m , " Agent " ) ;
char * soft_s = astman_get_header ( m , " Soft " ) ; /* "true" is don't hangup */
int soft ;
int ret ; /* return value of agent_logoff */
2005-10-27 02:19:37 +00:00
if ( ast_strlen_zero ( agent ) ) {
2005-08-26 20:24:16 +00:00
astman_send_error ( s , m , " No agent specified " ) ;
return 0 ;
}
if ( ast_true ( soft_s ) )
soft = 1 ;
else
soft = 0 ;
ret = agent_logoff ( agent , soft ) ;
if ( ret = = 0 )
astman_send_ack ( s , m , " Agent logged out " ) ;
else
astman_send_error ( s , m , " No such agent " ) ;
return 0 ;
}
2006-01-18 22:17:31 +00:00
static char * complete_agent_logoff_cmd ( const char * line , const char * word , int pos , int state )
2005-01-30 06:55:10 +00:00
{
if ( pos = = 2 ) {
2006-03-28 13:46:04 +00:00
struct agent_pvt * p ;
char name [ AST_MAX_AGENT ] ;
int which = 0 , len = strlen ( word ) ;
2006-01-25 18:12:55 +00:00
AST_LIST_TRAVERSE ( & agents , p , list ) {
2005-01-30 06:55:10 +00:00
snprintf ( name , sizeof ( name ) , " Agent/%s " , p - > agent ) ;
2006-03-28 13:46:04 +00:00
if ( ! strncasecmp ( word , name , len ) & & + + which > state )
return ast_strdup ( name ) ;
2005-01-30 06:55:10 +00:00
}
} else if ( pos = = 3 & & state = = 0 ) {
2006-01-11 01:20:29 +00:00
return ast_strdup ( " soft " ) ;
2005-01-30 06:55:10 +00:00
}
return NULL ;
}
2004-12-01 05:00:29 +00:00
2005-09-07 20:44:57 +00:00
/**
* Show agents in cli .
*/
2002-09-02 15:20:28 +00:00
static int agents_show ( int fd , int argc , char * * argv )
{
struct agent_pvt * p ;
2004-02-03 16:57:00 +00:00
char username [ AST_MAX_BUF ] ;
2004-07-16 04:40:54 +00:00
char location [ AST_MAX_BUF ] = " " ;
char talkingto [ AST_MAX_BUF ] = " " ;
2004-02-03 16:57:00 +00:00
char moh [ AST_MAX_BUF ] ;
2005-05-15 02:48:16 +00:00
int count_agents = 0 ; /* Number of agents configured */
int online_agents = 0 ; /* Number of online agents */
int offline_agents = 0 ; /* Number of offline agents */
2002-09-02 15:20:28 +00:00
if ( argc ! = 2 )
return RESULT_SHOWUSAGE ;
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
AST_LIST_TRAVERSE ( & agents , p , list ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-07-01 16:16:28 +00:00
if ( p - > pending ) {
if ( p - > group )
ast_cli ( fd , " -- Pending call to group %d \n " , powerof ( p - > group ) ) ;
else
ast_cli ( fd , " -- Pending call to agent %s \n " , p - > agent ) ;
} else {
2004-05-09 07:51:44 +00:00
if ( ! ast_strlen_zero ( p - > name ) )
2003-07-01 16:16:28 +00:00
snprintf ( username , sizeof ( username ) , " (%s) " , p - > name ) ;
else
2004-07-16 04:40:54 +00:00
username [ 0 ] = ' \0 ' ;
2003-07-01 16:16:28 +00:00
if ( p - > chan ) {
snprintf ( location , sizeof ( location ) , " logged in on %s " , p - > chan - > name ) ;
2004-10-23 12:19:47 +00:00
if ( p - > owner & & ast_bridged_channel ( p - > owner ) ) {
snprintf ( talkingto , sizeof ( talkingto ) , " talking to %s " , ast_bridged_channel ( p - > owner ) - > name ) ;
2003-07-01 16:16:28 +00:00
} else {
2005-08-26 20:24:16 +00:00
strcpy ( talkingto , " is idle " ) ;
2003-07-01 16:16:28 +00:00
}
2005-05-15 02:48:16 +00:00
online_agents + + ;
2004-05-09 07:51:44 +00:00
} else if ( ! ast_strlen_zero ( p - > loginchan ) ) {
2003-07-14 02:31:56 +00:00
snprintf ( location , sizeof ( location ) - 20 , " available at '%s' " , p - > loginchan ) ;
2004-07-16 04:40:54 +00:00
talkingto [ 0 ] = ' \0 ' ;
2005-05-15 02:48:16 +00:00
online_agents + + ;
2003-07-14 02:31:56 +00:00
if ( p - > acknowledged )
2004-07-16 04:40:54 +00:00
strncat ( location , " (Confirmed) " , sizeof ( location ) - strlen ( location ) - 1 ) ;
2002-09-02 15:20:28 +00:00
} else {
2005-08-26 20:24:16 +00:00
strcpy ( location , " not logged in " ) ;
2004-07-16 04:40:54 +00:00
talkingto [ 0 ] = ' \0 ' ;
2005-05-15 02:48:16 +00:00
offline_agents + + ;
2002-09-02 15:20:28 +00:00
}
2004-05-09 07:51:44 +00:00
if ( ! ast_strlen_zero ( p - > moh ) )
2003-07-28 14:24:10 +00:00
snprintf ( moh , sizeof ( moh ) , " (musiconhold is '%s') " , p - > moh ) ;
2003-07-14 04:21:00 +00:00
ast_cli ( fd , " %-12.12s %s%s%s%s \n " , p - > agent ,
2005-09-14 00:28:06 +00:00
username , location , talkingto , moh ) ;
2005-05-15 02:48:16 +00:00
count_agents + + ;
2002-09-02 15:20:28 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
}
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2005-05-15 02:48:16 +00:00
if ( ! count_agents ) {
ast_cli ( fd , " No Agents are configured in %s \n " , config ) ;
} else {
ast_cli ( fd , " %d agents configured [%d online , %d offline] \n " , count_agents , online_agents , offline_agents ) ;
}
2005-07-25 16:53:28 +00:00
ast_cli ( fd , " \n " ) ;
2002-09-02 15:20:28 +00:00
return RESULT_SUCCESS ;
}
static char show_agents_usage [ ] =
" Usage: show agents \n "
" Provides summary information on agents. \n " ;
2005-01-30 06:55:10 +00:00
static char agent_logoff_usage [ ] =
" 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 " ;
2002-09-02 15:20:28 +00:00
static struct ast_cli_entry cli_show_agents = {
{ " show " , " agents " , NULL } , agents_show ,
" Show status of agents " , show_agents_usage , NULL } ;
2005-01-30 06:55:10 +00:00
static struct ast_cli_entry cli_agent_logoff = {
{ " agent " , " logoff " , NULL } , agent_logoff_cmd ,
" Sets an agent offline " , agent_logoff_usage , complete_agent_logoff_cmd } ;
2002-09-02 15:20:28 +00:00
LOCAL_USER_DECL ;
2005-11-06 22:17:47 +00:00
/*!
* \ brief Log in agent application .
2005-09-14 02:12:37 +00:00
*
2005-11-06 22:17:47 +00:00
* \ param chan
* \ param data
* \ param callbackmode non - zero for AgentCallbackLogin
2005-09-14 02:12:37 +00:00
*/
2003-07-14 02:31:56 +00:00
static int __login_exec ( struct ast_channel * chan , void * data , int callbackmode )
2002-09-02 15:20:28 +00:00
{
int res = 0 ;
int tries = 0 ;
2004-10-24 13:24:16 +00:00
int max_login_tries = maxlogintries ;
2002-09-02 15:20:28 +00:00
struct agent_pvt * p ;
struct localuser * u ;
2004-10-24 13:24:16 +00:00
int login_state = 0 ;
2004-07-16 04:40:54 +00:00
char user [ AST_MAX_AGENT ] = " " ;
2002-09-02 15:20:28 +00:00
char pass [ AST_MAX_AGENT ] ;
2004-02-14 04:54:39 +00:00
char agent [ AST_MAX_AGENT ] = " " ;
2002-09-02 15:20:28 +00:00
char xpass [ AST_MAX_AGENT ] = " " ;
char * errmsg ;
2005-10-28 17:11:20 +00:00
char * parse ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( agent_id ) ;
AST_APP_ARG ( options ) ;
AST_APP_ARG ( extension ) ;
) ;
2005-12-03 19:25:33 +00:00
const char * tmpoptions = NULL ;
2003-08-03 18:22:12 +00:00
char * context = NULL ;
2004-10-24 13:24:16 +00:00
int play_announcement = 1 ;
char agent_goodbye [ AST_MAX_FILENAME_LEN ] ;
int update_cdr = updatecdr ;
2003-07-14 02:31:56 +00:00
char * filename = " agent-loginok " ;
2006-01-11 19:13:33 +00:00
char tmpchan [ AST_MAX_BUF ] = " " ;
2005-10-26 16:16:05 +00:00
2002-09-02 15:20:28 +00:00
LOCAL_USER_ADD ( u ) ;
2002-12-06 16:22:19 +00:00
2006-01-21 17:50:04 +00:00
if ( ! ( parse = ast_strdupa ( data ) ) ) {
LOCAL_USER_REMOVE ( u ) ;
return - 1 ;
}
2005-10-26 16:16:05 +00:00
2005-10-28 17:11:20 +00:00
AST_STANDARD_APP_ARGS ( args , parse ) ;
2005-10-26 16:16:05 +00:00
ast_copy_string ( agent_goodbye , agentgoodbye , sizeof ( agent_goodbye ) ) ;
2004-10-24 13:24:16 +00:00
/* Set Channel Specific Login Overrides */
if ( pbx_builtin_getvar_helper ( chan , " AGENTLMAXLOGINTRIES " ) & & strlen ( pbx_builtin_getvar_helper ( chan , " AGENTLMAXLOGINTRIES " ) ) ) {
max_login_tries = atoi ( pbx_builtin_getvar_helper ( chan , " AGENTMAXLOGINTRIES " ) ) ;
if ( max_login_tries < 0 )
max_login_tries = 0 ;
tmpoptions = pbx_builtin_getvar_helper ( chan , " AGENTMAXLOGINTRIES " ) ;
2004-12-31 00:58:44 +00:00
if ( option_verbose > 2 )
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 ) ;
2004-10-24 13:24:16 +00:00
}
2004-12-31 00:58:44 +00:00
if ( pbx_builtin_getvar_helper ( chan , " AGENTUPDATECDR " ) & & ! ast_strlen_zero ( pbx_builtin_getvar_helper ( chan , " AGENTUPDATECDR " ) ) ) {
2004-10-24 13:24:16 +00:00
if ( ast_true ( pbx_builtin_getvar_helper ( chan , " AGENTUPDATECDR " ) ) )
update_cdr = 1 ;
else
update_cdr = 0 ;
tmpoptions = pbx_builtin_getvar_helper ( chan , " AGENTUPDATECDR " ) ;
2004-12-31 00:58:44 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'. \n " , tmpoptions , update_cdr , chan - > name ) ;
2004-10-24 13:24:16 +00:00
}
2004-12-31 00:58:44 +00:00
if ( pbx_builtin_getvar_helper ( chan , " AGENTGOODBYE " ) & & ! ast_strlen_zero ( pbx_builtin_getvar_helper ( chan , " AGENTGOODBYE " ) ) ) {
2004-10-24 13:24:16 +00:00
strcpy ( agent_goodbye , pbx_builtin_getvar_helper ( chan , " AGENTGOODBYE " ) ) ;
tmpoptions = pbx_builtin_getvar_helper ( chan , " AGENTGOODBYE " ) ;
2004-12-31 00:58:44 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'. \n " , tmpoptions , agent_goodbye , chan - > name ) ;
2004-10-24 13:24:16 +00:00
}
/* End Channel Specific Login Overrides */
2005-10-26 16:16:05 +00:00
2005-10-28 17:11:20 +00:00
if ( callbackmode & & args . extension ) {
parse = args . extension ;
args . extension = strsep ( & parse , " @ " ) ;
context = parse ;
2005-10-26 16:16:05 +00:00
}
2005-11-06 22:17:47 +00:00
if ( ! ast_strlen_zero ( args . options ) ) {
if ( strchr ( args . options , ' s ' ) ) {
2005-10-26 16:16:05 +00:00
play_announcement = 0 ;
2004-10-24 13:24:16 +00:00
}
2002-12-06 16:22:19 +00:00
}
2002-09-02 15:20:28 +00:00
if ( chan - > _state ! = AST_STATE_UP )
res = ast_answer ( chan ) ;
2002-12-06 16:22:19 +00:00
if ( ! res ) {
2005-10-28 17:11:20 +00:00
if ( ! ast_strlen_zero ( args . agent_id ) )
ast_copy_string ( user , args . agent_id , AST_MAX_AGENT ) ;
2002-12-06 16:22:19 +00:00
else
res = ast_app_getdata ( chan , " agent-user " , user , sizeof ( user ) - 1 , 0 ) ;
}
2004-10-24 13:24:16 +00:00
while ( ! res & & ( max_login_tries = = 0 | | tries < max_login_tries ) ) {
tries + + ;
2002-09-02 15:20:28 +00:00
/* Check for password */
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
AST_LIST_TRAVERSE ( & agents , p , list ) {
2003-07-01 16:16:28 +00:00
if ( ! strcmp ( p - > agent , user ) & & ! p - > pending )
2005-08-26 20:24:16 +00:00
ast_copy_string ( xpass , p - > password , sizeof ( xpass ) ) ;
2002-09-02 15:20:28 +00:00
}
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2002-09-02 15:20:28 +00:00
if ( ! res ) {
2004-05-09 07:51:44 +00:00
if ( ! ast_strlen_zero ( xpass ) )
2002-09-02 15:20:28 +00:00
res = ast_app_getdata ( chan , " agent-pass " , pass , sizeof ( pass ) - 1 , 0 ) ;
else
2004-07-16 04:40:54 +00:00
pass [ 0 ] = ' \0 ' ;
2002-09-02 15:20:28 +00:00
}
errmsg = " agent-incorrect " ;
#if 0
ast_log ( LOG_NOTICE , " user: %s, pass: %s \n " , user , pass ) ;
# endif
/* Check again for accuracy */
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
AST_LIST_TRAVERSE ( & agents , p , list ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
if ( ! strcmp ( p - > agent , user ) & &
2005-09-14 00:28:06 +00:00
! strcmp ( p - > password , pass ) & & ! p - > pending ) {
login_state = 1 ; /* Successful Login */
2005-09-14 00:59:51 +00:00
/* Ensure we can't be gotten until we're done */
gettimeofday ( & p - > lastdisc , NULL ) ;
p - > lastdisc . tv_sec + + ;
2006-01-13 06:11:41 +00:00
/* Set Channel Specific Agent Overrides */
2005-09-14 00:28:06 +00:00
if ( pbx_builtin_getvar_helper ( chan , " AGENTACKCALL " ) & & strlen ( pbx_builtin_getvar_helper ( chan , " AGENTACKCALL " ) ) ) {
if ( ! strcasecmp ( pbx_builtin_getvar_helper ( chan , " AGENTACKCALL " ) , " always " ) )
p - > ackcall = 2 ;
else if ( ast_true ( pbx_builtin_getvar_helper ( chan , " AGENTACKCALL " ) ) )
p - > ackcall = 1 ;
else
p - > ackcall = 0 ;
tmpoptions = pbx_builtin_getvar_helper ( chan , " AGENTACKCALL " ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'. \n " , tmpoptions , p - > ackcall , p - > agent ) ;
}
if ( pbx_builtin_getvar_helper ( chan , " AGENTAUTOLOGOFF " ) & & strlen ( pbx_builtin_getvar_helper ( chan , " AGENTAUTOLOGOFF " ) ) ) {
p - > autologoff = atoi ( pbx_builtin_getvar_helper ( chan , " AGENTAUTOLOGOFF " ) ) ;
if ( p - > autologoff < 0 )
p - > autologoff = 0 ;
tmpoptions = pbx_builtin_getvar_helper ( chan , " AGENTAUTOLOGOFF " ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'. \n " , tmpoptions , p - > autologoff , p - > agent ) ;
}
if ( pbx_builtin_getvar_helper ( chan , " AGENTWRAPUPTIME " ) & & strlen ( pbx_builtin_getvar_helper ( chan , " AGENTWRAPUPTIME " ) ) ) {
p - > wrapuptime = atoi ( pbx_builtin_getvar_helper ( chan , " AGENTWRAPUPTIME " ) ) ;
if ( p - > wrapuptime < 0 )
p - > wrapuptime = 0 ;
tmpoptions = pbx_builtin_getvar_helper ( chan , " AGENTWRAPUPTIME " ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'. \n " , tmpoptions , p - > wrapuptime , p - > agent ) ;
}
2006-01-13 06:11:41 +00:00
/* End Channel Specific Agent Overrides */
2005-09-14 00:28:06 +00:00
if ( ! p - > chan ) {
char last_loginchan [ 80 ] = " " ;
long logintime ;
snprintf ( agent , sizeof ( agent ) , " Agent/%s " , p - > agent ) ;
if ( callbackmode ) {
int pos = 0 ;
/* Retrieve login chan */
for ( ; ; ) {
2005-10-28 17:22:34 +00:00
if ( ! ast_strlen_zero ( args . extension ) ) {
2005-10-28 17:11:20 +00:00
ast_copy_string ( tmpchan , args . extension , sizeof ( tmpchan ) ) ;
2005-09-14 00:28:06 +00:00
res = 0 ;
} else
res = ast_app_getdata ( chan , " agent-newlocation " , tmpchan + pos , sizeof ( tmpchan ) - 2 , 0 ) ;
2006-01-12 19:07:18 +00:00
if ( ast_strlen_zero ( tmpchan ) )
2005-09-14 00:28:06 +00:00
break ;
2006-03-27 19:31:54 +00:00
if ( ast_exists_extension ( chan , S_OR ( context , " default " ) , tmpchan , 1 , NULL ) ) {
2006-01-12 19:07:18 +00:00
if ( ! allow_multiple_login ( tmpchan , context ) ) {
args . extension = NULL ;
pos = 0 ;
} else
break ;
}
2005-10-28 17:11:20 +00:00
if ( args . extension ) {
ast_log ( LOG_WARNING , " Extension '%s' is not valid for automatic login of agent '%s' \n " , args . extension , p - > agent ) ;
args . extension = NULL ;
2005-09-14 00:28:06 +00:00
pos = 0 ;
} else {
2006-03-27 19:31:54 +00:00
ast_log ( LOG_WARNING , " Extension '%s@%s' is not valid for automatic login of agent '%s' \n " , tmpchan , S_OR ( context , " default " ) , p - > agent ) ;
2005-09-14 00:28:06 +00:00
res = ast_streamfile ( chan , " invalid " , chan - > language ) ;
if ( ! res )
res = ast_waitstream ( chan , AST_DIGIT_ANY ) ;
if ( res > 0 ) {
tmpchan [ 0 ] = res ;
tmpchan [ 1 ] = ' \0 ' ;
pos = 1 ;
2003-08-16 15:31:18 +00:00
} else {
2005-09-14 00:28:06 +00:00
tmpchan [ 0 ] = ' \0 ' ;
pos = 0 ;
2003-08-16 15:31:18 +00:00
}
}
2005-09-14 00:28:06 +00:00
}
2005-10-28 17:11:20 +00:00
args . extension = tmpchan ;
2005-09-14 00:28:06 +00:00
if ( ! res ) {
2005-09-14 00:39:05 +00:00
set_agentbycallerid ( p - > logincallerid , NULL ) ;
2005-10-27 02:19:37 +00:00
if ( ! ast_strlen_zero ( context ) & & ! ast_strlen_zero ( tmpchan ) )
2005-09-14 00:28:06 +00:00
snprintf ( p - > loginchan , sizeof ( p - > loginchan ) , " %s@%s " , tmpchan , context ) ;
else {
ast_copy_string ( last_loginchan , p - > loginchan , sizeof ( last_loginchan ) ) ;
ast_copy_string ( p - > loginchan , tmpchan , sizeof ( p - > loginchan ) ) ;
}
p - > acknowledged = 0 ;
if ( ast_strlen_zero ( p - > loginchan ) ) {
login_state = 2 ;
filename = " agent-loggedoff " ;
} else {
if ( chan - > cid . cid_num ) {
ast_copy_string ( p - > logincallerid , chan - > cid . cid_num , sizeof ( p - > logincallerid ) ) ;
2005-09-14 00:39:05 +00:00
set_agentbycallerid ( p - > logincallerid , p - > agent ) ;
2005-09-14 00:28:06 +00:00
} else
p - > logincallerid [ 0 ] = ' \0 ' ;
}
2005-07-06 01:29:15 +00:00
2005-09-14 00:28:06 +00:00
if ( update_cdr & & chan - > cdr )
snprintf ( chan - > cdr - > channel , sizeof ( chan - > cdr - > channel ) , " Agent/%s " , p - > agent ) ;
2004-04-03 00:41:47 +00:00
2005-09-14 00:28:06 +00:00
}
} else {
p - > loginchan [ 0 ] = ' \0 ' ;
p - > logincallerid [ 0 ] = ' \0 ' ;
p - > acknowledged = 0 ;
}
ast_mutex_unlock ( & p - > lock ) ;
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2005-09-14 00:28:06 +00:00
if ( ! res & & play_announcement = = 1 )
res = ast_streamfile ( chan , filename , chan - > language ) ;
if ( ! res )
ast_waitstream ( chan , " " ) ;
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
2005-09-14 00:28:06 +00:00
ast_mutex_lock ( & p - > lock ) ;
if ( ! res ) {
res = ast_set_read_format ( chan , ast_best_codec ( chan - > nativeformats ) ) ;
if ( res )
ast_log ( LOG_WARNING , " Unable to set read format to %d \n " , ast_best_codec ( chan - > nativeformats ) ) ;
}
if ( ! res ) {
res = ast_set_write_format ( chan , ast_best_codec ( chan - > nativeformats ) ) ;
if ( res )
ast_log ( LOG_WARNING , " Unable to set write format to %d \n " , ast_best_codec ( chan - > nativeformats ) ) ;
}
/* Check once more just in case */
if ( p - > chan )
res = - 1 ;
if ( callbackmode & & ! res ) {
/* Just say goodbye and be done with it */
if ( ! ast_strlen_zero ( p - > loginchan ) ) {
if ( p - > loginstart = = 0 )
time ( & p - > loginstart ) ;
manager_event ( EVENT_FLAG_AGENT , " Agentcallbacklogin " ,
" Agent: %s \r \n "
" Loginchan: %s \r \n "
" Uniqueid: %s \r \n " ,
p - > agent , p - > loginchan , chan - > uniqueid ) ;
ast_queue_log ( " NONE " , chan - > uniqueid , agent , " AGENTCALLBACKLOGIN " , " %s " , p - > loginchan ) ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Callback Agent '%s' logged in on %s \n " , p - > agent , p - > loginchan ) ;
ast_device_state_changed ( " Agent/%s " , p - > agent ) ;
2006-01-14 03:25:38 +00:00
if ( persistent_agents )
dump_agents ( ) ;
2003-07-14 02:31:56 +00:00
} else {
2005-09-14 00:28:06 +00:00
logintime = time ( NULL ) - p - > loginstart ;
p - > loginstart = 0 ;
2006-01-14 03:25:38 +00:00
agent_logoff_maintenance ( p , last_loginchan , logintime , chan - > uniqueid , NULL ) ;
2005-09-14 00:28:06 +00:00
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Callback Agent '%s' logged out \n " , p - > agent ) ;
2003-07-14 02:31:56 +00:00
}
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2002-09-02 15:20:28 +00:00
if ( ! res )
2005-09-14 00:28:06 +00:00
res = ast_safe_sleep ( chan , 500 ) ;
ast_mutex_unlock ( & p - > lock ) ;
} else if ( ! res ) {
# ifdef HONOR_MUSIC_CLASS
/* check if the moh class was changed with setmusiconhold */
if ( * ( chan - > musicclass ) )
ast_copy_string ( p - > moh , chan - > musicclass , sizeof ( p - > moh ) ) ;
# endif
ast_moh_start ( chan , p - > moh ) ;
if ( p - > loginstart = = 0 )
time ( & p - > loginstart ) ;
manager_event ( EVENT_FLAG_AGENT , " Agentlogin " ,
" Agent: %s \r \n "
" Channel: %s \r \n "
" Uniqueid: %s \r \n " ,
p - > agent , chan - > name , chan - > uniqueid ) ;
if ( update_cdr & & chan - > cdr )
snprintf ( chan - > cdr - > channel , sizeof ( chan - > cdr - > channel ) , " Agent/%s " , p - > agent ) ;
ast_queue_log ( " NONE " , chan - > uniqueid , agent , " AGENTLOGIN " , " %s " , chan - > name ) ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Agent '%s' logged in (format %s/%s) \n " , p - > agent ,
ast_getformatname ( chan - > readformat ) , ast_getformatname ( chan - > writeformat ) ) ;
/* Login this channel and wait for it to
go away */
p - > chan = chan ;
if ( p - > ackcall > 1 )
check_beep ( p , 0 ) ;
else
check_availability ( p , 0 ) ;
ast_mutex_unlock ( & p - > lock ) ;
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2005-09-14 00:28:06 +00:00
ast_device_state_changed ( " Agent/%s " , p - > agent ) ;
while ( res > = 0 ) {
ast_mutex_lock ( & p - > lock ) ;
if ( p - > chan ! = chan )
res = - 1 ;
ast_mutex_unlock ( & p - > lock ) ;
/* Yield here so other interested threads can kick in. */
sched_yield ( ) ;
2002-09-02 15:20:28 +00:00
if ( res )
2005-09-14 00:28:06 +00:00
break ;
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
2005-09-14 00:28:06 +00:00
ast_mutex_lock ( & p - > lock ) ;
if ( p - > lastdisc . tv_sec ) {
if ( ast_tvdiff_ms ( ast_tvnow ( ) , p - > lastdisc ) > p - > wrapuptime ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Wrapup time for %s expired! \n " , p - > agent ) ;
p - > lastdisc = ast_tv ( 0 , 0 ) ;
if ( p - > ackcall > 1 )
check_beep ( p , 0 ) ;
else
check_availability ( p , 0 ) ;
}
2004-06-03 17:33:35 +00:00
}
2005-09-14 00:28:06 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2005-09-14 00:28:06 +00:00
/* Synchronize channel ownership between call to agent and itself. */
ast_mutex_lock ( & p - > app_lock ) ;
ast_mutex_lock ( & p - > lock ) ;
p - > owning_app = pthread_self ( ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2005-09-14 00:28:06 +00:00
if ( p - > ackcall > 1 )
res = agent_ack_sleep ( p ) ;
2003-08-26 00:36:03 +00:00
else
2005-09-14 00:28:06 +00:00
res = ast_safe_sleep_conditional ( chan , 1000 ,
agent_cont_sleep , p ) ;
ast_mutex_unlock ( & p - > app_lock ) ;
if ( ( p - > ackcall > 1 ) & & ( res = = 1 ) ) {
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2005-09-14 00:28:06 +00:00
check_availability ( p , 0 ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2005-09-14 00:28:06 +00:00
res = 0 ;
2004-06-22 17:42:14 +00:00
}
2005-09-14 00:28:06 +00:00
sched_yield ( ) ;
2002-09-02 15:20:28 +00:00
}
2005-09-14 00:28:06 +00:00
ast_mutex_lock ( & p - > lock ) ;
if ( res & & p - > owner )
ast_log ( LOG_WARNING , " Huh? We broke out when there was still an owner? \n " ) ;
/* Log us off if appropriate */
if ( p - > chan = = chan )
p - > chan = NULL ;
p - > acknowledged = 0 ;
logintime = time ( NULL ) - p - > loginstart ;
p - > loginstart = 0 ;
ast_mutex_unlock ( & p - > lock ) ;
manager_event ( EVENT_FLAG_AGENT , " Agentlogoff " ,
" Agent: %s \r \n "
" Logintime: %ld \r \n "
" Uniqueid: %s \r \n " ,
p - > agent , logintime , chan - > uniqueid ) ;
ast_queue_log ( " NONE " , chan - > uniqueid , agent , " AGENTLOGOFF " , " %s|%ld " , chan - > name , logintime ) ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Agent '%s' logged out \n " , p - > agent ) ;
/* If there is no owner, go ahead and kill it now */
ast_device_state_changed ( " Agent/%s " , p - > agent ) ;
if ( p - > dead & & ! p - > owner ) {
ast_mutex_destroy ( & p - > lock ) ;
ast_mutex_destroy ( & p - > app_lock ) ;
free ( p ) ;
2002-12-06 16:22:19 +00:00
}
2005-09-14 00:28:06 +00:00
}
else {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
p = NULL ;
}
2005-09-14 00:28:06 +00:00
res = - 1 ;
} else {
ast_mutex_unlock ( & p - > lock ) ;
errmsg = " agent-alreadyon " ;
p = NULL ;
}
break ;
2002-09-02 15:20:28 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-09-02 15:20:28 +00:00
}
if ( ! p )
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2002-09-02 15:20:28 +00:00
2004-10-24 13:24:16 +00:00
if ( ! res & & ( max_login_tries = = 0 | | tries < max_login_tries ) )
2002-09-02 15:20:28 +00:00
res = ast_app_getdata ( chan , errmsg , user , sizeof ( user ) - 1 , 0 ) ;
}
2004-10-24 13:24:16 +00:00
if ( ! res )
res = ast_safe_sleep ( chan , 500 ) ;
/* AgentLogin() exit */
if ( ! callbackmode ) {
2005-10-26 16:16:05 +00:00
LOCAL_USER_REMOVE ( u ) ;
2004-10-24 13:24:16 +00:00
return - 1 ;
}
/* AgentCallbackLogin() exit*/
else {
/* Set variables */
if ( login_state > 0 ) {
pbx_builtin_setvar_helper ( chan , " AGENTNUMBER " , user ) ;
if ( login_state = = 1 ) {
pbx_builtin_setvar_helper ( chan , " AGENTSTATUS " , " on " ) ;
2005-10-28 17:11:20 +00:00
pbx_builtin_setvar_helper ( chan , " AGENTEXTEN " , args . extension ) ;
2004-10-24 13:24:16 +00:00
}
else {
pbx_builtin_setvar_helper ( chan , " AGENTSTATUS " , " off " ) ;
}
}
else {
pbx_builtin_setvar_helper ( chan , " AGENTSTATUS " , " fail " ) ;
}
2005-10-26 16:16:05 +00:00
if ( ast_exists_extension ( chan , chan - > context , chan - > exten , chan - > priority + 1 , chan - > cid . cid_num ) ) {
LOCAL_USER_REMOVE ( u ) ;
2004-10-24 13:24:16 +00:00
return 0 ;
2005-10-26 16:16:05 +00:00
}
2004-10-24 13:24:16 +00:00
/* Do we need to play agent-goodbye now that we will be hanging up? */
2005-10-26 16:16:05 +00:00
if ( play_announcement ) {
2004-10-24 13:24:16 +00:00
if ( ! res )
res = ast_safe_sleep ( chan , 1000 ) ;
res = ast_streamfile ( chan , agent_goodbye , chan - > language ) ;
if ( ! res )
res = ast_waitstream ( chan , " " ) ;
if ( ! res )
res = ast_safe_sleep ( chan , 1000 ) ;
}
}
2005-10-26 16:16:05 +00:00
LOCAL_USER_REMOVE ( u ) ;
2004-10-24 13:24:16 +00:00
/* We should never get here if next priority exists when in callbackmode */
return - 1 ;
2002-09-02 15:20:28 +00:00
}
2005-09-14 02:12:37 +00:00
/**
* Called by the AgentLogin application ( from the dial plan ) .
*
* @ param chan
* @ param data
* @ returns
* @ sa callback_login_exec ( ) , agentmonitoroutgoing_exec ( ) , load_module ( ) .
*/
2003-07-14 02:31:56 +00:00
static int login_exec ( struct ast_channel * chan , void * data )
{
return __login_exec ( chan , data , 0 ) ;
}
2005-09-14 02:12:37 +00:00
/**
* Called by the AgentCallbackLogin application ( from the dial plan ) .
*
* @ param chan
* @ param data
* @ returns
* @ sa login_exec ( ) , agentmonitoroutgoing_exec ( ) , load_module ( ) .
*/
2003-07-14 02:31:56 +00:00
static int callback_exec ( struct ast_channel * chan , void * data )
{
return __login_exec ( chan , data , 1 ) ;
}
2002-09-02 15:20:28 +00:00
2005-09-14 02:12:37 +00:00
/**
* 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 .
* @ param s
* @ param m
* @ returns
* @ sa action_agents ( ) , action_agent_logoff ( ) , load_module ( ) .
*/
2005-08-26 20:24:16 +00:00
static int action_agent_callback_login ( struct mansession * s , struct message * m )
{
char * agent = astman_get_header ( m , " Agent " ) ;
char * exten = astman_get_header ( m , " Exten " ) ;
char * context = astman_get_header ( m , " Context " ) ;
char * wrapuptime_s = astman_get_header ( m , " WrapupTime " ) ;
char * ackcall_s = astman_get_header ( m , " AckCall " ) ;
struct agent_pvt * p ;
int login_state = 0 ;
if ( ast_strlen_zero ( agent ) ) {
astman_send_error ( s , m , " No agent specified " ) ;
return 0 ;
}
if ( ast_strlen_zero ( exten ) ) {
astman_send_error ( s , m , " No extension specified " ) ;
return 0 ;
}
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
AST_LIST_TRAVERSE ( & agents , p , list ) {
2005-08-26 20:24:16 +00:00
if ( strcmp ( p - > agent , agent ) | | p - > pending ) {
continue ;
}
if ( p - > chan ) {
login_state = 2 ; /* already logged in (and on the phone)*/
break ;
}
ast_mutex_lock ( & p - > lock ) ;
login_state = 1 ; /* Successful Login */
if ( ast_strlen_zero ( context ) )
2005-10-13 21:59:25 +00:00
ast_copy_string ( p - > loginchan , exten , sizeof ( p - > loginchan ) ) ;
2005-08-26 20:24:16 +00:00
else
snprintf ( p - > loginchan , sizeof ( p - > loginchan ) , " %s@%s " , exten , context ) ;
2005-10-27 02:19:37 +00:00
if ( ! ast_strlen_zero ( wrapuptime_s ) ) {
2005-08-26 20:24:16 +00:00
p - > wrapuptime = atoi ( wrapuptime_s ) ;
if ( p - > wrapuptime < 0 )
p - > wrapuptime = 0 ;
}
if ( ast_true ( ackcall_s ) )
p - > ackcall = 1 ;
else
p - > ackcall = 0 ;
if ( p - > loginstart = = 0 )
time ( & p - > loginstart ) ;
manager_event ( EVENT_FLAG_AGENT , " Agentcallbacklogin " ,
2005-09-14 00:28:06 +00:00
" Agent: %s \r \n "
" Loginchan: %s \r \n " ,
p - > agent , p - > loginchan ) ;
2005-08-26 20:24:16 +00:00
ast_queue_log ( " NONE " , " NONE " , agent , " AGENTCALLBACKLOGIN " , " %s " , p - > loginchan ) ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Callback Agent '%s' logged in on %s \n " , p - > agent , p - > loginchan ) ;
ast_device_state_changed ( " Agent/%s " , p - > agent ) ;
ast_mutex_unlock ( & p - > lock ) ;
2006-02-15 01:22:54 +00:00
if ( persistent_agents )
dump_agents ( ) ;
2005-08-26 20:24:16 +00:00
}
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2005-08-26 20:24:16 +00:00
if ( login_state = = 1 )
astman_send_ack ( s , m , " Agent logged in " ) ;
else if ( login_state = = 0 )
astman_send_error ( s , m , " No such agent " ) ;
else if ( login_state = = 2 )
astman_send_error ( s , m , " Agent already logged in " ) ;
return 0 ;
}
2005-09-14 02:12:37 +00:00
/**
* Called by the AgentMonitorOutgoing application ( from the dial plan ) .
*
* @ param chan
* @ param data
* @ returns
* @ sa login_exec ( ) , callback_login_exec ( ) , load_module ( ) .
*/
2004-02-05 21:13:17 +00:00
static int agentmonitoroutgoing_exec ( struct ast_channel * chan , void * data )
{
int exitifnoagentid = 0 ;
int nowarnings = 0 ;
2004-12-10 17:37:20 +00:00
int changeoutgoing = 0 ;
2004-02-05 21:13:17 +00:00
int res = 0 ;
2005-12-03 19:25:33 +00:00
char agent [ AST_MAX_AGENT ] ;
2004-12-31 00:58:44 +00:00
2004-02-05 21:13:17 +00:00
if ( data ) {
if ( strchr ( data , ' d ' ) )
exitifnoagentid = 1 ;
if ( strchr ( data , ' n ' ) )
nowarnings = 1 ;
2004-12-10 17:37:20 +00:00
if ( strchr ( data , ' c ' ) )
changeoutgoing = 1 ;
2004-02-05 21:13:17 +00:00
}
2004-10-02 00:58:31 +00:00
if ( chan - > cid . cid_num ) {
2005-12-03 19:25:33 +00:00
const char * tmp ;
2004-02-05 21:13:17 +00:00
char agentvar [ AST_MAX_BUF ] ;
2004-10-02 00:58:31 +00:00
snprintf ( agentvar , sizeof ( agentvar ) , " %s_%s " , GETAGENTBYCALLERID , chan - > cid . cid_num ) ;
2004-02-05 21:13:17 +00:00
if ( ( tmp = pbx_builtin_getvar_helper ( NULL , agentvar ) ) ) {
2006-01-25 18:12:55 +00:00
struct agent_pvt * p ;
2005-08-26 20:24:16 +00:00
ast_copy_string ( agent , tmp , sizeof ( agent ) ) ;
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
AST_LIST_TRAVERSE ( & agents , p , list ) {
2004-02-05 21:13:17 +00:00
if ( ! strcasecmp ( p - > agent , tmp ) ) {
2004-12-10 17:37:20 +00:00
if ( changeoutgoing ) snprintf ( chan - > cdr - > channel , sizeof ( chan - > cdr - > channel ) , " Agent/%s " , p - > agent ) ;
2004-02-05 21:13:17 +00:00
__agent_start_monitoring ( chan , p , 1 ) ;
break ;
}
}
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2004-02-05 21:13:17 +00:00
} else {
res = - 1 ;
if ( ! nowarnings )
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 ) ;
}
} else {
res = - 1 ;
if ( ! nowarnings )
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 " ) ;
}
/* check if there is n + 101 priority */
if ( res ) {
2005-09-14 00:28:06 +00:00
if ( ast_exists_extension ( chan , chan - > context , chan - > exten , chan - > priority + 101 , chan - > cid . cid_num ) ) {
2004-02-05 21:13:17 +00:00
chan - > priority + = 100 ;
2004-12-31 00:58:44 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Going to %d priority because there is no callerid or the agentid cannot be found. \n " , chan - > priority ) ;
2005-09-14 00:28:06 +00:00
}
2004-02-05 21:13:17 +00:00
else if ( exitifnoagentid )
return res ;
}
return 0 ;
}
2005-09-14 02:12:37 +00:00
/**
* Dump AgentCallbackLogin agents to the database for persistence
2005-01-01 00:57:04 +00:00
*/
static void dump_agents ( void )
{
struct agent_pvt * cur_agent = NULL ;
2005-07-06 01:29:15 +00:00
char buf [ 256 ] ;
2005-03-03 20:31:21 +00:00
2006-01-25 18:12:55 +00:00
AST_LIST_TRAVERSE ( & agents , cur_agent , list ) {
2005-03-03 20:31:21 +00:00
if ( cur_agent - > chan )
2005-01-01 00:57:04 +00:00
continue ;
2005-03-03 20:31:21 +00:00
2005-01-01 00:57:04 +00:00
if ( ! ast_strlen_zero ( cur_agent - > loginchan ) ) {
2005-07-06 01:29:15 +00:00
snprintf ( buf , sizeof ( buf ) , " %s;%s " , cur_agent - > loginchan , cur_agent - > logincallerid ) ;
if ( ast_db_put ( pa_family , cur_agent - > agent , buf ) )
2005-01-01 00:57:04 +00:00
ast_log ( LOG_WARNING , " failed to create persistent entry! \n " ) ;
2005-03-03 20:31:21 +00:00
else if ( option_debug )
ast_log ( LOG_DEBUG , " Saved Agent: %s on %s \n " , cur_agent - > agent , cur_agent - > loginchan ) ;
2005-01-01 00:57:04 +00:00
} else {
/* Delete - no agent or there is an error */
ast_db_del ( pa_family , cur_agent - > agent ) ;
}
}
}
2005-09-07 20:44:57 +00:00
/**
* Reload the persistent agents from astdb .
*/
2005-01-01 00:57:04 +00:00
static void reload_agents ( void )
{
2005-03-03 20:31:21 +00:00
char * agent_num ;
struct ast_db_entry * db_tree ;
struct ast_db_entry * entry ;
struct agent_pvt * cur_agent ;
2005-07-06 01:29:15 +00:00
char agent_data [ 256 ] ;
char * parse ;
char * agent_chan ;
char * agent_callerid ;
2005-01-01 00:57:04 +00:00
2005-03-03 20:31:21 +00:00
db_tree = ast_db_gettree ( pa_family , NULL ) ;
2005-01-01 00:57:04 +00:00
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
2005-03-03 20:31:21 +00:00
for ( entry = db_tree ; entry ; entry = entry - > next ) {
2005-03-05 02:54:49 +00:00
agent_num = entry - > key + strlen ( pa_family ) + 2 ;
2006-01-25 18:12:55 +00:00
AST_LIST_TRAVERSE ( & agents , cur_agent , list ) {
2005-01-01 00:57:04 +00:00
ast_mutex_lock ( & cur_agent - > lock ) ;
2005-03-03 20:31:21 +00:00
if ( strcmp ( agent_num , cur_agent - > agent ) = = 0 )
2005-01-01 00:57:04 +00:00
break ;
ast_mutex_unlock ( & cur_agent - > lock ) ;
}
if ( ! cur_agent ) {
2005-03-03 20:31:21 +00:00
ast_db_del ( pa_family , agent_num ) ;
2005-01-01 00:57:04 +00:00
continue ;
} else
ast_mutex_unlock ( & cur_agent - > lock ) ;
2005-03-03 20:31:21 +00:00
if ( ! ast_db_get ( pa_family , agent_num , agent_data , sizeof ( agent_data ) - 1 ) ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Reload Agent: %s on %s \n " , cur_agent - > agent , agent_data ) ;
2005-07-06 01:29:15 +00:00
parse = agent_data ;
agent_chan = strsep ( & parse , " ; " ) ;
agent_callerid = strsep ( & parse , " ; " ) ;
ast_copy_string ( cur_agent - > loginchan , agent_chan , sizeof ( cur_agent - > loginchan ) ) ;
2005-07-06 14:47:25 +00:00
if ( agent_callerid ) {
2005-07-06 01:29:15 +00:00
ast_copy_string ( cur_agent - > logincallerid , agent_callerid , sizeof ( cur_agent - > logincallerid ) ) ;
2005-09-14 00:39:05 +00:00
set_agentbycallerid ( cur_agent - > logincallerid , cur_agent - > agent ) ;
2005-07-06 14:47:25 +00:00
} else
2005-07-06 01:29:15 +00:00
cur_agent - > logincallerid [ 0 ] = ' \0 ' ;
2005-01-01 00:57:04 +00:00
if ( cur_agent - > loginstart = = 0 )
time ( & cur_agent - > loginstart ) ;
ast_device_state_changed ( " Agent/%s " , cur_agent - > agent ) ;
}
}
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2005-03-03 20:31:21 +00:00
if ( db_tree ) {
2006-01-13 06:11:41 +00:00
ast_log ( LOG_NOTICE , " Agents successfully reloaded from database. \n " ) ;
2005-03-03 20:31:21 +00:00
ast_db_freetree ( db_tree ) ;
2005-01-01 00:57:04 +00:00
}
}
2006-01-20 00:18:42 +00:00
/*! \brief Part of PBX channel interface ---*/
2004-11-12 03:50:19 +00:00
static int agent_devicestate ( void * data )
{
struct agent_pvt * p ;
char * s ;
2005-01-15 21:51:38 +00:00
ast_group_t groupmatch ;
2005-01-17 04:47:01 +00:00
int groupoff ;
2004-11-12 03:50:19 +00:00
int waitforagent = 0 ;
int res = AST_DEVICE_INVALID ;
s = data ;
2005-01-17 04:47:01 +00:00
if ( ( s [ 0 ] = = ' @ ' ) & & ( sscanf ( s + 1 , " %d " , & groupoff ) = = 1 ) ) {
groupmatch = ( 1 < < groupoff ) ;
} else if ( ( s [ 0 ] = = ' : ' ) & & ( sscanf ( s + 1 , " %d " , & groupoff ) = = 1 ) ) {
groupmatch = ( 1 < < groupoff ) ;
2004-11-12 03:50:19 +00:00
waitforagent = 1 ;
} else {
groupmatch = 0 ;
}
/* Check actual logged in agents first */
2006-01-25 18:12:55 +00:00
AST_LIST_LOCK ( & agents ) ;
AST_LIST_TRAVERSE ( & agents , p , list ) {
2004-11-12 03:50:19 +00:00
ast_mutex_lock ( & p - > lock ) ;
if ( ! p - > pending & & ( ( groupmatch & & ( p - > group & groupmatch ) ) | | ! strcmp ( data , p - > agent ) ) ) {
if ( p - > owner ) {
if ( res ! = AST_DEVICE_INUSE )
res = AST_DEVICE_BUSY ;
} else {
if ( res = = AST_DEVICE_BUSY )
res = AST_DEVICE_INUSE ;
if ( p - > chan | | ! ast_strlen_zero ( p - > loginchan ) ) {
if ( res = = AST_DEVICE_INVALID )
res = AST_DEVICE_UNKNOWN ;
} else if ( res = = AST_DEVICE_INVALID )
res = AST_DEVICE_UNAVAILABLE ;
}
if ( ! strcmp ( data , p - > agent ) ) {
ast_mutex_unlock ( & p - > lock ) ;
break ;
}
}
ast_mutex_unlock ( & p - > lock ) ;
}
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
2004-11-12 03:50:19 +00:00
return res ;
}
2005-12-20 19:56:52 +00:00
struct agent_pvt * find_agent ( char * agentid )
{
2006-01-25 18:12:55 +00:00
struct agent_pvt * cur ;
2005-12-20 19:56:52 +00:00
2006-01-25 18:12:55 +00:00
AST_LIST_TRAVERSE ( & agents , cur , list ) {
2005-12-20 19:56:52 +00:00
if ( ! strcmp ( cur - > agent , agentid ) )
break ;
}
return cur ;
}
2006-02-12 04:28:58 +00:00
static int function_agent ( struct ast_channel * chan , char * cmd , char * data , char * buf , size_t len )
2005-12-20 19:56:52 +00:00
{
2006-01-25 19:06:37 +00:00
char * parse ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( agentid ) ;
AST_APP_ARG ( item ) ;
) ;
2005-12-20 19:56:52 +00:00
char * tmp ;
struct agent_pvt * agent ;
buf [ 0 ] = ' \0 ' ;
if ( ast_strlen_zero ( data ) ) {
ast_log ( LOG_WARNING , " The AGENT function requires an argument - agentid! \n " ) ;
2006-02-12 04:28:58 +00:00
return - 1 ;
2005-12-20 19:56:52 +00:00
}
2006-01-25 19:06:37 +00:00
if ( ! ( parse = ast_strdupa ( data ) ) )
2006-02-12 04:28:58 +00:00
return - 1 ;
2005-12-20 19:56:52 +00:00
2006-01-25 19:06:37 +00:00
AST_NONSTANDARD_APP_ARGS ( args , parse , ' : ' ) ;
if ( ! args . item )
args . item = " status " ;
2005-12-20 19:56:52 +00:00
2006-01-25 19:06:37 +00:00
if ( ! ( agent = find_agent ( args . agentid ) ) ) {
ast_log ( LOG_WARNING , " Agent '%s' not found! \n " , args . agentid ) ;
2006-02-12 04:28:58 +00:00
return - 1 ;
2005-12-20 19:56:52 +00:00
}
2006-01-25 19:06:37 +00:00
if ( ! strcasecmp ( args . item , " status " ) ) {
2005-12-20 19:56:52 +00:00
if ( agent - > chan | | ! ast_strlen_zero ( agent - > loginchan ) ) {
ast_copy_string ( buf , " LOGGEDIN " , len ) ;
} else {
ast_copy_string ( buf , " LOGGEDOUT " , len ) ;
}
2006-01-25 19:06:37 +00:00
} else if ( ! strcasecmp ( args . item , " password " ) ) {
2005-12-20 19:56:52 +00:00
ast_copy_string ( buf , agent - > password , len ) ;
2006-01-25 19:06:37 +00:00
} else if ( ! strcasecmp ( args . item , " name " ) ) {
2005-12-20 19:56:52 +00:00
ast_copy_string ( buf , agent - > name , len ) ;
2006-01-25 19:06:37 +00:00
} else if ( ! strcasecmp ( args . item , " mohclass " ) ) {
2005-12-20 19:56:52 +00:00
ast_copy_string ( buf , agent - > moh , len ) ;
2006-01-25 19:06:37 +00:00
} else if ( ! strcasecmp ( args . item , " channel " ) ) {
2005-12-20 19:56:52 +00:00
if ( agent - > chan ) {
ast_copy_string ( buf , agent - > chan - > name , len ) ;
tmp = strrchr ( buf , ' - ' ) ;
if ( tmp )
* tmp = ' \0 ' ;
}
2006-01-25 19:06:37 +00:00
} else if ( ! strcasecmp ( args . item , " exten " ) ) {
2005-12-20 19:56:52 +00:00
ast_copy_string ( buf , agent - > loginchan , len ) ;
}
2006-02-12 04:28:58 +00:00
return 0 ;
2005-12-20 19:56:52 +00:00
}
struct ast_custom_function agent_function = {
. name = " AGENT " ,
. synopsis = " Gets information about an Agent " ,
. syntax = " AGENT(<agentid>[:item]) " ,
. read = function_agent ,
. desc = " The valid items to retrieve are: \n "
" - status (default) The status of the agent \n "
" LOGGEDIN | LOGGEDOUT \n "
" - password The password of the agent \n "
" - name The name of the agent \n "
" - mohclass MusicOnHold class \n "
" - exten The callback extension for the Agent (AgentCallbackLogin) \n "
" - channel The name of the active channel for the Agent (AgentLogin) \n "
} ;
2005-09-07 20:44:57 +00:00
/**
* Initialize the Agents module .
2006-01-13 06:11:41 +00:00
* This function is being called by Asterisk when loading the module . Among other thing it registers applications , cli commands and reads the cofiguration file .
2005-09-07 20:44:57 +00:00
*
* @ returns int Always 0.
*/
2002-09-02 15:20:28 +00:00
int load_module ( )
{
2004-12-31 00:58:44 +00:00
/* Make sure we can register our agent channel type */
2005-03-04 06:47:24 +00:00
if ( ast_channel_register ( & agent_tech ) ) {
2006-02-01 23:05:28 +00:00
ast_log ( LOG_ERROR , " Unable to register channel class 'Agent' \n " ) ;
2002-09-02 15:20:28 +00:00
return - 1 ;
}
2004-12-31 00:58:44 +00:00
/* Dialplan applications */
2002-09-02 15:20:28 +00:00
ast_register_application ( app , login_exec , synopsis , descrip ) ;
2003-07-14 02:31:56 +00:00
ast_register_application ( app2 , callback_exec , synopsis2 , descrip2 ) ;
2004-02-05 21:13:17 +00:00
ast_register_application ( app3 , agentmonitoroutgoing_exec , synopsis3 , descrip3 ) ;
2005-08-26 20:24:16 +00:00
/* Manager commands */
2005-03-22 19:10:21 +00:00
ast_manager_register2 ( " Agents " , EVENT_FLAG_AGENT , action_agents , " Lists agents and their status " , mandescr_agents ) ;
2005-08-26 20:24:16 +00:00
ast_manager_register2 ( " AgentLogoff " , EVENT_FLAG_AGENT , action_agent_logoff , " Sets an agent as no longer logged in " , mandescr_agent_logoff ) ;
ast_manager_register2 ( " AgentCallbackLogin " , EVENT_FLAG_AGENT , action_agent_callback_login , " Sets an agent as logged in by callback " , mandescr_agent_callback_login ) ;
2005-12-20 19:56:52 +00:00
/* CLI Commands */
2002-09-02 15:20:28 +00:00
ast_cli_register ( & cli_show_agents ) ;
2005-01-30 06:55:10 +00:00
ast_cli_register ( & cli_agent_logoff ) ;
2005-12-20 19:56:52 +00:00
/* Dialplan Functions */
ast_custom_function_register ( & agent_function ) ;
2002-09-02 15:20:28 +00:00
/* Read in the config */
read_agent_config ( ) ;
2005-01-01 00:57:04 +00:00
if ( persistent_agents )
2005-03-05 02:53:27 +00:00
reload_agents ( ) ;
2002-09-02 15:20:28 +00:00
return 0 ;
}
int reload ( )
{
read_agent_config ( ) ;
2005-01-01 00:57:04 +00:00
if ( persistent_agents )
2005-03-05 02:53:27 +00:00
reload_agents ( ) ;
2002-09-02 15:20:28 +00:00
return 0 ;
}
int unload_module ( )
{
struct agent_pvt * p ;
/* First, take us out of the channel loop */
2005-12-20 19:56:52 +00:00
/* Unregister dialplan functions */
ast_custom_function_unregister ( & agent_function ) ;
/* Unregister CLI commands */
2002-09-02 15:20:28 +00:00
ast_cli_unregister ( & cli_show_agents ) ;
2005-01-30 06:55:10 +00:00
ast_cli_unregister ( & cli_agent_logoff ) ;
2004-12-31 00:58:44 +00:00
/* Unregister dialplan applications */
2002-09-02 15:20:28 +00:00
ast_unregister_application ( app ) ;
2003-07-14 02:31:56 +00:00
ast_unregister_application ( app2 ) ;
2004-02-05 21:13:17 +00:00
ast_unregister_application ( app3 ) ;
2004-12-31 00:58:44 +00:00
/* Unregister manager command */
2004-12-01 05:00:29 +00:00
ast_manager_unregister ( " Agents " ) ;
2005-08-26 20:24:16 +00:00
ast_manager_unregister ( " AgentLogoff " ) ;
ast_manager_unregister ( " AgentCallbackLogin " ) ;
2004-12-31 00:58:44 +00:00
/* Unregister channel */
2005-03-04 06:47:24 +00:00
ast_channel_unregister ( & agent_tech ) ;
2006-01-25 18:12:55 +00:00
if ( ! AST_LIST_LOCK ( & agents ) ) {
2002-09-02 15:20:28 +00:00
/* Hangup all interfaces if they have an owner */
2006-01-25 18:12:55 +00:00
AST_LIST_TRAVERSE ( & agents , p , list ) {
2002-09-02 15:20:28 +00:00
if ( p - > owner )
ast_softhangup ( p - > owner , AST_SOFTHANGUP_APPUNLOAD ) ;
}
2006-01-25 18:12:55 +00:00
AST_LIST_UNLOCK ( & agents ) ;
AST_LIST_HEAD_INIT ( & agents ) ;
2002-09-02 15:20:28 +00:00
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
return 0 ;
}
int usecount ( )
{
2005-06-24 02:15:04 +00:00
return usecnt ;
2002-09-02 15:20:28 +00:00
}
char * key ( )
{
return ASTERISK_GPL_KEY ;
}
char * description ( )
{
2005-03-04 06:47:24 +00:00
return ( char * ) desc ;
2002-09-02 15:20:28 +00:00
}