Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:48:26 2009

## Asterisk developer's documentation

# chan_agent.c File Reference

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

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

Include dependency graph for chan_agent.c:

Go to the source code of this file.

## Data Structures

struct | agent_pvt

## Defines

#define | AST_MAX_AGENT 80
#define | AST_MAX_BUF 256
#define | AST_MAX_FILENAME_LEN 256
#define | CHECK_FORMATS(ast, p)
#define | CLEANUP(ast, p)
#define | GETAGENTBYCALLERID "AGENTBYCALLERID"
#define | PA_MAX_LEN 2048

## Functions

static int | __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock)
static int | __login_exec (struct ast_channel *chan, void *data, int callbackmode)
| Log in agent application.
static int | action_agent_callback_login (struct mansession *s, struct message *m)
static int | action_agent_logoff (struct mansession *s, struct message *m)
static int | action_agents (struct mansession *s, struct message *m)
static struct agent_pvt * | add_agent (char *agent, int pending)
static int | agent_ack_sleep (void *data)
static int | agent_answer (struct ast_channel *ast)
static struct ast_channel * | agent_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge)
static int | agent_call (struct ast_channel *ast, char *dest, int timeout)
static int | agent_cleanup (struct agent_pvt *p)
static int | agent_cont_sleep (void *data)
static int | agent_devicestate (void *data)
static int | agent_digit (struct ast_channel *ast, char digit)
static int | agent_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
static int | agent_hangup (struct ast_channel *ast)
static int | agent_indicate (struct ast_channel *ast, int condition)
static int | agent_logoff (char *agent, int soft)
static int | agent_logoff_cmd (int fd, int argc, char **argv)
static struct ast_channel * | agent_new (struct agent_pvt *p, int state)
static struct ast_frame * | agent_read (struct ast_channel *ast)
static struct ast_channel * | agent_request (const char *type, int format, void *data, int *cause)
static int | agent_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen)
static int | agent_sendtext (struct ast_channel *ast, const char *text)
static int | agent_start_monitoring (struct ast_channel *ast, int needlock)
static void | agent_unlink (struct agent_pvt *agent)
static int | agent_write (struct ast_channel *ast, struct ast_frame *f)
static int | agentmonitoroutgoing_exec (struct ast_channel *chan, void *data)
static int | agents_show (int fd, int argc, char **argv)
| AST_MUTEX_DEFINE_STATIC (agentlock)
| AST_MUTEX_DEFINE_STATIC (usecnt_lock)
static int | callback_exec (struct ast_channel *chan, void *data)
static int | check_availability (struct agent_pvt *newlyavailable, int needlock)
static int | check_beep (struct agent_pvt *newlyavailable, int needlock)
static char * | complete_agent_logoff_cmd (char *line, char *word, int pos, int state)
char * | description ()
| Provides a description of the module.
static void | dump_agents (void)
char * | key ()
| Returns the ASTERISK_GPL_KEY.
int | load_module ()
| Initialize the module.
static int | login_exec (struct ast_channel *chan, void *data)
static int | powerof (unsigned int v)
static int | read_agent_config (void)
int | reload ()
| Reload stuff.
static void | reload_agents (void)
static void | set_agentbycallerid (const char *callerid, const char *agent)
int | unload_module ()
| Cleanup all module structures, sockets, etc.
int | usecount ()
| Provides a usecount.

## Variables

static int | ackcall
static char | agent_logoff_usage []
static struct ast_channel_tech | agent_tech
static char | agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye"
static struct agent_pvt * | agents = NULL
static const char | app [] = "AgentLogin"
static const char | app2 [] = "AgentCallbackLogin"
static const char | app3 [] = "AgentMonitorOutgoing"
static int | autologoff
static char | beep [AST_MAX_BUF] = "beep"
static const char | channeltype [] = "Agent"
static struct ast_cli_entry | cli_agent_logoff
static struct ast_cli_entry | cli_show_agents
static const char | config [] = "agents.conf"
static int | createlink = 0
static const char | desc [] = "Agent Proxy Channel"
static const char | descrip []
static const char | descrip2 []
static const char | descrip3 []
static ast_group_t | group
| LOCAL_USER_DECL
static const char | mandescr_agent_callback_login []
static const char | mandescr_agent_logoff []
static const char | mandescr_agents []
static int | maxlogintries = 3
static char | moh [80] = "default"
static const char | pa_family [] = "/Agents"
static int | persistent_agents = 0
static int | recordagentcalls = 0
static char | recordformat [AST_MAX_BUF] = ""
static char | recordformatext [AST_MAX_BUF] = ""
static char | savecallsin [AST_MAX_BUF] = ""
static char | show_agents_usage []
| STANDARD_LOCAL_USER
static const char | synopsis [] = "Call agent login"
static const char | synopsis2 [] = "Call agent callback login"
static const char | synopsis3 [] = "Record agent's outgoing call"
static const char | tdesc [] = "Call Agent Proxy Channel"
static int | updatecdr = 0
static char | urlprefix [AST_MAX_BUF] = ""
static int | usecnt = 0
static int | wrapuptime

## Detailed Description

Implementation of Agents (proxy channel).

This file is the implementation of Agents modules. It is a dynamic module that is loaded by Asterisk.

See also
  - Agent configuration

Definition in file chan_agent.c.

## Define Documentation

#define AST_MAX_AGENT 80

Agent ID or Password max length

Definition at line 141 of file chan_agent.c.

Referenced by __login_exec(), agent_hangup(), agentmonitoroutgoing_exec(), and complete_agent_logoff_cmd().

#define AST_MAX_BUF 256

Definition at line 142 of file chan_agent.c.

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

#define AST_MAX_FILENAME_LEN 256

Definition at line 143 of file chan_agent.c.

Referenced by __login_exec().

#define CHECK_FORMATS | ( | ast,
|  | p |  | ) |

Definition at line 210 of file chan_agent.c.

Referenced by agent_read(), and agent_write().

#define CLEANUP | ( | ast,
|  | p |  | ) |

Definition at line 231 of file chan_agent.c.

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

#define GETAGENTBYCALLERID "AGENTBYCALLERID"

Definition at line 176 of file chan_agent.c.

Referenced by agentmonitoroutgoing_exec(), and set_agentbycallerid().

#define PA_MAX_LEN 2048

The maximum length of each persistent member agent database entry

Definition at line 148 of file chan_agent.c.

## Function Documentation

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

Definition at line 430 of file chan_agent.c.

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

Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().

    00431 {
    00432    char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
    00433    char filename[AST_MAX_BUF];
    00434    int res = -1;
    00435    if (!p)
    00436       return -1;
    00437    if (!ast->monitor) {
    00438       snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
    00439       /* substitute . for - */
    00440       if ((pointer = strchr(filename, '.')))
    00441          *pointer = '-';
    00442       snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
    00443       ast_monitor_start(ast, recordformat, tmp, needlock);
    00444       ast_monitor_setjoinfiles(ast, 1);
    00445       snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
    00446 #if 0
    00447       ast_verbose("name is %s, link is %s\n",tmp, tmp2);
    00448 #endif
    00449       if (!ast->cdr)
    00450          ast->cdr = ast_cdr_alloc();
    00451       ast_cdr_setuserfield(ast, tmp2);
    00452       res = 0;
    00453    } else
    00454       ast_log(LOG_ERROR, "Recording already started on that call.\n");
    00455    return res;
    00456 }

static int __login_exec | ( | struct ast_channel * | chan,
|  | void * | data,
|  | int | callbackmode |
| ) |  |  | `[static]`

Log in agent application.

Parameters:

  | chan |
  | data |
  | callbackmode | non-zero for AgentCallbackLogin

Definition at line 1698 of file chan_agent.c.

References ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), agent_pvt::app_lock, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), AST_DECLARE_APP_ARGS, ast_device_state_changed(), AST_DIGIT_ANY, ast_exists_extension(), ast_getformatname(), ast_log(), AST_MAX_AGENT, AST_MAX_BUF, AST_MAX_FILENAME_LEN, ast_moh_start(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_verbose(), ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, context, agent_pvt::dead, dump_agents(), EVENT_FLAG_AGENT, ast_channel::exten, free, ast_channel::language, agent_pvt::lastdisc, LOCAL_USER_ADD, LOCAL_USER_REMOVE, agent_pvt::lock, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, ast_channel::musicclass, ast_channel::name, ast_channel::nativeformats, agent_pvt::next, option_debug, option_verbose, agent_pvt::owner, agent_pvt::owning_app, parse(), pass, agent_pvt::password, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), agent_pvt::pending, ast_channel::priority, ast_channel::readformat, set_agentbycallerid(), strsep(), ast_channel::uniqueid, user, VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, agent_pvt::wrapuptime, and ast_channel::writeformat.

