media formats: re-architect handling of media for performance improvements
[asterisk/asterisk.git] / apps / app_agent_pool.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013 Digium, Inc.
5  *
6  * Richard Mudgett <rmudgett@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  * \brief Call center agent pool.
22  *
23  * \author Richard Mudgett <rmudgett@digium.com>
24  *
25  * See Also:
26  * \arg \ref AstCREDITS
27  * \arg \ref Config_agent
28  */
29 /*** MODULEINFO
30         <support_level>core</support_level>
31  ***/
32
33
34 #include "asterisk.h"
35
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37
38 #include "asterisk/cli.h"
39 #include "asterisk/app.h"
40 #include "asterisk/pbx.h"
41 #include "asterisk/module.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/bridge.h"
44 #include "asterisk/bridge_internal.h"
45 #include "asterisk/bridge_basic.h"
46 #include "asterisk/bridge_after.h"
47 #include "asterisk/config_options.h"
48 #include "asterisk/features_config.h"
49 #include "asterisk/astobj2.h"
50 #include "asterisk/stringfields.h"
51 #include "asterisk/stasis_channels.h"
52 #include "asterisk/causes.h"
53
54 /*** DOCUMENTATION
55         <application name="AgentLogin" language="en_US">
56                 <synopsis>
57                         Login an agent.
58                 </synopsis>
59                 <syntax argsep=",">
60                         <parameter name="AgentId" required="true" />
61                         <parameter name="options">
62                                 <optionlist>
63                                         <option name="s">
64                                                 <para>silent login - do not announce the login ok segment after
65                                                 agent logged on.</para>
66                                         </option>
67                                 </optionlist>
68                         </parameter>
69                 </syntax>
70                 <description>
71                         <para>Login an agent to the system.  Any agent authentication is assumed to
72                         already be done by dialplan.  While logged in, the agent can receive calls
73                         and will hear the sound file specified by the config option custom_beep
74                         when a new call comes in for the agent.  Login failures will continue in
75                         the dialplan with <variable>AGENT_STATUS</variable> set.</para>
76                         <para>Before logging in, you can setup on the real agent channel the
77                         CHANNEL(dtmf-features) an agent will have when talking to a caller
78                         and you can setup on the channel running this application the
79                         CONNECTEDLINE() information the agent will see while waiting for a
80                         caller.</para>
81                         <para><variable>AGENT_STATUS</variable> enumeration values:</para>
82                         <enumlist>
83                                 <enum name = "INVALID"><para>The specified agent is invalid.</para></enum>
84                                 <enum name = "ALREADY_LOGGED_IN"><para>The agent is already logged in.</para></enum>
85                         </enumlist>
86                         <note><para>The Agents:<replaceable>AgentId</replaceable> device state is
87                         available to monitor the status of the agent.</para></note>
88                 </description>
89                 <see-also>
90                         <ref type="application">Authenticate</ref>
91                         <ref type="application">Queue</ref>
92                         <ref type="application">AddQueueMember</ref>
93                         <ref type="application">RemoveQueueMember</ref>
94                         <ref type="application">PauseQueueMember</ref>
95                         <ref type="application">UnpauseQueueMember</ref>
96                         <ref type="function">AGENT</ref>
97                         <ref type="function">CHANNEL(dtmf-features)</ref>
98                         <ref type="function">CONNECTEDLINE()</ref>
99                         <ref type="filename">agents.conf</ref>
100                         <ref type="filename">queues.conf</ref>
101                 </see-also>
102         </application>
103         <application name="AgentRequest" language="en_US">
104                 <synopsis>
105                         Request an agent to connect with the channel.
106                 </synopsis>
107                 <syntax argsep=",">
108                         <parameter name="AgentId" required="true" />
109                 </syntax>
110                 <description>
111                         <para>Request an agent to connect with the channel.  Failure to find,
112                         alert the agent, or acknowledge the call will continue in the dialplan
113                         with <variable>AGENT_STATUS</variable> set.</para>
114                         <para><variable>AGENT_STATUS</variable> enumeration values:</para>
115                         <enumlist>
116                                 <enum name = "INVALID"><para>The specified agent is invalid.</para></enum>
117                                 <enum name = "NOT_LOGGED_IN"><para>The agent is not available.</para></enum>
118                                 <enum name = "BUSY"><para>The agent is on another call.</para></enum>
119                                 <enum name = "NOT_CONNECTED"><para>The agent did not connect with the
120                                 call.  The agent most likely did not acknowledge the call.</para></enum>
121                                 <enum name = "ERROR"><para>Alerting the agent failed.</para></enum>
122                         </enumlist>
123                 </description>
124                 <see-also>
125                         <ref type="application">AgentLogin</ref>
126                 </see-also>
127         </application>
128         <function name="AGENT" language="en_US">
129                 <synopsis>
130                         Gets information about an Agent
131                 </synopsis>
132                 <syntax argsep=":">
133                         <parameter name="AgentId" required="true" />
134                         <parameter name="item">
135                                 <para>The valid items to retrieve are:</para>
136                                 <enumlist>
137                                         <enum name="status">
138                                                 <para>(default) The status of the agent (LOGGEDIN | LOGGEDOUT)</para>
139                                         </enum>
140                                         <enum name="password">
141                                                 <para>Deprecated.  The dialplan handles any agent authentication.</para>
142                                         </enum>
143                                         <enum name="name">
144                                                 <para>The name of the agent</para>
145                                         </enum>
146                                         <enum name="mohclass">
147                                                 <para>MusicOnHold class</para>
148                                         </enum>
149                                         <enum name="channel">
150                                                 <para>The name of the active channel for the Agent (AgentLogin)</para>
151                                         </enum>
152                                         <enum name="fullchannel">
153                                                 <para>The untruncated name of the active channel for the Agent (AgentLogin)</para>
154                                         </enum>
155                                 </enumlist>
156                         </parameter>
157                 </syntax>
158                 <description></description>
159         </function>
160         <manager name="Agents" language="en_US">
161                 <synopsis>
162                         Lists agents and their status.
163                 </synopsis>
164                 <syntax>
165                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
166                 </syntax>
167                 <description>
168                         <para>Will list info about all defined agents.</para>
169                 </description>
170                 <see-also>
171                         <ref type="managerEvent">Agents</ref>
172                         <ref type="managerEvent">AgentsComplete</ref>
173                 </see-also>
174         </manager>
175         <managerEvent language="en_US" name="Agents">
176                 <managerEventInstance class="EVENT_FLAG_AGENT">
177                         <synopsis>
178                                 Response event in a series to the Agents AMI action containing
179                                 information about a defined agent.
180                         </synopsis>
181                         <syntax>
182                                 <parameter name="Agent">
183                                         <para>Agent ID of the agent.</para>
184                                 </parameter>
185                                 <parameter name="Name">
186                                         <para>User friendly name of the agent.</para>
187                                 </parameter>
188                                 <parameter name="Status">
189                                         <para>Current status of the agent.</para>
190                                         <para>The valid values are:</para>
191                                         <enumlist>
192                                                 <enum name="AGENT_LOGGEDOFF" />
193                                                 <enum name="AGENT_IDLE" />
194                                                 <enum name="AGENT_ONCALL" />
195                                         </enumlist>
196                                 </parameter>
197                                 <parameter name="TalkingToChan">
198                                         <para><variable>BRIDGEPEER</variable> value on agent channel.</para>
199                                         <para>Present if Status value is <literal>AGENT_ONCALL</literal>.</para>
200                                 </parameter>
201                                 <parameter name="CallStarted">
202                                         <para>Epoche time when the agent started talking with the caller.</para>
203                                         <para>Present if Status value is <literal>AGENT_ONCALL</literal>.</para>
204                                 </parameter>
205                                 <parameter name="LoggedInTime">
206                                         <para>Epoche time when the agent logged in.</para>
207                                         <para>Present if Status value is <literal>AGENT_IDLE</literal> or <literal>AGENT_ONCALL</literal>.</para>
208                                 </parameter>
209                                 <channel_snapshot/>
210                                 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
211                         </syntax>
212                         <description>
213                                 <para>The channel snapshot is present if the Status value is <literal>AGENT_IDLE</literal> or <literal>AGENT_ONCALL</literal>.</para>
214                         </description>
215                         <see-also>
216                                 <ref type="manager">Agents</ref>
217                         </see-also>
218                 </managerEventInstance>
219         </managerEvent>
220         <managerEvent language="en_US" name="AgentsComplete">
221                 <managerEventInstance class="EVENT_FLAG_AGENT">
222                         <synopsis>
223                                 Final response event in a series of events to the Agents AMI action.
224                         </synopsis>
225                         <syntax>
226                                 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
227                         </syntax>
228                         <see-also>
229                                 <ref type="manager">Agents</ref>
230                         </see-also>
231                 </managerEventInstance>
232         </managerEvent>
233         <manager name="AgentLogoff" language="en_US">
234                 <synopsis>
235                         Sets an agent as no longer logged in.
236                 </synopsis>
237                 <syntax>
238                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
239                         <parameter name="Agent" required="true">
240                                 <para>Agent ID of the agent to log off.</para>
241                         </parameter>
242                         <parameter name="Soft">
243                                 <para>Set to <literal>true</literal> to not hangup existing calls.</para>
244                         </parameter>
245                 </syntax>
246                 <description>
247                         <para>Sets an agent as no longer logged in.</para>
248                 </description>
249         </manager>
250         <configInfo name="app_agent_pool" language="en_US">
251                 <synopsis>Agent pool applications</synopsis>
252                 <description>
253                         <note><para>Option changes take effect on agent login or after an agent
254                         disconnects from a call.</para></note>
255                 </description>
256                 <configFile name="agents.conf">
257                         <configObject name="global">
258                                 <synopsis>Unused, but reserved.</synopsis>
259                         </configObject>
260                         <configObject name="agent-id">
261                                 <synopsis>Configure an agent for the pool.</synopsis>
262                                 <description>
263                                         <xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
264                                 </description>
265                                 <configOption name="ackcall">
266                                         <synopsis>Enable to require the agent to acknowledge a call.</synopsis>
267                                         <description>
268                                                 <para>Enable to require the agent to give a DTMF acknowledgement
269                                                 when the agent receives a call.</para>
270                                                 <note><para>The option is overridden by <variable>AGENTACKCALL</variable> on agent login.</para></note>
271                                                 <xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
272                                         </description>
273                                 </configOption>
274                                 <configOption name="acceptdtmf">
275                                         <synopsis>DTMF key sequence the agent uses to acknowledge a call.</synopsis>
276                                         <description>
277                                                 <note><para>The option is overridden by <variable>AGENTACCEPTDTMF</variable> on agent login.</para></note>
278                                                 <note><para>The option is ignored unless the ackcall option is enabled.</para></note>
279                                                 <xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
280                                         </description>
281                                 </configOption>
282                                 <configOption name="autologoff">
283                                         <synopsis>Time the agent has to acknowledge a call before being logged off.</synopsis>
284                                         <description>
285                                                 <para>Set how many seconds a call for the agent has to wait for the
286                                                 agent to acknowledge the call before the agent is automatically
287                                                 logged off.  If set to zero then the call will wait forever for
288                                                 the agent to acknowledge.</para>
289                                                 <note><para>The option is overridden by <variable>AGENTAUTOLOGOFF</variable> on agent login.</para></note>
290                                                 <note><para>The option is ignored unless the ackcall option is enabled.</para></note>
291                                                 <xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
292                                         </description>
293                                 </configOption>
294                                 <configOption name="wrapuptime">
295                                         <synopsis>Minimum time the agent has between calls.</synopsis>
296                                         <description>
297                                                 <para>Set the minimum amount of time in milliseconds after
298                                                 disconnecting a call before the agent can receive a new call.</para>
299                                                 <note><para>The option is overridden by <variable>AGENTWRAPUPTIME</variable> on agent login.</para></note>
300                                                 <xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
301                                         </description>
302                                 </configOption>
303                                 <configOption name="musiconhold">
304                                         <synopsis>Music on hold class the agent listens to between calls.</synopsis>
305                                         <description>
306                                                 <xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
307                                         </description>
308                                 </configOption>
309                                 <configOption name="recordagentcalls">
310                                         <synopsis>Enable to automatically record calls the agent takes.</synopsis>
311                                         <description>
312                                                 <para>Enable recording calls the agent takes automatically by
313                                                 invoking the automixmon DTMF feature when the agent connects
314                                                 to a caller.  See <filename>features.conf.sample</filename> for information about
315                                                 the automixmon feature.</para>
316                                                 <xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
317                                         </description>
318                                 </configOption>
319                                 <configOption name="custom_beep">
320                                         <synopsis>Sound file played to alert the agent when a call is present.</synopsis>
321                                         <description>
322                                                 <xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
323                                         </description>
324                                 </configOption>
325                                 <configOption name="fullname">
326                                         <synopsis>A friendly name for the agent used in log messages.</synopsis>
327                                         <description>
328                                                 <xi:include xpointer="xpointer(/docs/configInfo[@name='app_agent_pool']/description/note)" />
329                                         </description>
330                                 </configOption>
331                         </configObject>
332                 </configFile>
333         </configInfo>
334  ***/
335
336 /* ------------------------------------------------------------------- */
337
338 #define AST_MAX_BUF     256
339
340 /*! Maximum wait time (in ms) for the custom_beep file to play announcing the caller. */
341 #define CALLER_SAFETY_TIMEOUT_TIME      (2 * 60 * 1000)
342
343 /*! Number of seconds to wait for local channel optimizations to complete. */
344 #define LOGIN_WAIT_TIMEOUT_TIME         5
345
346 static const char app_agent_login[] = "AgentLogin";
347 static const char app_agent_request[] = "AgentRequest";
348
349 /*! Agent config parameters. */
350 struct agent_cfg {
351         AST_DECLARE_STRING_FIELDS(
352                 /*! Identification of the agent.  (agents config container key) */
353                 AST_STRING_FIELD(username);
354                 /*! Name of agent for logging and querying purposes */
355                 AST_STRING_FIELD(full_name);
356
357                 /*!
358                  * \brief DTMF string for an agent to accept a call.
359                  *
360                  * \note The channel variable AGENTACCEPTDTMF overrides on login.
361                  */
362                 AST_STRING_FIELD(dtmf_accept);
363                 /*! Beep sound file to use.  Alert the agent a call is waiting. */
364                 AST_STRING_FIELD(beep_sound);
365                 /*! MOH class to use while agent waiting for call. */
366                 AST_STRING_FIELD(moh);
367         );
368         /*!
369          * \brief Number of seconds for agent to ack a call before being logged off.
370          *
371          * \note The channel variable AGENTAUTOLOGOFF overrides on login.
372          * \note If zero then timer is disabled.
373          */
374         unsigned int auto_logoff;
375         /*!
376          * \brief Time after a call in ms before the agent can get a new call.
377          *
378          * \note The channel variable AGENTWRAPUPTIME overrides on login.
379          */
380         unsigned int wrapup_time;
381         /*!
382          * \brief TRUE if agent needs to ack a call to accept it.
383          *
384          * \note The channel variable AGENTACKCALL overrides on login.
385          */
386         int ack_call;
387         /*! TRUE if agent calls are automatically recorded. */
388         int record_agent_calls;
389 };
390
391 /*!
392  * \internal
393  * \brief Agent config ao2 container sort function.
394  * \since 12.0.0
395  *
396  * \param obj_left pointer to the (user-defined part) of an object.
397  * \param obj_right pointer to the (user-defined part) of an object.
398  * \param flags flags from ao2_callback()
399  *   OBJ_POINTER - if set, 'obj_right', is an object.
400  *   OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
401  *   OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
402  *
403  * \retval <0 if obj_left < obj_right
404  * \retval =0 if obj_left == obj_right
405  * \retval >0 if obj_left > obj_right
406  */
407 static int agent_cfg_sort_cmp(const void *obj_left, const void *obj_right, int flags)
408 {
409         const struct agent_cfg *cfg_left = obj_left;
410         const struct agent_cfg *cfg_right = obj_right;
411         const char *right_key = obj_right;
412         int cmp;
413
414         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
415         default:
416         case OBJ_POINTER:
417                 right_key = cfg_right->username;
418                 /* Fall through */
419         case OBJ_KEY:
420                 cmp = strcmp(cfg_left->username, right_key);
421                 break;
422         case OBJ_PARTIAL_KEY:
423                 cmp = strncmp(cfg_left->username, right_key, strlen(right_key));
424                 break;
425         }
426         return cmp;
427 }
428
429 static void agent_cfg_destructor(void *vdoomed)
430 {
431         struct agent_cfg *doomed = vdoomed;
432
433         ast_string_field_free_memory(doomed);
434 }
435
436 static void *agent_cfg_alloc(const char *name)
437 {
438         struct agent_cfg *cfg;
439
440         cfg = ao2_alloc_options(sizeof(*cfg), agent_cfg_destructor,
441                 AO2_ALLOC_OPT_LOCK_NOLOCK);
442         if (!cfg || ast_string_field_init(cfg, 64)) {
443                 return NULL;
444         }
445         ast_string_field_set(cfg, username, name);
446         return cfg;
447 }
448
449 static void *agent_cfg_find(struct ao2_container *agents, const char *username)
450 {
451         return ao2_find(agents, username, OBJ_KEY);
452 }
453
454 /*! Agents configuration */
455 struct agents_cfg {
456         /*! Master configured agents container. */
457         struct ao2_container *agents;
458 };
459
460 static struct aco_type agent_type = {
461         .type = ACO_ITEM,
462         .name = "agent-id",
463         .category_match = ACO_BLACKLIST,
464         .category = "^(general|agents)$",
465         .item_alloc = agent_cfg_alloc,
466         .item_find = agent_cfg_find,
467         .item_offset = offsetof(struct agents_cfg, agents),
468 };
469
470 static struct aco_type *agent_types[] = ACO_TYPES(&agent_type);
471
472 /* The general category is reserved, but unused */
473 static struct aco_type general_type = {
474         .type = ACO_GLOBAL,
475         .name = "global",
476         .category_match = ACO_WHITELIST,
477         .category = "^general$",
478 };
479
480 static struct aco_file agents_conf = {
481         .filename = "agents.conf",
482         .types = ACO_TYPES(&general_type, &agent_type),
483 };
484
485 static AO2_GLOBAL_OBJ_STATIC(cfg_handle);
486
487 static void agents_cfg_destructor(void *vdoomed)
488 {
489         struct agents_cfg *doomed = vdoomed;
490
491         ao2_cleanup(doomed->agents);
492         doomed->agents = NULL;
493 }
494
495 /*!
496  * \internal
497  * \brief Create struct agents_cfg object.
498  * \since 12.0.0
499  *
500  * \note A lock is not needed for the object or any secondary
501  * created cfg objects.  These objects are immutable after the
502  * config is loaded and applied.
503  *
504  * \retval New struct agents_cfg object.
505  * \retval NULL on error.
506  */
507 static void *agents_cfg_alloc(void)
508 {
509         struct agents_cfg *cfg;
510
511         cfg = ao2_alloc_options(sizeof(*cfg), agents_cfg_destructor,
512                 AO2_ALLOC_OPT_LOCK_NOLOCK);
513         if (!cfg) {
514                 return NULL;
515         }
516         cfg->agents = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
517                 AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, agent_cfg_sort_cmp, NULL);
518         if (!cfg->agents) {
519                 ao2_ref(cfg, -1);
520                 cfg = NULL;
521         }
522         return cfg;
523 }
524
525 static void agents_post_apply_config(void);
526
527 CONFIG_INFO_STANDARD(cfg_info, cfg_handle, agents_cfg_alloc,
528         .files = ACO_FILES(&agents_conf),
529         .post_apply_config = agents_post_apply_config,
530 );
531
532 static void destroy_config(void)
533 {
534         ao2_global_obj_release(cfg_handle);
535         aco_info_destroy(&cfg_info);
536 }
537
538 static int load_config(void)
539 {
540         if (aco_info_init(&cfg_info)) {
541                 return -1;
542         }
543
544         /* Agent options */
545         aco_option_register(&cfg_info, "ackcall", ACO_EXACT, agent_types, "no", OPT_BOOL_T, 1, FLDSET(struct agent_cfg, ack_call));
546         aco_option_register(&cfg_info, "acceptdtmf", ACO_EXACT, agent_types, "#", OPT_STRINGFIELD_T, 1, STRFLDSET(struct agent_cfg, dtmf_accept));
547         aco_option_register(&cfg_info, "autologoff", ACO_EXACT, agent_types, "0", OPT_UINT_T, 0, FLDSET(struct agent_cfg, auto_logoff));
548         aco_option_register(&cfg_info, "wrapuptime", ACO_EXACT, agent_types, "0", OPT_UINT_T, 0, FLDSET(struct agent_cfg, wrapup_time));
549         aco_option_register(&cfg_info, "musiconhold", ACO_EXACT, agent_types, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, moh));
550         aco_option_register(&cfg_info, "recordagentcalls", ACO_EXACT, agent_types, "no", OPT_BOOL_T, 1, FLDSET(struct agent_cfg, record_agent_calls));
551         aco_option_register(&cfg_info, "custom_beep", ACO_EXACT, agent_types, "beep", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, beep_sound));
552         aco_option_register(&cfg_info, "fullname", ACO_EXACT, agent_types, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, full_name));
553
554         if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
555                 goto error;
556         }
557
558         return 0;
559
560 error:
561         destroy_config();
562         return -1;
563 }
564
565 enum agent_state {
566         /*! The agent is defined but an agent is not present. */
567         AGENT_STATE_LOGGED_OUT,
568         /*! Forced initial login wait to allow any local channel optimizations to happen. */
569         AGENT_STATE_PROBATION_WAIT,
570         /*! The agent is ready for a call. */
571         AGENT_STATE_READY_FOR_CALL,
572         /*! The agent has a call waiting to connect. */
573         AGENT_STATE_CALL_PRESENT,
574         /*! The agent needs to ack the call. */
575         AGENT_STATE_CALL_WAIT_ACK,
576         /*! The agent is connected with a call. */
577         AGENT_STATE_ON_CALL,
578         /*! The agent is resting between calls. */
579         AGENT_STATE_CALL_WRAPUP,
580         /*! The agent is being kicked out. */
581         AGENT_STATE_LOGGING_OUT,
582 };
583
584 /*! Agent config option override flags. */
585 enum agent_override_flags {
586         AGENT_FLAG_ACK_CALL = (1 << 0),
587         AGENT_FLAG_DTMF_ACCEPT = (1 << 1),
588         AGENT_FLAG_AUTO_LOGOFF = (1 << 2),
589         AGENT_FLAG_WRAPUP_TIME = (1 << 3),
590 };
591
592 /*! \brief Structure representing an agent. */
593 struct agent_pvt {
594         AST_DECLARE_STRING_FIELDS(
595                 /*! Identification of the agent.  (agents container key) */
596                 AST_STRING_FIELD(username);
597                 /*! Login override DTMF string for an agent to accept a call. */
598                 AST_STRING_FIELD(override_dtmf_accept);
599         );
600         /*! Connected line information to send when reentering the holding bridge. */
601         struct ast_party_connected_line waiting_colp;
602         /*! Flags show if settings were overridden by channel vars. */
603         unsigned int flags;
604         /*! Login override number of seconds for agent to ack a call before being logged off. */
605         unsigned int override_auto_logoff;
606         /*! Login override time after a call in ms before the agent can get a new call. */
607         unsigned int override_wrapup_time;
608         /*! Login override if agent needs to ack a call to accept it. */
609         unsigned int override_ack_call:1;
610
611         /*! TRUE if the agent is requested to logoff when the current call ends. */
612         unsigned int deferred_logoff:1;
613
614         /*! Mark and sweep config update to determine if an agent is dead. */
615         unsigned int the_mark:1;
616         /*!
617          * \brief TRUE if the agent is no longer configured and is being destroyed.
618          *
619          * \note Agents cannot log in if they are dead.
620          */
621         unsigned int dead:1;
622
623         /*! Agent control state variable. */
624         enum agent_state state;
625         /*! Custom device state of agent. */
626         enum ast_device_state devstate;
627
628         /*! When agent first logged in */
629         time_t login_start;
630         /*! When agent login probation started. */
631         time_t probation_start;
632         /*! When call started */
633         time_t call_start;
634         /*! When ack timer started */
635         struct timeval ack_time;
636         /*! When last disconnected */
637         struct timeval last_disconnect;
638
639         /*! Caller is waiting in this bridge for agent to join. (Holds ref) */
640         struct ast_bridge *caller_bridge;
641         /*! Agent is logged in with this channel. (Holds ref) (NULL if not logged in.) */
642         struct ast_channel *logged;
643         /*! Active config values from config file. (Holds ref) */
644         struct agent_cfg *cfg;
645 };
646
647 /*! Container of defined agents. */
648 static struct ao2_container *agents;
649
650 /*!
651  * \brief Lock the agent.
652  *
653  * \param agent Agent to lock
654  *
655  * \return Nothing
656  */
657 #define agent_lock(agent)       _agent_lock(agent, __FILE__, __PRETTY_FUNCTION__, __LINE__, #agent)
658 static inline void _agent_lock(struct agent_pvt *agent, const char *file, const char *function, int line, const char *var)
659 {
660         __ao2_lock(agent, AO2_LOCK_REQ_MUTEX, file, function, line, var);
661 }
662
663 /*!
664  * \brief Unlock the agent.
665  *
666  * \param agent Agent to unlock
667  *
668  * \return Nothing
669  */
670 #define agent_unlock(agent)     _agent_unlock(agent, __FILE__, __PRETTY_FUNCTION__, __LINE__, #agent)
671 static inline void _agent_unlock(struct agent_pvt *agent, const char *file, const char *function, int line, const char *var)
672 {
673         __ao2_unlock(agent, file, function, line, var);
674 }
675
676 /*!
677  * \internal
678  * \brief Obtain the agent logged in channel lock if it exists.
679  * \since 12.0.0
680  *
681  * \param agent Pointer to the LOCKED agent_pvt.
682  *
683  * \note Assumes the agent lock is already obtained.
684  *
685  * \note Defined locking order is channel lock then agent lock.
686  *
687  * \return Nothing
688  */
689 static struct ast_channel *agent_lock_logged(struct agent_pvt *agent)
690 {
691         struct ast_channel *logged;
692
693         for (;;) {
694                 if (!agent->logged) { /* No owner. Nothing to do. */
695                         return NULL;
696                 }
697
698                 /* If we don't ref the logged, it could be killed when we unlock the agent. */
699                 logged = ast_channel_ref(agent->logged);
700
701                 /* Locking logged requires us to lock channel, then agent. */
702                 agent_unlock(agent);
703                 ast_channel_lock(logged);
704                 agent_lock(agent);
705
706                 /* Check if logged changed during agent unlock period */
707                 if (logged != agent->logged) {
708                         /* Channel changed. Unref and do another pass. */
709                         ast_channel_unlock(logged);
710                         ast_channel_unref(logged);
711                 } else {
712                         /* Channel stayed the same. Return it. */
713                         return logged;
714                 }
715         }
716 }
717
718 /*!
719  * \internal
720  * \brief Get the Agent:agent_id device state.
721  * \since 12.0.0
722  *
723  * \param agent_id Username of the agent.
724  *
725  * \details
726  * Search the agents container for the agent and return the
727  * current state.
728  *
729  * \return Device state of the agent.
730  */
731 static enum ast_device_state agent_pvt_devstate_get(const char *agent_id)
732 {
733         RAII_VAR(struct agent_pvt *, agent, ao2_find(agents, agent_id, OBJ_KEY), ao2_cleanup);
734
735         if (agent) {
736                 return agent->devstate;
737         }
738         return AST_DEVICE_INVALID;
739 }
740
741 /*!
742  * \internal
743  * \brief Request an agent device state be updated.
744  * \since 12.0.0
745  *
746  * \param agent_id Which agent needs the device state updated.
747  *
748  * \return Nothing
749  */
750 static void agent_devstate_changed(const char *agent_id)
751 {
752         ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "Agent:%s", agent_id);
753 }
754
755 static void agent_pvt_destructor(void *vdoomed)
756 {
757         struct agent_pvt *doomed = vdoomed;
758
759         /* Make sure device state reflects agent destruction. */
760         if (!ast_strlen_zero(doomed->username)) {
761                 ast_debug(1, "Agent %s: Destroyed.\n", doomed->username);
762                 agent_devstate_changed(doomed->username);
763         }
764
765         ast_party_connected_line_free(&doomed->waiting_colp);
766         if (doomed->caller_bridge) {
767                 ast_bridge_destroy(doomed->caller_bridge, 0);
768                 doomed->caller_bridge = NULL;
769         }
770         if (doomed->logged) {
771                 doomed->logged = ast_channel_unref(doomed->logged);
772         }
773         ao2_cleanup(doomed->cfg);
774         doomed->cfg = NULL;
775         ast_string_field_free_memory(doomed);
776 }
777
778 static struct agent_pvt *agent_pvt_new(struct agent_cfg *cfg)
779 {
780         struct agent_pvt *agent;
781
782         agent = ao2_alloc(sizeof(*agent), agent_pvt_destructor);
783         if (!agent) {
784                 return NULL;
785         }
786         if (ast_string_field_init(agent, 32)) {
787                 ao2_ref(agent, -1);
788                 return NULL;
789         }
790         ast_string_field_set(agent, username, cfg->username);
791         ast_party_connected_line_init(&agent->waiting_colp);
792         ao2_ref(cfg, +1);
793         agent->cfg = cfg;
794         agent->devstate = AST_DEVICE_UNAVAILABLE;
795         return agent;
796 }
797
798 /*!
799  * \internal
800  * \brief Agents ao2 container sort function.
801  * \since 12.0.0
802  *
803  * \param obj_left pointer to the (user-defined part) of an object.
804  * \param obj_right pointer to the (user-defined part) of an object.
805  * \param flags flags from ao2_callback()
806  *   OBJ_POINTER - if set, 'obj_right', is an object.
807  *   OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
808  *   OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
809  *
810  * \retval <0 if obj_left < obj_right
811  * \retval =0 if obj_left == obj_right
812  * \retval >0 if obj_left > obj_right
813  */
814 static int agent_pvt_sort_cmp(const void *obj_left, const void *obj_right, int flags)
815 {
816         const struct agent_pvt *agent_left = obj_left;
817         const struct agent_pvt *agent_right = obj_right;
818         const char *right_key = obj_right;
819         int cmp;
820
821         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
822         default:
823         case OBJ_POINTER:
824                 right_key = agent_right->username;
825                 /* Fall through */
826         case OBJ_KEY:
827                 cmp = strcmp(agent_left->username, right_key);
828                 break;
829         case OBJ_PARTIAL_KEY:
830                 cmp = strncmp(agent_left->username, right_key, strlen(right_key));
831                 break;
832         }
833         return cmp;
834 }
835
836 /*!
837  * \internal
838  * \brief ao2_find() callback function.
839  * \since 12.0.0
840  *
841  * Usage:
842  * found = ao2_find(agents, agent, OBJ_POINTER);
843  * found = ao2_find(agents, "agent-id", OBJ_KEY);
844  * found = ao2_find(agents, agent->logged, 0);
845  */
846 static int agent_pvt_cmp(void *obj, void *arg, int flags)
847 {
848         const struct agent_pvt *agent = obj;
849         int cmp;
850
851         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
852         case OBJ_POINTER:
853         case OBJ_KEY:
854         case OBJ_PARTIAL_KEY:
855                 cmp = CMP_MATCH;
856                 break;
857         default:
858                 if (agent->logged == arg) {
859                         cmp = CMP_MATCH;
860                 } else {
861                         cmp = 0;
862                 }
863                 break;
864         }
865         return cmp;
866 }
867
868 static int agent_mark(void *obj, void *arg, int flags)
869 {
870         struct agent_pvt *agent = obj;
871
872         agent_lock(agent);
873         agent->the_mark = 1;
874         agent_unlock(agent);
875         return 0;
876 }
877
878 static void agents_mark(void)
879 {
880         ao2_callback(agents, 0, agent_mark, NULL);
881 }
882
883 static int agent_sweep(void *obj, void *arg, int flags)
884 {
885         struct agent_pvt *agent = obj;
886         int cmp = 0;
887
888         agent_lock(agent);
889         if (agent->the_mark) {
890                 agent->the_mark = 0;
891                 agent->dead = 1;
892                 /* Unlink dead agents immediately. */
893                 cmp = CMP_MATCH;
894         }
895         agent_unlock(agent);
896         return cmp;
897 }
898
899 static void agents_sweep(void)
900 {
901         struct ao2_iterator *iter;
902         struct agent_pvt *agent;
903         struct ast_channel *logged;
904
905         iter = ao2_callback(agents, OBJ_MULTIPLE | OBJ_UNLINK, agent_sweep, NULL);
906         if (!iter) {
907                 return;
908         }
909         for (; (agent = ao2_iterator_next(iter)); ao2_ref(agent, -1)) {
910                 agent_lock(agent);
911                 if (agent->logged) {
912                         logged = ast_channel_ref(agent->logged);
913                 } else {
914                         logged = NULL;
915                 }
916                 agent_unlock(agent);
917                 if (!logged) {
918                         continue;
919                 }
920                 ast_log(LOG_NOTICE,
921                         "Forced logoff of agent %s(%s).  Agent no longer configured.\n",
922                         agent->username, ast_channel_name(logged));
923                 ast_softhangup(logged, AST_SOFTHANGUP_EXPLICIT);
924                 ast_channel_unref(logged);
925         }
926         ao2_iterator_destroy(iter);
927 }
928
929 static void agents_post_apply_config(void)
930 {
931         struct ao2_iterator iter;
932         struct agent_cfg *cfg;
933         RAII_VAR(struct agents_cfg *, cfgs, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
934
935         ast_assert(cfgs != NULL);
936
937         agents_mark();
938         iter = ao2_iterator_init(cfgs->agents, 0);
939         for (; (cfg = ao2_iterator_next(&iter)); ao2_ref(cfg, -1)) {
940                 RAII_VAR(struct agent_pvt *, agent, ao2_find(agents, cfg->username, OBJ_KEY), ao2_cleanup);
941
942                 if (agent) {
943                         agent_lock(agent);
944                         agent->the_mark = 0;
945                         if (!agent->logged) {
946                                 struct agent_cfg *cfg_old;
947
948                                 /* Replace the config of agents not logged in. */
949                                 cfg_old = agent->cfg;
950                                 ao2_ref(cfg, +1);
951                                 agent->cfg = cfg;
952                                 ao2_cleanup(cfg_old);
953                         }
954                         agent_unlock(agent);
955                         continue;
956                 }
957                 agent = agent_pvt_new(cfg);
958                 if (!agent) {
959                         continue;
960                 }
961                 ao2_link(agents, agent);
962                 ast_debug(1, "Agent %s: Created.\n", agent->username);
963                 agent_devstate_changed(agent->username);
964         }
965         ao2_iterator_destroy(&iter);
966         agents_sweep();
967 }
968
969 static int agent_logoff_request(const char *agent_id, int soft)
970 {
971         struct ast_channel *logged;
972         RAII_VAR(struct agent_pvt *, agent, ao2_find(agents, agent_id, OBJ_KEY), ao2_cleanup);
973
974         if (!agent) {
975                 return -1;
976         }
977
978         agent_lock(agent);
979         logged = agent_lock_logged(agent);
980         if (logged) {
981                 if (soft) {
982                         agent->deferred_logoff = 1;
983                 } else {
984                         ast_softhangup(logged, AST_SOFTHANGUP_EXPLICIT);
985                 }
986                 ast_channel_unlock(logged);
987                 ast_channel_unref(logged);
988         }
989         agent_unlock(agent);
990         return 0;
991 }
992
993 /*! Agent holding bridge instance holder. */
994 static AO2_GLOBAL_OBJ_STATIC(agent_holding);
995
996 /*! Agent holding bridge deferred creation lock. */
997 AST_MUTEX_DEFINE_STATIC(agent_holding_lock);
998
999 /*!
1000  * \internal
1001  * \brief Callback to clear AGENT_STATUS on the caller channel.
1002  *
1003  * \param bridge_channel Which channel to operate on.
1004  * \param payload Data to pass to the callback. (NULL if none).
1005  * \param payload_size Size of the payload if payload is non-NULL.  A number otherwise.
1006  *
1007  * \note The payload MUST NOT have any resources that need to be freed.
1008  *
1009  * \return Nothing
1010  */
1011 static void clear_agent_status(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
1012 {
1013         pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", NULL);
1014 }
1015
1016 /*!
1017  * \internal
1018  * \brief Connect the agent with the waiting caller.
1019  * \since 12.0.0
1020  *
1021  * \param bridge_channel Agent channel connecting to the caller.
1022  * \param agent Which agent is connecting to the caller.
1023  *
1024  * \note The agent is locked on entry and not locked on exit.
1025  *
1026  * \return Nothing
1027  */
1028 static void agent_connect_caller(struct ast_bridge_channel *bridge_channel, struct agent_pvt *agent)
1029 {
1030         struct ast_bridge *caller_bridge;
1031         int record_agent_calls;
1032         int res;
1033
1034         record_agent_calls = agent->cfg->record_agent_calls;
1035         caller_bridge = agent->caller_bridge;
1036         agent->caller_bridge = NULL;
1037         agent->state = AGENT_STATE_ON_CALL;
1038         time(&agent->call_start);
1039         agent_unlock(agent);
1040
1041         if (!caller_bridge) {
1042                 /* Reset agent. */
1043                 ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
1044                         AST_CAUSE_NORMAL_CLEARING);
1045                 return;
1046         }
1047         res = ast_bridge_move(caller_bridge, bridge_channel->bridge, bridge_channel->chan,
1048                 NULL, 0);
1049         if (res) {
1050                 /* Reset agent. */
1051                 ast_bridge_destroy(caller_bridge, 0);
1052                 ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
1053                         AST_CAUSE_NORMAL_CLEARING);
1054                 return;
1055         }
1056         res = ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_ANSWER, NULL, 0)
1057                 || ast_bridge_channel_write_callback(bridge_channel, 0, clear_agent_status, NULL, 0);
1058         if (res) {
1059                 /* Reset agent. */
1060                 ast_bridge_destroy(caller_bridge, 0);
1061                 return;
1062         }
1063
1064         if (record_agent_calls) {
1065                 struct ast_bridge_features_automixmonitor options = {
1066                         .start_stop = AUTO_MONITOR_START,
1067                         };
1068
1069                 /*
1070                  * The agent is in the new bridge so we can invoke the
1071                  * mixmonitor hook to only start recording.
1072                  */
1073                 ast_bridge_features_do(AST_BRIDGE_BUILTIN_AUTOMIXMON, bridge_channel, &options);
1074         }
1075
1076         ao2_t_ref(caller_bridge, -1, "Agent successfully in caller_bridge");
1077 }
1078
1079 static int bridge_agent_hold_ack(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
1080 {
1081         struct agent_pvt *agent = hook_pvt;
1082
1083         agent_lock(agent);
1084         switch (agent->state) {
1085         case AGENT_STATE_CALL_WAIT_ACK:
1086                 /* Connect to caller now. */
1087                 ast_debug(1, "Agent %s: Acked call.\n", agent->username);
1088                 agent_connect_caller(bridge_channel, agent);/* Will unlock agent. */
1089                 return 0;
1090         default:
1091                 break;
1092         }
1093         agent_unlock(agent);
1094         return 0;
1095 }
1096
1097 static int bridge_agent_hold_heartbeat(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
1098 {
1099         struct agent_pvt *agent = hook_pvt;
1100         int probation_timedout = 0;
1101         int ack_timedout = 0;
1102         int wrapup_timedout = 0;
1103         int deferred_logoff;
1104         unsigned int wrapup_time;
1105         unsigned int auto_logoff;
1106
1107         agent_lock(agent);
1108         deferred_logoff = agent->deferred_logoff;
1109         if (deferred_logoff) {
1110                 agent->state = AGENT_STATE_LOGGING_OUT;
1111         }
1112
1113         switch (agent->state) {
1114         case AGENT_STATE_PROBATION_WAIT:
1115                 probation_timedout =
1116                         LOGIN_WAIT_TIMEOUT_TIME <= (time(NULL) - agent->probation_start);
1117                 if (probation_timedout) {
1118                         /* Now ready for a caller. */
1119                         agent->state = AGENT_STATE_READY_FOR_CALL;
1120                         agent->devstate = AST_DEVICE_NOT_INUSE;
1121                 }
1122                 break;
1123         case AGENT_STATE_CALL_WAIT_ACK:
1124                 /* Check ack call time. */
1125                 auto_logoff = agent->cfg->auto_logoff;
1126                 if (ast_test_flag(agent, AGENT_FLAG_AUTO_LOGOFF)) {
1127                         auto_logoff = agent->override_auto_logoff;
1128                 }
1129                 if (auto_logoff) {
1130                         auto_logoff *= 1000;
1131                         ack_timedout = ast_tvdiff_ms(ast_tvnow(), agent->ack_time) > auto_logoff;
1132                         if (ack_timedout) {
1133                                 agent->state = AGENT_STATE_LOGGING_OUT;
1134                         }
1135                 }
1136                 break;
1137         case AGENT_STATE_CALL_WRAPUP:
1138                 /* Check wrapup time. */
1139                 wrapup_time = agent->cfg->wrapup_time;
1140                 if (ast_test_flag(agent, AGENT_FLAG_WRAPUP_TIME)) {
1141                         wrapup_time = agent->override_wrapup_time;
1142                 }
1143                 wrapup_timedout = ast_tvdiff_ms(ast_tvnow(), agent->last_disconnect) > wrapup_time;
1144                 if (wrapup_timedout) {
1145                         agent->state = AGENT_STATE_READY_FOR_CALL;
1146                         agent->devstate = AST_DEVICE_NOT_INUSE;
1147                 }
1148                 break;
1149         default:
1150                 break;
1151         }
1152         agent_unlock(agent);
1153
1154         if (deferred_logoff) {
1155                 ast_debug(1, "Agent %s: Deferred logoff.\n", agent->username);
1156                 ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
1157                         AST_CAUSE_NORMAL_CLEARING);
1158         } else if (probation_timedout) {
1159                 ast_debug(1, "Agent %s: Login complete.\n", agent->username);
1160                 agent_devstate_changed(agent->username);
1161         } else if (ack_timedout) {
1162                 ast_debug(1, "Agent %s: Ack call timeout.\n", agent->username);
1163                 ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
1164                         AST_CAUSE_NORMAL_CLEARING);
1165         } else if (wrapup_timedout) {
1166                 ast_debug(1, "Agent %s: Wrapup timeout. Ready for new call.\n", agent->username);
1167                 agent_devstate_changed(agent->username);
1168         }
1169
1170         return 0;
1171 }
1172
1173 static void agent_after_bridge_cb(struct ast_channel *chan, void *data);
1174 static void agent_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data);
1175
1176 /*!
1177  * \internal
1178  * \brief ast_bridge agent_hold push method.
1179  * \since 12.0.0
1180  *
1181  * \param self Bridge to operate upon.
1182  * \param bridge_channel Bridge channel to push.
1183  * \param swap Bridge channel to swap places with if not NULL.
1184  *
1185  * \note On entry, self is already locked.
1186  *
1187  * \retval 0 on success
1188  * \retval -1 on failure
1189  */
1190 static int bridge_agent_hold_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
1191 {
1192         int res = 0;
1193         unsigned int wrapup_time;
1194         char dtmf[AST_FEATURE_MAX_LEN];
1195         struct ast_channel *chan;
1196         const char *moh_class;
1197         RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
1198
1199         chan = bridge_channel->chan;
1200
1201         agent = ao2_find(agents, swap ? swap->chan : chan, 0);
1202         if (!agent) {
1203                 /* Could not find the agent. */
1204                 return -1;
1205         }
1206
1207         /* Setup agent entertainment */
1208         agent_lock(agent);
1209         moh_class = ast_strdupa(agent->cfg->moh);
1210         agent_unlock(agent);
1211         res |= ast_channel_add_bridge_role(chan, "holding_participant");
1212         res |= ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "musiconhold");
1213         res |= ast_channel_set_bridge_role_option(chan, "holding_participant", "moh_class", moh_class);
1214
1215         /* Add DTMF acknowledge hook. */
1216         dtmf[0] = '\0';
1217         agent_lock(agent);
1218         if (ast_test_flag(agent, AGENT_FLAG_ACK_CALL)
1219                 ? agent->override_ack_call : agent->cfg->ack_call) {
1220                 const char *dtmf_accept;
1221
1222                 dtmf_accept = ast_test_flag(agent, AGENT_FLAG_DTMF_ACCEPT)
1223                         ? agent->override_dtmf_accept : agent->cfg->dtmf_accept;
1224                 ast_copy_string(dtmf, dtmf_accept, sizeof(dtmf));
1225         }
1226         agent_unlock(agent);
1227         if (!ast_strlen_zero(dtmf)) {
1228                 ao2_ref(agent, +1);
1229                 if (ast_bridge_dtmf_hook(bridge_channel->features, dtmf, bridge_agent_hold_ack,
1230                         agent, __ao2_cleanup, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
1231                         ao2_ref(agent, -1);
1232                         res = -1;
1233                 }
1234         }
1235
1236         /* Add heartbeat interval hook. */
1237         ao2_ref(agent, +1);
1238         if (ast_bridge_interval_hook(bridge_channel->features, 0, 1000,
1239                 bridge_agent_hold_heartbeat, agent, __ao2_cleanup, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
1240                 ao2_ref(agent, -1);
1241                 res = -1;
1242         }
1243
1244         res |= ast_bridge_base_v_table.push(self, bridge_channel, swap);
1245         if (res) {
1246                 ast_channel_remove_bridge_role(chan, "holding_participant");
1247                 return -1;
1248         }
1249
1250         if (swap) {
1251                 res = ast_bridge_set_after_callback(chan, agent_after_bridge_cb,
1252                         agent_after_bridge_cb_failed, chan);
1253                 if (res) {
1254                         ast_channel_remove_bridge_role(chan, "holding_participant");
1255                         return -1;
1256                 }
1257
1258                 agent_lock(agent);
1259                 ast_channel_unref(agent->logged);
1260                 agent->logged = ast_channel_ref(chan);
1261                 agent_unlock(agent);
1262
1263                 /*
1264                  * Kick the channel out so it can come back in fully controlled.
1265                  * Otherwise, the after bridge callback will linger and the
1266                  * agent will have some slightly different behavior in corner
1267                  * cases.
1268                  */
1269                 ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
1270                         AST_CAUSE_NORMAL_CLEARING);
1271                 return 0;
1272         }
1273
1274         agent_lock(agent);
1275         switch (agent->state) {
1276         case AGENT_STATE_LOGGED_OUT:
1277                 /*!
1278                  * \todo XXX the login probation time should be only if it is needed.
1279                  *
1280                  * Need to determine if there are any local channels that can
1281                  * optimize and wait until they actually do before leaving the
1282                  * AGENT_STATE_PROBATION_WAIT state.  For now, the blind
1283                  * timer of LOGIN_WAIT_TIMEOUT_TIME will do.
1284                  */
1285                 /*
1286                  * Start the login probation timer.
1287                  *
1288                  * We cannot handle an agent local channel optimization when the
1289                  * agent is on a call.  The optimization may kick the agent
1290                  * channel we know about out of the call without our being able
1291                  * to switch to the replacement channel.  Get any agent local
1292                  * channel optimization out of the way while the agent is in the
1293                  * holding bridge.
1294                  */
1295                 time(&agent->probation_start);
1296                 agent->state = AGENT_STATE_PROBATION_WAIT;
1297                 agent_unlock(agent);
1298                 break;
1299         case AGENT_STATE_PROBATION_WAIT:
1300                 /* Restart the probation timer. */
1301                 time(&agent->probation_start);
1302                 agent_unlock(agent);
1303                 break;
1304         case AGENT_STATE_READY_FOR_CALL:
1305                 /*
1306                  * Likely someone manually kicked us out of the holding bridge
1307                  * and we came right back in.
1308                  */
1309                 agent_unlock(agent);
1310                 break;
1311         default:
1312                 /* Unexpected agent state. */
1313                 ast_assert(0);
1314                 /* Fall through */
1315         case AGENT_STATE_CALL_PRESENT:
1316         case AGENT_STATE_CALL_WAIT_ACK:
1317                 agent->state = AGENT_STATE_READY_FOR_CALL;
1318                 agent->devstate = AST_DEVICE_NOT_INUSE;
1319                 agent_unlock(agent);
1320                 ast_debug(1, "Agent %s: Call abort recovery complete.\n", agent->username);
1321                 agent_devstate_changed(agent->username);
1322                 break;
1323         case AGENT_STATE_ON_CALL:
1324         case AGENT_STATE_CALL_WRAPUP:
1325                 wrapup_time = agent->cfg->wrapup_time;
1326                 if (ast_test_flag(agent, AGENT_FLAG_WRAPUP_TIME)) {
1327                         wrapup_time = agent->override_wrapup_time;
1328                 }
1329                 if (wrapup_time) {
1330                         agent->state = AGENT_STATE_CALL_WRAPUP;
1331                 } else {
1332                         agent->state = AGENT_STATE_READY_FOR_CALL;
1333                         agent->devstate = AST_DEVICE_NOT_INUSE;
1334                 }
1335                 agent_unlock(agent);
1336                 if (!wrapup_time) {
1337                         /* No wrapup time. */
1338                         ast_debug(1, "Agent %s: Ready for new call.\n", agent->username);
1339                         agent_devstate_changed(agent->username);
1340                 }
1341                 break;
1342         }
1343
1344         return 0;
1345 }
1346
1347 /*!
1348  * \internal
1349  * \brief ast_bridge agent_hold pull method.
1350  *
1351  * \param self Bridge to operate upon.
1352  * \param bridge_channel Bridge channel to pull.
1353  *
1354  * \details
1355  * Remove any channel hooks controlled by the bridge.  Release
1356  * any resources held by bridge_channel->bridge_pvt and release
1357  * bridge_channel->bridge_pvt.
1358  *
1359  * \note On entry, self is already locked.
1360  *
1361  * \return Nothing
1362  */
1363 static void bridge_agent_hold_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
1364 {
1365         ast_channel_remove_bridge_role(bridge_channel->chan, "holding_participant");
1366         ast_bridge_base_v_table.pull(self, bridge_channel);
1367 }
1368
1369 /*!
1370  * \brief The bridge is being dissolved.
1371  *
1372  * \param self Bridge to operate upon.
1373  *
1374  * \details
1375  * The bridge is being dissolved.  Remove any external
1376  * references to the bridge so it can be destroyed.
1377  *
1378  * \note On entry, self must NOT be locked.
1379  *
1380  * \return Nothing
1381  */
1382 static void bridge_agent_hold_dissolving(struct ast_bridge *self)
1383 {
1384         ao2_global_obj_release(agent_holding);
1385         ast_bridge_base_v_table.dissolving(self);
1386 }
1387
1388 static struct ast_bridge_methods bridge_agent_hold_v_table;
1389
1390 static struct ast_bridge *bridge_agent_hold_new(void)
1391 {
1392         struct ast_bridge *bridge;
1393
1394         bridge = bridge_alloc(sizeof(struct ast_bridge), &bridge_agent_hold_v_table);
1395         bridge = bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING,
1396                 AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
1397                         | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED,
1398                 "AgentPool", NULL, NULL);
1399         bridge = bridge_register(bridge);
1400         return bridge;
1401 }
1402
1403 static void bridge_init_agent_hold(void)
1404 {
1405         /* Setup bridge agent_hold subclass v_table. */
1406         bridge_agent_hold_v_table = ast_bridge_base_v_table;
1407         bridge_agent_hold_v_table.name = "agent_hold";
1408         bridge_agent_hold_v_table.dissolving = bridge_agent_hold_dissolving;
1409         bridge_agent_hold_v_table.push = bridge_agent_hold_push;
1410         bridge_agent_hold_v_table.pull = bridge_agent_hold_pull;
1411 }
1412
1413 static int bridge_agent_hold_deferred_create(void)
1414 {
1415         RAII_VAR(struct ast_bridge *, holding, ao2_global_obj_ref(agent_holding), ao2_cleanup);
1416
1417         if (!holding) {
1418                 ast_mutex_lock(&agent_holding_lock);
1419                 holding = ao2_global_obj_ref(agent_holding);
1420                 if (!holding) {
1421                         holding = bridge_agent_hold_new();
1422                         ao2_global_obj_replace_unref(agent_holding, holding);
1423                 }
1424                 ast_mutex_unlock(&agent_holding_lock);
1425                 if (!holding) {
1426                         ast_log(LOG_ERROR, "Could not create agent holding bridge.\n");
1427                         return -1;
1428                 }
1429         }
1430         return 0;
1431 }
1432
1433 static void send_agent_login(struct ast_channel *chan, const char *agent)
1434 {
1435         RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
1436
1437         ast_assert(agent != NULL);
1438
1439         blob = ast_json_pack("{s: s}",
1440                 "agent", agent);
1441         if (!blob) {
1442                 return;
1443         }
1444
1445         ast_channel_publish_cached_blob(chan, ast_channel_agent_login_type(), blob);
1446 }
1447
1448 static void send_agent_logoff(struct ast_channel *chan, const char *agent, long logintime)
1449 {
1450         RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
1451
1452         ast_assert(agent != NULL);
1453
1454         blob = ast_json_pack("{s: s, s: i}",
1455                 "agent", agent,
1456                 "logintime", logintime);
1457         if (!blob) {
1458                 return;
1459         }
1460
1461         ast_channel_publish_cached_blob(chan, ast_channel_agent_logoff_type(), blob);
1462 }
1463
1464 /*!
1465  * \internal
1466  * \brief Logout the agent.
1467  * \since 12.0.0
1468  *
1469  * \param agent Which agent logging out.
1470  *
1471  * \note On entry agent is already locked.  On exit it is no longer locked.
1472  *
1473  * \return Nothing
1474  */
1475 static void agent_logout(struct agent_pvt *agent)
1476 {
1477         struct ast_channel *logged;
1478         struct ast_bridge *caller_bridge;
1479         long time_logged_in;
1480
1481         time_logged_in = time(NULL) - agent->login_start;
1482         logged = agent->logged;
1483         agent->logged = NULL;
1484         caller_bridge = agent->caller_bridge;
1485         agent->caller_bridge = NULL;
1486         agent->state = AGENT_STATE_LOGGED_OUT;
1487         agent->devstate = AST_DEVICE_UNAVAILABLE;
1488         ast_clear_flag(agent, AST_FLAGS_ALL);
1489         agent_unlock(agent);
1490         agent_devstate_changed(agent->username);
1491
1492         if (caller_bridge) {
1493                 ast_bridge_destroy(caller_bridge, 0);
1494         }
1495
1496         ast_channel_lock(logged);
1497         send_agent_logoff(logged, agent->username, time_logged_in);
1498         ast_channel_unlock(logged);
1499         ast_verb(2, "Agent '%s' logged out.  Logged in for %ld seconds.\n",
1500                 agent->username, time_logged_in);
1501         ast_channel_unref(logged);
1502 }
1503
1504 /*!
1505  * \internal
1506  * \brief Agent driver loop.
1507  * \since 12.0.0
1508  *
1509  * \param agent Which agent.
1510  * \param logged The logged in channel.
1511  *
1512  * \return Nothing
1513  */
1514 static void agent_run(struct agent_pvt *agent, struct ast_channel *logged)
1515 {
1516         struct ast_bridge_features features;
1517
1518         if (ast_bridge_features_init(&features)) {
1519                 ast_channel_hangupcause_set(logged, AST_CAUSE_NORMAL_CLEARING);
1520                 goto agent_run_cleanup;
1521         }
1522         for (;;) {
1523                 struct agents_cfg *cfgs;
1524                 struct agent_cfg *cfg_new;
1525                 struct agent_cfg *cfg_old;
1526                 struct ast_bridge *holding;
1527                 struct ast_bridge *caller_bridge;
1528
1529                 ast_channel_hangupcause_set(logged, AST_CAUSE_NORMAL_CLEARING);
1530
1531                 holding = ao2_global_obj_ref(agent_holding);
1532                 if (!holding) {
1533                         ast_debug(1, "Agent %s: Someone destroyed the agent holding bridge.\n",
1534                                 agent->username);
1535                         break;
1536                 }
1537
1538                 /*
1539                  * When the agent channel leaves the bridging system we usually
1540                  * want to put the agent back into the holding bridge for the
1541                  * next caller.
1542                  */
1543                 ast_bridge_join(holding, logged, NULL, &features, NULL,
1544                         AST_BRIDGE_JOIN_PASS_REFERENCE);
1545                 if (logged != agent->logged) {
1546                         /* This channel is no longer the logged in agent. */
1547                         break;
1548                 }
1549
1550                 if (agent->dead) {
1551                         /* The agent is no longer configured. */
1552                         break;
1553                 }
1554
1555                 /* Update the agent's config before rejoining the holding bridge. */
1556                 cfgs = ao2_global_obj_ref(cfg_handle);
1557                 if (!cfgs) {
1558                         /* There is no agent configuration.  All agents were destroyed. */
1559                         break;
1560                 }
1561                 cfg_new = ao2_find(cfgs->agents, agent->username, OBJ_KEY);
1562                 ao2_ref(cfgs, -1);
1563                 if (!cfg_new) {
1564                         /* The agent is no longer configured. */
1565                         break;
1566                 }
1567                 agent_lock(agent);
1568                 cfg_old = agent->cfg;
1569                 agent->cfg = cfg_new;
1570
1571                 agent->last_disconnect = ast_tvnow();
1572
1573                 /* Clear out any caller bridge before rejoining the holding bridge. */
1574                 caller_bridge = agent->caller_bridge;
1575                 agent->caller_bridge = NULL;
1576                 agent_unlock(agent);
1577                 ao2_ref(cfg_old, -1);
1578                 if (caller_bridge) {
1579                         ast_bridge_destroy(caller_bridge, 0);
1580                 }
1581
1582                 if (agent->state == AGENT_STATE_LOGGING_OUT
1583                         || agent->deferred_logoff
1584                         || ast_check_hangup_locked(logged)) {
1585                         /* The agent was requested to logout or hungup. */
1586                         break;
1587                 }
1588
1589                 /*
1590                  * It is safe to access agent->waiting_colp without a lock.  It
1591                  * is only setup on agent login and not changed.
1592                  */
1593                 ast_channel_update_connected_line(logged, &agent->waiting_colp, NULL);
1594         }
1595         ast_bridge_features_cleanup(&features);
1596
1597 agent_run_cleanup:
1598         agent_lock(agent);
1599         if (logged != agent->logged) {
1600                 /*
1601                  * We are no longer the agent channel because of local channel
1602                  * optimization.
1603                  */
1604                 agent_unlock(agent);
1605                 ast_debug(1, "Agent %s: Channel %s is no longer the agent.\n",
1606                         agent->username, ast_channel_name(logged));
1607                 return;
1608         }
1609         agent_logout(agent);
1610 }
1611
1612 static void agent_after_bridge_cb(struct ast_channel *chan, void *data)
1613 {
1614         struct agent_pvt *agent;
1615
1616         agent = ao2_find(agents, chan, 0);
1617         if (!agent) {
1618                 return;
1619         }
1620
1621         ast_debug(1, "Agent %s: New agent channel %s.\n",
1622                 agent->username, ast_channel_name(chan));
1623         agent_run(agent, chan);
1624         ao2_ref(agent, -1);
1625 }
1626
1627 static void agent_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data)
1628 {
1629         struct ast_channel *chan = data;
1630         struct agent_pvt *agent;
1631
1632         agent = ao2_find(agents, chan, 0);
1633         if (!agent) {
1634                 return;
1635         }
1636         ast_log(LOG_WARNING, "Agent %s: Forced logout.  Lost control of %s because: %s\n",
1637                 agent->username, ast_channel_name(chan),
1638                 ast_bridge_after_cb_reason_string(reason));
1639         agent_lock(agent);
1640         agent_logout(agent);
1641         ao2_ref(agent, -1);
1642 }
1643
1644 /*!
1645  * \internal
1646  * \brief Get the lock on the agent bridge_channel and return it.
1647  * \since 12.0.0
1648  *
1649  * \param agent Whose bridge_channel to get.
1650  *
1651  * \retval bridge_channel on success (Reffed and locked).
1652  * \retval NULL on error.
1653  */
1654 static struct ast_bridge_channel *agent_bridge_channel_get_lock(struct agent_pvt *agent)
1655 {
1656         struct ast_channel *logged;
1657         struct ast_bridge_channel *bc;
1658
1659         for (;;) {
1660                 agent_lock(agent);
1661                 logged = agent->logged;
1662                 if (!logged) {
1663                         agent_unlock(agent);
1664                         return NULL;
1665                 }
1666                 ast_channel_ref(logged);
1667                 agent_unlock(agent);
1668
1669                 ast_channel_lock(logged);
1670                 bc = ast_channel_get_bridge_channel(logged);
1671                 ast_channel_unlock(logged);
1672                 ast_channel_unref(logged);
1673                 if (!bc) {
1674                         if (agent->logged != logged) {
1675                                 continue;
1676                         }
1677                         return NULL;
1678                 }
1679
1680                 ast_bridge_channel_lock(bc);
1681                 if (bc->chan != logged || agent->logged != logged) {
1682                         ast_bridge_channel_unlock(bc);
1683                         ao2_ref(bc, -1);
1684                         continue;
1685                 }
1686                 return bc;
1687         }
1688 }
1689
1690 static void caller_abort_agent(struct agent_pvt *agent)
1691 {
1692         struct ast_bridge_channel *logged;
1693
1694         logged = agent_bridge_channel_get_lock(agent);
1695         if (!logged) {
1696                 struct ast_bridge *caller_bridge;
1697
1698                 ast_debug(1, "Agent '%s' no longer logged in.\n", agent->username);
1699
1700                 agent_lock(agent);
1701                 caller_bridge = agent->caller_bridge;
1702                 agent->caller_bridge = NULL;
1703                 agent_unlock(agent);
1704                 if (caller_bridge) {
1705                         ast_bridge_destroy(caller_bridge, 0);
1706                 }
1707                 return;
1708         }
1709
1710         /* Kick the agent out of the holding bridge to reset it. */
1711         ast_bridge_channel_leave_bridge_nolock(logged, BRIDGE_CHANNEL_STATE_END,
1712                 AST_CAUSE_NORMAL_CLEARING);
1713         ast_bridge_channel_unlock(logged);
1714 }
1715
1716 static int caller_safety_timeout(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
1717 {
1718         struct agent_pvt *agent = hook_pvt;
1719
1720         if (agent->state == AGENT_STATE_CALL_PRESENT) {
1721                 ast_log(LOG_WARNING, "Agent '%s' process did not respond.  Safety timeout.\n",
1722                         agent->username);
1723                 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "ERROR");
1724
1725                 ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, 0);
1726                 caller_abort_agent(agent);
1727         }
1728
1729         return -1;
1730 }
1731
1732 static void agent_alert(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
1733 {
1734         const char *agent_id = payload;
1735         const char *playfile;
1736         RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
1737
1738         agent = ao2_find(agents, agent_id, OBJ_KEY);
1739         if (!agent) {
1740                 ast_debug(1, "Agent '%s' does not exist.  Where did it go?\n", agent_id);
1741                 return;
1742         }
1743
1744         /* Change holding bridge participant role's idle mode to silence */
1745         ast_bridge_channel_lock_bridge(bridge_channel);
1746         ast_bridge_channel_clear_roles(bridge_channel);
1747         ast_channel_set_bridge_role_option(bridge_channel->chan, "holding_participant", "idle_mode", "silence");
1748         ast_bridge_channel_establish_roles(bridge_channel);
1749         ast_bridge_unlock(bridge_channel->bridge);
1750
1751         /* Alert the agent. */
1752         agent_lock(agent);
1753         playfile = ast_strdupa(agent->cfg->beep_sound);
1754         agent_unlock(agent);
1755         ast_stream_and_wait(bridge_channel->chan, playfile, AST_DIGIT_NONE);
1756
1757         agent_lock(agent);
1758         switch (agent->state) {
1759         case AGENT_STATE_CALL_PRESENT:
1760                 if (ast_test_flag(agent, AGENT_FLAG_ACK_CALL)
1761                         ? agent->override_ack_call : agent->cfg->ack_call) {
1762                         agent->state = AGENT_STATE_CALL_WAIT_ACK;
1763                         agent->ack_time = ast_tvnow();
1764                         break;
1765                 }
1766
1767                 /* Connect to caller now. */
1768                 ast_debug(1, "Agent %s: Immediately connecting to call.\n", agent->username);
1769                 agent_connect_caller(bridge_channel, agent);/* Will unlock agent. */
1770                 return;
1771         default:
1772                 break;
1773         }
1774         agent_unlock(agent);
1775 }
1776
1777 static int send_alert_to_agent(struct ast_bridge_channel *bridge_channel, const char *agent_id)
1778 {
1779         return ast_bridge_channel_queue_callback(bridge_channel,
1780                 AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA, agent_alert, agent_id, strlen(agent_id) + 1);
1781 }
1782
1783 static int send_colp_to_agent(struct ast_bridge_channel *bridge_channel, struct ast_party_connected_line *connected)
1784 {
1785         struct ast_set_party_connected_line update = {
1786                 .id.name = 1,
1787                 .id.number = 1,
1788                 .id.subaddress = 1,
1789         };
1790         unsigned char data[1024];       /* This should be large enough */
1791         size_t datalen;
1792
1793         datalen = ast_connected_line_build_data(data, sizeof(data), connected, &update);
1794         if (datalen == (size_t) -1) {
1795                 return 0;
1796         }
1797
1798         return ast_bridge_channel_queue_control_data(bridge_channel,
1799                 AST_CONTROL_CONNECTED_LINE, data, datalen);
1800 }
1801
1802 /*!
1803  * \internal
1804  * \brief Caller joined the bridge event callback.
1805  *
1806  * \param bridge_channel Channel executing the feature
1807  * \param hook_pvt Private data passed in when the hook was created
1808  *
1809  * \retval 0 Keep the callback hook.
1810  * \retval -1 Remove the callback hook.
1811  */
1812 static int caller_joined_bridge(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
1813 {
1814         struct agent_pvt *agent = hook_pvt;
1815         struct ast_bridge_channel *logged;
1816         int res;
1817
1818         logged = agent_bridge_channel_get_lock(agent);
1819         if (!logged) {
1820                 ast_verb(3, "Agent '%s' not logged in.\n", agent->username);
1821                 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "NOT_LOGGED_IN");
1822
1823                 ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, 0);
1824                 caller_abort_agent(agent);
1825                 return -1;
1826         }
1827
1828         res = send_alert_to_agent(logged, agent->username);
1829         ast_bridge_channel_unlock(logged);
1830         ao2_ref(logged, -1);
1831         if (res) {
1832                 ast_verb(3, "Agent '%s': Failed to alert the agent.\n", agent->username);
1833                 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "ERROR");
1834
1835                 ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, 0);
1836                 caller_abort_agent(agent);
1837                 return -1;
1838         }
1839
1840         pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "NOT_CONNECTED");
1841         ast_indicate(bridge_channel->chan, AST_CONTROL_RINGING);
1842         return -1;
1843 }
1844
1845 /*!
1846  * \brief Dialplan AgentRequest application to locate an agent to talk with.
1847  *
1848  * \param chan Channel wanting to talk with an agent.
1849  * \param data Application parameters
1850  *
1851  * \retval 0 To continue in dialplan.
1852  * \retval -1 To hangup.
1853  */
1854 static int agent_request_exec(struct ast_channel *chan, const char *data)
1855 {
1856         struct ast_bridge *caller_bridge;
1857         struct ast_bridge_channel *logged;
1858         char *parse;
1859         int res;
1860         struct ast_bridge_features caller_features;
1861         struct ast_party_connected_line connected;
1862         AST_DECLARE_APP_ARGS(args,
1863                 AST_APP_ARG(agent_id);
1864                 AST_APP_ARG(other);             /* Any remaining unused arguments */
1865         );
1866
1867         RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
1868
1869         if (bridge_agent_hold_deferred_create()) {
1870                 return -1;
1871         }
1872
1873         parse = ast_strdupa(data);
1874         AST_STANDARD_APP_ARGS(args, parse);
1875
1876         if (ast_strlen_zero(args.agent_id)) {
1877                 ast_log(LOG_WARNING, "AgentRequest requires an AgentId\n");
1878                 return -1;
1879         }
1880
1881         /* Find the agent. */
1882         agent = ao2_find(agents, args.agent_id, OBJ_KEY);
1883         if (!agent) {
1884                 ast_verb(3, "Agent '%s' does not exist.\n", args.agent_id);
1885                 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "INVALID");
1886                 return 0;
1887         }
1888
1889         if (ast_bridge_features_init(&caller_features)) {
1890                 return -1;
1891         }
1892
1893         /* Add safety timeout hook. */
1894         ao2_ref(agent, +1);
1895         if (ast_bridge_interval_hook(&caller_features, 0, CALLER_SAFETY_TIMEOUT_TIME,
1896                 caller_safety_timeout, agent, __ao2_cleanup, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
1897                 ao2_ref(agent, -1);
1898                 ast_bridge_features_cleanup(&caller_features);
1899                 return -1;
1900         }
1901
1902         /* Setup the alert agent on caller joining the bridge hook. */
1903         ao2_ref(agent, +1);
1904         if (ast_bridge_join_hook(&caller_features, caller_joined_bridge, agent,
1905                 __ao2_cleanup, 0)) {
1906                 ao2_ref(agent, -1);
1907                 ast_bridge_features_cleanup(&caller_features);
1908                 return -1;
1909         }
1910
1911         caller_bridge = ast_bridge_basic_new();
1912         if (!caller_bridge) {
1913                 ast_bridge_features_cleanup(&caller_features);
1914                 return -1;
1915         }
1916
1917         agent_lock(agent);
1918         switch (agent->state) {
1919         case AGENT_STATE_LOGGED_OUT:
1920         case AGENT_STATE_LOGGING_OUT:
1921                 agent_unlock(agent);
1922                 ast_bridge_destroy(caller_bridge, 0);
1923                 ast_bridge_features_cleanup(&caller_features);
1924                 ast_verb(3, "Agent '%s' not logged in.\n", agent->username);
1925                 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "NOT_LOGGED_IN");
1926                 return 0;
1927         case AGENT_STATE_READY_FOR_CALL:
1928                 ao2_ref(caller_bridge, +1);
1929                 agent->caller_bridge = caller_bridge;
1930                 agent->state = AGENT_STATE_CALL_PRESENT;
1931                 agent->devstate = AST_DEVICE_INUSE;
1932                 break;
1933         default:
1934                 agent_unlock(agent);
1935                 ast_bridge_destroy(caller_bridge, 0);
1936                 ast_bridge_features_cleanup(&caller_features);
1937                 ast_verb(3, "Agent '%s' is busy.\n", agent->username);
1938                 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "BUSY");
1939                 return 0;
1940         }
1941         agent_unlock(agent);
1942         agent_devstate_changed(agent->username);
1943
1944         /* Get COLP for agent. */
1945         ast_party_connected_line_init(&connected);
1946         ast_channel_lock(chan);
1947         ast_connected_line_copy_from_caller(&connected, ast_channel_caller(chan));
1948         ast_channel_unlock(chan);
1949
1950         logged = agent_bridge_channel_get_lock(agent);
1951         if (!logged) {
1952                 ast_party_connected_line_free(&connected);
1953                 caller_abort_agent(agent);
1954                 ast_bridge_destroy(caller_bridge, 0);
1955                 ast_bridge_features_cleanup(&caller_features);
1956                 ast_verb(3, "Agent '%s' not logged in.\n", agent->username);
1957                 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "NOT_LOGGED_IN");
1958                 return 0;
1959         }
1960
1961         send_colp_to_agent(logged, &connected);
1962         ast_bridge_channel_unlock(logged);
1963         ao2_ref(logged, -1);
1964         ast_party_connected_line_free(&connected);
1965
1966         if (ast_bridge_join(caller_bridge, chan, NULL, &caller_features, NULL,
1967                 AST_BRIDGE_JOIN_PASS_REFERENCE)) {
1968                 caller_abort_agent(agent);
1969                 ast_verb(3, "Agent '%s': Caller %s failed to join the bridge.\n",
1970                         agent->username, ast_channel_name(chan));
1971                 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "ERROR");
1972         }
1973         ast_bridge_features_cleanup(&caller_features);
1974
1975         /* Determine if we need to continue in the dialplan after the bridge. */
1976         ast_channel_lock(chan);
1977         if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
1978                 /*
1979                  * The bridge was broken for a hangup that isn't real.
1980                  * Don't run the h extension, because the channel isn't
1981                  * really hung up.  This should really only happen with
1982                  * AST_SOFTHANGUP_ASYNCGOTO.
1983                  */
1984                 res = 0;
1985         } else {
1986                 res = ast_check_hangup(chan)
1987                         || ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
1988                         || ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENT_STATUS"));
1989         }
1990         ast_channel_unlock(chan);
1991
1992         return res ? -1 : 0;
1993 }
1994
1995 /*!
1996  * \internal
1997  * \brief Get agent config values from the login channel.
1998  * \since 12.0.0
1999  *
2000  * \param agent What to setup channel config values on.
2001  * \param chan Channel logging in as an agent.
2002  *
2003  * \return Nothing
2004  */
2005 static void agent_login_channel_config(struct agent_pvt *agent, struct ast_channel *chan)
2006 {
2007         struct ast_flags opts = { 0 };
2008         struct ast_party_connected_line connected;
2009         unsigned int override_ack_call = 0;
2010         unsigned int override_auto_logoff = 0;
2011         unsigned int override_wrapup_time = 0;
2012         const char *override_dtmf_accept = NULL;
2013         const char *var;
2014
2015         ast_party_connected_line_init(&connected);
2016
2017         /* Get config values from channel. */
2018         ast_channel_lock(chan);
2019         ast_party_connected_line_copy(&connected, ast_channel_connected(chan));
2020
2021         var = pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
2022         if (!ast_strlen_zero(var)) {
2023                 override_ack_call = ast_true(var) ? 1 : 0;
2024                 ast_set_flag(&opts, AGENT_FLAG_ACK_CALL);
2025         }
2026
2027         var = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
2028         if (!ast_strlen_zero(var)) {
2029                 override_dtmf_accept = ast_strdupa(var);
2030                 ast_set_flag(&opts, AGENT_FLAG_DTMF_ACCEPT);
2031         }
2032
2033         var = pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
2034         if (!ast_strlen_zero(var)) {
2035                 if (sscanf(var, "%u", &override_auto_logoff) == 1) {
2036                         ast_set_flag(&opts, AGENT_FLAG_AUTO_LOGOFF);
2037                 }
2038         }
2039
2040         var = pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
2041         if (!ast_strlen_zero(var)) {
2042                 if (sscanf(var, "%u", &override_wrapup_time) == 1) {
2043                         ast_set_flag(&opts, AGENT_FLAG_WRAPUP_TIME);
2044                 }
2045         }
2046         ast_channel_unlock(chan);
2047
2048         /* Set config values on agent. */
2049         agent_lock(agent);
2050         ast_party_connected_line_free(&agent->waiting_colp);
2051         agent->waiting_colp = connected;
2052
2053         ast_string_field_set(agent, override_dtmf_accept, override_dtmf_accept);
2054         ast_copy_flags(agent, &opts, AST_FLAGS_ALL);
2055         agent->override_auto_logoff = override_auto_logoff;
2056         agent->override_wrapup_time = override_wrapup_time;
2057         agent->override_ack_call = override_ack_call;
2058         agent_unlock(agent);
2059 }
2060
2061 enum AGENT_LOGIN_OPT_FLAGS {
2062         OPT_SILENT = (1 << 0),
2063 };
2064 AST_APP_OPTIONS(agent_login_opts, BEGIN_OPTIONS
2065         AST_APP_OPTION('s', OPT_SILENT),
2066 END_OPTIONS);
2067
2068 /*!
2069  * \brief Dialplan AgentLogin application to log in an agent.
2070  *
2071  * \param chan Channel attempting to login as an agent.
2072  * \param data Application parameters
2073  *
2074  * \retval 0 To continue in dialplan.
2075  * \retval -1 To hangup.
2076  */
2077 static int agent_login_exec(struct ast_channel *chan, const char *data)
2078 {
2079         char *parse;
2080         struct ast_flags opts;
2081         AST_DECLARE_APP_ARGS(args,
2082                 AST_APP_ARG(agent_id);
2083                 AST_APP_ARG(options);
2084                 AST_APP_ARG(other);             /* Any remaining unused arguments */
2085         );
2086
2087         RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
2088
2089         if (bridge_agent_hold_deferred_create()) {
2090                 return -1;
2091         }
2092
2093         if (ast_channel_state(chan) != AST_STATE_UP && ast_answer(chan)) {
2094                 return -1;
2095         }
2096
2097         parse = ast_strdupa(data);
2098         AST_STANDARD_APP_ARGS(args, parse);
2099
2100         if (ast_strlen_zero(args.agent_id)) {
2101                 ast_log(LOG_WARNING, "AgentLogin requires an AgentId\n");
2102                 return -1;
2103         }
2104
2105         if (ast_app_parse_options(agent_login_opts, &opts, NULL, args.options)) {
2106                 /* General invalid option syntax. */
2107                 return -1;
2108         }
2109
2110         /* Find the agent. */
2111         agent = ao2_find(agents, args.agent_id, OBJ_KEY);
2112         if (!agent) {
2113                 ast_verb(3, "Agent '%s' does not exist.\n", args.agent_id);
2114                 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "INVALID");
2115                 return 0;
2116         }
2117
2118         /* Has someone already logged in as this agent already? */
2119         agent_lock(agent);
2120         if (agent->logged) {
2121                 agent_unlock(agent);
2122                 ast_verb(3, "Agent '%s' already logged in.\n", agent->username);
2123                 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "ALREADY_LOGGED_IN");
2124                 return 0;
2125         }
2126         agent->logged = ast_channel_ref(chan);
2127         agent->last_disconnect = ast_tvnow();
2128         time(&agent->login_start);
2129         agent->deferred_logoff = 0;
2130         agent_unlock(agent);
2131
2132         agent_login_channel_config(agent, chan);
2133
2134         if (!ast_test_flag(&opts, OPT_SILENT)) {
2135                 ast_stream_and_wait(chan, "agent-loginok", AST_DIGIT_NONE);
2136         }
2137
2138         ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", agent->username,
2139                 ast_format_get_name(ast_channel_readformat(chan)),
2140                 ast_format_get_name(ast_channel_writeformat(chan)));
2141         ast_channel_lock(chan);
2142         send_agent_login(chan, agent->username);
2143         ast_channel_unlock(chan);
2144
2145         agent_run(agent, chan);
2146         return -1;
2147 }
2148
2149 static int agent_function_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
2150 {
2151         char *parse;
2152         struct agent_pvt *agent;
2153         struct ast_channel *logged;
2154         AST_DECLARE_APP_ARGS(args,
2155                 AST_APP_ARG(agentid);
2156                 AST_APP_ARG(item);
2157         );
2158
2159         buf[0] = '\0';
2160
2161         parse = ast_strdupa(data ?: "");
2162         AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2163
2164         if (ast_strlen_zero(args.agentid)) {
2165                 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2166                 return -1;
2167         }
2168         if (!args.item) {
2169                 args.item = "status";
2170         }
2171
2172         agent = ao2_find(agents, args.agentid, OBJ_KEY);
2173         if (!agent) {
2174                 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2175                 return -1;
2176         }
2177
2178         agent_lock(agent);
2179         if (!strcasecmp(args.item, "status")) {
2180                 const char *status;
2181
2182                 if (agent->logged) {
2183                         status = "LOGGEDIN";
2184                 } else {
2185                         status = "LOGGEDOUT";
2186                 }
2187                 ast_copy_string(buf, status, len);
2188         } else if (!strcasecmp(args.item, "name")) {
2189                 ast_copy_string(buf, agent->cfg->full_name, len);
2190         } else if (!strcasecmp(args.item, "mohclass")) {
2191                 ast_copy_string(buf, agent->cfg->moh, len);
2192         } else if (!strcasecmp(args.item, "channel")) {
2193                 logged = agent_lock_logged(agent);
2194                 if (logged) {
2195                         char *pos;
2196
2197                         ast_copy_string(buf, ast_channel_name(logged), len);
2198                         ast_channel_unlock(logged);
2199                         ast_channel_unref(logged);
2200
2201                         pos = strrchr(buf, '-');
2202                         if (pos) {
2203                                 *pos = '\0';
2204                         }
2205                 }
2206         } else if (!strcasecmp(args.item, "fullchannel")) {
2207                 logged = agent_lock_logged(agent);
2208                 if (logged) {
2209                         ast_copy_string(buf, ast_channel_name(logged), len);
2210                         ast_channel_unlock(logged);
2211                         ast_channel_unref(logged);
2212                 }
2213         }
2214         agent_unlock(agent);
2215         ao2_ref(agent, -1);
2216
2217         return 0;
2218 }
2219
2220 static struct ast_custom_function agent_function = {
2221         .name = "AGENT",
2222         .read = agent_function_read,
2223 };
2224
2225 struct agent_complete {
2226         /*! Nth match to return. */
2227         int state;
2228         /*! Which match currently on. */
2229         int which;
2230 };
2231
2232 static int complete_agent_search(void *obj, void *arg, void *data, int flags)
2233 {
2234         struct agent_complete *search = data;
2235
2236         if (++search->which > search->state) {
2237                 return CMP_MATCH;
2238         }
2239         return 0;
2240 }
2241
2242 static char *complete_agent(const char *word, int state)
2243 {
2244         char *ret;
2245         struct agent_pvt *agent;
2246         struct agent_complete search = {
2247                 .state = state,
2248         };
2249
2250         agent = ao2_callback_data(agents, ast_strlen_zero(word) ? 0 : OBJ_PARTIAL_KEY,
2251                 complete_agent_search, (char *) word, &search);
2252         if (!agent) {
2253                 return NULL;
2254         }
2255         ret = ast_strdup(agent->username);
2256         ao2_ref(agent, -1);
2257         return ret;
2258 }
2259
2260 static int complete_agent_logoff_search(void *obj, void *arg, void *data, int flags)
2261 {
2262         struct agent_pvt *agent = obj;
2263         struct agent_complete *search = data;
2264
2265         if (!agent->logged) {
2266                 return 0;
2267         }
2268         if (++search->which > search->state) {
2269                 return CMP_MATCH;
2270         }
2271         return 0;
2272 }
2273
2274 static char *complete_agent_logoff(const char *word, int state)
2275 {
2276         char *ret;
2277         struct agent_pvt *agent;
2278         struct agent_complete search = {
2279                 .state = state,
2280         };
2281
2282         agent = ao2_callback_data(agents, ast_strlen_zero(word) ? 0 : OBJ_PARTIAL_KEY,
2283                 complete_agent_logoff_search, (char *) word, &search);
2284         if (!agent) {
2285                 return NULL;
2286         }
2287         ret = ast_strdup(agent->username);
2288         ao2_ref(agent, -1);
2289         return ret;
2290 }
2291
2292 static void agent_show_requested(struct ast_cli_args *a, int online_only)
2293 {
2294 #define FORMAT_HDR "%-8s %-20s %-11s %-30s %s\n"
2295 #define FORMAT_ROW "%-8s %-20s %-11s %-30s %s\n"
2296
2297         struct ao2_iterator iter;
2298         struct agent_pvt *agent;
2299         struct ast_str *out = ast_str_alloca(512);
2300         unsigned int agents_total = 0;
2301         unsigned int agents_logged_in = 0;
2302         unsigned int agents_talking = 0;
2303
2304         ast_cli(a->fd, FORMAT_HDR, "Agent-ID", "Name", "State", "Channel", "Talking with");
2305         iter = ao2_iterator_init(agents, 0);
2306         for (; (agent = ao2_iterator_next(&iter)); ao2_ref(agent, -1)) {
2307                 struct ast_channel *logged;
2308
2309                 ++agents_total;
2310
2311                 agent_lock(agent);
2312                 logged = agent_lock_logged(agent);
2313                 if (logged) {
2314                         const char *talking_with;
2315
2316                         ++agents_logged_in;
2317
2318                         talking_with = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
2319                         if (!ast_strlen_zero(talking_with)) {
2320                                 ++agents_talking;
2321                         } else {
2322                                 talking_with = "";
2323                         }
2324                         ast_str_set(&out, 0, FORMAT_ROW, agent->username, agent->cfg->full_name,
2325                                 ast_devstate_str(agent->devstate), ast_channel_name(logged), talking_with);
2326                         ast_channel_unlock(logged);
2327                         ast_channel_unref(logged);
2328                 } else {
2329                         ast_str_set(&out, 0, FORMAT_ROW, agent->username, agent->cfg->full_name,
2330                                 ast_devstate_str(agent->devstate), "", "");
2331                 }
2332                 agent_unlock(agent);
2333
2334                 if (!online_only || logged) {
2335                         ast_cli(a->fd, "%s", ast_str_buffer(out));
2336                 }
2337         }
2338         ao2_iterator_destroy(&iter);
2339
2340         ast_cli(a->fd, "\nDefined agents: %u, Logged in: %u, Talking: %u\n",
2341                 agents_total, agents_logged_in, agents_talking);
2342
2343 #undef FORMAT_HDR
2344 #undef FORMAT_ROW
2345 }
2346
2347 static char *agent_handle_show_online(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2348 {
2349         switch (cmd) {
2350         case CLI_INIT:
2351                 e->command = "agent show online";
2352                 e->usage =
2353                         "Usage: agent show online\n"
2354                         "       Provides summary information for logged in agents.\n";
2355                 return NULL;
2356         case CLI_GENERATE:
2357                 return NULL;
2358         }
2359
2360         if (a->argc != 3) {
2361                 return CLI_SHOWUSAGE;
2362         }
2363
2364         agent_show_requested(a, 1);
2365
2366         return CLI_SUCCESS;
2367 }
2368
2369 static char *agent_handle_show_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2370 {
2371         switch (cmd) {
2372         case CLI_INIT:
2373                 e->command = "agent show all";
2374                 e->usage =
2375                         "Usage: agent show all\n"
2376                         "       Provides summary information for all agents.\n";
2377                 return NULL;
2378         case CLI_GENERATE:
2379                 return NULL;
2380         }
2381
2382         if (a->argc != 3) {
2383                 return CLI_SHOWUSAGE;
2384         }
2385
2386         agent_show_requested(a, 0);
2387
2388         return CLI_SUCCESS;
2389 }
2390
2391 static char *agent_handle_show_specific(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2392 {
2393         struct agent_pvt *agent;
2394         struct ast_channel *logged;
2395         struct ast_str *out = ast_str_alloca(4096);
2396
2397         switch (cmd) {
2398         case CLI_INIT:
2399                 e->command = "agent show";
2400                 e->usage =
2401                         "Usage: agent show <agent-id>\n"
2402                         "       Show information about the <agent-id> agent\n";
2403                 return NULL;
2404         case CLI_GENERATE:
2405                 if (a->pos == 2) {
2406                         return complete_agent(a->word, a->n);
2407                 }
2408                 return NULL;
2409         }
2410
2411         if (a->argc != 3) {
2412                 return CLI_SHOWUSAGE;
2413         }
2414
2415         agent = ao2_find(agents, a->argv[2], OBJ_KEY);
2416         if (!agent) {
2417                 ast_cli(a->fd, "Agent '%s' not found\n", a->argv[2]);
2418                 return CLI_SUCCESS;
2419         }
2420
2421         agent_lock(agent);
2422         logged = agent_lock_logged(agent);
2423         ast_str_set(&out, 0, "Id: %s\n", agent->username);
2424         ast_str_append(&out, 0, "Name: %s\n", agent->cfg->full_name);
2425         ast_str_append(&out, 0, "Beep: %s\n", agent->cfg->beep_sound);
2426         ast_str_append(&out, 0, "MOH: %s\n", agent->cfg->moh);
2427         ast_str_append(&out, 0, "RecordCalls: %s\n", AST_CLI_YESNO(agent->cfg->record_agent_calls));
2428         ast_str_append(&out, 0, "State: %s\n", ast_devstate_str(agent->devstate));
2429         if (logged) {
2430                 const char *talking_with;
2431
2432                 ast_str_append(&out, 0, "LoggedInChannel: %s\n", ast_channel_name(logged));
2433                 ast_str_append(&out, 0, "LoggedInTime: %ld\n", (long) agent->login_start);
2434                 talking_with = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
2435                 if (!ast_strlen_zero(talking_with)) {
2436                         ast_str_append(&out, 0, "TalkingWith: %s\n", talking_with);
2437                         ast_str_append(&out, 0, "CallStarted: %ld\n", (long) agent->call_start);
2438                 }
2439                 ast_channel_unlock(logged);
2440                 ast_channel_unref(logged);
2441         }
2442         agent_unlock(agent);
2443         ao2_ref(agent, -1);
2444
2445         ast_cli(a->fd, "%s", ast_str_buffer(out));
2446
2447         return CLI_SUCCESS;
2448 }
2449
2450 static char *agent_handle_logoff_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2451 {
2452         switch (cmd) {
2453         case CLI_INIT:
2454                 e->command = "agent logoff";
2455                 e->usage =
2456                         "Usage: agent logoff <agent-id> [soft]\n"
2457                         "       Sets an agent as no longer logged in.\n"
2458                         "       If 'soft' is specified, do not hangup existing calls.\n";
2459                 return NULL;
2460         case CLI_GENERATE:
2461                 if (a->pos == 2) {
2462                         return complete_agent_logoff(a->word, a->n);
2463                 } else if (a->pos == 3 && a->n == 0
2464                         && (ast_strlen_zero(a->word)
2465                                 || !strncasecmp("soft", a->word, strlen(a->word)))) {
2466                         return ast_strdup("soft");
2467                 }
2468                 return NULL;
2469         }
2470
2471         if (a->argc < 3 || 4 < a->argc) {
2472                 return CLI_SHOWUSAGE;
2473         }
2474         if (a->argc == 4 && strcasecmp(a->argv[3], "soft")) {
2475                 return CLI_SHOWUSAGE;
2476         }
2477
2478         if (!agent_logoff_request(a->argv[2], a->argc == 4)) {
2479                 ast_cli(a->fd, "Logging out %s\n", a->argv[2]);
2480         }
2481
2482         return CLI_SUCCESS;
2483 }
2484
2485 static struct ast_cli_entry cli_agents[] = {
2486         AST_CLI_DEFINE(agent_handle_show_online, "Show status of online agents"),
2487         AST_CLI_DEFINE(agent_handle_show_all, "Show status of all agents"),
2488         AST_CLI_DEFINE(agent_handle_show_specific, "Show information about an agent"),
2489         AST_CLI_DEFINE(agent_handle_logoff_cmd, "Sets an agent offline"),
2490 };
2491
2492 static int action_agents(struct mansession *s, const struct message *m)
2493 {
2494         const char *id = astman_get_header(m, "ActionID");
2495         char id_text[AST_MAX_BUF];
2496         struct ao2_iterator iter;
2497         struct agent_pvt *agent;
2498         struct ast_str *out = ast_str_alloca(4096);
2499
2500         if (!ast_strlen_zero(id)) {
2501                 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
2502         } else {
2503                 id_text[0] = '\0';
2504         }
2505         astman_send_ack(s, m, "Agents will follow");
2506
2507         iter = ao2_iterator_init(agents, 0);
2508         for (; (agent = ao2_iterator_next(&iter)); ao2_ref(agent, -1)) {
2509                 struct ast_channel *logged;
2510
2511                 agent_lock(agent);
2512                 logged = agent_lock_logged(agent);
2513
2514                 /*
2515                  * Status Values:
2516                  * AGENT_LOGGEDOFF - Agent isn't logged in
2517                  * AGENT_IDLE      - Agent is logged in, and waiting for call
2518                  * AGENT_ONCALL    - Agent is logged in, and on a call
2519                  * AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this.
2520                  */
2521                 ast_str_set(&out, 0, "Agent: %s\r\n", agent->username);
2522                 ast_str_append(&out, 0, "Name: %s\r\n", agent->cfg->full_name);
2523
2524                 if (logged) {
2525                         const char *talking_to_chan;
2526                         struct ast_str *logged_headers;
2527                         RAII_VAR(struct ast_channel_snapshot *, logged_snapshot, ast_channel_snapshot_create(logged), ao2_cleanup);
2528
2529                         if (!logged_snapshot
2530                                 || !(logged_headers =
2531                                          ast_manager_build_channel_state_string(logged_snapshot))) {
2532                                 ast_channel_unlock(logged);
2533                                 ast_channel_unref(logged);
2534                                 agent_unlock(agent);
2535                                 continue;
2536                         }
2537
2538                         talking_to_chan = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
2539                         if (!ast_strlen_zero(talking_to_chan)) {
2540                                 ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_ONCALL");
2541                                 ast_str_append(&out, 0, "TalkingToChan: %s\r\n", talking_to_chan);
2542                                 ast_str_append(&out, 0, "CallStarted: %ld\n", (long) agent->call_start);
2543                         } else {
2544                                 ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_IDLE");
2545                         }
2546                         ast_str_append(&out, 0, "LoggedInTime: %ld\r\n", (long) agent->login_start);
2547                         ast_str_append(&out, 0, "%s", ast_str_buffer(logged_headers));
2548                         ast_channel_unlock(logged);
2549                         ast_channel_unref(logged);
2550                         ast_free(logged_headers);
2551                 } else {
2552                         ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_LOGGEDOFF");
2553                 }
2554
2555                 agent_unlock(agent);
2556
2557                 astman_append(s, "Event: Agents\r\n"
2558                         "%s%s\r\n",
2559                         ast_str_buffer(out), id_text);
2560         }
2561         ao2_iterator_destroy(&iter);
2562
2563         astman_append(s, "Event: AgentsComplete\r\n"
2564                 "%s"
2565                 "\r\n", id_text);
2566         return 0;
2567 }
2568
2569 static int action_agent_logoff(struct mansession *s, const struct message *m)
2570 {
2571         const char *agent = astman_get_header(m, "Agent");
2572         const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
2573
2574         if (ast_strlen_zero(agent)) {
2575                 astman_send_error(s, m, "No agent specified");
2576                 return 0;
2577         }
2578
2579         if (!agent_logoff_request(agent, ast_true(soft_s))) {
2580                 astman_send_ack(s, m, "Agent logged out");
2581         } else {
2582                 astman_send_error(s, m, "No such agent");
2583         }
2584
2585         return 0;
2586 }
2587
2588 static int unload_module(void)
2589 {
2590         struct ast_bridge *holding;
2591
2592         /* Unregister dialplan applications */
2593         ast_unregister_application(app_agent_login);
2594         ast_unregister_application(app_agent_request);
2595
2596         /* Unregister dialplan functions */
2597         ast_custom_function_unregister(&agent_function);
2598
2599         /* Unregister manager command */
2600         ast_manager_unregister("Agents");
2601         ast_manager_unregister("AgentLogoff");
2602
2603         /* Unregister CLI commands */
2604         ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
2605
2606         ast_devstate_prov_del("Agent");
2607
2608         /* Destroy agent holding bridge. */
2609         holding = ao2_global_obj_replace(agent_holding, NULL);
2610         if (holding) {
2611                 ast_bridge_destroy(holding, 0);
2612         }
2613
2614         destroy_config();
2615         ao2_ref(agents, -1);
2616         agents = NULL;
2617         return 0;
2618 }
2619
2620 static int load_module(void)
2621 {
2622         int res = 0;
2623
2624         agents = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX,
2625                 AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, agent_pvt_sort_cmp, agent_pvt_cmp);
2626         if (!agents) {
2627                 return AST_MODULE_LOAD_FAILURE;
2628         }
2629         if (load_config()) {
2630                 ast_log(LOG_ERROR, "Unable to load config. Not loading module.\n");
2631                 ao2_ref(agents, -1);
2632                 agents = NULL;
2633                 return AST_MODULE_LOAD_DECLINE;
2634         }
2635
2636         /* Init agent holding bridge v_table. */
2637         bridge_init_agent_hold();
2638
2639         /* Setup to provide Agent:agent-id device state. */
2640         res |= ast_devstate_prov_add("Agent", agent_pvt_devstate_get);
2641
2642         /* CLI Commands */
2643         res |= ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
2644
2645         /* Manager commands */
2646         res |= ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
2647         res |= ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
2648
2649         /* Dialplan Functions */
2650         res |= ast_custom_function_register(&agent_function);
2651
2652         /* Dialplan applications */
2653         res |= ast_register_application_xml(app_agent_login, agent_login_exec);
2654         res |= ast_register_application_xml(app_agent_request, agent_request_exec);
2655
2656         if (res) {
2657                 unload_module();
2658                 return AST_MODULE_LOAD_FAILURE;
2659         }
2660         return AST_MODULE_LOAD_SUCCESS;
2661 }
2662
2663 static int reload(void)
2664 {
2665         if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
2666                 /* Just keep the config we already have in place. */
2667                 return -1;
2668         }
2669         return 0;
2670 }
2671
2672 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Call center agent pool applications",
2673         .load = load_module,
2674         .unload = unload_module,
2675         .reload = reload,
2676         .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
2677 );