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