Referenced by callback_exec(), and login_exec().

    01699 {
    01700    int res=0;
    01701    int tries = 0;
    01702    int max_login_tries = maxlogintries;
    01703    struct agent_pvt *p;
    01704    struct localuser *u;
    01705    int login_state = 0;
    01706    char user[AST_MAX_AGENT] = "";
    01707    char pass[AST_MAX_AGENT];
    01708    char agent[AST_MAX_AGENT] = "";
    01709    char xpass[AST_MAX_AGENT] = "";
    01710    char *errmsg;
    01711    char *parse;
    01712    AST_DECLARE_APP_ARGS(args,
    01713               AST_APP_ARG(agent_id);
    01714               AST_APP_ARG(options);
    01715               AST_APP_ARG(extension);
    01716       );
    01717    char *tmpoptions = NULL;
    01718    char *context = NULL;
    01719    int play_announcement = 1;
    01720    char agent_goodbye[AST_MAX_FILENAME_LEN];
    01721    int update_cdr = updatecdr;
    01722    char *filename = "agent-loginok";
    01723    char tmpchan[AST_MAX_BUF] = "";
    01724
    01725    LOCAL_USER_ADD(u);
    01726
    01727    if (!(parse = ast_strdupa(data))) {
    01728       ast_log(LOG_ERROR, "Out of memory!\n");
    01729       LOCAL_USER_REMOVE(u);
    01730       return -1;
    01731    }
    01732
    01733    AST_STANDARD_APP_ARGS(args, parse);
    01734
    01735    ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
    01736
    01737    /* Set Channel Specific Login Overrides */
    01738    if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
    01739       max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
    01740       if (max_login_tries < 0)
    01741          max_login_tries = 0;
    01742       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
    01743       if (option_verbose > 2)
    01744          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);
    01745    }
    01746    if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
    01747       if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
    01748          update_cdr = 1;
    01749       else
    01750          update_cdr = 0;
    01751       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
    01752       if (option_verbose > 2)
    01753          ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
    01754    }
    01755    if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
    01756       strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
    01757       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
    01758       if (option_verbose > 2)
    01759          ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
    01760    }
    01761    /* End Channel Specific Login Overrides */
    01762
    01763    if (callbackmode && args.extension) {
    01764       parse = args.extension;
    01765       args.extension = strsep(&parse, "@");
    01766       context = parse;
    01767    }
    01768
    01769    if (!ast_strlen_zero(args.options)) {
    01770       if (strchr(args.options, 's')) {
    01771          play_announcement = 0;
    01772       }
    01773    }
    01774
    01775    if (chan->_state != AST_STATE_UP)
    01776       res = ast_answer(chan);
    01777    if (!res) {
    01778       if (!ast_strlen_zero(args.agent_id))
    01779          ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
    01780       else
    01781          res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
    01782    }
    01783    while (!res && (max_login_tries==0 || tries < max_login_tries)) {
    01784       tries++;
    01785       /* Check for password */
    01786       ast_mutex_lock(&agentlock);
    01787       p = agents;
    01788       while(p) {
    01789          if (!strcmp(p->agent, user) && !p->pending)
    01790             ast_copy_string(xpass, p->password, sizeof(xpass));
    01791          p = p->next;
    01792       }
    01793       ast_mutex_unlock(&agentlock);
    01794       if (!res) {
    01795          if (!ast_strlen_zero(xpass))
    01796             res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
    01797          else
    01798             pass[0] = '\0';
    01799       }
    01800       errmsg = "agent-incorrect";
    01801
    01802 #if 0
    01803       ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
    01804 #endif
    01805
    01806       /* Check again for accuracy */
    01807       ast_mutex_lock(&agentlock);
    01808       p = agents;
    01809       while(p) {
    01810          ast_mutex_lock(&p->lock);
    01811          if (!strcmp(p->agent, user) &&
    01812              !strcmp(p->password, pass) && !p->pending) {
    01813             login_state = 1; /* Successful Login */
    01814
    01815             /* Ensure we can't be gotten until we're done */
    01816             gettimeofday(&p->lastdisc, NULL);
    01817             p->lastdisc.tv_sec++;
    01818
    01819             /* Set Channel Specific Agent Overrides */
    01820             if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
    01821                if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
    01822                   p->ackcall = 2;
    01823                else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
    01824                   p->ackcall = 1;
    01825                else
    01826                   p->ackcall = 0;
    01827                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
    01828                if (option_verbose > 2)
    01829                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
    01830             }
    01831             if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
    01832                p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
    01833                if (p->autologoff < 0)
    01834                   p->autologoff = 0;
    01835                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
    01836                if (option_verbose > 2)
    01837                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
    01838             }
    01839             if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
    01840                p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
    01841                if (p->wrapuptime < 0)
    01842                   p->wrapuptime = 0;
    01843                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
    01844                if (option_verbose > 2)
    01845                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
    01846             }
    01847             /* End Channel Specific Agent Overrides */
    01848             if (!p->chan) {
    01849                char last_loginchan[80] = "";
    01850                long logintime;
    01851                snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
    01852
    01853                if (callbackmode) {
    01854                   int pos = 0;
    01855                   /* Retrieve login chan */
    01856                   for (;;) {
    01857                      if (!ast_strlen_zero(args.extension)) {
    01858                         ast_copy_string(tmpchan, args.extension, sizeof(tmpchan));
    01859                         res = 0;
    01860                      } else
    01861                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
    01862                      if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, !ast_strlen_zero(context) ? context : "default", tmpchan,
    01863                                             1, NULL))
    01864                         break;
    01865                      if (args.extension) {
    01866                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent);
    01867                         args.extension = NULL;
    01868                         pos = 0;
    01869                      } else {
    01870                         ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, !ast_strlen_zero(context) ? context : "default", p->agent);
    01871                         res = ast_streamfile(chan, "invalid", chan->language);
    01872                         if (!res)
    01873                            res = ast_waitstream(chan, AST_DIGIT_ANY);
    01874                         if (res > 0) {
    01875                            tmpchan[0] = res;
    01876                            tmpchan[1] = '\0';
    01877                            pos = 1;
    01878                         } else {
    01879                            tmpchan[0] = '\0';
    01880                            pos = 0;
    01881                         }
    01882                      }
    01883                   }
    01884                   args.extension = tmpchan;
    01885                   if (!res) {
    01886                      set_agentbycallerid(p->logincallerid, NULL);
    01887                      if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
    01888                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
    01889                      else {
    01890                         ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
    01891                         ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
    01892                      }
    01893                      p->acknowledged = 0;
    01894                      if (ast_strlen_zero(p->loginchan)) {
    01895                         login_state = 2;
    01896                         filename = "agent-loggedoff";
    01897                      } else {
    01898                         if (chan->cid.cid_num) {
    01899                            ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
    01900                            set_agentbycallerid(p->logincallerid, p->agent);
    01901                         } else
    01902                            p->logincallerid[0] = '\0';
    01903                      }
    01904
    01905                      if(update_cdr && chan->cdr)
    01906                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
    01907
    01908                   }
    01909                } else {
    01910                   p->loginchan[0] = '\0';
    01911                   p->logincallerid[0] = '\0';
    01912                   p->acknowledged = 0;
    01913                }
    01914                ast_mutex_unlock(&p->lock);
    01915                ast_mutex_unlock(&agentlock);
    01916                if( !res && play_announcement==1 )
    01917                   res = ast_streamfile(chan, filename, chan->language);
    01918                if (!res)
    01919                   ast_waitstream(chan, "");
    01920                ast_mutex_lock(&agentlock);
    01921                ast_mutex_lock(&p->lock);
    01922                if (!res) {
    01923                   res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
    01924                   if (res)
    01925                      ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
    01926                }
    01927                if (!res) {
    01928                   res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
    01929                   if (res)
    01930                      ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
    01931                }
    01932                /* Check once more just in case */
    01933                if (p->chan)
    01934                   res = -1;
    01935                if (callbackmode && !res) {
    01936                   /* Just say goodbye and be done with it */
    01937                   if (!ast_strlen_zero(p->loginchan)) {
    01938                      if (p->loginstart == 0)
    01939                         time(&p->loginstart);
    01940                      manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
    01941                               "Agent: %s\r\n"
    01942                               "Loginchan: %s\r\n"
    01943                               "Uniqueid: %s\r\n",
    01944                               p->agent, p->loginchan, chan->uniqueid);
    01945                      ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
    01946                      if (option_verbose > 1)
    01947                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
    01948                      ast_device_state_changed("Agent/%s", p->agent);
    01949                   } else {
    01950                      logintime = time(NULL) - p->loginstart;
    01951                      p->loginstart = 0;
    01952                      manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
    01953                               "Agent: %s\r\n"
    01954                               "Loginchan: %s\r\n"
    01955                               "Logintime: %ld\r\n"
    01956                               "Uniqueid: %s\r\n",
    01957                               p->agent, last_loginchan, logintime, chan->uniqueid);
    01958                      ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
    01959                      if (option_verbose > 1)
    01960                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
    01961                      ast_device_state_changed("Agent/%s", p->agent);
    01962                   }
    01963                   ast_mutex_unlock(&agentlock);
    01964                   if (!res)
    01965                      res = ast_safe_sleep(chan, 500);
    01966                   ast_mutex_unlock(&p->lock);
    01967                   if (persistent_agents)
    01968                      dump_agents();
    01969                } else if (!res) {
    01970 #ifdef HONOR_MUSIC_CLASS
    01971                   /* check if the moh class was changed with setmusiconhold */
    01972                   if (*(chan->musicclass))
    01973                      ast_copy_string(p->moh, chan->musicclass, sizeof(p->moh));
    01974 #endif
    01975                   ast_moh_start(chan, p->moh);
    01976                   if (p->loginstart == 0)
    01977                      time(&p->loginstart);
    01978                   manager_event(EVENT_FLAG_AGENT, "Agentlogin",
    01979                            "Agent: %s\r\n"
    01980                            "Channel: %s\r\n"
    01981                            "Uniqueid: %s\r\n",
    01982                            p->agent, chan->name, chan->uniqueid);
    01983                   if (update_cdr && chan->cdr)
    01984                      snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
    01985                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
    01986                   if (option_verbose > 1)
    01987                      ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
    01988                             ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
    01989                   /* Login this channel and wait for it to
    01990                      go away */
    01991                   p->chan = chan;
    01992                   if (p->ackcall > 1)
    01993                      check_beep(p, 0);
    01994                   else
    01995                      check_availability(p, 0);
    01996                   ast_mutex_unlock(&p->lock);
    01997                   ast_mutex_unlock(&agentlock);
    01998                   ast_device_state_changed("Agent/%s", p->agent);
    01999                   while (res >= 0) {
    02000                      ast_mutex_lock(&p->lock);
    02001                      if (!p->loginstart && p->chan)
    02002                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
    02003                      if (p->chan != chan)
    02004                         res = -1;
    02005                      ast_mutex_unlock(&p->lock);
    02006                      /* Yield here so other interested threads can kick in. */
    02007                      sched_yield();
    02008                      if (res)
    02009                         break;
    02010
    02011                      ast_mutex_lock(&agentlock);
    02012                      ast_mutex_lock(&p->lock);
    02013                      if (p->lastdisc.tv_sec) {
    02014                         if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
    02015                            if (option_debug)
    02016                               ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
    02017                            p->lastdisc = ast_tv(0, 0);
    02018                            if (p->ackcall > 1)
    02019                               check_beep(p, 0);
    02020                            else
    02021                               check_availability(p, 0);
    02022                         }
    02023                      }
    02024                      ast_mutex_unlock(&p->lock);
    02025                      ast_mutex_unlock(&agentlock);
    02026                      /* Synchronize channel ownership between call to agent and itself. */
    02027                      ast_mutex_lock( &p->app_lock );
    02028                      ast_mutex_lock(&p->lock);
    02029                      p->owning_app = pthread_self();
    02030                      ast_mutex_unlock(&p->lock);
    02031                      if (p->ackcall > 1)
    02032                         res = agent_ack_sleep(p);
    02033                      else
    02034                         res = ast_safe_sleep_conditional( chan, 1000,
    02035                                       agent_cont_sleep, p );
    02036                      ast_mutex_unlock( &p->app_lock );
    02037                      if ((p->ackcall > 1)  && (res == 1)) {
    02038                         ast_mutex_lock(&agentlock);
    02039                         ast_mutex_lock(&p->lock);
    02040                         check_availability(p, 0);
    02041                         ast_mutex_unlock(&p->lock);
    02042                         ast_mutex_unlock(&agentlock);
    02043                         res = 0;
    02044                      }
    02045                      sched_yield();
    02046                   }
    02047                   ast_mutex_lock(&p->lock);
    02048                   if (res && p->owner)
    02049                      ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
    02050                   /* Log us off if appropriate */
    02051                   if (p->chan == chan)
    02052                      p->chan = NULL;
    02053                   p->acknowledged = 0;
    02054                   logintime = time(NULL) - p->loginstart;
    02055                   p->loginstart = 0;
    02056                   ast_mutex_unlock(&p->lock);
    02057                   manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
    02058                            "Agent: %s\r\n"
    02059                            "Logintime: %ld\r\n"
    02060                            "Uniqueid: %s\r\n",
    02061                            p->agent, logintime, chan->uniqueid);
    02062                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
    02063                   if (option_verbose > 1)
    02064                      ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
    02065                   /* If there is no owner, go ahead and kill it now */
    02066                   ast_device_state_changed("Agent/%s", p->agent);
    02067                   if (p->dead && !p->owner) {
    02068                      ast_mutex_destroy(&p->lock);
    02069                      ast_mutex_destroy(&p->app_lock);
    02070                      free(p);
    02071                   }
    02072                }
    02073                else {
    02074                   ast_mutex_unlock(&p->lock);
    02075                   p = NULL;
    02076                }
    02077                res = -1;
    02078             } else {
    02079                ast_mutex_unlock(&p->lock);
    02080                errmsg = "agent-alreadyon";
    02081                p = NULL;
    02082             }
    02083             break;
    02084          }
    02085          ast_mutex_unlock(&p->lock);
    02086          p = p->next;
    02087       }
    02088       if (!p)
    02089          ast_mutex_unlock(&agentlock);
    02090
    02091       if (!res && (max_login_tries==0 || tries < max_login_tries))
    02092          res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
    02093    }
    02094
    02095    if (!res)
    02096       res = ast_safe_sleep(chan, 500);
    02097
    02098    /* AgentLogin() exit */
    02099    if (!callbackmode) {
    02100       LOCAL_USER_REMOVE(u);
    02101       return -1;
    02102    }
    02103    /* AgentCallbackLogin() exit*/
    02104    else {
    02105       /* Set variables */
    02106       if (login_state > 0) {
    02107          pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
    02108          if (login_state==1) {
    02109             pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
    02110             pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension);
    02111          }
    02112          else {
    02113             pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
    02114          }
    02115       }
    02116       else {
    02117          pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
    02118       }
    02119       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
    02120          LOCAL_USER_REMOVE(u);
    02121          return 0;
    02122       }
    02123       /* Do we need to play agent-goodbye now that we will be hanging up? */
    02124       if (play_announcement) {
    02125          if (!res)
    02126             res = ast_safe_sleep(chan, 1000);
    02127          res = ast_streamfile(chan, agent_goodbye, chan->language);
    02128          if (!res)
    02129             res = ast_waitstream(chan, "");
    02130          if (!res)
    02131             res = ast_safe_sleep(chan, 1000);
    02132       }
    02133    }
    02134
    02135    LOCAL_USER_REMOVE(u);
    02136
    02137    /* We should never get here if next priority exists when in callbackmode */
    02138    return -1;
    02139 }

static int action_agent_callback_login | ( | struct mansession * | s,
|  | struct message * | m |
| ) |  |  | `[static]`

