Sat Oct 11 06:49:54 2008

Asterisk developer's documentation


chan_agent.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 
00020 /*! \file
00021  * \brief Implementation of Agents (proxy channel)
00022  *
00023  * This file is the implementation of Agents modules.
00024  * It is a dynamic module that is loaded by Asterisk. 
00025  * \par See also
00026  * \arg \ref Config_agent
00027  *
00028  * \ingroup channel_drivers
00029  */
00030 
00031 #include <stdio.h>
00032 #include <string.h>
00033 #include <errno.h>
00034 #include <unistd.h>
00035 #include <sys/socket.h>
00036 #include <stdlib.h>
00037 #include <fcntl.h>
00038 #include <netdb.h>
00039 #include <netinet/in.h>
00040 #include <arpa/inet.h>
00041 #include <sys/signal.h>
00042 
00043 #include "asterisk.h"
00044 
00045 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 76653 $")
00046 
00047 #include "asterisk/lock.h"
00048 #include "asterisk/channel.h"
00049 #include "asterisk/config.h"
00050 #include "asterisk/logger.h"
00051 #include "asterisk/module.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/options.h"
00054 #include "asterisk/lock.h"
00055 #include "asterisk/sched.h"
00056 #include "asterisk/io.h"
00057 #include "asterisk/rtp.h"
00058 #include "asterisk/acl.h"
00059 #include "asterisk/callerid.h"
00060 #include "asterisk/file.h"
00061 #include "asterisk/cli.h"
00062 #include "asterisk/app.h"
00063 #include "asterisk/musiconhold.h"
00064 #include "asterisk/manager.h"
00065 #include "asterisk/features.h"
00066 #include "asterisk/utils.h"
00067 #include "asterisk/causes.h"
00068 #include "asterisk/astdb.h"
00069 #include "asterisk/devicestate.h"
00070 #include "asterisk/monitor.h"
00071 
00072 static const char desc[] = "Agent Proxy Channel";
00073 static const char channeltype[] = "Agent";
00074 static const char tdesc[] = "Call Agent Proxy Channel";
00075 static const char config[] = "agents.conf";
00076 
00077 static const char app[] = "AgentLogin";
00078 static const char app2[] = "AgentCallbackLogin";
00079 static const char app3[] = "AgentMonitorOutgoing";
00080 
00081 static const char synopsis[] = "Call agent login";
00082 static const char synopsis2[] = "Call agent callback login";
00083 static const char synopsis3[] = "Record agent's outgoing call";
00084 
00085 static const char descrip[] =
00086 "  AgentLogin([AgentNo][|options]):\n"
00087 "Asks the agent to login to the system.  Always returns -1.  While\n"
00088 "logged in, the agent can receive calls and will hear a 'beep'\n"
00089 "when a new call comes in. The agent can dump the call by pressing\n"
00090 "the star key.\n"
00091 "The option string may contain zero or more of the following characters:\n"
00092 "      's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
00093 
00094 static const char descrip2[] =
00095 "  AgentCallbackLogin([AgentNo][|[options][|[exten]@context]]):\n"
00096 "Asks the agent to login to the system with callback.\n"
00097 "The agent's callback extension is called (optionally with the specified\n"
00098 "context).\n"
00099 "The option string may contain zero or more of the following characters:\n"
00100 "      's' -- silent login - do not announce the login ok segment agent logged in/off\n";
00101 
00102 static const char descrip3[] =
00103 "  AgentMonitorOutgoing([options]):\n"
00104 "Tries to figure out the id of the agent who is placing outgoing call based on\n"
00105 "comparison of the callerid of the current interface and the global variable \n"
00106 "placed by the AgentCallbackLogin application. That's why it should be used only\n"
00107 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
00108 "instead of Monitor application. That have to be configured in the agents.conf file.\n"
00109 "\nReturn value:\n"
00110 "Normally the app returns 0 unless the options are passed. Also if the callerid or\n"
00111 "the agentid are not specified it'll look for n+101 priority.\n"
00112 "\nOptions:\n"
00113 "  'd' - make the app return -1 if there is an error condition and there is\n"
00114 "        no extension n+101\n"
00115 "  'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
00116 "  'n' - don't generate the warnings when there is no callerid or the\n"
00117 "        agentid is not known.\n"
00118 "             It's handy if you want to have one context for agent and non-agent calls.\n";
00119 
00120 static const char mandescr_agents[] =
00121 "Description: Will list info about all possible agents.\n"
00122 "Variables: NONE\n";
00123 
00124 static const char mandescr_agent_logoff[] =
00125 "Description: Sets an agent as no longer logged in.\n"
00126 "Variables: (Names marked with * are required)\n"
00127 "  *Agent: Agent ID of the agent to log off\n"
00128 "  Soft: Set to 'true' to not hangup existing calls\n";
00129 
00130 static const char mandescr_agent_callback_login[] =
00131 "Description: Sets an agent as logged in with callback.\n"
00132 "Variables: (Names marked with * are required)\n"
00133 "  *Agent: Agent ID of the agent to login\n"
00134 "  *Exten: Extension to use for callback\n"
00135 "  Context: Context to use for callback\n"
00136 "  AckCall: Set to 'true' to require an acknowledgement by '#' when agent is called back\n"
00137 "  WrapupTime: the minimum amount of time after disconnecting before the caller can receive a new call\n";
00138 
00139 static char moh[80] = "default";
00140 
00141 #define AST_MAX_AGENT   80    /**< Agent ID or Password max length */
00142 #define AST_MAX_BUF  256
00143 #define AST_MAX_FILENAME_LEN  256
00144 
00145 /** Persistent Agents astdb family */
00146 static const char pa_family[] = "/Agents";
00147 /** The maximum length of each persistent member agent database entry */
00148 #define PA_MAX_LEN 2048
00149 /** queues.conf [general] option */
00150 static int persistent_agents = 0;
00151 static void dump_agents(void);
00152 
00153 static ast_group_t group;
00154 static int autologoff;
00155 static int wrapuptime;
00156 static int ackcall;
00157 
00158 static int maxlogintries = 3;
00159 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
00160 
00161 static int usecnt =0;
00162 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
00163 
00164 /* Protect the interface list (of pvt's) */
00165 AST_MUTEX_DEFINE_STATIC(agentlock);
00166 
00167 static int recordagentcalls = 0;
00168 static char recordformat[AST_MAX_BUF] = "";
00169 static char recordformatext[AST_MAX_BUF] = "";
00170 static int createlink = 0;
00171 static char urlprefix[AST_MAX_BUF] = "";
00172 static char savecallsin[AST_MAX_BUF] = "";
00173 static int updatecdr = 0;
00174 static char beep[AST_MAX_BUF] = "beep";
00175 
00176 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
00177 
00178 /**
00179  * Structure representing an agent.
00180  */
00181 struct agent_pvt {
00182    ast_mutex_t lock;              /**< Channel private lock */
00183    int dead;                      /**< Poised for destruction? */
00184    int pending;                   /**< Not a real agent -- just pending a match */
00185    int abouttograb;               /**< About to grab */
00186    int autologoff;                /**< Auto timeout time */
00187    int ackcall;                   /**< ackcall */
00188    time_t loginstart;             /**< When agent first logged in (0 when logged off) */
00189    time_t start;                  /**< When call started */
00190    struct timeval lastdisc;       /**< When last disconnected */
00191    int wrapuptime;                /**< Wrapup time in ms */
00192    ast_group_t group;             /**< Group memberships */
00193    int acknowledged;              /**< Acknowledged */
00194    char moh[80];                  /**< Which music on hold */
00195    char agent[AST_MAX_AGENT];     /**< Agent ID */
00196    char password[AST_MAX_AGENT];  /**< Password for Agent login */
00197    char name[AST_MAX_AGENT];
00198    ast_mutex_t app_lock;          /**< Synchronization between owning applications */
00199    volatile pthread_t owning_app; /**< Owning application thread id */
00200    volatile int app_sleep_cond;   /**< Sleep condition for the login app */
00201    struct ast_channel *owner;     /**< Agent */
00202    char loginchan[80];            /**< channel they logged in from */
00203    char logincallerid[80];        /**< Caller ID they had when they logged in */
00204    struct ast_channel *chan;      /**< Channel we use */
00205    struct agent_pvt *next;        /**< Next Agent in the linked list. */
00206 };
00207 
00208 static struct agent_pvt *agents = NULL;  /**< Holds the list of agents (loaded form agents.conf). */
00209 
00210 #define CHECK_FORMATS(ast, p) do { \
00211    if (p->chan) {\
00212       if (ast->nativeformats != p->chan->nativeformats) { \
00213          ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
00214          /* Native formats changed, reset things */ \
00215          ast->nativeformats = p->chan->nativeformats; \
00216          ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
00217          ast_set_read_format(ast, ast->readformat); \
00218          ast_set_write_format(ast, ast->writeformat); \
00219       } \
00220       if (p->chan->readformat != ast->rawreadformat && !p->chan->generator)  \
00221          ast_set_read_format(p->chan, ast->rawreadformat); \
00222       if (p->chan->writeformat != ast->rawwriteformat && !p->chan->generator) \
00223          ast_set_write_format(p->chan, ast->rawwriteformat); \
00224    } \
00225 } while(0)
00226 
00227 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
00228    properly for a timingfd XXX This might need more work if agents were logged in as agents or other
00229    totally impractical combinations XXX */
00230 
00231 #define CLEANUP(ast, p) do { \
00232    int x; \
00233    if (p->chan) { \
00234       for (x=0;x<AST_MAX_FDS;x++) {\
00235          if (x != AST_MAX_FDS - 2) \
00236             ast->fds[x] = p->chan->fds[x]; \
00237       } \
00238       ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
00239    } \
00240 } while(0)
00241 
00242 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
00243 static int agent_devicestate(void *data);
00244 static int agent_digit(struct ast_channel *ast, char digit);
00245 static int agent_call(struct ast_channel *ast, char *dest, int timeout);
00246 static int agent_hangup(struct ast_channel *ast);
00247 static int agent_answer(struct ast_channel *ast);
00248 static struct ast_frame *agent_read(struct ast_channel *ast);
00249 static int agent_write(struct ast_channel *ast, struct ast_frame *f);
00250 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00251 static int agent_sendtext(struct ast_channel *ast, const char *text);
00252 static int agent_indicate(struct ast_channel *ast, int condition);
00253 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00254 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
00255 
00256 static const struct ast_channel_tech agent_tech = {
00257    .type = channeltype,
00258    .description = tdesc,
00259    .capabilities = -1,
00260    .requester = agent_request,
00261    .devicestate = agent_devicestate,
00262    .send_digit = agent_digit,
00263    .call = agent_call,
00264    .hangup = agent_hangup,
00265    .answer = agent_answer,
00266    .read = agent_read,
00267    .write = agent_write,
00268    .send_html = agent_sendhtml,
00269    .send_text = agent_sendtext,
00270    .exception = agent_read,
00271    .indicate = agent_indicate,
00272    .fixup = agent_fixup,
00273    .bridged_channel = agent_bridgedchannel,
00274 };
00275 
00276 /**
00277  * Unlink (that is, take outside of the linked list) an agent.
00278  *
00279  * @param agent Agent to be unlinked.
00280  */
00281 static void agent_unlink(struct agent_pvt *agent)
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 }
00303 
00304 /**
00305  * Adds an agent to the global list of agents.
00306  *
00307  * @param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
00308  * @param pending If it is pending or not.
00309  * @return The just created agent.
00310  * @sa agent_pvt, agents.
00311  */
00312 static struct agent_pvt *add_agent(char *agent, int pending)
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 }
00397 
00398 /**
00399  * Deletes an agent after doing some clean up.
00400  * Further documentation: How safe is this function ? What state should the agent be to be cleaned.
00401  * @param p Agent to be deleted.
00402  * @returns Always 0.
00403  */
00404 static int agent_cleanup(struct agent_pvt *p)
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 }
00421 
00422 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
00423 
00424 static int agent_answer(struct ast_channel *ast)
00425 {
00426    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00427    return -1;
00428 }
00429 
00430 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
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 }
00457 
00458 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
00459 {
00460    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00461 }
00462 
00463 static struct ast_frame *agent_read(struct ast_channel *ast)
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 }
00555 
00556 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
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 }
00566 
00567 static int agent_sendtext(struct ast_channel *ast, const char *text)
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 }
00577 
00578 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
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 }
00598 
00599 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
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 }
00612 
00613 static int agent_indicate(struct ast_channel *ast, int condition)
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 }
00625 
00626 static int agent_digit(struct ast_channel *ast, char digit)
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 }
00638 
00639 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
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 }
00715 
00716 /* store/clear the global variable that stores agentid based on the callerid */
00717 static void set_agentbycallerid(const char *callerid, const char *agent)
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 }
00728 
00729 static int agent_hangup(struct ast_channel *ast)
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<