a0fd09a98044eba5d231d4526d592cb92fc41a60
[asterisk/asterisk.git] / channels / chan_agent.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2012, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19
20 /*! \file
21  * 
22  * \brief Implementation of Agents (proxy channel)
23  *
24  * \author Mark Spencer <markster@digium.com>
25  *
26  * This file is the implementation of Agents modules.
27  * It is a dynamic module that is loaded by Asterisk. 
28  * \par See also
29  * \arg \ref Config_agent
30  *
31  * \ingroup channel_drivers
32  */
33 /*** MODULEINFO
34         <depend>chan_local</depend>
35         <depend>res_monitor</depend>
36         <support_level>core</support_level>
37  ***/
38
39 #include "asterisk.h"
40
41 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
42
43 #include <sys/socket.h>
44 #include <fcntl.h>
45 #include <netdb.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <sys/signal.h>
49
50 #include "asterisk/lock.h"
51 #include "asterisk/channel.h"
52 #include "asterisk/config.h"
53 #include "asterisk/module.h"
54 #include "asterisk/pbx.h"
55 #include "asterisk/sched.h"
56 #include "asterisk/io.h"
57 #include "asterisk/acl.h"
58 #include "asterisk/callerid.h"
59 #include "asterisk/file.h"
60 #include "asterisk/cli.h"
61 #include "asterisk/app.h"
62 #include "asterisk/musiconhold.h"
63 #include "asterisk/manager.h"
64 #include "asterisk/features.h"
65 #include "asterisk/utils.h"
66 #include "asterisk/causes.h"
67 #include "asterisk/astdb.h"
68 #include "asterisk/devicestate.h"
69 #include "asterisk/monitor.h"
70 #include "asterisk/stringfields.h"
71 #include "asterisk/event.h"
72 #include "asterisk/data.h"
73
74 /*** DOCUMENTATION
75         <application name="AgentLogin" language="en_US">
76                 <synopsis>
77                         Call agent login.
78                 </synopsis>
79                 <syntax>
80                         <parameter name="AgentNo" />
81                         <parameter name="options">
82                                 <optionlist>
83                                         <option name="s">
84                                                 <para>silent login - do not announce the login ok segment after
85                                                 agent logged on/off</para>
86                                         </option>
87                                 </optionlist>
88                         </parameter>
89                 </syntax>
90                 <description>
91                         <para>Asks the agent to login to the system. Always returns <literal>-1</literal>.
92                         While logged in, the agent can receive calls and will hear a <literal>beep</literal>
93                         when a new call comes in. The agent can dump the call by pressing the star key.</para>
94                 </description>
95                 <see-also>
96                         <ref type="application">Queue</ref>
97                         <ref type="application">AddQueueMember</ref>
98                         <ref type="application">RemoveQueueMember</ref>
99                         <ref type="application">PauseQueueMember</ref>
100                         <ref type="application">UnpauseQueueMember</ref>
101                         <ref type="function">AGENT</ref>
102                         <ref type="filename">agents.conf</ref>
103                         <ref type="filename">queues.conf</ref>
104                 </see-also>
105         </application>
106         <application name="AgentMonitorOutgoing" language="en_US">
107                 <synopsis>
108                         Record agent's outgoing call.
109                 </synopsis>
110                 <syntax>
111                         <parameter name="options">
112                                 <optionlist>
113                                         <option name="d">
114                                                 <para>make the app return <literal>-1</literal> if there is an error condition.</para>
115                                         </option>
116                                         <option name="c">
117                                                 <para>change the CDR so that the source of the call is
118                                                 <literal>Agent/agent_id</literal></para>
119                                         </option>
120                                         <option name="n">
121                                                 <para>don't generate the warnings when there is no callerid or the
122                                                 agentid is not known. It's handy if you want to have one context
123                                                 for agent and non-agent calls.</para>
124                                         </option>
125                                 </optionlist>
126                         </parameter>
127                 </syntax>
128                 <description>
129                         <para>Tries to figure out the id of the agent who is placing outgoing call based on
130                         comparison of the callerid of the current interface and the global variable
131                         placed by the AgentCallbackLogin application. That's why it should be used only
132                         with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent
133                         instead of Monitor application. That has to be configured in the
134                         <filename>agents.conf</filename> file.</para>
135                         <para>Normally the app returns <literal>0</literal> unless the options are passed.</para>
136                 </description>
137                 <see-also>
138                         <ref type="filename">agents.conf</ref>
139                 </see-also>
140         </application>
141         <function name="AGENT" language="en_US">
142                 <synopsis>
143                         Gets information about an Agent
144                 </synopsis>
145                 <syntax argsep=":">
146                         <parameter name="agentid" required="true" />
147                         <parameter name="item">
148                                 <para>The valid items to retrieve are:</para>
149                                 <enumlist>
150                                         <enum name="status">
151                                                 <para>(default) The status of the agent (LOGGEDIN | LOGGEDOUT)</para>
152                                         </enum>
153                                         <enum name="password">
154                                                 <para>The password of the agent</para>
155                                         </enum>
156                                         <enum name="name">
157                                                 <para>The name of the agent</para>
158                                         </enum>
159                                         <enum name="mohclass">
160                                                 <para>MusicOnHold class</para>
161                                         </enum>
162                                         <enum name="channel">
163                                                 <para>The name of the active channel for the Agent (AgentLogin)</para>
164                                         </enum>
165                                         <enum name="fullchannel">
166                                                 <para>The untruncated name of the active channel for the Agent (AgentLogin)</para>
167                                         </enum>
168                                 </enumlist>
169                         </parameter>
170                 </syntax>
171                 <description></description>
172         </function>
173         <manager name="Agents" language="en_US">
174                 <synopsis>
175                         Lists agents and their status.
176                 </synopsis>
177                 <syntax>
178                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
179                 </syntax>
180                 <description>
181                         <para>Will list info about all possible agents.</para>
182                 </description>
183         </manager>
184         <manager name="AgentLogoff" language="en_US">
185                 <synopsis>
186                         Sets an agent as no longer logged in.
187                 </synopsis>
188                 <syntax>
189                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
190                         <parameter name="Agent" required="true">
191                                 <para>Agent ID of the agent to log off.</para>
192                         </parameter>
193                         <parameter name="Soft">
194                                 <para>Set to <literal>true</literal> to not hangup existing calls.</para>
195                         </parameter>
196                 </syntax>
197                 <description>
198                         <para>Sets an agent as no longer logged in.</para>
199                 </description>
200         </manager>
201  ***/
202
203 static const char tdesc[] = "Call Agent Proxy Channel";
204 static const char config[] = "agents.conf";
205
206 static const char app[] = "AgentLogin";
207 static const char app3[] = "AgentMonitorOutgoing";
208
209 static char moh[80] = "default";
210
211 #define AST_MAX_AGENT   80                          /*!< Agent ID or Password max length */
212 #define AST_MAX_BUF     256
213 #define AST_MAX_FILENAME_LEN    256
214
215 static const char pa_family[] = "Agents";          /*!< Persistent Agents astdb family */
216 #define PA_MAX_LEN 2048                             /*!< The maximum length of each persistent member agent database entry */
217
218 #define DEFAULT_ACCEPTDTMF '#'
219 #define DEFAULT_ENDDTMF '*'
220
221 static ast_group_t group;
222 static int autologoff;
223 static int wrapuptime;
224 static int ackcall;
225 static int endcall;
226 static int multiplelogin = 1;
227 static int autologoffunavail = 0;
228 static char acceptdtmf = DEFAULT_ACCEPTDTMF;
229 static char enddtmf = DEFAULT_ENDDTMF;
230
231 static int maxlogintries = 3;
232 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
233
234 static int recordagentcalls = 0;
235 static char recordformat[AST_MAX_BUF] = "";
236 static char recordformatext[AST_MAX_BUF] = "";
237 static char urlprefix[AST_MAX_BUF] = "";
238 static char savecallsin[AST_MAX_BUF] = "";
239 static int updatecdr = 0;
240 static char beep[AST_MAX_BUF] = "beep";
241
242 #define GETAGENTBYCALLERID      "AGENTBYCALLERID"
243
244 enum {
245         AGENT_FLAG_ACKCALL = (1 << 0),
246         AGENT_FLAG_AUTOLOGOFF = (1 << 1),
247         AGENT_FLAG_WRAPUPTIME = (1 << 2),
248         AGENT_FLAG_ACCEPTDTMF = (1 << 3),
249         AGENT_FLAG_ENDDTMF = (1 << 4),
250 };
251
252 /*! \brief Structure representing an agent.  */
253 struct agent_pvt {
254         ast_mutex_t lock;              /*!< Channel private lock */
255         int dead;                      /*!< Poised for destruction? */
256         int pending;                   /*!< Not a real agent -- just pending a match */
257         int abouttograb;               /*!< About to grab */
258         int autologoff;                /*!< Auto timeout time */
259         int ackcall;                   /*!< ackcall */
260         int deferlogoff;               /*!< Defer logoff to hangup */
261         char acceptdtmf;
262         char enddtmf;
263         time_t loginstart;             /*!< When agent first logged in (0 when logged off) */
264         time_t start;                  /*!< When call started */
265         struct timeval lastdisc;       /*!< When last disconnected */
266         int wrapuptime;                /*!< Wrapup time in ms */
267         ast_group_t group;             /*!< Group memberships */
268         int acknowledged;              /*!< Acknowledged */
269         char moh[80];                  /*!< Which music on hold */
270         char agent[AST_MAX_AGENT];     /*!< Agent ID */
271         char password[AST_MAX_AGENT];  /*!< Password for Agent login */
272         char name[AST_MAX_AGENT];
273         int app_lock_flag;
274         ast_cond_t app_complete_cond;
275         ast_cond_t login_wait_cond;
276         volatile int app_sleep_cond;   /**< Sleep condition for the login app */
277         struct ast_channel *owner;     /**< Agent */
278         char logincallerid[80];        /**< Caller ID they had when they logged in */
279         struct ast_channel *chan;      /**< Channel we use */
280         unsigned int flags;            /**< Flags show if settings were applied with channel vars */
281         AST_LIST_ENTRY(agent_pvt) list; /**< Next Agent in the linked list. */
282 };
283
284 #define DATA_EXPORT_AGENT(MEMBER)                               \
285         MEMBER(agent_pvt, autologoff, AST_DATA_INTEGER)         \
286         MEMBER(agent_pvt, ackcall, AST_DATA_BOOLEAN)            \
287         MEMBER(agent_pvt, deferlogoff, AST_DATA_BOOLEAN)        \
288         MEMBER(agent_pvt, wrapuptime, AST_DATA_MILLISECONDS)    \
289         MEMBER(agent_pvt, acknowledged, AST_DATA_BOOLEAN)       \
290         MEMBER(agent_pvt, name, AST_DATA_STRING)                \
291         MEMBER(agent_pvt, password, AST_DATA_PASSWORD)          \
292         MEMBER(agent_pvt, acceptdtmf, AST_DATA_CHARACTER)       \
293         MEMBER(agent_pvt, logincallerid, AST_DATA_STRING)
294
295 AST_DATA_STRUCTURE(agent_pvt, DATA_EXPORT_AGENT);
296
297 static AST_LIST_HEAD_STATIC(agents, agent_pvt); /*!< Holds the list of agents (loaded form agents.conf). */
298
299 #define CHECK_FORMATS(ast, p) do { \
300         if (p->chan) {\
301                 if (!(ast_format_cap_identical(ast->nativeformats, p->chan->nativeformats))) { \
302                         char tmp1[256], tmp2[256]; \
303                         ast_debug(1, "Native formats changing from '%s' to '%s'\n", ast_getformatname_multiple(tmp1, sizeof(tmp1), ast->nativeformats), ast_getformatname_multiple(tmp2, sizeof(tmp2), p->chan->nativeformats)); \
304                         /* Native formats changed, reset things */ \
305                         ast_format_cap_copy(ast->nativeformats, p->chan->nativeformats); \
306                         ast_debug(1, "Resetting read to '%s' and write to '%s'\n", ast_getformatname(&ast->readformat), ast_getformatname(&ast->writeformat));\
307                         ast_set_read_format(ast, &ast->readformat); \
308                         ast_set_write_format(ast, &ast->writeformat); \
309                 } \
310                 if ((ast_format_cmp(&p->chan->readformat, &ast->rawreadformat) != AST_FORMAT_CMP_EQUAL) && !p->chan->generator)  \
311                         ast_set_read_format(p->chan, &ast->rawreadformat); \
312                 if ((ast_format_cmp(&p->chan->writeformat, &ast->rawwriteformat) != AST_FORMAT_CMP_EQUAL) && !p->chan->generator) \
313                         ast_set_write_format(p->chan, &ast->rawwriteformat); \
314         } \
315 } while(0)
316
317 /*! \brief Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
318    properly for a timingfd XXX This might need more work if agents were logged in as agents or other
319    totally impractical combinations XXX */
320
321 #define CLEANUP(ast, p) do { \
322         int x; \
323         if (p->chan) { \
324                 for (x=0;x<AST_MAX_FDS;x++) {\
325                         if (x != AST_TIMING_FD) \
326                                 ast_channel_set_fd(ast, x, p->chan->fds[x]); \
327                 } \
328                 ast_channel_set_fd(ast, AST_AGENT_FD, p->chan->fds[AST_TIMING_FD]); \
329         } \
330 } while(0)
331
332 /*--- Forward declarations */
333 static struct ast_channel *agent_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
334 static int agent_devicestate(const char *data);
335 static int agent_digit_begin(struct ast_channel *ast, char digit);
336 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
337 static int agent_call(struct ast_channel *ast, const char *dest, int timeout);
338 static int agent_hangup(struct ast_channel *ast);
339 static int agent_answer(struct ast_channel *ast);
340 static struct ast_frame *agent_read(struct ast_channel *ast);
341 static int agent_write(struct ast_channel *ast, struct ast_frame *f);
342 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
343 static int agent_sendtext(struct ast_channel *ast, const char *text);
344 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
345 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
346 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
347 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state);
348 static struct ast_channel* agent_get_base_channel(struct ast_channel *chan);
349 static int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base);
350 static int agent_logoff(const char *agent, int soft);
351
352 /*! \brief Channel interface description for PBX integration */
353 static struct ast_channel_tech agent_tech = {
354         .type = "Agent",
355         .description = tdesc,
356         .requester = agent_request,
357         .devicestate = agent_devicestate,
358         .send_digit_begin = agent_digit_begin,
359         .send_digit_end = agent_digit_end,
360         .call = agent_call,
361         .hangup = agent_hangup,
362         .answer = agent_answer,
363         .read = agent_read,
364         .write = agent_write,
365         .write_video = agent_write,
366         .send_html = agent_sendhtml,
367         .send_text = agent_sendtext,
368         .exception = agent_read,
369         .indicate = agent_indicate,
370         .fixup = agent_fixup,
371         .bridged_channel = agent_bridgedchannel,
372         .get_base_channel = agent_get_base_channel,
373         .set_base_channel = agent_set_base_channel,
374 };
375
376 /*!
377  * \brief Locks the owning channel for a LOCKED pvt while obeying locking order. The pvt
378  * must enter this function locked and will be returned locked, but this function will
379  * unlock the pvt for a short time, so it can't be used while expecting the pvt to remain
380  * static. If function returns a non NULL channel, it will need to be unlocked and
381  * unrefed once it is no longer needed.
382  *
383  * \param pvt Pointer to the LOCKED agent_pvt for which the owner is needed
384  * \ret locked channel which owns the pvt at the time of completion. NULL if not available.
385  */
386 static struct ast_channel *agent_lock_owner(struct agent_pvt *pvt)
387 {
388         struct ast_channel *owner;
389
390         for (;;) {
391                 if (!pvt->owner) { /* No owner. Nothing to do. */
392                         return NULL;
393                 }
394
395                 /* If we don't ref the owner, it could be killed when we unlock the pvt. */
396                 owner = ast_channel_ref(pvt->owner);
397
398                 /* Locking order requires us to lock channel, then pvt. */
399                 ast_mutex_unlock(&pvt->lock);
400                 ast_channel_lock(owner);
401                 ast_mutex_lock(&pvt->lock);
402
403                 /* Check if owner changed during pvt unlock period */
404                 if (owner != pvt->owner) { /* Channel changed. Unref and do another pass. */
405                         ast_channel_unlock(owner);
406                         owner = ast_channel_unref(owner);
407                 } else { /* Channel stayed the same. Return it. */
408                         return owner;
409                 }
410         }
411 }
412
413 /*!
414  * Adds an agent to the global list of agents.
415  *
416  * \param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
417  * \param pending If it is pending or not.
418  * @return The just created agent.
419  * \sa agent_pvt, agents.
420  */
421 static struct agent_pvt *add_agent(const char *agent, int pending)
422 {
423         char *parse;
424         AST_DECLARE_APP_ARGS(args,
425                 AST_APP_ARG(agt);
426                 AST_APP_ARG(password);
427                 AST_APP_ARG(name);
428         );
429         char *password = NULL;
430         char *name = NULL;
431         char *agt = NULL;
432         struct agent_pvt *p;
433
434         parse = ast_strdupa(agent);
435
436         /* Extract username (agt), password and name from agent (args). */
437         AST_STANDARD_APP_ARGS(args, parse);
438
439         if(args.argc == 0) {
440                 ast_log(LOG_WARNING, "A blank agent line!\n");
441                 return NULL;
442         }
443
444         if(ast_strlen_zero(args.agt) ) {
445                 ast_log(LOG_WARNING, "An agent line with no agentid!\n");
446                 return NULL;
447         } else
448                 agt = args.agt;
449
450         if(!ast_strlen_zero(args.password)) {
451                 password = args.password;
452                 while (*password && *password < 33) password++;
453         }
454         if(!ast_strlen_zero(args.name)) {
455                 name = args.name;
456                 while (*name && *name < 33) name++;
457         }
458         
459         /* Are we searching for the agent here ? To see if it exists already ? */
460         AST_LIST_TRAVERSE(&agents, p, list) {
461                 if (!pending && !strcmp(p->agent, agt))
462                         break;
463         }
464         if (!p) {
465                 // Build the agent.
466                 if (!(p = ast_calloc(1, sizeof(*p))))
467                         return NULL;
468                 ast_copy_string(p->agent, agt, sizeof(p->agent));
469                 ast_mutex_init(&p->lock);
470                 ast_cond_init(&p->app_complete_cond, NULL);
471                 ast_cond_init(&p->login_wait_cond, NULL);
472                 p->app_lock_flag = 0;
473                 p->app_sleep_cond = 1;
474                 p->group = group;
475                 p->pending = pending;
476                 AST_LIST_INSERT_TAIL(&agents, p, list);
477         }
478         
479         ast_copy_string(p->password, password ? password : "", sizeof(p->password));
480         ast_copy_string(p->name, name ? name : "", sizeof(p->name));
481         ast_copy_string(p->moh, moh, sizeof(p->moh));
482         if (!ast_test_flag(p, AGENT_FLAG_ACKCALL)) {
483                 p->ackcall = ackcall;
484         }
485         if (!ast_test_flag(p, AGENT_FLAG_AUTOLOGOFF)) {
486                 p->autologoff = autologoff;
487         }
488         if (!ast_test_flag(p, AGENT_FLAG_ACCEPTDTMF)) {
489                 p->acceptdtmf = acceptdtmf;
490         }
491         if (!ast_test_flag(p, AGENT_FLAG_ENDDTMF)) {
492                 p->enddtmf = enddtmf;
493         }
494
495         /* If someone reduces the wrapuptime and reloads, we want it
496          * to change the wrapuptime immediately on all calls */
497         if (!ast_test_flag(p, AGENT_FLAG_WRAPUPTIME) && p->wrapuptime > wrapuptime) {
498                 struct timeval now = ast_tvnow();
499                 /* XXX check what is this exactly */
500
501                 /* We won't be pedantic and check the tv_usec val */
502                 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
503                         p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
504                         p->lastdisc.tv_usec = now.tv_usec;
505                 }
506         }
507         p->wrapuptime = wrapuptime;
508
509         if (pending)
510                 p->dead = 1;
511         else
512                 p->dead = 0;
513         return p;
514 }
515
516 /*!
517  * Deletes an agent after doing some clean up.
518  * Further documentation: How safe is this function ? What state should the agent be to be cleaned.
519  * \param p Agent to be deleted.
520  * \returns Always 0.
521  */
522 static int agent_cleanup(struct agent_pvt *p)
523 {
524         struct ast_channel *chan = NULL;
525         ast_mutex_lock(&p->lock);
526         chan = p->owner;
527         p->owner = NULL;
528         chan->tech_pvt = NULL;
529         /* Release ownership of the agent to other threads (presumably running the login app). */
530         p->app_sleep_cond = 1;
531         p->app_lock_flag = 0;
532         ast_cond_signal(&p->app_complete_cond);
533         if (chan) {
534                 chan = ast_channel_release(chan);
535         }
536         if (p->dead) {
537                 ast_mutex_unlock(&p->lock);
538                 ast_mutex_destroy(&p->lock);
539                 ast_cond_destroy(&p->app_complete_cond);
540                 ast_cond_destroy(&p->login_wait_cond);
541                 ast_free(p);
542         }
543         return 0;
544 }
545
546 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
547
548 static int agent_answer(struct ast_channel *ast)
549 {
550         ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
551         return -1;
552 }
553
554 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
555 {
556         char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
557         char filename[AST_MAX_BUF];
558         int res = -1;
559         if (!p)
560                 return -1;
561         if (!ast->monitor) {
562                 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast_channel_uniqueid(ast));
563                 /* substitute . for - */
564                 if ((pointer = strchr(filename, '.')))
565                         *pointer = '-';
566                 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
567                 ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT);
568                 ast_monitor_setjoinfiles(ast, 1);
569                 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
570 #if 0
571                 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
572 #endif
573                 if (!ast->cdr)
574                         ast->cdr = ast_cdr_alloc();
575                 ast_cdr_setuserfield(ast, tmp2);
576                 res = 0;
577         } else
578                 ast_log(LOG_ERROR, "Recording already started on that call.\n");
579         return res;
580 }
581
582 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
583 {
584         return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
585 }
586
587 static struct ast_frame *agent_read(struct ast_channel *ast)
588 {
589         struct agent_pvt *p = ast->tech_pvt;
590         struct ast_frame *f = NULL;
591         static struct ast_frame answer_frame = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
592         int cur_time = time(NULL);
593         struct ast_channel *owner;
594
595         ast_mutex_lock(&p->lock);
596         owner = agent_lock_owner(p);
597
598         CHECK_FORMATS(ast, p);
599         if (!p->start) {
600                 p->start = cur_time;
601         }
602         if (p->chan) {
603                 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
604                 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
605                 f = ast_read(p->chan);
606         } else
607                 f = &ast_null_frame;
608         if (!f) {
609                 /* If there's a channel, make it NULL */
610                 if (p->chan) {
611                         p->chan->_bridge = NULL;
612                         p->chan = NULL;
613                         ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
614                         p->acknowledged = 0;
615                 }
616         } else {
617                 /* if acknowledgement is not required, and the channel is up, we may have missed
618                         an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
619                 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) {
620                         p->acknowledged = 1;
621                 }
622
623                 if (!p->acknowledged) {
624                         int howlong = cur_time - p->start;
625                         if (p->autologoff && (howlong >= p->autologoff)) {
626                                 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
627                                 if (owner || p->chan) {
628                                         if (owner) {
629                                                 ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
630                                                 ast_channel_unlock(owner);
631                                                 owner = ast_channel_unref(owner);
632                                         }
633
634                                         while (p->chan && ast_channel_trylock(p->chan)) {
635                                                 DEADLOCK_AVOIDANCE(&p->lock);
636                                         }
637                                         if (p->chan) {
638                                                 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
639                                                 ast_channel_unlock(p->chan);
640                                         }
641                                 }
642                         }
643                 }
644                 switch (f->frametype) {
645                 case AST_FRAME_CONTROL:
646                         if (f->subclass.integer == AST_CONTROL_ANSWER) {
647                                 if (p->ackcall) {
648                                         ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", ast_channel_name(p->chan), p->acceptdtmf);
649                                         /* Don't pass answer along */
650                                         ast_frfree(f);
651                                         f = &ast_null_frame;
652                                 } else {
653                                         p->acknowledged = 1;
654                                         /* Use the builtin answer frame for the 
655                                            recording start check below. */
656                                         ast_frfree(f);
657                                         f = &answer_frame;
658                                 }
659                         }
660                         break;
661                 case AST_FRAME_DTMF_BEGIN:
662                         /*ignore DTMF begin's as it can cause issues with queue announce files*/
663                         if((!p->acknowledged && f->subclass.integer == p->acceptdtmf) || (f->subclass.integer == p->enddtmf && endcall)){
664                                 ast_frfree(f);
665                                 f = &ast_null_frame;
666                         }
667                         break;
668                 case AST_FRAME_DTMF_END:
669                         if (!p->acknowledged && (f->subclass.integer == p->acceptdtmf)) {
670                                 ast_verb(3, "%s acknowledged\n", ast_channel_name(p->chan));
671                                 p->acknowledged = 1;
672                                 ast_frfree(f);
673                                 f = &answer_frame;
674                         } else if (f->subclass.integer == p->enddtmf && endcall) {
675                                 /* terminates call */
676                                 ast_frfree(f);
677                                 f = NULL;
678                         }
679                         break;
680                 case AST_FRAME_VOICE:
681                 case AST_FRAME_VIDEO:
682                         /* don't pass voice or video until the call is acknowledged */
683                         if (!p->acknowledged) {
684                                 ast_frfree(f);
685                                 f = &ast_null_frame;
686                         }
687                 default:
688                         /* pass everything else on through */
689                         break;
690                 }
691         }
692
693         if (owner) {
694                 ast_channel_unlock(owner);
695                 owner = ast_channel_unref(owner);
696         }
697
698         CLEANUP(ast,p);
699         if (p->chan && !p->chan->_bridge) {
700                 if (strcasecmp(p->chan->tech->type, "Local")) {
701                         p->chan->_bridge = ast;
702                         if (p->chan)
703                                 ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", ast_channel_name(p->chan), ast_channel_name(p->chan->_bridge));
704                 }
705         }
706         ast_mutex_unlock(&p->lock);
707         if (recordagentcalls && f == &answer_frame)
708                 agent_start_monitoring(ast,0);
709         return f;
710 }
711
712 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
713 {
714         struct agent_pvt *p = ast->tech_pvt;
715         int res = -1;
716         ast_mutex_lock(&p->lock);
717         if (p->chan) 
718                 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
719         ast_mutex_unlock(&p->lock);
720         return res;
721 }
722
723 static int agent_sendtext(struct ast_channel *ast, const char *text)
724 {
725         struct agent_pvt *p = ast->tech_pvt;
726         int res = -1;
727         ast_mutex_lock(&p->lock);
728         if (p->chan) 
729                 res = ast_sendtext(p->chan, text);
730         ast_mutex_unlock(&p->lock);
731         return res;
732 }
733
734 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
735 {
736         struct agent_pvt *p = ast->tech_pvt;
737         int res = -1;
738         CHECK_FORMATS(ast, p);
739         ast_mutex_lock(&p->lock);
740         if (!p->chan) 
741                 res = 0;
742         else {
743                 if ((f->frametype != AST_FRAME_VOICE) ||
744                     (f->frametype != AST_FRAME_VIDEO) ||
745                     (ast_format_cmp(&f->subclass.format, &p->chan->writeformat) != AST_FORMAT_CMP_NOT_EQUAL)) {
746                         res = ast_write(p->chan, f);
747                 } else {
748                         ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
749                                 f->frametype == AST_FRAME_VOICE ? "audio" : "video",
750                                 ast_channel_name(ast), ast_channel_name(p->chan));
751                         res = 0;
752                 }
753         }
754         CLEANUP(ast, p);
755         ast_mutex_unlock(&p->lock);
756         return res;
757 }
758
759 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
760 {
761         struct agent_pvt *p = newchan->tech_pvt;
762         ast_mutex_lock(&p->lock);
763         if (p->owner != oldchan) {
764                 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
765                 ast_mutex_unlock(&p->lock);
766                 return -1;
767         }
768         p->owner = newchan;
769         ast_mutex_unlock(&p->lock);
770         return 0;
771 }
772
773 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
774 {
775         struct agent_pvt *p = ast->tech_pvt;
776         int res = -1;
777         ast_mutex_lock(&p->lock);
778         if (p->chan && !ast_check_hangup(p->chan)) {
779                 while (ast_channel_trylock(p->chan)) {
780                         int res;
781                         if ((res = ast_channel_unlock(ast))) {
782                                 ast_log(LOG_ERROR, "chan_agent bug! Channel was not locked upon entry to agent_indicate: %s\n", strerror(res));
783                                 ast_mutex_unlock(&p->lock);
784                                 return -1;
785                         }
786                         usleep(1);
787                         ast_channel_lock(ast);
788                 }
789                 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
790                 ast_channel_unlock(p->chan);
791         } else
792                 res = 0;
793         ast_mutex_unlock(&p->lock);
794         return res;
795 }
796
797 static int agent_digit_begin(struct ast_channel *ast, char digit)
798 {
799         struct agent_pvt *p = ast->tech_pvt;
800         ast_mutex_lock(&p->lock);
801         if (p->chan) {
802                 ast_senddigit_begin(p->chan, digit);
803         }
804         ast_mutex_unlock(&p->lock);
805         return 0;
806 }
807
808 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
809 {
810         struct agent_pvt *p = ast->tech_pvt;
811         ast_mutex_lock(&p->lock);
812         if (p->chan) {
813                 ast_senddigit_end(p->chan, digit, duration);
814         }
815         ast_mutex_unlock(&p->lock);
816         return 0;
817 }
818
819 static int agent_call(struct ast_channel *ast, const char *dest, int timeout)
820 {
821         struct agent_pvt *p = ast->tech_pvt;
822         int res = -1;
823         int newstate=0;
824         struct ast_channel *chan;
825
826         ast_mutex_lock(&p->lock);
827         p->acknowledged = 0;
828
829         if (p->pending) {
830                 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
831                 ast_mutex_unlock(&p->lock);
832                 ast_setstate(ast, AST_STATE_DIALING);
833                 return 0;
834         }
835
836         if (!p->chan) {
837                 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
838                 ast_mutex_unlock(&p->lock);
839                 return res;
840         }
841         ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, ast_channel_name(p->chan));
842         ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(p->chan));
843         
844         chan = p->chan;
845         ast_mutex_unlock(&p->lock);
846
847         res = ast_streamfile(chan, beep, ast_channel_language(chan));
848         ast_debug(3, "Played beep, result '%d'\n", res);
849         if (!res) {
850                 res = ast_waitstream(chan, "");
851                 ast_debug(3, "Waited for stream, result '%d'\n", res);
852         }
853         
854         ast_mutex_lock(&p->lock);
855         if (!p->chan) {
856                 /* chan went away while we were streaming, this shouldn't be possible */
857                 res = -1;
858         }
859
860         if (!res) {
861                 struct ast_format tmpfmt;
862                 res = ast_set_read_format_from_cap(p->chan, p->chan->nativeformats);
863                 ast_debug(3, "Set read format, result '%d'\n", res);
864                 if (res)
865                         ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(&tmpfmt));
866         } else {
867                 /* Agent hung-up */
868                 p->chan = NULL;
869                 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
870         }
871
872         if (!res) {
873                 struct ast_format tmpfmt;
874                 res = ast_set_write_format_from_cap(p->chan, p->chan->nativeformats);
875                 ast_debug(3, "Set write format, result '%d'\n", res);
876                 if (res)
877                         ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(&tmpfmt));
878         }
879         if(!res) {
880                 /* Call is immediately up, or might need ack */
881                 if (p->ackcall) {
882                         newstate = AST_STATE_RINGING;
883                 } else {
884                         newstate = AST_STATE_UP;
885                         if (recordagentcalls)
886                                 agent_start_monitoring(ast, 0);
887                         p->acknowledged = 1;
888                 }
889                 res = 0;
890         }
891         CLEANUP(ast, p);
892         ast_mutex_unlock(&p->lock);
893         if (newstate)
894                 ast_setstate(ast, newstate);
895         return res;
896 }
897
898 /*! \brief return the channel or base channel if one exists.  This function assumes the channel it is called on is already locked */
899 struct ast_channel* agent_get_base_channel(struct ast_channel *chan)
900 {
901         struct agent_pvt *p = NULL;
902         struct ast_channel *base = chan;
903
904         /* chan is locked by the calling function */
905         if (!chan || !chan->tech_pvt) {
906                 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) with a tech_pvt (0x%ld) to get a base channel.\n", (long)chan, (chan)?(long)chan->tech_pvt:(long)NULL);
907                 return NULL;
908         }
909         p = chan->tech_pvt;
910         if (p->chan) 
911                 base = p->chan;
912         return base;
913 }
914
915 int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base)
916 {
917         struct agent_pvt *p = NULL;
918         
919         if (!chan || !base) {
920                 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
921                 return -1;
922         }
923         p = chan->tech_pvt;
924         if (!p) {
925                 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", ast_channel_name(chan));
926                 return -1;
927         }
928         p->chan = base;
929         return 0;
930 }
931
932 static int agent_hangup(struct ast_channel *ast)
933 {
934         struct agent_pvt *p = ast->tech_pvt;
935         struct ast_channel *indicate_chan = NULL;
936         char *tmp_moh; /* moh buffer for indicating after unlocking p */
937
938         if (p->pending) {
939                 AST_LIST_LOCK(&agents);
940                 AST_LIST_REMOVE(&agents, p, list);
941                 AST_LIST_UNLOCK(&agents);
942         }
943
944         ast_mutex_lock(&p->lock);
945         p->owner = NULL;
946         ast->tech_pvt = NULL;
947         p->app_sleep_cond = 1;
948         p->acknowledged = 0;
949
950         /* Release ownership of the agent to other threads (presumably running the login app). */
951         p->app_lock_flag = 0;
952         ast_cond_signal(&p->app_complete_cond);
953
954         /* if they really are hung up then set start to 0 so the test
955          * later if we're called on an already downed channel
956          * doesn't cause an agent to be logged out like when
957          * agent_request() is followed immediately by agent_hangup()
958          * as in apps/app_chanisavail.c:chanavail_exec()
959          */
960
961         ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state));
962         if (p->start && (ast->_state != AST_STATE_UP)) {
963                 p->start = 0;
964         } else
965                 p->start = 0;
966         if (p->chan) {
967                 p->chan->_bridge = NULL;
968                 /* If they're dead, go ahead and hang up on the agent now */
969                 if (p->dead) {
970                         ast_channel_lock(p->chan);
971                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
972                         ast_channel_unlock(p->chan);
973                 } else if (p->loginstart) {
974                         indicate_chan = ast_channel_ref(p->chan);
975                         tmp_moh = ast_strdupa(p->moh);
976                 }
977         }
978         ast_mutex_unlock(&p->lock);
979
980         if (indicate_chan) {
981                 ast_channel_lock(indicate_chan);
982                 ast_indicate_data(indicate_chan, AST_CONTROL_HOLD,
983                         S_OR(tmp_moh, NULL),
984                         !ast_strlen_zero(tmp_moh) ? strlen(tmp_moh) + 1 : 0);
985                 ast_channel_unlock(indicate_chan);
986                 indicate_chan = ast_channel_unref(indicate_chan);
987         }
988
989         /* Only register a device state change if the agent is still logged in */
990         if (!p->loginstart) {
991                 p->logincallerid[0] = '\0';
992         } else {
993                 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
994         }
995
996         if (p->abouttograb) {
997                 /* Let the "about to grab" thread know this isn't valid anymore, and let it
998                    kill it later */
999                 p->abouttograb = 0;
1000         } else if (p->dead) {
1001                 ast_mutex_destroy(&p->lock);
1002                 ast_cond_destroy(&p->app_complete_cond);
1003                 ast_cond_destroy(&p->login_wait_cond);
1004                 ast_free(p);
1005         } else {
1006                 if (p->chan) {
1007                         /* Not dead -- check availability now */
1008                         ast_mutex_lock(&p->lock);
1009                         /* Store last disconnect time */
1010                         p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
1011                         ast_mutex_unlock(&p->lock);
1012                 }
1013         }
1014         return 0;
1015 }
1016
1017 static int agent_cont_sleep( void *data )
1018 {
1019         struct agent_pvt *p;
1020         int res;
1021
1022         p = (struct agent_pvt *)data;
1023
1024         ast_mutex_lock(&p->lock);
1025         res = p->app_sleep_cond;
1026         if (p->lastdisc.tv_sec) {
1027                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
1028                         res = 1;
1029         }
1030         ast_mutex_unlock(&p->lock);
1031
1032         if (!res)
1033                 ast_debug(5, "agent_cont_sleep() returning %d\n", res );
1034
1035         return res;
1036 }
1037
1038 static int agent_ack_sleep(void *data)
1039 {
1040         struct agent_pvt *p;
1041         int res=0;
1042         int to = 1000;
1043         struct ast_frame *f;
1044
1045         /* Wait a second and look for something */
1046
1047         p = (struct agent_pvt *) data;
1048         if (!p->chan) 
1049                 return -1;
1050
1051         for(;;) {
1052                 to = ast_waitfor(p->chan, to);
1053                 if (to < 0) 
1054                         return -1;
1055                 if (!to) 
1056                         return 0;
1057                 f = ast_read(p->chan);
1058                 if (!f) 
1059                         return -1;
1060                 if (f->frametype == AST_FRAME_DTMF)
1061                         res = f->subclass.integer;
1062                 else
1063                         res = 0;
1064                 ast_frfree(f);
1065                 ast_mutex_lock(&p->lock);
1066                 if (!p->app_sleep_cond) {
1067                         ast_mutex_unlock(&p->lock);
1068                         return 0;
1069                 } else if (res == p->acceptdtmf) {
1070                         ast_mutex_unlock(&p->lock);
1071                         return 1;
1072                 }
1073                 ast_mutex_unlock(&p->lock);
1074                 res = 0;
1075         }
1076         return res;
1077 }
1078
1079 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
1080 {
1081         struct agent_pvt *p = bridge->tech_pvt;
1082         struct ast_channel *ret = NULL;
1083
1084         if (p) {
1085                 if (chan == p->chan)
1086                         ret = bridge->_bridge;
1087                 else if (chan == bridge->_bridge)
1088                         ret = p->chan;
1089         }
1090
1091         ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", ast_channel_name(chan), ast_channel_name(bridge), ret ? ast_channel_name(ret) : "<none>");
1092         return ret;
1093 }
1094
1095 /*! \brief Create new agent channel */
1096 static struct ast_channel *agent_new(struct agent_pvt *p, int state, const char *linkedid)
1097 {
1098         struct ast_channel *tmp;
1099 #if 0
1100         if (!p->chan) {
1101                 ast_log(LOG_WARNING, "No channel? :(\n");
1102                 return NULL;
1103         }
1104 #endif  
1105         if (p->pending)
1106                 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? ast_channel_exten(p->chan):"", p->chan ? ast_channel_context(p->chan):"", linkedid, 0, "Agent/P%s-%d", p->agent, (int) ast_random() & 0xffff);
1107         else
1108                 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? ast_channel_exten(p->chan):"", p->chan ? ast_channel_context(p->chan):"", linkedid, 0, "Agent/%s", p->agent);
1109         if (!tmp) {
1110                 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
1111                 return NULL;
1112         }
1113
1114         tmp->tech = &agent_tech;
1115         if (p->chan) {
1116                 ast_format_cap_copy(tmp->nativeformats, p->chan->nativeformats);
1117                 ast_format_copy(&tmp->writeformat, &p->chan->writeformat);
1118                 ast_format_copy(&tmp->rawwriteformat, &p->chan->writeformat);
1119                 ast_format_copy(&tmp->readformat, &p->chan->readformat);
1120                 ast_format_copy(&tmp->rawreadformat, &p->chan->readformat);
1121                 ast_channel_language_set(tmp, ast_channel_language(p->chan));
1122                 ast_channel_context_set(tmp, ast_channel_context(p->chan));
1123                 ast_channel_exten_set(tmp, ast_channel_exten(p->chan));
1124                 /* XXX Is this really all we copy form the originating channel?? */
1125         } else {
1126                 ast_format_set(&tmp->writeformat, AST_FORMAT_SLINEAR, 0);
1127                 ast_format_set(&tmp->rawwriteformat, AST_FORMAT_SLINEAR, 0);
1128                 ast_format_set(&tmp->readformat, AST_FORMAT_SLINEAR, 0);
1129                 ast_format_set(&tmp->rawreadformat, AST_FORMAT_SLINEAR, 0);
1130                 ast_format_cap_add(tmp->nativeformats, &tmp->writeformat);
1131         }
1132         /* Safe, agentlock already held */
1133         tmp->tech_pvt = p;
1134         p->owner = tmp;
1135         tmp->priority = 1;
1136         return tmp;
1137 }
1138
1139
1140 /*!
1141  * Read configuration data. The file named agents.conf.
1142  *
1143  * \returns Always 0, or so it seems.
1144  */
1145 static int read_agent_config(int reload)
1146 {
1147         struct ast_config *cfg;
1148         struct ast_config *ucfg;
1149         struct ast_variable *v;
1150         struct agent_pvt *p;
1151         const char *catname;
1152         const char *hasagent;
1153         int genhasagent;
1154         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1155
1156         group = 0;
1157         autologoff = 0;
1158         wrapuptime = 0;
1159         ackcall = 0;
1160         endcall = 1;
1161         cfg = ast_config_load(config, config_flags);
1162         if (!cfg) {
1163                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
1164                 return 0;
1165         } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1166                 return -1;
1167         } else if (cfg == CONFIG_STATUS_FILEINVALID) {
1168                 ast_log(LOG_ERROR, "%s contains a parsing error.  Aborting\n", config);
1169                 return 0;
1170         }
1171         if ((ucfg = ast_config_load("users.conf", config_flags))) {
1172                 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
1173                         ucfg = NULL;
1174                 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
1175                         ast_log(LOG_ERROR, "users.conf contains a parsing error.  Aborting\n");
1176                         return 0;
1177                 }
1178         }
1179
1180         AST_LIST_LOCK(&agents);
1181         AST_LIST_TRAVERSE(&agents, p, list) {
1182                 p->dead = 1;
1183         }
1184         strcpy(moh, "default");
1185         /* set the default recording values */
1186         recordagentcalls = 0;
1187         strcpy(recordformat, "wav");
1188         strcpy(recordformatext, "wav");
1189         urlprefix[0] = '\0';
1190         savecallsin[0] = '\0';
1191
1192         /* Read in [general] section for persistence */
1193         multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
1194
1195         /* Read in the [agents] section */
1196         v = ast_variable_browse(cfg, "agents");
1197         while(v) {
1198                 /* Create the interface list */
1199                 if (!strcasecmp(v->name, "agent")) {
1200                         add_agent(v->value, 0);
1201                 } else if (!strcasecmp(v->name, "group")) {
1202                         group = ast_get_group(v->value);
1203                 } else if (!strcasecmp(v->name, "autologoff")) {
1204                         autologoff = atoi(v->value);
1205                         if (autologoff < 0)
1206                                 autologoff = 0;
1207                 } else if (!strcasecmp(v->name, "ackcall")) {
1208                         if (ast_true(v->value) || !strcasecmp(v->value, "always")) {
1209                                 ackcall = 1;
1210                         }
1211                 } else if (!strcasecmp(v->name, "endcall")) {
1212                         endcall = ast_true(v->value);
1213                 } else if (!strcasecmp(v->name, "acceptdtmf")) {
1214                         acceptdtmf = *(v->value);
1215                         ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf);
1216                 } else if (!strcasecmp(v->name, "enddtmf")) {
1217                         enddtmf = *(v->value);
1218                 } else if (!strcasecmp(v->name, "wrapuptime")) {
1219                         wrapuptime = atoi(v->value);
1220                         if (wrapuptime < 0)
1221                                 wrapuptime = 0;
1222                 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1223                         maxlogintries = atoi(v->value);
1224                         if (maxlogintries < 0)
1225                                 maxlogintries = 0;
1226                 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1227                         strcpy(agentgoodbye,v->value);
1228                 } else if (!strcasecmp(v->name, "musiconhold")) {
1229                         ast_copy_string(moh, v->value, sizeof(moh));
1230                 } else if (!strcasecmp(v->name, "updatecdr")) {
1231                         if (ast_true(v->value))
1232                                 updatecdr = 1;
1233                         else
1234                                 updatecdr = 0;
1235                 } else if (!strcasecmp(v->name, "autologoffunavail")) {
1236                         if (ast_true(v->value))
1237                                 autologoffunavail = 1;
1238                         else
1239                                 autologoffunavail = 0;
1240                 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1241                         recordagentcalls = ast_true(v->value);
1242                 } else if (!strcasecmp(v->name, "recordformat")) {
1243                         ast_copy_string(recordformat, v->value, sizeof(recordformat));
1244                         if (!strcasecmp(v->value, "wav49"))
1245                                 strcpy(recordformatext, "WAV");
1246                         else
1247                                 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1248                 } else if (!strcasecmp(v->name, "urlprefix")) {
1249                         ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1250                         if (urlprefix[strlen(urlprefix) - 1] != '/')
1251                                 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1252                 } else if (!strcasecmp(v->name, "savecallsin")) {
1253                         if (v->value[0] == '/')
1254                                 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1255                         else
1256                                 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1257                         if (savecallsin[strlen(savecallsin) - 1] != '/')
1258                                 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1259                 } else if (!strcasecmp(v->name, "custom_beep")) {
1260                         ast_copy_string(beep, v->value, sizeof(beep));
1261                 }
1262                 v = v->next;
1263         }
1264         if (ucfg) {
1265                 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
1266                 catname = ast_category_browse(ucfg, NULL);
1267                 while(catname) {
1268                         if (strcasecmp(catname, "general")) {
1269                                 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
1270                                 if (ast_true(hasagent) || (!hasagent && genhasagent)) {
1271                                         char tmp[256];
1272                                         const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
1273                                         const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
1274                                         if (!fullname)
1275                                                 fullname = "";
1276                                         if (!secret)
1277                                                 secret = "";
1278                                         snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
1279                                         add_agent(tmp, 0);
1280                                 }
1281                         }
1282                         catname = ast_category_browse(ucfg, catname);
1283                 }
1284                 ast_config_destroy(ucfg);
1285         }
1286         AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
1287                 if (p->dead) {
1288                         AST_LIST_REMOVE_CURRENT(list);
1289                         /* Destroy if  appropriate */
1290                         if (!p->owner) {
1291                                 if (!p->chan) {
1292                                         ast_mutex_destroy(&p->lock);
1293                                         ast_cond_destroy(&p->app_complete_cond);
1294                                         ast_cond_destroy(&p->login_wait_cond);
1295                                         ast_free(p);
1296                                 } else {
1297                                         /* Cause them to hang up */
1298                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1299                                 }
1300                         }
1301                 }
1302         }
1303         AST_LIST_TRAVERSE_SAFE_END;
1304         AST_LIST_UNLOCK(&agents);
1305         ast_config_destroy(cfg);
1306         return 1;
1307 }
1308
1309 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1310 {
1311         struct ast_channel *chan=NULL, *parent=NULL;
1312         struct agent_pvt *p;
1313         int res;
1314
1315         ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
1316         if (needlock)
1317                 AST_LIST_LOCK(&agents);
1318         AST_LIST_TRAVERSE(&agents, p, list) {
1319                 if (p == newlyavailable) {
1320                         continue;
1321                 }
1322                 ast_mutex_lock(&p->lock);
1323                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1324                         ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", ast_channel_name(p->owner), newlyavailable->agent);
1325                         /* We found a pending call, time to merge */
1326                         chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? ast_channel_linkedid(p->owner) : NULL);
1327                         parent = p->owner;
1328                         p->abouttograb = 1;
1329                         ast_mutex_unlock(&p->lock);
1330                         break;
1331                 }
1332                 ast_mutex_unlock(&p->lock);
1333         }
1334         if (needlock)
1335                 AST_LIST_UNLOCK(&agents);
1336         if (parent && chan)  {
1337                 if (newlyavailable->ackcall) {
1338                         /* Don't do beep here */
1339                         res = 0;
1340                 } else {
1341                         ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(newlyavailable->chan));
1342                         res = ast_streamfile(newlyavailable->chan, beep, ast_channel_language(newlyavailable->chan));
1343                         ast_debug(3, "Played beep, result '%d'\n", res);
1344                         if (!res) {
1345                                 res = ast_waitstream(newlyavailable->chan, "");
1346                                 ast_debug(1, "Waited for stream, result '%d'\n", res);
1347                         }
1348                 }
1349                 if (!res) {
1350                         /* Note -- parent may have disappeared */
1351                         if (p->abouttograb) {
1352                                 newlyavailable->acknowledged = 1;
1353                                 /* Safe -- agent lock already held */
1354                                 ast_setstate(parent, AST_STATE_UP);
1355                                 ast_setstate(chan, AST_STATE_UP);
1356                                 ast_channel_context_set(parent, ast_channel_context(chan));
1357                                 ast_channel_masquerade(parent, chan);
1358                                 ast_hangup(chan);
1359                                 p->abouttograb = 0;
1360                         } else {
1361                                 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
1362                                 agent_cleanup(newlyavailable);
1363                         }
1364                 } else {
1365                         ast_debug(1, "Ugh...  Agent hung up at exactly the wrong time\n");
1366                         agent_cleanup(newlyavailable);
1367                 }
1368         }
1369         return 0;
1370 }
1371
1372 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1373 {
1374         struct agent_pvt *p;
1375         int res=0;
1376
1377         ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
1378         if (needlock)
1379                 AST_LIST_LOCK(&agents);
1380         AST_LIST_TRAVERSE(&agents, p, list) {
1381                 if (p == newlyavailable) {
1382                         continue;
1383                 }
1384                 ast_mutex_lock(&p->lock);
1385                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1386                         ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", ast_channel_name(p->owner), newlyavailable->agent);
1387                         ast_mutex_unlock(&p->lock);
1388                         break;
1389                 }
1390                 ast_mutex_unlock(&p->lock);
1391         }
1392         if (needlock)
1393                 AST_LIST_UNLOCK(&agents);
1394         if (p) {
1395                 ast_mutex_unlock(&newlyavailable->lock);
1396                 ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(newlyavailable->chan));
1397                 res = ast_streamfile(newlyavailable->chan, beep, ast_channel_language(newlyavailable->chan));
1398                 ast_debug(1, "Played beep, result '%d'\n", res);
1399                 if (!res) {
1400                         res = ast_waitstream(newlyavailable->chan, "");
1401                         ast_debug(1, "Waited for stream, result '%d'\n", res);
1402                 }
1403                 ast_mutex_lock(&newlyavailable->lock);
1404         }
1405         return res;
1406 }
1407
1408 /*! \brief Part of the Asterisk PBX interface */
1409 static struct ast_channel *agent_request(const char *type, struct ast_format_cap *cap, const struct ast_channel* requestor, const char *data, int *cause)
1410 {
1411         struct agent_pvt *p;
1412         struct ast_channel *chan = NULL;
1413         const char *s;
1414         ast_group_t groupmatch;
1415         int groupoff;
1416         int waitforagent=0;
1417         int hasagent = 0;
1418         struct timeval now;
1419
1420         s = data;
1421         if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
1422                 groupmatch = (1 << groupoff);
1423         } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
1424                 groupmatch = (1 << groupoff);
1425                 waitforagent = 1;
1426         } else 
1427                 groupmatch = 0;
1428
1429         /* Check actual logged in agents first */
1430         AST_LIST_LOCK(&agents);
1431         AST_LIST_TRAVERSE(&agents, p, list) {
1432                 ast_mutex_lock(&p->lock);
1433                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1434                         if (p->chan)
1435                                 hasagent++;
1436                         now = ast_tvnow();
1437                         if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
1438                                 p->lastdisc = ast_tv(0, 0);
1439                                 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1440                                 if (!p->owner && p->chan) {
1441                                         /* Fixed agent */
1442                                         chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
1443                                 }
1444                                 if (chan) {
1445                                         ast_mutex_unlock(&p->lock);
1446                                         break;
1447                                 }
1448                         }
1449                 }
1450                 ast_mutex_unlock(&p->lock);
1451         }
1452         if (!p) {
1453                 AST_LIST_TRAVERSE(&agents, p, list) {
1454                         ast_mutex_lock(&p->lock);
1455                         if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1456                                 if (p->chan) {
1457                                         hasagent++;
1458                                 }
1459                                 now = ast_tvnow();
1460                                 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
1461                                         p->lastdisc = ast_tv(0, 0);
1462                                         /* Agent must be registered, but not have any active call, and not be in a waiting state */
1463                                         if (!p->owner && p->chan) {
1464                                                 /* Could still get a fixed agent */
1465                                                 chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
1466                                         }
1467                                         if (chan) {
1468                                                 ast_mutex_unlock(&p->lock);
1469                                                 break;
1470                                         }
1471                                 }
1472                         }
1473                         ast_mutex_unlock(&p->lock);
1474                 }
1475         }
1476
1477         if (!chan && waitforagent) {
1478                 /* No agent available -- but we're requesting to wait for one.
1479                    Allocate a place holder */
1480                 if (hasagent) {
1481                         ast_debug(1, "Creating place holder for '%s'\n", s);
1482                         p = add_agent(data, 1);
1483                         p->group = groupmatch;
1484                         chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
1485                         if (!chan) 
1486                                 ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
1487                 } else {
1488                         ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
1489                 }
1490         }
1491         *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
1492         AST_LIST_UNLOCK(&agents);
1493
1494         if (chan) {
1495                 ast_mutex_lock(&p->lock);
1496                 if (p->pending) {
1497                         ast_mutex_unlock(&p->lock);
1498                         return chan;
1499                 }
1500
1501                 if (!p->chan) {
1502                         ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
1503                         *cause = AST_CAUSE_UNREGISTERED;
1504                         ast_mutex_unlock(&p->lock);
1505                         agent_hangup(chan);
1506                         return NULL;
1507                 }
1508
1509                 /* we need to take control of the channel from the login app
1510                  * thread */
1511                 p->app_sleep_cond = 0;
1512                 p->app_lock_flag = 1;
1513
1514                 ast_queue_frame(p->chan, &ast_null_frame);
1515                 ast_cond_wait(&p->login_wait_cond, &p->lock);
1516
1517                 if (!p->chan) {
1518                         ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
1519                         p->app_sleep_cond = 1;
1520                         p->app_lock_flag = 0;
1521                         ast_cond_signal(&p->app_complete_cond);
1522                         ast_mutex_unlock(&p->lock);
1523                         *cause = AST_CAUSE_UNREGISTERED;
1524                         agent_hangup(chan);
1525                         return NULL;
1526                 }
1527
1528                 ast_indicate(p->chan, AST_CONTROL_UNHOLD);
1529                 ast_mutex_unlock(&p->lock);
1530         }
1531
1532         return chan;
1533 }
1534
1535 static force_inline int powerof(unsigned int d)
1536 {
1537         int x = ffs(d);
1538
1539         if (x)
1540                 return x - 1;
1541
1542         return 0;
1543 }
1544
1545 /*!
1546  * Lists agents and their status to the Manager API.
1547  * It is registered on load_module() and it gets called by the manager backend.
1548  * This function locks both the pvt and the channel that owns it for a while, but
1549  * does not keep these locks.
1550  * \param s
1551  * \param m
1552  * \returns 
1553  * \sa action_agent_logoff(), load_module().
1554  */
1555 static int action_agents(struct mansession *s, const struct message *m)
1556 {
1557         const char *id = astman_get_header(m,"ActionID");
1558         char idText[256] = "";
1559         struct agent_pvt *p;
1560         char *username = NULL;
1561         char *loginChan = NULL;
1562         char *talkingto = NULL;
1563         char *talkingtoChan = NULL;
1564         char *status = NULL;
1565         struct ast_channel *bridge;
1566
1567         if (!ast_strlen_zero(id))
1568                 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1569         astman_send_ack(s, m, "Agents will follow");
1570         AST_LIST_LOCK(&agents);
1571         AST_LIST_TRAVERSE(&agents, p, list) {
1572                 struct ast_channel *owner;
1573                 ast_mutex_lock(&p->lock);
1574                 owner = agent_lock_owner(p);
1575
1576                 /* Status Values:
1577                    AGENT_LOGGEDOFF - Agent isn't logged in
1578                    AGENT_IDLE      - Agent is logged in, and waiting for call
1579                    AGENT_ONCALL    - Agent is logged in, and on a call
1580                    AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
1581
1582                 username = S_OR(p->name, "None");
1583
1584                 /* Set a default status. It 'should' get changed. */
1585                 status = "AGENT_UNKNOWN";
1586
1587                 if (p->chan) {
1588                         loginChan = ast_strdupa(ast_channel_name(p->chan));
1589                         if (owner && owner->_bridge) {
1590                                 talkingto = S_COR(p->chan->caller.id.number.valid,
1591                                         p->chan->caller.id.number.str, "n/a");
1592                                 if ((bridge = ast_bridged_channel(owner))) {
1593                                         talkingtoChan = ast_strdupa(ast_channel_name(bridge));
1594                                 } else {
1595                                         talkingtoChan = "n/a";
1596                                 }
1597                                 status = "AGENT_ONCALL";
1598                         } else {
1599                                 talkingto = "n/a";
1600                                 talkingtoChan = "n/a";
1601                                 status = "AGENT_IDLE";
1602                         }
1603                 } else {
1604                         loginChan = "n/a";
1605                         talkingto = "n/a";
1606                         talkingtoChan = "n/a";
1607                         status = "AGENT_LOGGEDOFF";
1608                 }
1609
1610                 if (owner) {
1611                         ast_channel_unlock(owner);
1612                         owner = ast_channel_unref(owner);
1613                 }
1614
1615                 astman_append(s, "Event: Agents\r\n"
1616                         "Agent: %s\r\n"
1617                         "Name: %s\r\n"
1618                         "Status: %s\r\n"
1619                         "LoggedInChan: %s\r\n"
1620                         "LoggedInTime: %d\r\n"
1621                         "TalkingTo: %s\r\n"
1622                         "TalkingToChan: %s\r\n"
1623                         "%s"
1624                         "\r\n",
1625                         p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
1626                 ast_mutex_unlock(&p->lock);
1627         }
1628         AST_LIST_UNLOCK(&agents);
1629         astman_append(s, "Event: AgentsComplete\r\n"
1630                 "%s"
1631                 "\r\n",idText);
1632         return 0;
1633 }
1634
1635 static int agent_logoff(const char *agent, int soft)
1636 {
1637         struct agent_pvt *p;
1638         int ret = -1; /* Return -1 if no agent if found */
1639
1640         AST_LIST_LOCK(&agents);
1641         AST_LIST_TRAVERSE(&agents, p, list) {
1642                 if (!strcasecmp(p->agent, agent)) {
1643                         ret = 0;
1644                         if (p->owner || p->chan) {
1645                                 if (!soft) {
1646                                         struct ast_channel *owner;
1647                                         ast_mutex_lock(&p->lock);
1648                                         owner = agent_lock_owner(p);
1649
1650                                         if (owner) {
1651                                                 ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
1652                                                 ast_channel_unlock(owner);
1653                                                 owner = ast_channel_unref(owner);
1654                                         }
1655
1656                                         while (p->chan && ast_channel_trylock(p->chan)) {
1657                                                 DEADLOCK_AVOIDANCE(&p->lock);
1658                                         }
1659                                         if (p->chan) {
1660                                                 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1661                                                 ast_channel_unlock(p->chan);
1662                                         }
1663
1664                                         ast_mutex_unlock(&p->lock);
1665                                 } else
1666                                         p->deferlogoff = 1;
1667                         }
1668                         break;
1669                 }
1670         }
1671         AST_LIST_UNLOCK(&agents);
1672
1673         return ret;
1674 }
1675
1676 static char *agent_logoff_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1677 {
1678         int ret;
1679         const char *agent;
1680
1681         switch (cmd) {
1682         case CLI_INIT:
1683                 e->command = "agent logoff";
1684                 e->usage =
1685                         "Usage: agent logoff <channel> [soft]\n"
1686                         "       Sets an agent as no longer logged in.\n"
1687                         "       If 'soft' is specified, do not hangup existing calls.\n";
1688                 return NULL;
1689         case CLI_GENERATE:
1690                 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 
1691         }
1692
1693         if (a->argc < 3 || a->argc > 4)
1694                 return CLI_SHOWUSAGE;
1695         if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
1696                 return CLI_SHOWUSAGE;
1697
1698         agent = a->argv[2] + 6;
1699         ret = agent_logoff(agent, a->argc == 4);
1700         if (ret == 0)
1701                 ast_cli(a->fd, "Logging out %s\n", agent);
1702
1703         return CLI_SUCCESS;
1704 }
1705
1706 /*!
1707  * Sets an agent as no longer logged in in the Manager API.
1708  * It is registered on load_module() and it gets called by the manager backend.
1709  * \param s
1710  * \param m
1711  * \returns 
1712  * \sa action_agents(), load_module().
1713  */
1714 static int action_agent_logoff(struct mansession *s, const struct message *m)
1715 {
1716         const char *agent = astman_get_header(m, "Agent");
1717         const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1718         int soft;
1719         int ret; /* return value of agent_logoff */
1720
1721         if (ast_strlen_zero(agent)) {
1722                 astman_send_error(s, m, "No agent specified");
1723                 return 0;
1724         }
1725
1726         soft = ast_true(soft_s) ? 1 : 0;
1727         ret = agent_logoff(agent, soft);
1728         if (ret == 0)
1729                 astman_send_ack(s, m, "Agent logged out");
1730         else
1731                 astman_send_error(s, m, "No such agent");
1732
1733         return 0;
1734 }
1735
1736 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
1737 {
1738         char *ret = NULL;
1739
1740         if (pos == 2) {
1741                 struct agent_pvt *p;
1742                 char name[AST_MAX_AGENT];
1743                 int which = 0, len = strlen(word);
1744
1745                 AST_LIST_LOCK(&agents);
1746                 AST_LIST_TRAVERSE(&agents, p, list) {
1747                         snprintf(name, sizeof(name), "Agent/%s", p->agent);
1748                         if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
1749                                 ret = ast_strdup(name);
1750                                 break;
1751                         }
1752                 }
1753                 AST_LIST_UNLOCK(&agents);
1754         } else if (pos == 3 && state == 0) 
1755                 return ast_strdup("soft");
1756         
1757         return ret;
1758 }
1759
1760 /*!
1761  * Show agents in cli.
1762  */
1763 static char *agents_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1764 {
1765         struct agent_pvt *p;
1766         char username[AST_MAX_BUF];
1767         char location[AST_MAX_BUF] = "";
1768         char talkingto[AST_MAX_BUF] = "";
1769         char music[AST_MAX_BUF];
1770         int count_agents = 0;           /*!< Number of agents configured */
1771         int online_agents = 0;          /*!< Number of online agents */
1772         int offline_agents = 0;         /*!< Number of offline agents */
1773
1774         switch (cmd) {
1775         case CLI_INIT:
1776                 e->command = "agent show";
1777                 e->usage =
1778                         "Usage: agent show\n"
1779                         "       Provides summary information on agents.\n";
1780                 return NULL;
1781         case CLI_GENERATE:
1782                 return NULL;
1783         }
1784
1785         if (a->argc != 2)
1786                 return CLI_SHOWUSAGE;
1787
1788         AST_LIST_LOCK(&agents);
1789         AST_LIST_TRAVERSE(&agents, p, list) {
1790                 struct ast_channel *owner;
1791                 ast_mutex_lock(&p->lock);
1792                 owner = agent_lock_owner(p);
1793                 if (p->pending) {
1794                         if (p->group)
1795                                 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
1796                         else
1797                                 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
1798                 } else {
1799                         if (!ast_strlen_zero(p->name))
1800                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1801                         else
1802                                 username[0] = '\0';
1803                         if (p->chan) {
1804                                 snprintf(location, sizeof(location), "logged in on %s", ast_channel_name(p->chan));
1805                                 if (owner && ast_bridged_channel(owner)) {
1806                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_channel_name(ast_bridged_channel(p->owner)));
1807                                 } else {
1808                                         strcpy(talkingto, " is idle");
1809                                 }
1810                                 online_agents++;
1811                         } else {
1812                                 strcpy(location, "not logged in");
1813                                 talkingto[0] = '\0';
1814                                 offline_agents++;
1815                         }
1816                         if (!ast_strlen_zero(p->moh))
1817                                 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
1818                         ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 
1819                                 username, location, talkingto, music);
1820                         count_agents++;
1821                 }
1822
1823                 if (owner) {
1824                         ast_channel_unlock(owner);
1825                         owner = ast_channel_unref(owner);
1826                 }
1827                 ast_mutex_unlock(&p->lock);
1828         }
1829         AST_LIST_UNLOCK(&agents);
1830         if ( !count_agents ) 
1831                 ast_cli(a->fd, "No Agents are configured in %s\n",config);
1832         else 
1833                 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1834         ast_cli(a->fd, "\n");
1835                         
1836         return CLI_SUCCESS;
1837 }
1838
1839
1840 static char *agents_show_online(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1841 {
1842         struct agent_pvt *p;
1843         char username[AST_MAX_BUF];
1844         char location[AST_MAX_BUF] = "";
1845         char talkingto[AST_MAX_BUF] = "";
1846         char music[AST_MAX_BUF];
1847         int count_agents = 0;           /* Number of agents configured */
1848         int online_agents = 0;          /* Number of online agents */
1849         int agent_status = 0;           /* 0 means offline, 1 means online */
1850
1851         switch (cmd) {
1852         case CLI_INIT:
1853                 e->command = "agent show online";
1854                 e->usage =
1855                         "Usage: agent show online\n"
1856                         "       Provides a list of all online agents.\n";
1857                 return NULL;
1858         case CLI_GENERATE:
1859                 return NULL;
1860         }
1861
1862         if (a->argc != 3)
1863                 return CLI_SHOWUSAGE;
1864
1865         AST_LIST_LOCK(&agents);
1866         AST_LIST_TRAVERSE(&agents, p, list) {
1867                 struct ast_channel *owner;
1868
1869                 agent_status = 0;       /* reset it to offline */
1870                 ast_mutex_lock(&p->lock);
1871                 owner = agent_lock_owner(p);
1872
1873                 if (!ast_strlen_zero(p->name))
1874                         snprintf(username, sizeof(username), "(%s) ", p->name);
1875                 else
1876                         username[0] = '\0';
1877                 if (p->chan) {
1878                         snprintf(location, sizeof(location), "logged in on %s", ast_channel_name(p->chan));
1879                         if (p->owner && ast_bridged_channel(p->owner)) {
1880                                 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_channel_name(ast_bridged_channel(p->owner)));
1881                         } else {
1882                                 strcpy(talkingto, " is idle");
1883                         }
1884                         agent_status = 1;
1885                         online_agents++;
1886                 }
1887
1888                 if (owner) {
1889                         ast_channel_unlock(owner);
1890                         owner = ast_channel_unref(owner);
1891                 }
1892
1893                 if (!ast_strlen_zero(p->moh))
1894                         snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
1895                 if (agent_status)
1896                         ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
1897                 count_agents++;
1898                 ast_mutex_unlock(&p->lock);
1899         }
1900         AST_LIST_UNLOCK(&agents);
1901         if (!count_agents) 
1902                 ast_cli(a->fd, "No Agents are configured in %s\n", config);
1903         else
1904                 ast_cli(a->fd, "%d agents online\n", online_agents);
1905         ast_cli(a->fd, "\n");
1906         return CLI_SUCCESS;
1907 }
1908
1909 static const char agent_logoff_usage[] =
1910 "Usage: agent logoff <channel> [soft]\n"
1911 "       Sets an agent as no longer logged in.\n"
1912 "       If 'soft' is specified, do not hangup existing calls.\n";
1913
1914 static struct ast_cli_entry cli_agents[] = {
1915         AST_CLI_DEFINE(agents_show, "Show status of agents"),
1916         AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
1917         AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
1918 };
1919
1920 /*!
1921  * Called by the AgentLogin application (from the dial plan).
1922  * 
1923  * \brief Log in agent application.
1924  *
1925  * \param chan
1926  * \param data
1927  * \returns
1928  * \sa agentmonitoroutgoing_exec(), load_module().
1929  */
1930 static int login_exec(struct ast_channel *chan, const char *data)
1931 {
1932         int res=0;
1933         int tries = 0;
1934         int max_login_tries = maxlogintries;
1935         struct agent_pvt *p;
1936         struct ast_module_user *u;
1937         char user[AST_MAX_AGENT] = "";
1938         char pass[AST_MAX_AGENT];
1939         char agent[AST_MAX_AGENT] = "";
1940         char xpass[AST_MAX_AGENT] = "";
1941         char *errmsg;
1942         char *parse;
1943         AST_DECLARE_APP_ARGS(args,
1944                              AST_APP_ARG(agent_id);
1945                              AST_APP_ARG(options);
1946                              AST_APP_ARG(extension);
1947                 );
1948         const char *tmpoptions = NULL;
1949         int play_announcement = 1;
1950         char agent_goodbye[AST_MAX_FILENAME_LEN];
1951         int update_cdr = updatecdr;
1952         char *filename = "agent-loginok";
1953
1954         u = ast_module_user_add(chan);
1955
1956         parse = ast_strdupa(data);
1957
1958         AST_STANDARD_APP_ARGS(args, parse);
1959
1960         ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
1961
1962         ast_channel_lock(chan);
1963         /* Set Channel Specific Login Overrides */
1964         if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1965                 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1966                 if (max_login_tries < 0)
1967                         max_login_tries = 0;
1968                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1969                 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,ast_channel_name(chan));
1970         }
1971         if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1972                 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1973                         update_cdr = 1;
1974                 else
1975                         update_cdr = 0;
1976                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1977                 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,ast_channel_name(chan));
1978         }
1979         if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1980                 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1981                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1982                 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,ast_channel_name(chan));
1983         }
1984         ast_channel_unlock(chan);
1985         /* End Channel Specific Login Overrides */
1986         
1987         if (!ast_strlen_zero(args.options)) {
1988                 if (strchr(args.options, 's')) {
1989                         play_announcement = 0;
1990                 }
1991         }
1992
1993         if (chan->_state != AST_STATE_UP)
1994                 res = ast_answer(chan);
1995         if (!res) {
1996                 if (!ast_strlen_zero(args.agent_id))
1997                         ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
1998                 else
1999                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
2000         }
2001         while (!res && (max_login_tries==0 || tries < max_login_tries)) {
2002                 tries++;
2003                 /* Check for password */
2004                 AST_LIST_LOCK(&agents);
2005                 AST_LIST_TRAVERSE(&agents, p, list) {
2006                         if (!strcmp(p->agent, user) && !p->pending)
2007                                 ast_copy_string(xpass, p->password, sizeof(xpass));
2008                 }
2009                 AST_LIST_UNLOCK(&agents);
2010                 if (!res) {
2011                         if (!ast_strlen_zero(xpass))
2012                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
2013                         else
2014                                 pass[0] = '\0';
2015                 }
2016                 errmsg = "agent-incorrect";
2017
2018 #if 0
2019                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
2020 #endif          
2021
2022                 /* Check again for accuracy */
2023                 AST_LIST_LOCK(&agents);
2024                 AST_LIST_TRAVERSE(&agents, p, list) {
2025                         int unlock_channel = 1;
2026                         ast_channel_lock(chan);
2027                         ast_mutex_lock(&p->lock);
2028                         if (!strcmp(p->agent, user) &&
2029                             !strcmp(p->password, pass) && !p->pending) {
2030
2031                                 /* Ensure we can't be gotten until we're done */
2032                                 p->lastdisc = ast_tvnow();
2033                                 p->lastdisc.tv_sec++;
2034
2035                                 /* Set Channel Specific Agent Overrides */
2036                                 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
2037                                         if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
2038                                                 p->ackcall = 1;
2039                                         } else {
2040                                                 p->ackcall = 0;
2041                                         }
2042                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
2043                                         ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent);
2044                                         ast_set_flag(p, AGENT_FLAG_ACKCALL);
2045                                 } else {
2046                                         p->ackcall = ackcall;
2047                                 }
2048                                 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
2049                                         p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
2050                                         if (p->autologoff < 0)
2051                                                 p->autologoff = 0;
2052                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
2053                                         ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent);
2054                                         ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF);
2055                                 } else {
2056                                         p->autologoff = autologoff;
2057                                 }
2058                                 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
2059                                         p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
2060                                         if (p->wrapuptime < 0)
2061                                                 p->wrapuptime = 0;
2062                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
2063                                         ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent);
2064                                         ast_set_flag(p, AGENT_FLAG_WRAPUPTIME);
2065                                 } else {
2066                                         p->wrapuptime = wrapuptime;
2067                                 }
2068                                 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
2069                                 if (!ast_strlen_zero(tmpoptions)) {
2070                                         p->acceptdtmf = *tmpoptions;
2071                                         ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent);
2072                                         ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF);
2073                                 }
2074                                 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF");
2075                                 if (!ast_strlen_zero(tmpoptions)) {
2076                                         p->enddtmf = *tmpoptions;
2077                                         ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent);
2078                                         ast_set_flag(p, AGENT_FLAG_ENDDTMF);
2079                                 }
2080                                 ast_channel_unlock(chan);
2081                                 unlock_channel = 0;
2082                                 /* End Channel Specific Agent Overrides */
2083                                 if (!p->chan) {
2084                                         long logintime;
2085                                         snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
2086
2087                                         p->logincallerid[0] = '\0';
2088                                         p->acknowledged = 0;
2089                                         
2090                                         ast_mutex_unlock(&p->lock);
2091                                         AST_LIST_UNLOCK(&agents);
2092                                         if( !res && play_announcement==1 )
2093                                                 res = ast_streamfile(chan, filename, ast_channel_language(chan));
2094                                         if (!res)
2095                                                 ast_waitstream(chan, "");
2096                                         AST_LIST_LOCK(&agents);
2097                                         ast_mutex_lock(&p->lock);
2098                                         if (!res) {
2099                                                 struct ast_format tmpfmt;
2100                                                 res = ast_set_read_format_from_cap(chan, chan->nativeformats);
2101                                                 if (res) {
2102                                                         ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(&tmpfmt));
2103                                                 }
2104                                         }
2105                                         if (!res) {
2106                                                 struct ast_format tmpfmt;
2107                                                 res = ast_set_write_format_from_cap(chan, chan->nativeformats);
2108                                                 if (res) {
2109                                                         ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(&tmpfmt));
2110                                                 }
2111                                         }
2112                                         /* Check once more just in case */
2113                                         if (p->chan)
2114                                                 res = -1;
2115                                         if (!res) {
2116                                                 ast_indicate_data(chan, AST_CONTROL_HOLD, 
2117                                                         S_OR(p->moh, NULL), 
2118                                                         !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
2119                                                 if (p->loginstart == 0)
2120                                                         time(&p->loginstart);
2121                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
2122                                                               "Agent: %s\r\n"
2123                                                               "Channel: %s\r\n"
2124                                                               "Uniqueid: %s\r\n",
2125                                                               p->agent, ast_channel_name(chan), ast_channel_uniqueid(chan));
2126                                                 if (update_cdr && chan->cdr)
2127                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2128                                                 ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGIN", "%s", ast_channel_name(chan));
2129                                                 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent,
2130                                                                     ast_getformatname(&chan->readformat), ast_getformatname(&chan->writeformat));
2131                                                 /* Login this channel and wait for it to go away */
2132                                                 p->chan = chan;
2133                                                 if (p->ackcall) {
2134                                                         check_beep(p, 0);
2135                                                 } else {
2136                                                         check_availability(p, 0);
2137                                                 }
2138                                                 ast_mutex_unlock(&p->lock);
2139                                                 AST_LIST_UNLOCK(&agents);
2140                                                 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
2141                                                 while (res >= 0) {
2142                                                         ast_mutex_lock(&p->lock);
2143                                                         if (p->deferlogoff && p->chan) {
2144                                                                 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
2145                                                                 p->deferlogoff = 0;
2146                                                         }
2147                                                         if (p->chan != chan)
2148                                                                 res = -1;
2149                                                         ast_mutex_unlock(&p->lock);
2150                                                         /* Yield here so other interested threads can kick in. */
2151                                                         sched_yield();
2152                                                         if (res)
2153                                                                 break;
2154
2155                                                         AST_LIST_LOCK(&agents);
2156                                                         ast_mutex_lock(&p->lock);
2157                                                         if (p->lastdisc.tv_sec) {
2158                                                                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
2159                                                                         ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
2160                                                                         p->lastdisc = ast_tv(0, 0);
2161                                                                         ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
2162                                                                         if (p->ackcall) {
2163                                                                                 check_beep(p, 0);
2164                                                                         } else {
2165                                                                                 check_availability(p, 0);
2166                                                                         }
2167                                                                 }
2168                                                         }
2169                                                         ast_mutex_unlock(&p->lock);
2170                                                         AST_LIST_UNLOCK(&agents);
2171
2172                                                         /*      Synchronize channel ownership between call to agent and itself. */
2173                                                         ast_mutex_lock(&p->lock);
2174                                                         if (p->app_lock_flag == 1) {
2175                                                                 ast_cond_signal(&p->login_wait_cond);
2176                                                                 ast_cond_wait(&p->app_complete_cond, &p->lock);
2177                                                         }
2178                                                         ast_mutex_unlock(&p->lock);
2179                                                         if (p->ackcall) {
2180                                                                 res = agent_ack_sleep(p);
2181                                                         } else {
2182                                                                 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
2183                                                         }
2184                                                         if (p->ackcall && (res == 1)) {
2185                                                                 AST_LIST_LOCK(&agents);
2186                                                                 ast_mutex_lock(&p->lock);
2187                                                                 check_availability(p, 0);
2188                                                                 ast_mutex_unlock(&p->lock);
2189                                                                 AST_LIST_UNLOCK(&agents);
2190                                                                 res = 0;
2191                                                         }
2192                                                         sched_yield();
2193                                                 }
2194                                                 ast_mutex_lock(&p->lock);
2195                                                 /* Log us off if appropriate */
2196                                                 if (p->chan == chan) {
2197                                                         p->chan = NULL;
2198                                                 }
2199
2200                                                 /* Synchronize channel ownership between call to agent and itself. */
2201                                                 if (p->app_lock_flag == 1) {
2202                                                         ast_cond_signal(&p->login_wait_cond);
2203                                                         ast_cond_wait(&p->app_complete_cond, &p->lock);
2204                                                 }
2205
2206                                                 if (res && p->owner)
2207                                                         ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
2208
2209                                                 p->acknowledged = 0;
2210                                                 logintime = time(NULL) - p->loginstart;
2211                                                 p->loginstart = 0;
2212                                                 ast_mutex_unlock(&p->lock);
2213                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
2214                                                               "Agent: %s\r\n"
2215                                                               "Logintime: %ld\r\n"
2216                                                               "Uniqueid: %s\r\n",
2217                                                               p->agent, logintime, ast_channel_uniqueid(chan));
2218                                                 ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGOFF", "%s|%ld", ast_channel_name(chan), logintime);
2219                                                 ast_verb(2, "Agent '%s' logged out\n", p->agent);
2220                                                 /* If there is no owner, go ahead and kill it now */
2221                                                 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
2222                                                 if (p->dead && !p->owner) {
2223                                                         ast_mutex_destroy(&p->lock);
2224                                                         ast_cond_destroy(&p->app_complete_cond);
2225                                                         ast_cond_destroy(&p->login_wait_cond);
2226                                                         ast_free(p);
2227                                                 }
2228                                         }
2229                                         else {
2230                                                 ast_mutex_unlock(&p->lock);
2231                                                 p = NULL;
2232                                         }
2233                                         res = -1;
2234                                 } else {
2235                                         ast_mutex_unlock(&p->lock);
2236                                         errmsg = "agent-alreadyon";
2237                                         p = NULL;
2238                                 }
2239                                 break;
2240                         }
2241                         ast_mutex_unlock(&p->lock);
2242                         if (unlock_channel) {
2243                                 ast_channel_unlock(chan);
2244                         }
2245                 }
2246                 if (!p)
2247                         AST_LIST_UNLOCK(&agents);
2248
2249                 if (!res && (max_login_tries==0 || tries < max_login_tries))
2250                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2251         }
2252                 
2253         if (!res)
2254                 res = ast_safe_sleep(chan, 500);
2255
2256         ast_module_user_remove(u);
2257         
2258         return -1;
2259 }
2260
2261 /*!
2262  *  \brief Called by the AgentMonitorOutgoing application (from the dial plan).
2263  *
2264  * \param chan
2265  * \param data
2266  * \returns
2267  * \sa login_exec(), load_module().
2268  */
2269 static int agentmonitoroutgoing_exec(struct ast_channel *chan, const char *data)
2270 {
2271         int exitifnoagentid = 0;
2272         int nowarnings = 0;
2273         int changeoutgoing = 0;
2274         int res = 0;
2275         char agent[AST_MAX_AGENT];
2276
2277         if (data) {
2278                 if (strchr(data, 'd'))
2279                         exitifnoagentid = 1;
2280                 if (strchr(data, 'n'))
2281                         nowarnings = 1;
2282                 if (strchr(data, 'c'))
2283                         changeoutgoing = 1;
2284         }
2285         if (chan->caller.id.number.valid
2286                 && !ast_strlen_zero(chan->caller.id.number.str)) {
2287                 const char *tmp;
2288                 char agentvar[AST_MAX_BUF];
2289                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID,
2290                         chan->caller.id.number.str);
2291                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2292                         struct agent_pvt *p;
2293                         ast_copy_string(agent, tmp, sizeof(agent));
2294                         AST_LIST_LOCK(&agents);
2295                         AST_LIST_TRAVERSE(&agents, p, list) {
2296                                 if (!strcasecmp(p->agent, tmp)) {
2297                                         if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2298                                         __agent_start_monitoring(chan, p, 1);
2299                                         break;
2300                                 }
2301                         }
2302                         AST_LIST_UNLOCK(&agents);
2303                         
2304                 } else {
2305                         res = -1;
2306                         if (!nowarnings)
2307                                 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);
2308                 }
2309         } else {
2310                 res = -1;
2311                 if (!nowarnings)
2312                         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");
2313         }
2314         if (res) {
2315                 if (exitifnoagentid)
2316                         return res;
2317         }
2318         return 0;
2319 }
2320
2321 /*! \brief Part of PBX channel interface */
2322 static int agent_devicestate(const char *data)
2323 {
2324         struct agent_pvt *p;
2325         const char *s;
2326         ast_group_t groupmatch;
2327         int groupoff;
2328         int res = AST_DEVICE_INVALID;
2329         
2330         s = data;
2331         if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1))
2332                 groupmatch = (1 << groupoff);
2333         else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
2334                 groupmatch = (1 << groupoff);
2335         } else 
2336                 groupmatch = 0;
2337
2338         /* Check actual logged in agents first */
2339         AST_LIST_LOCK(&agents);
2340         AST_LIST_TRAVERSE(&agents, p, list) {
2341                 ast_mutex_lock(&p->lock);
2342                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2343                         if (p->owner) {
2344                                 if (res != AST_DEVICE_INUSE)
2345                                         res = AST_DEVICE_BUSY;
2346                         } else {
2347                                 if (res == AST_DEVICE_BUSY)
2348                                         res = AST_DEVICE_INUSE;
2349                                 if (p->chan) {
2350                                         if (res == AST_DEVICE_INVALID)
2351                                                 res = AST_DEVICE_UNKNOWN;
2352                                 } else if (res == AST_DEVICE_INVALID)   
2353                                         res = AST_DEVICE_UNAVAILABLE;
2354                         }
2355                         if (!strcmp(data, p->agent)) {
2356                                 ast_mutex_unlock(&p->lock);
2357                                 break;
2358                         }
2359                 }
2360                 ast_mutex_unlock(&p->lock);
2361         }
2362         AST_LIST_UNLOCK(&agents);
2363         return res;
2364 }
2365
2366 /*!
2367  * \note This function expects the agent list to be locked
2368  */
2369 static struct agent_pvt *find_agent(char *agentid)
2370 {
2371         struct agent_pvt *cur;
2372
2373         AST_LIST_TRAVERSE(&agents, cur, list) {
2374                 if (!strcmp(cur->agent, agentid))
2375                         break;  
2376         }
2377
2378         return cur;     
2379 }
2380
2381 static int function_agent(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
2382 {
2383         char *parse;    
2384         AST_DECLARE_APP_ARGS(args,
2385                 AST_APP_ARG(agentid);
2386                 AST_APP_ARG(item);
2387         );
2388         char *tmp;
2389         struct agent_pvt *agent;
2390
2391         buf[0] = '\0';
2392
2393         if (ast_strlen_zero(data)) {
2394                 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2395                 return -1;
2396         }
2397
2398         parse = ast_strdupa(data);
2399
2400         AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2401         if (!args.item)
2402                 args.item = "status";
2403
2404         AST_LIST_LOCK(&agents);
2405
2406         if (!(agent = find_agent(args.agentid))) {
2407                 AST_LIST_UNLOCK(&agents);
2408                 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2409                 return -1;
2410         }
2411
2412         if (!strcasecmp(args.item, "status")) {
2413                 char *status = "LOGGEDOUT";
2414                 if (agent->chan) {
2415                         status = "LOGGEDIN";
2416                 }
2417                 ast_copy_string(buf, status, len);
2418         } else if (!strcasecmp(args.item, "password")) 
2419                 ast_copy_string(buf, agent->password, len);
2420         else if (!strcasecmp(args.item, "name"))
2421                 ast_copy_string(buf, agent->name, len);
2422         else if (!strcasecmp(args.item, "mohclass"))
2423                 ast_copy_string(buf, agent->moh, len);
2424         else if (!strcasecmp(args.item, "channel")) {
2425                 if (agent->chan) {
2426                         ast_channel_lock(agent->chan);
2427                         ast_copy_string(buf, ast_channel_name(agent->chan), len);
2428                         ast_channel_unlock(agent->chan);
2429                         tmp = strrchr(buf, '-');
2430                         if (tmp)
2431                                 *tmp = '\0';
2432                 } 
2433         } else if (!strcasecmp(args.item, "fullchannel")) {
2434                 if (agent->chan) {
2435                         ast_channel_lock(agent->chan);
2436                         ast_copy_string(buf, ast_channel_name(agent->chan), len);
2437                         ast_channel_unlock(agent->chan);
2438                 } 
2439         } else if (!strcasecmp(args.item, "exten")) {
2440                 buf[0] = '\0';
2441         }
2442
2443         AST_LIST_UNLOCK(&agents);
2444
2445         return 0;
2446 }
2447
2448 static struct ast_custom_function agent_function = {
2449         .name = "AGENT",
2450         .read = function_agent,
2451 };
2452
2453 /*!
2454  * \internal
2455  * \brief Callback used to generate the agents tree.
2456  * \param[in] search The search pattern tree.
2457  * \retval NULL on error.
2458  * \retval non-NULL The generated tree.
2459  */
2460 static int agents_data_provider_get(const struct ast_data_search *search,
2461         struct ast_data *data_root)
2462 {
2463         struct agent_pvt *p;
2464         struct ast_data *data_agent, *data_channel, *data_talkingto;
2465
2466         AST_LIST_LOCK(&agents);
2467         AST_LIST_TRAVERSE(&agents, p, list) {
2468                 struct ast_channel *owner;
2469
2470                 data_agent = ast_data_add_node(data_root, "agent");
2471                 if (!data_agent) {
2472                         continue;
2473                 }
2474
2475                 ast_mutex_lock(&p->lock);
2476                 owner = agent_lock_owner(p);
2477
2478                 if (!(p->pending)) {
2479                         ast_data_add_str(data_agent, "id", p->agent);
2480                         ast_data_add_structure(agent_pvt, data_agent, p);
2481
2482                         ast_data_add_bool(data_agent, "logged", p->chan ? 1 : 0);
2483                         if (p->chan) {
2484                                 data_channel = ast_data_add_node(data_agent, "loggedon");
2485                                 if (!data_channel) {
2486                                         ast_mutex_unlock(&p->lock);
2487                                         ast_data_remove_node(data_root, data_agent);
2488                                         if (owner) {
2489                                                 ast_channel_unlock(owner);
2490                                                 owner = ast_channel_unref(owner);
2491                                         }
2492                                         continue;
2493                                 }
2494                                 ast_channel_data_add_structure(data_channel, p->chan, 0);
2495                                 if (owner && ast_bridged_channel(owner)) {
2496                                         data_talkingto = ast_data_add_node(data_agent, "talkingto");
2497                                         if (!data_talkingto) {
2498                                                 ast_mutex_unlock(&p->lock);
2499                                                 ast_data_remove_node(data_root, data_agent);
2500                                                 if (owner) {
2501                                                         ast_channel_unlock(owner);
2502                                                         owner = ast_channel_unref(owner);
2503                                                 }
2504                                                 continue;
2505                                         }
2506                                         ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0);
2507                                 }
2508                         } else {
2509                                 ast_data_add_node(data_agent, "talkingto");
2510                                 ast_data_add_node(data_agent, "loggedon");
2511                         }
2512                         ast_data_add_str(data_agent, "musiconhold", p->moh);
2513                 }
2514
2515                 if (owner) {
2516                         ast_channel_unlock(owner);
2517                         owner = ast_channel_unref(owner);
2518                 }
2519
2520                 ast_mutex_unlock(&p->lock);
2521
2522                 /* if this agent doesn't match remove the added agent. */
2523                 if (!ast_data_search_match(search, data_agent)) {
2524                         ast_data_remove_node(data_root, data_agent);
2525                 }
2526         }
2527         AST_LIST_UNLOCK(&agents);
2528
2529         return 0;
2530 }
2531
2532 static const struct ast_data_handler agents_data_provider = {
2533         .version = AST_DATA_HANDLER_VERSION,
2534         .get = agents_data_provider_get
2535 };
2536
2537 static const struct ast_data_entry agents_data_providers[] = {
2538         AST_DATA_ENTRY("asterisk/channel/agent/list", &agents_data_provider),
2539 };
2540
2541 /*!
2542  * \brief Initialize the Agents module.
2543  * This function is being called by Asterisk when loading the module. 
2544  * Among other things it registers applications, cli commands and reads the cofiguration file.
2545  *
2546  * \returns int Always 0.
2547  */
2548 static int load_module(void)
2549 {
2550         if (!(agent_tech.capabilities = ast_format_cap_alloc())) {
2551                 ast_log(LOG_ERROR, "ast_format_cap_alloc_nolock fail.\n");
2552                 return AST_MODULE_LOAD_FAILURE;
2553         }
2554         ast_format_cap_add_all(agent_tech.capabilities);
2555         /* Make sure we can register our agent channel type */
2556         if (ast_channel_register(&agent_tech)) {
2557                 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
2558                 return AST_MODULE_LOAD_FAILURE;
2559         }
2560         /* Read in the config */
2561         if (!read_agent_config(0))
2562                 return AST_MODULE_LOAD_DECLINE;
2563         /* Dialplan applications */
2564         ast_register_application_xml(app, login_exec);
2565         ast_register_application_xml(app3, agentmonitoroutgoing_exec);
2566
2567         /* data tree */
2568         ast_data_register_multiple(agents_data_providers, ARRAY_LEN(agents_data_providers));
2569
2570         /* Manager commands */
2571         ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
2572         ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
2573
2574         /* CLI Commands */
2575         ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
2576
2577         /* Dialplan Functions */
2578         ast_custom_function_register(&agent_function);
2579
2580         return AST_MODULE_LOAD_SUCCESS;
2581 }
2582
2583 static int reload(void)
2584 {
2585         return read_agent_config(1);
2586 }
2587
2588 static int unload_module(void)
2589 {
2590         struct agent_pvt *p;
2591         /* First, take us out of the channel loop */
2592         ast_channel_unregister(&agent_tech);
2593         /* Unregister dialplan functions */
2594         ast_custom_function_unregister(&agent_function);        
2595         /* Unregister CLI commands */
2596         ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
2597         /* Unregister dialplan applications */
2598         ast_unregister_application(app);
2599         ast_unregister_application(app3);
2600         /* Unregister manager command */
2601         ast_manager_unregister("Agents");
2602         ast_manager_unregister("AgentLogoff");
2603         /* Unregister the data tree */
2604         ast_data_unregister(NULL);
2605         /* Unregister channel */
2606         AST_LIST_LOCK(&agents);
2607         /* Hangup all interfaces if they have an owner */
2608         while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
2609                 if (p->owner)
2610                         ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2611                 ast_free(p);
2612         }
2613         AST_LIST_UNLOCK(&agents);
2614
2615         agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
2616         return 0;
2617 }
2618
2619 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Agent Proxy Channel",
2620                 .load = load_module,
2621                 .unload = unload_module,
2622                 .reload = reload,
2623                 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
2624                 .nonoptreq = "res_monitor,chan_local",
2625                );