Sets an agent as logged in by callback in the Manager API. It is registered on load_module() and it gets called by the manager backend.

Parameters:

  | s |
  | m |

Returns:

See also:
  action_agents(), action_agent_logoff(), load_module().

Definition at line 2175 of file chan_agent.c.

References agent_pvt::ackcall, agent_pvt::agent, ast_device_state_changed(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_strlen_zero(), ast_true(), ast_verbose(), astman_get_header(), astman_send_ack(), astman_send_error(), agent_pvt::chan, context, dump_agents(), EVENT_FLAG_AGENT, exten, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::next, option_verbose, agent_pvt::pending, VERBOSE_PREFIX_2, and agent_pvt::wrapuptime.

Referenced by load_module().

    02176 {
    02177    char *agent = astman_get_header(m, "Agent");
    02178    char *exten = astman_get_header(m, "Exten");
    02179    char *context = astman_get_header(m, "Context");
    02180    char *wrapuptime_s = astman_get_header(m, "WrapupTime");
    02181    char *ackcall_s = astman_get_header(m, "AckCall");
    02182    struct agent_pvt *p;
    02183    int login_state = 0;
    02184
    02185    if (ast_strlen_zero(agent)) {
    02186       astman_send_error(s, m, "No agent specified");
    02187       return 0;
    02188    }
    02189
    02190    if (ast_strlen_zero(exten)) {
    02191       astman_send_error(s, m, "No extension specified");
    02192       return 0;
    02193    }
    02194
    02195    ast_mutex_lock(&agentlock);
    02196    p = agents;
    02197    while(p) {
    02198       if (strcmp(p->agent, agent) || p->pending) {
    02199          p = p->next;
    02200          continue;
    02201       }
    02202       if (p->chan) {
    02203          login_state = 2; /* already logged in (and on the phone)*/
    02204          break;
    02205       }
    02206       ast_mutex_lock(&p->lock);
    02207       login_state = 1; /* Successful Login */
    02208
    02209       if (ast_strlen_zero(context))
    02210          ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
    02211       else
    02212          snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
    02213
    02214       if (!ast_strlen_zero(wrapuptime_s)) {
    02215          p->wrapuptime = atoi(wrapuptime_s);
    02216          if (p->wrapuptime < 0)
    02217             p->wrapuptime = 0;
    02218       }
    02219
    02220       if (ast_true(ackcall_s))
    02221          p->ackcall = 1;
    02222       else
    02223          p->ackcall = 0;
    02224
    02225       if (p->loginstart == 0)
    02226          time(&p->loginstart);
    02227       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
    02228                "Agent: %s\r\n"
    02229                "Loginchan: %s\r\n",
    02230                p->agent, p->loginchan);
    02231       ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
    02232       if (option_verbose > 1)
    02233          ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
    02234       ast_device_state_changed("Agent/%s", p->agent);
    02235       ast_mutex_unlock(&p->lock);
    02236       p = p->next;
    02237       if (persistent_agents)
    02238          dump_agents();
    02239    }
    02240    ast_mutex_unlock(&agentlock);
    02241
    02242    if (login_state == 1)
    02243       astman_send_ack(s, m, "Agent logged in");
    02244    else if (login_state == 0)
    02245       astman_send_error(s, m, "No such agent");
    02246    else if (login_state == 2)
    02247       astman_send_error(s, m, "Agent already logged in");
    02248
    02249    return 0;
    02250 }

static int action_agent_logoff | ( | struct mansession * | s,
|  | struct message * | m |
| ) |  |  | `[static]`

Sets an agent as no longer logged in in the Manager API. It is registered on load_module() and it gets called by the manager backend.

Parameters:

  | s |
  | m |

Returns:

See also:
  action_agents(), action_agent_callback_login(), load_module().

Definition at line 1553 of file chan_agent.c.

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

Referenced by load_module().

    01554 {
    01555    char *agent = astman_get_header(m, "Agent");
    01556    char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
    01557    int soft;
    01558    int ret; /* return value of agent_logoff */
    01559
    01560    if (ast_strlen_zero(agent)) {
    01561       astman_send_error(s, m, "No agent specified");
    01562       return 0;
    01563    }
    01564
    01565    if (ast_true(soft_s))
    01566       soft = 1;
    01567    else
    01568       soft = 0;
    01569
    01570    ret = agent_logoff(agent, soft);
    01571    if (ret == 0)
    01572       astman_send_ack(s, m, "Agent logged out");
    01573    else
    01574       astman_send_error(s, m, "No such agent");
    01575
    01576    return 0;
    01577 }

static int action_agents | ( | struct mansession * | s,
|  | struct message * | m |
| ) |  |  | `[static]`

Lists agents and their status to the Manager API. It is registered on load_module() and it gets called by the manager backend.

Parameters:

  | s |
  | m |

Returns:

See also:
  action_agent_logoff(), action_agent_callback_login(), load_module().

Definition at line 1408 of file chan_agent.c.

References ast_channel::_bridge, agent_pvt::acknowledged, agent_pvt::agent, ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), astman_get_header(), astman_send_ack(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_num, mansession::fd, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, ast_channel::name, agent_pvt::name, agent_pvt::next, agent_pvt::owner, and username.

Referenced by load_module().

    01409 {
    01410    char *id = astman_get_header(m,"ActionID");
    01411    char idText[256] = "";
    01412    char chanbuf[256];
    01413    struct agent_pvt *p;
    01414    char *username = NULL;
    01415    char *loginChan = NULL;
    01416    char *talkingtoChan = NULL;
    01417    char *status = NULL;
    01418
    01419    if (!ast_strlen_zero(id))
    01420       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
    01421    astman_send_ack(s, m, "Agents will follow");
    01422    ast_mutex_lock(&agentlock);
    01423    p = agents;
    01424    while(p) {
    01425          ast_mutex_lock(&p->lock);
    01426
    01427       /* Status Values:
    01428          AGENT_LOGGEDOFF - Agent isn't logged in
    01429          AGENT_IDLE      - Agent is logged in, and waiting for call
    01430          AGENT_ONCALL    - Agent is logged in, and on a call
    01431          AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
    01432
    01433       if(!ast_strlen_zero(p->name)) {
    01434          username = p->name;
    01435       } else {
    01436          username = "None";
    01437       }
    01438
    01439       /* Set a default status. It 'should' get changed. */
    01440       status = "AGENT_UNKNOWN";
    01441
    01442       if (!ast_strlen_zero(p->loginchan) && !p->chan) {
    01443          loginChan = p->loginchan;
    01444          talkingtoChan = "n/a";
    01445          status = "AGENT_IDLE";
    01446          if (p->acknowledged) {
    01447             snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
    01448             loginChan = chanbuf;
    01449          }
    01450       } else if (p->chan) {
    01451          loginChan = ast_strdupa(p->chan->name);
    01452          if (p->owner && p->owner->_bridge) {
    01453                talkingtoChan = p->chan->cid.cid_num;
    01454                status = "AGENT_ONCALL";
    01455          } else {
    01456                talkingtoChan = "n/a";
    01457                status = "AGENT_IDLE";
    01458          }
    01459       } else {
    01460          loginChan = "n/a";
    01461          talkingtoChan = "n/a";
    01462          status = "AGENT_LOGGEDOFF";
    01463       }
    01464
    01465       ast_cli(s->fd, "Event: Agents\r\n"
    01466          "Agent: %s\r\n"
    01467          "Name: %s\r\n"
    01468          "Status: %s\r\n"
    01469          "LoggedInChan: %s\r\n"
    01470          "LoggedInTime: %d\r\n"
    01471          "TalkingTo: %s\r\n"
    01472          "%s"
    01473          "\r\n",
    01474          p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText);
    01475       ast_mutex_unlock(&p->lock);
    01476       p = p->next;
    01477    }
    01478    ast_mutex_unlock(&agentlock);
    01479    ast_cli(s->fd, "Event: AgentsComplete\r\n"
    01480       "%s"
    01481       "\r\n",idText);
    01482    return 0;
    01483 }

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

Adds an agent to the global list of agents.

Parameters:

  | agent | A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
  | pending | If it is pending or not.

Returns:
  The just created agent.

See also:
  agent_pvt, agents.

Definition at line 312 of file chan_agent.c.

References agent_pvt::ackcall, agent_pvt::agent, agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_app_separate_args(), ast_log(), ast_mutex_init(), ast_strdupa, agent_pvt::autologoff, agent_pvt::dead, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_WARNING, malloc, agent_pvt::moh, agent_pvt::name, name, agent_pvt::next, agent_pvt::owning_app, agent_pvt::password, password, agent_pvt::pending, and agent_pvt::wrapuptime.

Referenced by agent_request(), and read_agent_config().

    00313 {
    00314    int argc;
    00315    char *argv[3];
    00316    char *args;
    00317    char *password = NULL;
    00318    char *name = NULL;
    00319    char *agt = NULL;
    00320    struct agent_pvt *p, *prev;
    00321
    00322    args = ast_strdupa(agent);
    00323
    00324    // Extract username (agt), password and name from agent (args).
    00325    if ((argc = ast_app_separate_args(args, ',', argv, sizeof(argv) / sizeof(argv[0])))) {
    00326       agt = argv[0];
    00327       if (argc > 1) {
    00328          password = argv[1];
    00329          while (*password && *password < 33) password++;
    00330       }
    00331       if (argc > 2) {
    00332          name = argv[2];
    00333          while (*name && *name < 33) name++;
    00334       }
    00335    } else {
    00336       ast_log(LOG_WARNING, "A blank agent line!\n");
    00337    }
    00338
    00339    // Are we searching for the agent here ? to see if it exists already ?
    00340    prev=NULL;
    00341    p = agents;
    00342    while(p) {
    00343       if (!pending && !strcmp(p->agent, agt))
    00344          break;
    00345       prev = p;
    00346       p = p->next;
    00347    }
    00348    if (!p) {
    00349       // Build the agent.
    00350       p = malloc(sizeof(struct agent_pvt));
    00351       if (p) {
    00352          memset(p, 0, sizeof(struct agent_pvt));
    00353          ast_copy_string(p->agent, agt, sizeof(p->agent));
    00354          ast_mutex_init(&p->lock);
    00355          ast_mutex_init(&p->app_lock);
    00356          p->owning_app = (pthread_t) -1;
    00357          p->app_sleep_cond = 1;
    00358          p->group = group;
    00359          p->pending = pending;
    00360          p->next = NULL;
    00361          if (prev)
    00362             prev->next = p;
    00363          else
    00364             agents = p;
    00365
    00366       } else {
    00367          return NULL;
    00368       }
    00369    }
    00370
    00371    ast_copy_string(p->password, password ? password : "", sizeof(p->password));
    00372    ast_copy_string(p->name, name ? name : "", sizeof(p->name));
    00373    ast_copy_string(p->moh, moh, sizeof(p->moh));
    00374    p->ackcall = ackcall;
    00375    p->autologoff = autologoff;
    00376
    00377    /* If someone reduces the wrapuptime and reloads, we want it
    00378     * to change the wrapuptime immediately on all calls */
    00379    if (p->wrapuptime > wrapuptime) {
    00380       struct timeval now = ast_tvnow();
    00381       /* XXX check what is this exactly */
    00382
    00383       /* We won't be pedantic and check the tv_usec val */
    00384       if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
    00385          p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
    00386          p->lastdisc.tv_usec = now.tv_usec;
    00387       }
    00388    }
    00389    p->wrapuptime = wrapuptime;
    00390
    00391    if (pending)
    00392       p->dead = 1;
    00393    else
    00394       p->dead = 0;
    00395    return p;
    00396 }

static int agent_ack_sleep | ( | void * | data | ) | `[static]`

Definition at line 870 of file chan_agent.c.

References agent_pvt::app_sleep_cond, AST_FRAME_DTMF, ast_frfree(), ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_waitfor(), agent_pvt::chan, ast_frame::frametype, agent_pvt::lock, and ast_frame::subclass.

Referenced by __login_exec().

    00871 {
    00872    struct agent_pvt *p;
    00873    int res=0;
    00874    int to = 1000;
    00875    struct ast_frame *f;
    00876
    00877    /* Wait a second and look for something */
    00878
    00879    p = (struct agent_pvt *)data;
    00880    if (p->chan) {
    00881       for(;;) {
    00882          to = ast_waitfor(p->chan, to);
    00883          if (to < 0) {
    00884             res = -1;
    00885             break;
    00886          }
    00887          if (!to) {
    00888             res = 0;
    00889             break;
    00890          }
    00891          f = ast_read(p->chan);
    00892          if (!f) {
    00893             res = -1;
    00894             break;
    00895          }
    00896          if (f->frametype == AST_FRAME_DTMF)
    00897             res = f->subclass;
    00898          else
    00899             res = 0;
    00900          ast_frfree(f);
    00901          ast_mutex_lock(&p->lock);
    00902          if (!p->app_sleep_cond) {
    00903             ast_mutex_unlock(&p->lock);
    00904             res = 0;
    00905             break;
    00906          } else if (res == '#') {
    00907             ast_mutex_unlock(&p->lock);
    00908             res = 1;
    00909             break;
    00910          }
    00911          ast_mutex_unlock(&p->lock);
    00912          res = 0;
    00913       }
    00914    } else
    00915       res = -1;
    00916    return res;
    00917 }

static int agent_answer | ( | struct ast_channel * | ast | ) | `[static]`

Definition at line 424 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

    00425 {
    00426    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
    00427    return -1;
    00428 }

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

Definition at line 919 of file chan_agent.c.

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

    00920 {
    00921    struct agent_pvt *p = bridge->tech_pvt;
    00922    struct ast_channel *ret=NULL;
    00923
    00924    if (p) {
    00925       if (chan == p->chan)
    00926          ret = bridge->_bridge;
    00927       else if (chan == bridge->_bridge)
    00928          ret = p->chan;
    00929    }
    00930
    00931    if (option_debug)
    00932       ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
    00933    return ret;
    00934 }

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

Definition at line 639 of file chan_agent.c.

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

    00640 {
    00641    struct agent_pvt *p = ast->tech_pvt;
    00642    int res = -1;
    00643    int newstate=0;
    00644    ast_mutex_lock(&p->lock);
    00645    p->acknowledged = 0;
    00646    if (!p->chan) {
    00647       if (p->pending) {
    00648          ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
    00649          newstate = AST_STATE_DIALING;
    00650          res = 0;
    00651       } else {
    00652          ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
    00653          res = -1;
    00654       }
    00655       ast_mutex_unlock(&p->lock);
    00656       if (newstate)
    00657          ast_setstate(ast, newstate);
    00658       return res;
    00659    } else if (!ast_strlen_zero(p->loginchan)) {
    00660       time(&p->start);
    00661       /* Call on this agent */
    00662       if (option_verbose > 2)
    00663          ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
    00664       ast_set_callerid(p->chan,
    00665          ast->cid.cid_num, ast->cid.cid_name, NULL);
    00666       ast_channel_inherit_variables(ast, p->chan);
    00667       res = ast_call(p->chan, p->loginchan, 0);
    00668       CLEANUP(ast,p);
    00669       ast_mutex_unlock(&p->lock);
    00670       return res;
    00671    }
    00672    ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
    00673    ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
    00674    res = ast_streamfile(p->chan, beep, p->chan->language);
    00675    ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
    00676    if (!res) {
    00677       res = ast_waitstream(p->chan, "");
    00678       ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
    00679    }
    00680    if (!res) {
    00681       res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
    00682       ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
    00683       if (res)
    00684          ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
    00685    } else {
    00686       /* Agent hung-up */
    00687       p->chan = NULL;
    00688    }
    00689
    00690    if (!res) {
    00691       ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
    00692       ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
    00693       if (res)
    00694          ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
    00695    }
    00696    if( !res )
    00697    {
    00698       /* Call is immediately up, or might need ack */
    00699       if (p->ackcall > 1)
    00700          newstate = AST_STATE_RINGING;
    00701       else {
    00702          newstate = AST_STATE_UP;
    00703          if (recordagentcalls)
    00704             agent_start_monitoring(ast,0);
    00705          p->acknowledged = 1;
    00706       }
    00707       res = 0;
    00708    }
    00709    CLEANUP(ast,p);
    00710    ast_mutex_unlock(&p->lock);
    00711    if (newstate)
    00712       ast_setstate(ast, newstate);
    00713    return res;
    00714 }

static int agent_cleanup | ( | struct agent_pvt * | p | ) | `[static]`

Deletes an agent after doing some clean up. Further documentation: How safe is this function ? What state should the agent be to be cleaned.

Parameters:

  | p | Agent to be deleted.

Returns:
  Always 0.

Definition at line 404 of file chan_agent.c.

References agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_channel_free(), ast_mutex_destroy(), ast_mutex_unlock(), agent_pvt::dead, free, agent_pvt::lock, agent_pvt::owner, and ast_channel::tech_pvt.

Referenced by check_availability().

    00405 {
    00406    struct ast_channel *chan = p->owner;
    00407    p->owner = NULL;
    00408    chan->tech_pvt = NULL;
    00409    p->app_sleep_cond = 1;
    00410    /* Release ownership of the agent to other threads (presumably running the login app). */
    00411    ast_mutex_unlock(&p->app_lock);
    00412    if (chan)
    00413       ast_channel_free(chan);
    00414    if (p->dead) {
    00415       ast_mutex_destroy(&p->lock);
    00416       ast_mutex_destroy(&p->app_lock);
    00417       free(p);
    00418         }
    00419    return 0;
    00420 }

static int agent_cont_sleep | ( | void * | data | ) | `[static]`

Definition at line 849 of file chan_agent.c.

References agent_pvt::app_sleep_cond, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::lastdisc, agent_pvt::lock, and LOG_DEBUG.

Referenced by __login_exec().

    00850 {
    00851    struct agent_pvt *p;
    00852    int res;
    00853
    00854    p = (struct agent_pvt *)data;
    00855
    00856    ast_mutex_lock(&p->lock);
    00857    res = p->app_sleep_cond;
    00858    if (p->lastdisc.tv_sec) {
    00859       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0)
    00860          res = 1;
    00861    }
    00862    ast_mutex_unlock(&p->lock);
    00863 #if 0
    00864    if( !res )
    00865       ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
    00866 #endif
    00867    return res;
    00868 }

static int agent_devicestate | ( | void * | data | ) | `[static]`

Definition at line 2398 of file chan_agent.c.

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

    02399 {
    02400    struct agent_pvt *p;
    02401    char *s;
    02402    ast_group_t groupmatch;
    02403    int groupoff;
    02404    int waitforagent=0;
    02405    int res = AST_DEVICE_INVALID;
    02406
    02407    s = data;
    02408    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
    02409       groupmatch = (1 << groupoff);
    02410    } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
    02411       groupmatch = (1 << groupoff);
    02412       waitforagent = 1;
    02413    } else {
    02414       groupmatch = 0;
    02415    }
    02416
    02417    /* Check actual logged in agents first */
    02418    ast_mutex_lock(&agentlock);
    02419    p = agents;
    02420    while(p) {
    02421       ast_mutex_lock(&p->lock);
    02422       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
    02423          if (p->owner) {
    02424             if (res != AST_DEVICE_INUSE)
    02425                res = AST_DEVICE_BUSY;
    02426          } else {
    02427             if (res == AST_DEVICE_BUSY)
    02428                res = AST_DEVICE_INUSE;
    02429             if (p->chan || !ast_strlen_zero(p->loginchan)) {
    02430                if (res == AST_DEVICE_INVALID)
    02431                   res = AST_DEVICE_UNKNOWN;
    02432             } else if (res == AST_DEVICE_INVALID)
    02433                res = AST_DEVICE_UNAVAILABLE;
    02434          }
    02435          if (!strcmp(data, p->agent)) {
    02436             ast_mutex_unlock(&p->lock);
    02437             break;
    02438          }
    02439       }
    02440       ast_mutex_unlock(&p->lock);
    02441       p = p->next;
    02442    }
    02443    ast_mutex_unlock(&agentlock);
    02444    return res;
    02445 }

static int agent_digit | ( | struct ast_channel * | ast,
|  | char | digit |
| ) |  |  | `[static]`

Definition at line 626 of file chan_agent.c.

References ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::lock, ast_channel_tech::send_digit, ast_channel::tech, and ast_channel::tech_pvt.

    00627 {
    00628    struct agent_pvt *p = ast->tech_pvt;
    00629    int res = -1;
    00630    ast_mutex_lock(&p->lock);
    00631    if (p->chan)
    00632       res = p->chan->tech->send_digit(p->chan, digit);
    00633    else
    00634       res = 0;
    00635    ast_mutex_unlock(&p->lock);
    00636    return res;
    00637 }

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

Definition at line 599 of file chan_agent.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::lock, LOG_WARNING, agent_pvt::owner, and ast_channel::tech_pvt.

    00600 {
    00601    struct agent_pvt *p = newchan->tech_pvt;
    00602    ast_mutex_lock(&p->lock);
    00603    if (p->owner != oldchan) {
    00604       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
    00605       ast_mutex_unlock(&p->lock);
    00606       return -1;
    00607    }
    00608    p->owner = newchan;
    00609    ast_mutex_unlock(&p->lock);
    00610    return 0;
    00611 }

static int agent_hangup | ( | struct ast_channel * | ast | ) | `[static]`

Definition at line 729 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::abouttograb, agent_pvt::acknowledged, agent_pvt::agent, agent_unlink(), agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_device_state_changed(), ast_hangup(), ast_log(), AST_MAX_AGENT, ast_moh_start(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_state2str(), AST_STATE_RESERVED, AST_STATE_UP, ast_strlen_zero(), ast_tvadd(), agent_pvt::autologoff, agent_pvt::chan, agent_pvt::dead, dump_agents(), EVENT_FLAG_AGENT, free, agent_pvt::lastdisc, ast_channel::lock, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, set_agentbycallerid(), agent_pvt::start, ast_channel::tech_pvt, ast_channel::uniqueid, usecnt_lock, and agent_pvt::wrapuptime.

    00730 {
    00731    struct agent_pvt *p = ast->tech_pvt;
    00732    int howlong = 0;
    00733    ast_mutex_lock(&p->lock);
    00734    p->owner = NULL;
    00735    ast->tech_pvt = NULL;
    00736    p->app_sleep_cond = 1;
    00737    p->acknowledged = 0;
    00738
    00739    /* if they really are hung up then set start to 0 so the test
    00740     * later if we're called on an already downed channel
    00741     * doesn't cause an agent to be logged out like when
    00742     * agent_request() is followed immediately by agent_hangup()
    00743     * as in apps/app_chanisavail.c:chanavail_exec()
    00744     */
    00745
    00746    ast_mutex_lock(&usecnt_lock);
    00747    usecnt--;
    00748    ast_mutex_unlock(&usecnt_lock);
    00749
    00750    ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
    00751    if (p->start && (ast->_state != AST_STATE_UP)) {
    00752       howlong = time(NULL) - p->start;
    00753       p->start = 0;
    00754    } else if (ast->_state == AST_STATE_RESERVED) {
    00755       howlong = 0;
    00756    } else
    00757       p->start = 0;
    00758    if (p->chan) {
    00759       p->chan->_bridge = NULL;
    00760       /* If they're dead, go ahead and hang up on the agent now */
    00761       if (!ast_strlen_zero(p->loginchan)) {
    00762          /* Store last disconnect time */
    00763          if (p->wrapuptime)
    00764             p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
    00765          else
    00766             p->lastdisc = ast_tv(0,0);
    00767          if (p->chan) {
    00768             /* Recognize the hangup and pass it along immediately */
    00769             ast_hangup(p->chan);
    00770             p->chan = NULL;
    00771          }
    00772          ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
    00773          if (howlong  && p->autologoff && (howlong > p->autologoff)) {
    00774             char agent[AST_MAX_AGENT] = "";
    00775             long logintime = time(NULL) - p->loginstart;
    00776             p->loginstart = 0;
    00777             ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
    00778             manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
    00779                      "Agent: %s\r\n"
    00780                      "Loginchan: %s\r\n"
    00781                      "Logintime: %ld\r\n"
    00782                      "Reason: Autologoff\r\n"
    00783                      "Uniqueid: %s\r\n",
    00784                      p->agent, p->loginchan, logintime, ast->uniqueid);
    00785             snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
    00786             ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
    00787             set_agentbycallerid(p->logincallerid, NULL);
    00788             ast_device_state_changed("Agent/%s", p->agent);
    00789             p->loginchan[0] = '\0';
    00790             p->logincallerid[0] = '\0';
    00791             if (persistent_agents)
    00792                dump_agents();
    00793          } else if (!p->loginstart) {
    00794             p->loginchan[0] = '\0';
    00795             p->logincallerid[0] = '\0';
    00796             if (persistent_agents)
    00797                dump_agents();
    00798          }
    00799       } else if (p->dead) {
    00800          ast_mutex_lock(&p->chan->lock);
    00801          ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
    00802          ast_mutex_unlock(&p->chan->lock);
    00803       } else if (p->loginstart) {
    00804          ast_mutex_lock(&p->chan->lock);
    00805          ast_moh_start(p->chan, p->moh);
    00806          ast_mutex_unlock(&p->chan->lock);
    00807       }
    00808    }
    00809    ast_mutex_unlock(&p->lock);
    00810
    00811    /* Only register a device state change if the agent is still logged in */
    00812    if (!p->loginstart) {
    00813       p->loginchan[0] = '\0';
    00814       p->logincallerid[0] = '\0';
    00815       if (persistent_agents)
    00816          dump_agents();
    00817    } else {
    00818       ast_device_state_changed("Agent/%s", p->agent);
    00819    }
    00820
    00821    if (p->pending) {
    00822       ast_mutex_lock(&agentlock);
    00823       agent_unlink(p);
    00824       ast_mutex_unlock(&agentlock);
    00825    }
    00826    if (p->abouttograb) {
    00827       /* Let the "about to grab" thread know this isn't valid anymore, and let it
    00828          kill it later */
    00829       p->abouttograb = 0;
    00830    } else if (p->dead) {
    00831       ast_mutex_destroy(&p->lock);
    00832       ast_mutex_destroy(&p->app_lock);
    00833       free(p);
    00834    } else {
    00835       if (p->chan) {
    00836          /* Not dead -- check availability now */
    00837          ast_mutex_lock(&p->lock);
    00838          /* Store last disconnect time */
    00839          p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
    00840          ast_mutex_unlock(&p->lock);
    00841       }
    00842       /* Release ownership of the agent to other threads (presumably running the login app). */
    00843       if (ast_strlen_zero(p->loginchan))
    00844          ast_mutex_unlock(&p->app_lock);
    00845    }
    00846    return 0;
    00847 }

static int agent_indicate | ( | struct ast_channel * | ast,
|  | int | condition |
| ) |  |  | `[static]`

Definition at line 613 of file chan_agent.c.

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

    00614 {
    00615    struct agent_pvt *p = ast->tech_pvt;
    00616    int res = -1;
    00617    ast_mutex_lock(&p->lock);
    00618    if (p->chan)
    00619       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition) : -1;
    00620    else
    00621       res = 0;
    00622    ast_mutex_unlock(&p->lock);
    00623    return res;
    00624 }

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

Definition at line 1485 of file chan_agent.c.

References agent_pvt::agent, ast_device_state_changed(), ast_queue_log(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agent_pvt::chan, dump_agents(), EVENT_FLAG_AGENT, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::next, agent_pvt::owner, and set_agentbycallerid().

Referenced by action_agent_logoff(), and agent_logoff_cmd().

    01486 {
    01487    struct agent_pvt *p;
    01488    long logintime;
    01489    int ret = -1; /* Return -1 if no agent if found */
    01490    int defer = 0;
    01491
    01492    for (p=agents; p; p=p->next) {
    01493       if (!strcasecmp(p->agent, agent)) {
    01494          if (p->owner || p->chan)
    01495             defer = 1;
    01496          if (!soft) {
    01497             if (p->owner)
    01498                ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
    01499             if (p->chan)
    01500                ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
    01501          }
    01502          ret = 0; /* found an agent => return 0 */
    01503          logintime = time(NULL) - p->loginstart;
    01504          p->loginstart = 0;
    01505
    01506          manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
    01507                   "Agent: %s\r\n"
    01508                   "Loginchan: %s\r\n"
    01509                   "Logintime: %ld\r\n",
    01510                   p->agent, p->loginchan, logintime);
    01511          ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
    01512          set_agentbycallerid(p->logincallerid, NULL);
    01513          if (!defer) {
    01514             p->loginchan[0] = '\0';
    01515             p->logincallerid[0] = '\0';
    01516          }
    01517          ast_device_state_changed("Agent/%s", p->agent);
    01518          if (persistent_agents)
    01519             dump_agents();
    01520          break;
    01521       }
    01522    }
    01523
    01524    return ret;
    01525 }

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

Definition at line 1527 of file chan_agent.c.

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

    01528 {
    01529    int ret;
    01530    char *agent;
    01531
    01532    if (argc < 3 || argc > 4)
    01533       return RESULT_SHOWUSAGE;
    01534    if (argc == 4 && strcasecmp(argv[3], "soft"))
    01535       return RESULT_SHOWUSAGE;
    01536
    01537    agent = argv[2] + 6;
    01538    ret = agent_logoff(agent, argc == 4);
    01539    if (ret == 0)
    01540       ast_cli(fd, "Logging out %s\n", agent);
    01541
    01542    return RESULT_SUCCESS;
    01543 }

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

Definition at line 937 of file chan_agent.c.

References agent_pvt::agent, agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_channel_alloc(), ast_channel_free(), AST_FLAG_BLOCKING, AST_FORMAT_SLINEAR, AST_FRAME_NULL, ast_log(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_queue_frame(), ast_setstate(), ast_strlen_zero(), ast_test_flag, ast_update_use_count(), agent_pvt::chan, ast_channel::context, CRASH, ast_channel::exten, ast_channel::language, agent_pvt::lock, LOG_ERROR, LOG_WARNING, agent_pvt::loginchan, ast_channel::name, ast_channel::nativeformats, agent_pvt::owner, agent_pvt::owning_app, agent_pvt::pending, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::tech, ast_channel::tech_pvt, ast_channel::type, usecnt_lock, and ast_channel::writeformat.

Referenced by agent_request(), and check_availability().

    00938 {
    00939    struct ast_channel *tmp;
    00940    struct ast_frame null_frame = { AST_FRAME_NULL };
    00941 #if 0
    00942    if (!p->chan) {
    00943       ast_log(LOG_WARNING, "No channel? :(\n");
    00944       return NULL;
    00945    }
    00946 #endif
    00947    tmp = ast_channel_alloc(0);
    00948    if (tmp) {
    00949       tmp->tech = &agent_tech;
    00950       if (p->chan) {
    00951          tmp->nativeformats = p->chan->nativeformats;
    00952          tmp->writeformat = p->chan->writeformat;
    00953          tmp->rawwriteformat = p->chan->writeformat;
    00954          tmp->readformat = p->chan->readformat;
    00955          tmp->rawreadformat = p->chan->readformat;
    00956          ast_copy_string(tmp->language, p->chan->language, sizeof(tmp->language));
    00957          ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
    00958          ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
    00959       } else {
    00960          tmp->nativeformats = AST_FORMAT_SLINEAR;
    00961          tmp->writeformat = AST_FORMAT_SLINEAR;
    00962          tmp->rawwriteformat = AST_FORMAT_SLINEAR;
    00963          tmp->readformat = AST_FORMAT_SLINEAR;
    00964          tmp->rawreadformat = AST_FORMAT_SLINEAR;
    00965       }
    00966       if (p->pending)
    00967          snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
    00968       else
    00969          snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
    00970       tmp->type = channeltype;
    00971       /* Safe, agentlock already held */
    00972       ast_setstate(tmp, state);
    00973       tmp->tech_pvt = p;
    00974       p->owner = tmp;
    00975       ast_mutex_lock(&usecnt_lock);
    00976       usecnt++;
    00977       ast_mutex_unlock(&usecnt_lock);
    00978       ast_update_use_count();
    00979       tmp->priority = 1;
    00980       /* Wake up and wait for other applications (by definition the login app)
    00981        * to release this channel). Takes ownership of the agent channel
    00982        * to this thread only.
    00983        * For signalling the other thread, ast_queue_frame is used until we
    00984        * can safely use signals for this purpose. The pselect() needs to be
    00985        * implemented in the kernel for this.
    00986        */
    00987       p->app_sleep_cond = 0;
    00988       if( ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock) )
    00989       {
    00990          if (p->chan) {
    00991             ast_queue_frame(p->chan, &null_frame);
    00992             ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
    00993             ast_mutex_lock(&p->app_lock);
    00994             ast_mutex_lock(&p->lock);
    00995          }
    00996          if( !p->chan )
    00997          {
    00998             ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
    00999             p->owner = NULL;
    01000             tmp->tech_pvt = NULL;
    01001             p->app_sleep_cond = 1;
    01002             ast_channel_free( tmp );
    01003             ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
    01004             ast_mutex_unlock(&p->app_lock);
    01005             return NULL;
    01006          }
    01007       } else if (!ast_strlen_zero(p->loginchan)) {
    01008          if (p->chan)
    01009             ast_queue_frame(p->chan, &null_frame);
    01010          if (!p->chan) {
    01011             ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
    01012             p->owner = NULL;
    01013             tmp->tech_pvt = NULL;
    01014             p->app_sleep_cond = 1;
    01015             ast_channel_free( tmp );
    01016             ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
    01017                                 return NULL;
    01018          }
    01019       }
    01020       p->owning_app = pthread_self();
    01021       /* After the above step, there should not be any blockers. */
    01022       if (p->chan) {
    01023          if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
    01024             ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
    01025             CRASH;
    01026          }
    01027          ast_moh_stop(p->chan);
    01028       }
    01029    } else
    01030       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
    01031    return tmp;
    01032 }

static struct ast_frame * agent_read | ( | struct ast_channel * | ast | ) | `[static, read]`

Definition at line 463 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_start_monitoring(), AST_CONTROL_ANSWER, ast_copy_flags, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_NULL, AST_FRAME_VOICE, ast_frfree(), ast_hangup(), ast_log(), AST_MAX_FDS, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), AST_STATE_UP, ast_strlen_zero(), ast_tvadd(), ast_verbose(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, ast_channel::fdno, ast_frame::frametype, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, agent_pvt::loginchan, ast_channel::name, option_verbose, ast_frame::subclass, ast_channel::tech_pvt, ast_channel::type, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

    00464 {
    00465    struct agent_pvt *p = ast->tech_pvt;
    00466    struct ast_frame *f = NULL;
    00467    static struct ast_frame null_frame = { AST_FRAME_NULL, };
    00468    static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
    00469    ast_mutex_lock(&p->lock);
    00470    CHECK_FORMATS(ast, p);
    00471    if (p->chan) {
    00472       ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
    00473       if (ast->fdno == AST_MAX_FDS - 3)
    00474          p->chan->fdno = AST_MAX_FDS - 2;
    00475       else
    00476          p->chan->fdno = ast->fdno;
    00477       f = ast_read(p->chan);
    00478    } else
    00479       f = &null_frame;
    00480    if (!f) {
    00481       /* If there's a channel, hang it up (if it's on a callback) make it NULL */
    00482       if (p->chan) {
    00483          p->chan->_bridge = NULL;
    00484          /* Note that we don't hangup if it's not a callback because Asterisk will do it
    00485             for us when the PBX instance that called login finishes */
    00486          if (!ast_strlen_zero(p->loginchan)) {
    00487             if (p->chan)
    00488                ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
    00489             ast_hangup(p->chan);
    00490             if (p->wrapuptime && p->acknowledged)
    00491                p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
    00492          }
    00493          p->chan = NULL;
    00494          p->acknowledged = 0;
    00495       }
    00496    } else {
    00497       /* if acknowledgement is not required, and the channel is up, we may have missed
    00498          an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
    00499       if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP))
    00500          p->acknowledged = 1;
    00501       switch (f->frametype) {
    00502       case AST_FRAME_CONTROL:
    00503          if (f->subclass == AST_CONTROL_ANSWER) {
    00504             if (p->ackcall) {
    00505                if (option_verbose > 2)
    00506                   ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
    00507                /* Don't pass answer along */
    00508                ast_frfree(f);
    00509                f = &null_frame;
    00510             } else {
    00511                p->acknowledged = 1;
    00512                /* Use the builtin answer frame for the
    00513                   recording start check below. */
    00514                ast_frfree(f);
    00515                f = &answer_frame;
    00516             }
    00517          }
    00518          break;
    00519       case AST_FRAME_DTMF:
    00520          if (!p->acknowledged && (f->subclass == '#')) {
    00521             if (option_verbose > 2)
    00522                ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
    00523             p->acknowledged = 1;
    00524             ast_frfree(f);
    00525             f = &answer_frame;
    00526          } else if (f->subclass == '*') {
    00527             /* terminates call */
    00528             ast_frfree(f);
    00529             f = NULL;
    00530          }
    00531          break;
    00532       case AST_FRAME_VOICE:
    00533          /* don't pass voice until the call is acknowledged */
    00534          if (!p->acknowledged) {
    00535             ast_frfree(f);
    00536             f = &null_frame;
    00537          }
    00538          break;
    00539       }
    00540    }
    00541
    00542    CLEANUP(ast,p);
    00543    if (p->chan && !p->chan->_bridge) {
    00544       if (strcasecmp(p->chan->type, "Local")) {
    00545          p->chan->_bridge = ast;
    00546          if (p->chan)
    00547             ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
    00548       }
    00549    }
    00550    ast_mutex_unlock(&p->lock);
    00551    if (recordagentcalls && f == &answer_frame)
    00552       agent_start_monitoring(ast,0);
    00553    return f;
    00554 }

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

Definition at line 1287 of file chan_agent.c.

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

    01288 {
    01289    struct agent_pvt *p;
    01290    struct ast_channel *chan = NULL;
    01291    char *s;
    01292    ast_group_t groupmatch;
    01293    int groupoff;
    01294    int waitforagent=0;
    01295    int hasagent = 0;
    01296    struct timeval tv;
    01297
    01298    s = data;
    01299    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
    01300       groupmatch = (1 << groupoff);
    01301    } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
    01302       groupmatch = (1 << groupoff);
    01303       waitforagent = 1;
    01304    } else {
    01305       groupmatch = 0;
    01306    }
    01307
    01308    /* Check actual logged in agents first */
    01309    ast_mutex_lock(&agentlock);
    01310    p = agents;
    01311    while(p) {
    01312       ast_mutex_lock(&p->lock);
    01313       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
    01314           ast_strlen_zero(p->loginchan)) {
    01315          if (p->chan)
    01316             hasagent++;
    01317          tv = ast_tvnow();
    01318          if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
    01319             p->lastdisc = ast_tv(0, 0);
    01320             /* Agent must be registered, but not have any active call, and not be in a waiting state */
    01321             if (!p->owner && p->chan) {
    01322                /* Fixed agent */
    01323                chan = agent_new(p, AST_STATE_DOWN);
    01324             }
    01325             if (chan) {
    01326                ast_mutex_unlock(&p->lock);
    01327                break;
    01328             }
    01329          }
    01330       }
    01331       ast_mutex_unlock(&p->lock);
    01332       p = p->next;
    01333    }
    01334    if (!p) {
    01335       p = agents;
    01336       while(p) {
    01337          ast_mutex_lock(&p->lock);
    01338          if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
    01339             if (p->chan || !ast_strlen_zero(p->loginchan))
    01340                hasagent++;
    01341             tv = ast_tvnow();
    01342 #if 0
    01343             ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
    01344 #endif
    01345             if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
    01346                p->lastdisc = ast_tv(0, 0);
    01347                /* Agent must be registered, but not have any active call, and not be in a waiting state */
    01348                if (!p->owner && p->chan) {
    01349                   /* Could still get a fixed agent */
    01350                   chan = agent_new(p, AST_STATE_DOWN);
    01351                } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
    01352                   /* Adjustable agent */
    01353                   p->chan = ast_request("Local", format, p->loginchan, cause);
    01354                   if (p->chan)
    01355                      chan = agent_new(p, AST_STATE_DOWN);
    01356                }
    01357                if (chan) {
    01358                   ast_mutex_unlock(&p->lock);
    01359                   break;
    01360                }
    01361             }
    01362          }
    01363          ast_mutex_unlock(&p->lock);
    01364          p = p->next;
    01365       }
    01366    }
    01367
    01368    if (!chan && waitforagent) {
    01369       /* No agent available -- but we're requesting to wait for one.
    01370          Allocate a place holder */
    01371       if (hasagent) {
    01372          if (option_debug)
    01373             ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
    01374          p = add_agent(data, 1);
    01375          p->group = groupmatch;
    01376          chan = agent_new(p, AST_STATE_DOWN);
    01377          if (!chan) {
    01378             ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
    01379          }
    01380       } else
    01381          ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
    01382    }
    01383    if (hasagent)
    01384       *cause = AST_CAUSE_BUSY;
    01385    else
    01386       *cause = AST_CAUSE_UNREGISTERED;
    01387    ast_mutex_unlock(&agentlock);
    01388    return chan;
    01389 }

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

Definition at line 556 of file chan_agent.c.

References ast_channel_sendhtml(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.

    00557 {
    00558    struct agent_pvt *p = ast->tech_pvt;
    00559    int res = -1;
    00560    ast_mutex_lock(&p->lock);
    00561    if (p->chan)
    00562       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
    00563    ast_mutex_unlock(&p->lock);
    00564    return res;
    00565 }

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

Definition at line 567 of file chan_agent.c.

References ast_mutex_lock(), ast_mutex_unlock(), ast_sendtext(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.

    00568 {
    00569    struct agent_pvt *p = ast->tech_pvt;
    00570    int res = -1;
    00571    ast_mutex_lock(&p->lock);
    00572    if (p->chan)
    00573       res = ast_sendtext(p->chan, text);
    00574    ast_mutex_unlock(&p->lock);
    00575    return res;
    00576 }

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

Definition at line 458 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

    00459 {
    00460    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
    00461 }

static void agent_unlink | ( | struct agent_pvt * | agent | ) | `[static]`

Unlink (that is, take outside of the linked list) an agent.

Parameters:

  | agent | Agent to be unlinked.

Definition at line 281 of file chan_agent.c.

References agent_pvt::next.

Referenced by agent_hangup().

    00282 {
    00283    struct agent_pvt *p, *prev;
    00284    prev = NULL;
    00285    p = agents;
    00286    // Iterate over all agents looking for the one.
    00287    while(p) {
    00288       if (p == agent) {
    00289          // Once it wal found, check if it is the first one.
    00290          if (prev)
    00291             // If it is not, tell the previous agent that the next one is the next one of the current (jumping the current).
    00292             prev->next = agent->next;
    00293          else
    00294             // If it is the first one, just change the general pointer to point to the second one.
    00295             agents = agent->next;
    00296          // We are done.
    00297          break;
    00298       }
    00299       prev = p;
    00300       p = p->next;
    00301    }
    00302 }

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

Definition at line 578 of file chan_agent.c.

References AST_FRAME_VOICE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_write(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, ast_frame::frametype, agent_pvt::lock, LOG_DEBUG, ast_channel::name, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.

    00579 {
    00580    struct agent_pvt *p = ast->tech_pvt;
    00581    int res = -1;
    00582    CHECK_FORMATS(ast, p);
    00583    ast_mutex_lock(&p->lock);
    00584    if (p->chan) {
    00585       if ((f->frametype != AST_FRAME_VOICE) ||
    00586           (f->subclass == p->chan->writeformat)) {
    00587          res = ast_write(p->chan, f);
    00588       } else {
    00589          ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
    00590          res = 0;
    00591       }
    00592    } else
    00593       res = 0;
    00594    CLEANUP(ast, p);
    00595    ast_mutex_unlock(&p->lock);
    00596    return res;
    00597 }

static int agentmonitoroutgoing_exec | ( | struct ast_channel * | chan,
|  | void * | data |
| ) |  |  | `[static]`

Called by the AgentMonitorOutgoing application (from the dial plan).

Parameters:

  | chan |
  | data |

Returns:

See also:
  login_exec(), callback_login_exec(), load_module().

Definition at line 2260 of file chan_agent.c.

References __agent_start_monitoring(), agent_pvt::agent, ast_exists_extension(), ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, GETAGENTBYCALLERID, LOG_WARNING, agent_pvt::next, option_verbose, pbx_builtin_getvar_helper(), ast_channel::priority, and VERBOSE_PREFIX_3.

Referenced by load_module().

    02261 {
    02262    int exitifnoagentid = 0;
    02263    int nowarnings = 0;
    02264    int changeoutgoing = 0;
    02265    int res = 0;
    02266    char agent[AST_MAX_AGENT], *tmp;
    02267
    02268    if (data) {
    02269       if (strchr(data, 'd'))
    02270          exitifnoagentid = 1;
    02271       if (strchr(data, 'n'))
    02272          nowarnings = 1;
    02273       if (strchr(data, 'c'))
    02274          changeoutgoing = 1;
    02275    }
    02276    if (chan->cid.cid_num) {
    02277       char agentvar[AST_MAX_BUF];
    02278       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
    02279       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
    02280          struct agent_pvt *p = agents;
    02281          ast_copy_string(agent, tmp, sizeof(agent));
    02282          ast_mutex_lock(&agentlock);
    02283          while (p) {
    02284             if (!strcasecmp(p->agent, tmp)) {
    02285                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
    02286                __agent_start_monitoring(chan, p, 1);
    02287                break;
    02288             }
    02289             p = p->next;
    02290          }
    02291          ast_mutex_unlock(&agentlock);
    02292
    02293       } else {
    02294          res = -1;
    02295          if (!nowarnings)
    02296             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);
    02297       }
    02298    } else {
    02299       res = -1;
    02300       if (!nowarnings)
    02301          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");
    02302    }
    02303    /* check if there is n + 101 priority */
    02304    if (res) {
    02305       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
    02306          chan->priority+=100;
    02307          if (option_verbose > 2)
    02308             ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
    02309       }
    02310       else if (exitifnoagentid)
    02311          return res;
    02312    }
    02313    return 0;
    02314 }

static int agents_show | ( | int | fd,
|  | int | argc,
|  | char ** | argv |
| ) |  |  | `[static]`

Show agents in cli.

Definition at line 1603 of file chan_agent.c.

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

    01604 {
    01605    struct agent_pvt *p;
    01606    char username[AST_MAX_BUF];
    01607    char location[AST_MAX_BUF] = "";
    01608    char talkingto[AST_MAX_BUF] = "";
    01609    char moh[AST_MAX_BUF];
    01610    int count_agents = 0;      /* Number of agents configured */
    01611    int online_agents = 0;     /* Number of online agents */
    01612    int offline_agents = 0;    /* Number of offline agents */
    01613    if (argc != 2)
    01614       return RESULT_SHOWUSAGE;
    01615    ast_mutex_lock(&agentlock);
    01616    p = agents;
    01617    while(p) {
    01618       ast_mutex_lock(&p->lock);
    01619       if (p->pending) {
    01620          if (p->group)
    01621             ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
    01622          else
    01623             ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
    01624       } else {
    01625          if (!ast_strlen_zero(p->name))
    01626             snprintf(username, sizeof(username), "(%s) ", p->name);
    01627          else
    01628             username[0] = '\0';
    01629          if (p->chan) {
    01630             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
    01631             if (p->owner && ast_bridged_channel(p->owner)) {
    01632                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
    01633             } else {
    01634                strcpy(talkingto, " is idle");
    01635             }
    01636             online_agents++;
    01637          } else if (!ast_strlen_zero(p->loginchan)) {
    01638             if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec))
    01639                snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
    01640             else
    01641                snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
    01642             talkingto[0] = '\0';
    01643             online_agents++;
    01644             if (p->acknowledged)
    01645                strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
    01646          } else {
    01647             strcpy(location, "not logged in");
    01648             talkingto[0] = '\0';
    01649             offline_agents++;
    01650          }
    01651          if (!ast_strlen_zero(p->moh))
    01652             snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
    01653          ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
    01654             username, location, talkingto, moh);
    01655          count_agents++;
    01656       }
    01657       ast_mutex_unlock(&p->lock);
    01658       p = p->next;
    01659    }
    01660    ast_mutex_unlock(&agentlock);
    01661    if ( !count_agents ) {
    01662       ast_cli(fd, "No Agents are configured in %s\n",config);
    01663    } else {
    01664       ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
    01665    }
    01666    ast_cli(fd, "\n");
    01667
    01668    return RESULT_SUCCESS;
    01669 }

AST_MUTEX_DEFINE_STATIC | ( | agentlock |  | ) |

AST_MUTEX_DEFINE_STATIC | ( | usecnt_lock |  | ) |

static int callback_exec | ( | struct ast_channel * | chan,
|  | void * | data |
| ) |  |  | `[static]`

Called by the AgentCallbackLogin application (from the dial plan).

Parameters:

  | chan |
  | data |

Returns:

See also:
  login_exec(), agentmonitoroutgoing_exec(), load_module().

Definition at line 2162 of file chan_agent.c.

References __login_exec().

Referenced by load_module().

    02163 {
    02164    return __login_exec(chan, data, 1);
    02165 }

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

Definition at line 1167 of file chan_agent.c.

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

Referenced by __login_exec().

    01168 {
    01169    struct ast_channel *chan=NULL, *parent=NULL;
    01170    struct agent_pvt *p;
    01171    int res;
    01172
    01173    if (option_debug)
    01174       ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
    01175    if (needlock)
    01176       ast_mutex_lock(&agentlock);
    01177    p = agents;
    01178    while(p) {
    01179       if (p == newlyavailable) {
    01180          p = p->next;
    01181          continue;
    01182       }
    01183       ast_mutex_lock(&p->lock);
    01184       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
    01185          if (option_debug)
    01186             ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
    01187          /* We found a pending call, time to merge */
    01188          chan = agent_new(newlyavailable, AST_STATE_DOWN);
    01189          parent = p->owner;
    01190          p->abouttograb = 1;
    01191          ast_mutex_unlock(&p->lock);
    01192          break;
    01193       }
    01194       ast_mutex_unlock(&p->lock);
    01195       p = p->next;
    01196    }
    01197    if (needlock)
    01198       ast_mutex_unlock(&agentlock);
    01199    if (parent && chan)  {
    01200       if (newlyavailable->ackcall > 1) {
    01201          /* Don't do beep here */
    01202          res = 0;
    01203       } else {
    01204          if (option_debug > 2)
    01205             ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
    01206          res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
    01207          if (option_debug > 2)
    01208             ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
    01209          if (!res) {
    01210             res = ast_waitstream(newlyavailable->chan, "");
    01211             ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
    01212          }
    01213       }
    01214       if (!res) {
    01215          /* Note -- parent may have disappeared */
    01216          if (p->abouttograb) {
    01217             newlyavailable->acknowledged = 1;
    01218             /* Safe -- agent lock already held */
    01219             ast_setstate(parent, AST_STATE_UP);
    01220             ast_setstate(chan, AST_STATE_UP);
    01221             ast_copy_string(parent->context, chan->context, sizeof(parent->context));
    01222             /* Go ahead and mark the channel as a zombie so that masquerade will
    01223                destroy it for us, and we need not call ast_hangup */
    01224             ast_mutex_lock(&parent->lock);
    01225             ast_set_flag(chan, AST_FLAG_ZOMBIE);
    01226             ast_channel_masquerade(parent, chan);
    01227             ast_mutex_unlock(&parent->lock);
    01228             p->abouttograb = 0;
    01229          } else {
    01230             if (option_debug)
    01231                ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
    01232             agent_cleanup(newlyavailable);
    01233          }
    01234       } else {
    01235          if (option_debug)
    01236             ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
    01237          agent_cleanup(newlyavailable);
    01238       }
    01239    }
    01240    return 0;
    01241 }

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

Definition at line 1243 of file chan_agent.c.

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

Referenced by __login_exec().

    01244 {
    01245    struct agent_pvt *p;
    01246    int res=0;
    01247
    01248    ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
    01249    if (needlock)
    01250       ast_mutex_lock(&agentlock);
    01251    p = agents;
    01252    while(p) {
    01253       if (p == newlyavailable) {
    01254          p = p->next;
    01255          continue;
    01256       }
    01257       ast_mutex_lock(&p->lock);
    01258       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
    01259          if (option_debug)
    01260             ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
    01261          ast_mutex_unlock(&p->lock);
    01262          break;
    01263       }
    01264       ast_mutex_unlock(&p->lock);
    01265       p = p->next;
    01266    }
    01267    if (needlock)
    01268       ast_mutex_unlock(&agentlock);
    01269    if (p) {
    01270       ast_mutex_unlock(&newlyavailable->lock);
    01271       if (option_debug > 2)
    01272          ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
    01273       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
    01274       if (option_debug > 2)
    01275          ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
    01276       if (!res) {
    01277          res = ast_waitstream(newlyavailable->chan, "");
    01278          if (option_debug)
    01279             ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
    01280       }
    01281       ast_mutex_lock(&newlyavailable->lock);
    01282    }
    01283    return res;
    01284 }

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

Definition at line 1579 of file chan_agent.c.

References agent_pvt::agent, AST_MAX_AGENT, name, agent_pvt::next, and strdup.

    01580 {
    01581    struct agent_pvt *p;
    01582    char name[AST_MAX_AGENT];
    01583    int which = 0;
    01584
    01585    if (pos == 2) {
    01586       for (p=agents; p; p=p->next) {
    01587          snprintf(name, sizeof(name), "Agent/%s", p->agent);
    01588          if (!strncasecmp(word, name, strlen(word))) {
    01589             if (++which > state) {
    01590                return strdup(name);
    01591             }
    01592          }
    01593       }
    01594    } else if (pos == 3 && state == 0) {
    01595       return strdup("soft");
    01596    }
    01597    return NULL;
    01598 }

char* description | ( | void |  | ) |

Provides a description of the module.

Returns:
  a short description of your module

Definition at line 2530 of file chan_agent.c.

    02531 {
    02532    return (char *) desc;
    02533 }

static void dump_agents | ( | void |  | ) | `[static]`

Dump AgentCallbackLogin agents to the database for persistence

Definition at line 2319 of file chan_agent.c.

References agent_pvt::agent, ast_db_del(), ast_db_put(), ast_log(), ast_strlen_zero(), agent_pvt::chan, LOG_DEBUG, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::next, and option_debug.

Referenced by __login_exec(), action_agent_callback_login(), agent_hangup(), and agent_logoff().

    02320 {
    02321    struct agent_pvt *cur_agent = NULL;
    02322    char buf[256];
    02323
    02324    for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
    02325       if (cur_agent->chan)
    02326          continue;
    02327
    02328       if (!ast_strlen_zero(cur_agent->loginchan)) {
    02329          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
    02330          if (ast_db_put(pa_family, cur_agent->agent, buf))
    02331             ast_log(LOG_WARNING, "failed to create persistent entry!\n");
    02332          else if (option_debug)
    02333             ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
    02334       } else {
    02335          /* Delete -  no agent or there is an error */
    02336          ast_db_del(pa_family, cur_agent->agent);
    02337       }
    02338    }
    02339 }

char* key | ( | void |  | ) |

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

     char *key(void) {
             return ASTERISK_GPL_KEY;
     }

Returns:
  ASTERISK_GPL_KEY

Definition at line 2525 of file chan_agent.c.

References ASTERISK_GPL_KEY.

    02526 {
    02527    return ASTERISK_GPL_KEY;
    02528 }

int load_module | ( | void |  | ) |

Initialize the module.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
  int Always 0.

Definition at line 2453 of file chan_agent.c.

References action_agent_callback_login(), action_agent_logoff(), action_agents(), agentmonitoroutgoing_exec(), ast_channel_register(), ast_cli_register(), ast_log(), ast_manager_register2(), ast_register_application(), callback_exec(), EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), read_agent_config(), and reload_agents().

    02454 {
    02455    /* Make sure we can register our agent channel type */
    02456    if (ast_channel_register(&agent_tech)) {
    02457       ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
    02458       return -1;
    02459    }
    02460    /* Dialplan applications */
    02461    ast_register_application(app, login_exec, synopsis, descrip);
    02462    ast_register_application(app2, callback_exec, synopsis2, descrip2);
    02463    ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
    02464    /* Manager commands */
    02465    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
    02466    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
    02467    ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
    02468    /* CLI Application */
    02469    ast_cli_register(&cli_show_agents);
    02470    ast_cli_register(&cli_agent_logoff);
    02471    /* Read in the config */
    02472    read_agent_config();
    02473    if (persistent_agents)
    02474       reload_agents();
    02475    return 0;
    02476 }

static int login_exec | ( | struct ast_channel * | chan,
|  | void * | data |
| ) |  |  | `[static]`

Called by the AgentLogin application (from the dial plan).

Parameters:

  | chan |
  | data |

Returns:

See also:
  callback_login_exec(), agentmonitoroutgoing_exec(), load_module().

Definition at line 2149 of file chan_agent.c.

References __login_exec().

Referenced by load_module().

    02150 {
    02151    return __login_exec(chan, data, 0);
    02152 }

static int powerof | ( | unsigned int | v | ) | `[static]`

Definition at line 1391 of file chan_agent.c.

    01392 {
    01393    int x;
    01394    for (x=0;x<32;x++) {
    01395       if (v & (1 << x)) return x;
    01396    }
    01397    return 0;
    01398 }

static int read_agent_config | ( | void |  | ) | `[static]`

Read configuration data. The file named agents.conf.

Returns:
  Always 0, or so it seems.

Definition at line 1040 of file chan_agent.c.

References add_agent(), agent_pvt::app_lock, ast_config_destroy(), ast_config_load(), ast_get_group(), ast_log(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), cfg, agent_pvt::chan, agent_pvt::dead, free, agent_pvt::lock, LOG_NOTICE, ast_variable::name, ast_variable::next, agent_pvt::next, agent_pvt::owner, and ast_variable::value.

Referenced by load_module(), and reload().

    01041 {
    01042    struct ast_config *cfg;
    01043    struct ast_variable *v;
    01044    struct agent_pvt *p, *pl, *pn;
    01045    char *general_val;
    01046
    01047    group = 0;
    01048    autologoff = 0;
    01049    wrapuptime = 0;
    01050    ackcall = 0;
    01051    cfg = ast_config_load(config);
    01052    if (!cfg) {
    01053       ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
    01054       return 0;
    01055    }
    01056    ast_mutex_lock(&agentlock);
    01057    p = agents;
    01058    while(p) {
    01059       p->dead = 1;
    01060       p = p->next;
    01061    }
    01062    strcpy(moh, "default");
    01063    /* set the default recording values */
    01064    recordagentcalls = 0;
    01065    createlink = 0;
    01066    strcpy(recordformat, "wav");
    01067    strcpy(recordformatext, "wav");
    01068    urlprefix[0] = '\0';
    01069    savecallsin[0] = '\0';
    01070
    01071    /* Read in [general] section for persistence */
    01072    if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
    01073       persistent_agents = ast_true(general_val);
    01074
    01075    /* Read in the [agents] section */
    01076    v = ast_variable_browse(cfg, "agents");
    01077    while(v) {
    01078       /* Create the interface list */
    01079       if (!strcasecmp(v->name, "agent")) {
    01080          add_agent(v->value, 0);
    01081       } else if (!strcasecmp(v->name, "group")) {
    01082          group = ast_get_group(v->value);
    01083       } else if (!strcasecmp(v->name, "autologoff")) {
    01084          autologoff = atoi(v->value);
    01085          if (autologoff < 0)
    01086             autologoff = 0;
    01087       } else if (!strcasecmp(v->name, "ackcall")) {
    01088          if (!strcasecmp(v->value, "always"))
    01089             ackcall = 2;
    01090          else if (ast_true(v->value))
    01091             ackcall = 1;
    01092          else
    01093             ackcall = 0;
    01094       } else if (!strcasecmp(v->name, "wrapuptime")) {
    01095          wrapuptime = atoi(v->value);
    01096          if (wrapuptime < 0)
    01097             wrapuptime = 0;
    01098       } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
    01099          maxlogintries = atoi(v->value);
    01100          if (maxlogintries < 0)
    01101             maxlogintries = 0;
    01102       } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
    01103          strcpy(agentgoodbye,v->value);
    01104       } else if (!strcasecmp(v->name, "musiconhold")) {
    01105          ast_copy_string(moh, v->value, sizeof(moh));
    01106       } else if (!strcasecmp(v->name, "updatecdr")) {
    01107          if (ast_true(v->value))
    01108             updatecdr = 1;
    01109          else
    01110             updatecdr = 0;
    01111       } else if (!strcasecmp(v->name, "recordagentcalls")) {
    01112          recordagentcalls = ast_true(v->value);
    01113       } else if (!strcasecmp(v->name, "createlink")) {
    01114          createlink = ast_true(v->value);
    01115       } else if (!strcasecmp(v->name, "recordformat")) {
    01116          ast_copy_string(recordformat, v->value, sizeof(recordformat));
    01117          if (!strcasecmp(v->value, "wav49"))
    01118             strcpy(recordformatext, "WAV");
    01119          else
    01120             ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
    01121       } else if (!strcasecmp(v->name, "urlprefix")) {
    01122          ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
    01123          if (urlprefix[strlen(urlprefix) - 1] != '/')
    01124             strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
    01125       } else if (!strcasecmp(v->name, "savecallsin")) {
    01126          if (v->value[0] == '/')
    01127             ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
    01128          else
    01129             snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
    01130          if (savecallsin[strlen(savecallsin) - 1] != '/')
    01131             strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
    01132       } else if (!strcasecmp(v->name, "custom_beep")) {
    01133          ast_copy_string(beep, v->value, sizeof(beep));
    01134       }
    01135       v = v->next;
    01136    }
    01137    p = agents;
    01138    pl = NULL;
    01139    while(p) {
    01140       pn = p->next;
    01141       if (p->dead) {
    01142          /* Unlink */
    01143          if (pl)
    01144             pl->next = p->next;
    01145          else
    01146             agents = p->next;
    01147          /* Destroy if  appropriate */
    01148          if (!p->owner) {
    01149             if (!p->chan) {
    01150                ast_mutex_destroy(&p->lock);
    01151                ast_mutex_destroy(&p->app_lock);
    01152                free(p);
    01153             } else {
    01154                /* Cause them to hang up */
    01155                ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
    01156             }
    01157          }
    01158       } else
    01159          pl = p;
    01160       p = pn;
    01161    }
    01162    ast_mutex_unlock(&agentlock);
    01163    ast_config_destroy(cfg);
    01164    return 0;
    01165 }

int reload | ( | void |  | ) |

Reload stuff.

This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.

Returns:
  The return value is not used.

Definition at line 2478 of file chan_agent.c.

References read_agent_config(), and reload_agents().

    02479 {
    02480    read_agent_config();
    02481    if (persistent_agents)
    02482       reload_agents();
    02483    return 0;
    02484 }

static void reload_agents | ( | void |  | ) | `[static]`

Reload the persistent agents from astdb.

Definition at line 2344 of file chan_agent.c.

References agent_pvt::agent, ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), ast_device_state_changed(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_db_entry::key, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::next, ast_db_entry::next, option_debug, parse(), set_agentbycallerid(), and strsep().

Referenced by load_module(), and reload().

    02345 {
    02346    char *agent_num;
    02347    struct ast_db_entry *db_tree;
    02348    struct ast_db_entry *entry;
    02349    struct agent_pvt *cur_agent;
    02350    char agent_data[256];
    02351    char *parse;
    02352    char *agent_chan;
    02353    char *agent_callerid;
    02354
    02355    db_tree = ast_db_gettree(pa_family, NULL);
    02356
    02357    ast_mutex_lock(&agentlock);
    02358    for (entry = db_tree; entry; entry = entry->next) {
    02359       agent_num = entry->key + strlen(pa_family) + 2;
    02360       cur_agent = agents;
    02361       while (cur_agent) {
    02362          ast_mutex_lock(&cur_agent->lock);
    02363          if (strcmp(agent_num, cur_agent->agent) == 0)
    02364             break;
    02365          ast_mutex_unlock(&cur_agent->lock);
    02366          cur_agent = cur_agent->next;
    02367       }
    02368       if (!cur_agent) {
    02369          ast_db_del(pa_family, agent_num);
    02370          continue;
    02371       } else
    02372          ast_mutex_unlock(&cur_agent->lock);
    02373       if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
    02374          if (option_debug)
    02375             ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
    02376          parse = agent_data;
    02377          agent_chan = strsep(&parse, ";");
    02378          agent_callerid = strsep(&parse, ";");
    02379          ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
    02380          if (agent_callerid) {
    02381             ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
    02382             set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
    02383          } else
    02384             cur_agent->logincallerid[0] = '\0';
    02385          if (cur_agent->loginstart == 0)
    02386             time(&cur_agent->loginstart);
    02387          ast_device_state_changed("Agent/%s", cur_agent->agent);
    02388       }
    02389    }
    02390    ast_mutex_unlock(&agentlock);
    02391    if (db_tree) {
    02392       ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
    02393       ast_db_freetree(db_tree);
    02394    }
    02395 }

static void set_agentbycallerid | ( | const char * | callerid,
|  | const char * | agent |
| ) |  |  | `[static]`

Definition at line 717 of file chan_agent.c.

References AST_MAX_BUF, ast_strlen_zero(), GETAGENTBYCALLERID, and pbx_builtin_setvar_helper().

Referenced by __login_exec(), agent_hangup(), agent_logoff(), and reload_agents().

    00718 {
    00719    char buf[AST_MAX_BUF];
    00720
    00721    /* if there is no Caller ID, nothing to do */
    00722    if (ast_strlen_zero(callerid))
    00723       return;
    00724
    00725    snprintf(buf, sizeof(buf), "%s_%s",GETAGENTBYCALLERID, callerid);
    00726    pbx_builtin_setvar_helper(NULL, buf, agent);
    00727 }

int unload_module | ( | void |  | ) |

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
  Zero on success, or non-zero on error.

Definition at line 2486 of file chan_agent.c.

References ast_channel_unregister(), ast_cli_unregister(), ast_log(), ast_manager_unregister(), ast_mutex_lock(), ast_mutex_unlock(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_unregister_application(), LOG_WARNING, agent_pvt::next, and agent_pvt::owner.

    02487 {
    02488    struct agent_pvt *p;
    02489    /* First, take us out of the channel loop */
    02490    /* Unregister CLI application */
    02491    ast_cli_unregister(&cli_show_agents);
    02492    ast_cli_unregister(&cli_agent_logoff);
    02493    /* Unregister dialplan applications */
    02494    ast_unregister_application(app);
    02495    ast_unregister_application(app2);
    02496    ast_unregister_application(app3);
    02497    /* Unregister manager command */
    02498    ast_manager_unregister("Agents");
    02499    ast_manager_unregister("AgentLogoff");
    02500    ast_manager_unregister("AgentCallbackLogin");
    02501    /* Unregister channel */
    02502    ast_channel_unregister(&agent_tech);
    02503    if (!ast_mutex_lock(&agentlock)) {
    02504       /* Hangup all interfaces if they have an owner */
    02505       p = agents;
    02506       while(p) {
    02507          if (p->owner)
    02508             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
    02509          p = p->next;
    02510       }
    02511       agents = NULL;
    02512       ast_mutex_unlock(&agentlock);
    02513    } else {
    02514       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
    02515       return -1;
    02516    }
    02517    return 0;
    02518 }

int usecount | ( | void |  | ) |

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
  The module's usecount.

Definition at line 2520 of file chan_agent.c.

    02521 {
    02522    return usecnt;
    02523 }

## Variable Documentation

int ackcall`[static]`

Definition at line 156 of file chan_agent.c.

char agent_logoff_usage[]`[static]`

Initial value:

    "Usage: agent logoff <channel> [soft]\n"
    "       Sets an agent as no longer logged in.\n"
    "       If 'soft' is specified, do not hangup existing calls.\n"

Definition at line 1675 of file chan_agent.c.

struct ast_channel_tech agent_tech`[static]`

Definition at line 256 of file chan_agent.c.

char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye"`[static]`

Definition at line 159 of file chan_agent.c.

struct agent_pvt* agents = NULL`[static]`

Holds the list of agents (loaded form agents.conf).

Definition at line 208 of file chan_agent.c.

const char app[] = "AgentLogin"`[static]`

Definition at line 77 of file chan_agent.c.

Referenced by __build_step(), action_originate(), exec_exec(), execif_exec(), feature_exec_app(), fillin_process(), handle_context_add_extension(), load_config(), load_module(), page_exec(), pbx_extension_helper(), realtime_exec(), and unload_module().

const char app2[] = "AgentCallbackLogin"`[static]`

Definition at line 78 of file chan_agent.c.

Referenced by macro_exec().

const char app3[] = "AgentMonitorOutgoing"`[static]`

Definition at line 79 of file chan_agent.c.

int autologoff`[static]`

Definition at line 154 of file chan_agent.c.

char beep[AST_MAX_BUF] = "beep"`[static]`

Definition at line 174 of file chan_agent.c.

const char channeltype[] = "Agent"`[static]`

Definition at line 73 of file chan_agent.c.

struct ast_cli_entry cli_agent_logoff`[static]`

Initial value:

     {
       { "agent", "logoff", NULL }, agent_logoff_cmd,
       "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd }

Definition at line 1684 of file chan_agent.c.

struct ast_cli_entry cli_show_agents`[static]`

Initial value:

     {
       { "show", "agents", NULL }, agents_show,
       "Show status of agents", show_agents_usage, NULL }

Definition at line 1680 of file chan_agent.c.

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

Definition at line 75 of file chan_agent.c.

int createlink = 0`[static]`

Definition at line 170 of file chan_agent.c.

const char desc[] = "Agent Proxy Channel"`[static]`

Definition at line 72 of file chan_agent.c.

Referenced by description().

const char descrip[]`[static]`

Definition at line 85 of file chan_agent.c.

Referenced by load_module().

const char descrip2[]`[static]`

Definition at line 94 of file chan_agent.c.

const char descrip3[]`[static]`

Definition at line 102 of file chan_agent.c.

ast_group_t group`[static]`

Definition at line 153 of file chan_agent.c.

Referenced by ast_app_group_set_channel(), ast_get_group(), ast_makesocket(), chanspy_exec(), get_group(), group_count_exec(), group_count_function_read(), group_match_count_exec(), group_match_count_function_read(), load_module(), main(), misdn_check_l2l1(), misdn_request(), modem_request(), and vpb_request().

LOCAL_USER_DECL

Definition at line 1689 of file chan_agent.c.

const char mandescr_agent_callback_login[]`[static]`

Definition at line 130 of file chan_agent.c.

const char mandescr_agent_logoff[]`[static]`

Initial value:

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

Definition at line 124 of file chan_agent.c.

const char mandescr_agents[]`[static]`

Initial value:

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

Definition at line 120 of file chan_agent.c.

int maxlogintries = 3`[static]`

Definition at line 158 of file chan_agent.c.

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

Definition at line 139 of file chan_agent.c.

Referenced by ast_moh_destroy(), dial_exec_full(), get_mohbyname(), init_classes(), moh_generate(), moh_release(), mohalloc(), and monmp3thread().

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

Persistent Agents astdb family

Definition at line 146 of file chan_agent.c.

int persistent_agents = 0`[static]`

queues.conf [general] option

Definition at line 150 of file chan_agent.c.

int recordagentcalls = 0`[static]`

Definition at line 167 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = ""`[static]`

Definition at line 168 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = ""`[static]`

Definition at line 169 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = ""`[static]`

Definition at line 172 of file chan_agent.c.

char show_agents_usage[]`[static]`

Initial value:

    "Usage: show agents\n"
    "       Provides summary information on agents.\n"

Definition at line 1671 of file chan_agent.c.

STANDARD_LOCAL_USER

Definition at line 1688 of file chan_agent.c.

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

Definition at line 81 of file chan_agent.c.

Referenced by function_enum(), handle_show_application(), handle_show_function(), load_module(), and load_pbx().

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

Definition at line 82 of file chan_agent.c.

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

Definition at line 83 of file chan_agent.c.

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

Definition at line 74 of file chan_agent.c.

Referenced by description().

int updatecdr = 0`[static]`

Definition at line 173 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = ""`[static]`

Definition at line 171 of file chan_agent.c.

Referenced by start_monitor_exec().

int usecnt = 0`[static]`

Definition at line 161 of file chan_agent.c.

Referenced by usecount(), and vpb_new().

int wrapuptime`[static]`

Definition at line 155 of file chan_agent.c.