Remove required type field from channel blobs
[asterisk/asterisk.git] / main / manager_channels.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@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 /*! \file
20  *
21  * \brief The Asterisk Management Interface - AMI (channel event handling)
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  *
25  * AMI generated many per-channel and global-channel events by converting Stasis
26  * messages to AMI events. It makes sense to simply put them into a single file.
27  */
28
29 #include "asterisk.h"
30
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32
33 #include "asterisk/callerid.h"
34 #include "asterisk/channel.h"
35 #include "asterisk/manager.h"
36 #include "asterisk/stasis_message_router.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/stasis_channels.h"
39
40 static struct stasis_message_router *channel_state_router;
41
42 /*** DOCUMENTATION
43         <managerEvent language="en_US" name="Newchannel">
44                 <managerEventInstance class="EVENT_FLAG_CALL">
45                         <synopsis>Raised when a new channel is created.</synopsis>
46                         <syntax>
47                                 <parameter name="Channel">
48                                 </parameter>
49                                 <parameter name="ChannelState">
50                                         <para>A numeric code for the channel's current state, related to ChannelStateDesc</para>
51                                 </parameter>
52                                 <parameter name="ChannelStateDesc">
53                                         <enumlist>
54                                                 <enum name="Down"/>
55                                                 <enum name="Rsrvd"/>
56                                                 <enum name="OffHook"/>
57                                                 <enum name="Dialing"/>
58                                                 <enum name="Ring"/>
59                                                 <enum name="Ringing"/>
60                                                 <enum name="Up"/>
61                                                 <enum name="Busy"/>
62                                                 <enum name="Dialing Offhook"/>
63                                                 <enum name="Pre-ring"/>
64                                                 <enum name="Unknown"/>
65                                         </enumlist>
66                                 </parameter>
67                                 <parameter name="CallerIDNum">
68                                 </parameter>
69                                 <parameter name="CallerIDName">
70                                 </parameter>
71                                 <parameter name="ConnectedLineNum">
72                                 </parameter>
73                                 <parameter name="ConnectedLineName">
74                                 </parameter>
75                                 <parameter name="AccountCode">
76                                 </parameter>
77                                 <parameter name="Context">
78                                 </parameter>
79                                 <parameter name="Exten">
80                                 </parameter>
81                                 <parameter name="Priority">
82                                 </parameter>
83                                 <parameter name="Uniqueid">
84                                 </parameter>
85                         </syntax>
86                 </managerEventInstance>
87         </managerEvent>
88         <managerEvent language="en_US" name="Newstate">
89                 <managerEventInstance class="EVENT_FLAG_CALL">
90                         <synopsis>Raised when a channel's state changes.</synopsis>
91                         <syntax>
92                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
93                         </syntax>
94                 </managerEventInstance>
95         </managerEvent>
96         <managerEvent language="en_US" name="Hangup">
97                 <managerEventInstance class="EVENT_FLAG_CALL">
98                         <synopsis>Raised when a channel is hung up.</synopsis>
99                         <syntax>
100                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
101                                 <parameter name="Cause">
102                                         <para>A numeric cause code for why the channel was hung up.</para>
103                                 </parameter>
104                                 <parameter name="Cause-txt">
105                                         <para>A description of why the channel was hung up.</para>
106                                 </parameter>
107                         </syntax>
108                 </managerEventInstance>
109         </managerEvent>
110         <managerEvent language="en_US" name="HangupRequest">
111                 <managerEventInstance class="EVENT_FLAG_CALL">
112                         <synopsis>Raised when a hangup is requested.</synopsis>
113                         <syntax>
114                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
115                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Hangup']/managerEventInstance/syntax/parameter[@name='Cause'])" />
116                         </syntax>
117                 </managerEventInstance>
118         </managerEvent>
119         <managerEvent language="en_US" name="SoftHangupRequest">
120                 <managerEventInstance class="EVENT_FLAG_CALL">
121                         <synopsis>Raised when a soft hangup is requested with a specific cause code.</synopsis>
122                         <syntax>
123                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
124                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Hangup']/managerEventInstance/syntax/parameter[@name='Cause'])" />
125                         </syntax>
126                 </managerEventInstance>
127         </managerEvent>
128         <managerEvent language="en_US" name="NewExten">
129                 <managerEventInstance class="EVENT_FLAG_DIALPLAN">
130                         <synopsis>Raised when a channel enters a new context, extension, priority.</synopsis>
131                         <syntax>
132                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
133                                 <parameter name="Extension">
134                                         <para>Deprecated in 12, but kept for
135                                         backward compatability. Please use
136                                         'Exten' instead.</para>
137                                 </parameter>
138                                 <parameter name="Application">
139                                         <para>The application about to be executed.</para>
140                                 </parameter>
141                                 <parameter name="AppData">
142                                         <para>The data to be passed to the application.</para>
143                                 </parameter>
144                         </syntax>
145                 </managerEventInstance>
146         </managerEvent>
147         <managerEvent language="en_US" name="NewCallerid">
148                 <managerEventInstance class="EVENT_FLAG_CALL">
149                         <synopsis>Raised when a channel receives new Caller ID information.</synopsis>
150                         <syntax>
151                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
152                                 <parameter name="CID-CallingPres">
153                                         <para>A description of the Caller ID presentation.</para>
154                                 </parameter>
155                         </syntax>
156                 </managerEventInstance>
157         </managerEvent>
158         <managerEvent language="en_US" name="DialBegin">
159                 <managerEventInstance class="EVENT_FLAG_CALL">
160                         <synopsis>Raised when a dial action has started.</synopsis>
161                         <syntax>
162                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
163                                 <parameter name="ChannelDest">
164                                 </parameter>
165                                 <parameter name="ChannelStateDest">
166                                         <para>A numeric code for the channel's current state, related to ChannelStateDescDest</para>
167                                 </parameter>
168                                 <parameter name="ChannelStateDescDest">
169                                         <enumlist>
170                                                 <enum name="Down"/>
171                                                 <enum name="Rsrvd"/>
172                                                 <enum name="OffHook"/>
173                                                 <enum name="Dialing"/>
174                                                 <enum name="Ring"/>
175                                                 <enum name="Ringing"/>
176                                                 <enum name="Up"/>
177                                                 <enum name="Busy"/>
178                                                 <enum name="Dialing Offhook"/>
179                                                 <enum name="Pre-ring"/>
180                                                 <enum name="Unknown"/>
181                                         </enumlist>
182                                 </parameter>
183                                 <parameter name="CallerIDNumDest">
184                                 </parameter>
185                                 <parameter name="CallerIDNameDest">
186                                 </parameter>
187                                 <parameter name="ConnectedLineNumDest">
188                                 </parameter>
189                                 <parameter name="ConnectedLineNameDest">
190                                 </parameter>
191                                 <parameter name="AccountCodeDest">
192                                 </parameter>
193                                 <parameter name="ContextDest">
194                                 </parameter>
195                                 <parameter name="ExtenDest">
196                                 </parameter>
197                                 <parameter name="PriorityDest">
198                                 </parameter>
199                                 <parameter name="UniqueidDest">
200                                 </parameter>
201                                 <parameter name="DialString">
202                                         <para>The non-technology specific device being dialed.</para>
203                                 </parameter>
204                         </syntax>
205                         <see-also>
206                                 <ref type="application">Dial</ref>
207                         </see-also>
208                 </managerEventInstance>
209         </managerEvent>
210         <managerEvent language="en_US" name="DialEnd">
211                 <managerEventInstance class="EVENT_FLAG_CALL">
212                         <synopsis>Raised when a dial action has completed.</synopsis>
213                         <syntax>
214                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
215                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='DialBegin']/managerEventInstance/syntax/parameter[contains(@name, 'Dest')])" />
216                                 <parameter name="DialStatus">
217                                         <para>The result of the dial operation.</para>
218                                         <enumlist>
219                                                 <enum name="ANSWER" />
220                                                 <enum name="BUSY" />
221                                                 <enum name="CANCEL" />
222                                                 <enum name="CHANUNAVAIL" />
223                                                 <enum name="CONGESTION" />
224                                                 <enum name="NOANSWER" />
225                                         </enumlist>
226                                 </parameter>
227                         </syntax>
228                         <see-also>
229                                 <ref type="application">Dial</ref>
230                         </see-also>
231                 </managerEventInstance>
232         </managerEvent>
233  ***/
234
235 struct ast_str *ast_manager_build_channel_state_string_suffix(
236                 const struct ast_channel_snapshot *snapshot,
237                 const char *suffix)
238 {
239         struct ast_str *out = ast_str_create(1024);
240         int res = 0;
241         if (!out) {
242                 return NULL;
243         }
244         res = ast_str_set(&out, 0,
245                 "Channel%s: %s\r\n"
246                 "ChannelState%s: %d\r\n"
247                 "ChannelStateDesc%s: %s\r\n"
248                 "CallerIDNum%s: %s\r\n"
249                 "CallerIDName%s: %s\r\n"
250                 "ConnectedLineNum%s: %s\r\n"
251                 "ConnectedLineName%s: %s\r\n"
252                 "AccountCode%s: %s\r\n"
253                 "Context%s: %s\r\n"
254                 "Exten%s: %s\r\n"
255                 "Priority%s: %d\r\n"
256                 "Uniqueid%s: %s\r\n",
257                 suffix, snapshot->name,
258                 suffix, snapshot->state,
259                 suffix, ast_state2str(snapshot->state),
260                 suffix, S_OR(snapshot->caller_number, "<unknown>"),
261                 suffix, S_OR(snapshot->caller_name, "<unknown>"),
262                 suffix, S_OR(snapshot->connected_number, "<unknown>"),
263                 suffix, S_OR(snapshot->connected_name, "<unknown>"),
264                 suffix, snapshot->accountcode,
265                 suffix, snapshot->context,
266                 suffix, snapshot->exten,
267                 suffix, snapshot->priority,
268                 suffix, snapshot->uniqueid);
269
270         if (!res) {
271                 return NULL;
272         }
273
274         if (snapshot->manager_vars) {
275                 struct ast_var_t *var;
276                 AST_LIST_TRAVERSE(snapshot->manager_vars, var, entries) {
277                         ast_str_append(&out, 0, "ChanVariable%s: %s=%s\r\n",
278                                        suffix,
279                                        var->name, var->value);
280                 }
281         }
282
283         return out;
284 }
285
286 struct ast_str *ast_manager_build_channel_state_string(
287         const struct ast_channel_snapshot *snapshot)
288 {
289         return ast_manager_build_channel_state_string_suffix(snapshot, "");
290 }
291
292 /*! \brief Struct containing info for an AMI channel event to send out. */
293 struct snapshot_manager_event {
294         /*! event_flags manager_event() flags parameter. */
295         int event_flags;
296         /*!  manager_event manager_event() category. */
297         const char *manager_event;
298         AST_DECLARE_STRING_FIELDS(
299                 /* extra fields to include in the event. */
300                 AST_STRING_FIELD(extra_fields);
301                 );
302 };
303
304 static void snapshot_manager_event_dtor(void *obj)
305 {
306         struct snapshot_manager_event *ev = obj;
307         ast_string_field_free_memory(ev);
308 }
309
310 /*!
311  * \brief Construct a \ref snapshot_manager_event.
312  * \param event_flags manager_event() flags parameter.
313  * \param manager_event manager_event() category.
314  * \param extra_fields_fmt Format string for extra fields to include.
315  *                         Or NO_EXTRA_FIELDS for no extra fields.
316  * \return New \ref snapshot_manager_event object.
317  * \return \c NULL on error.
318  */
319 static struct snapshot_manager_event *
320 __attribute__((format(printf, 3, 4)))
321 snapshot_manager_event_create(
322         int event_flags,
323         const char *manager_event,
324         const char *extra_fields_fmt,
325         ...)
326 {
327         RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
328         va_list argp;
329
330         ast_assert(extra_fields_fmt != NULL);
331         ast_assert(manager_event != NULL);
332
333         ev = ao2_alloc(sizeof(*ev), snapshot_manager_event_dtor);
334         if (!ev) {
335                 return NULL;
336         }
337
338         if (ast_string_field_init(ev, 20)) {
339                 return NULL;
340         }
341
342         ev->manager_event = manager_event;
343         ev->event_flags = event_flags;
344
345         va_start(argp, extra_fields_fmt);
346         ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt,
347                                       argp);
348         va_end(argp);
349
350         ao2_ref(ev, +1);
351         return ev;
352 }
353
354 /*! GCC warns about blank or NULL format strings. So, shenanigans! */
355 #define NO_EXTRA_FIELDS "%s", ""
356
357 /*! \brief Typedef for callbacks that get called on channel snapshot updates */
358 typedef struct snapshot_manager_event *(*snapshot_monitor)(
359         struct ast_channel_snapshot *old_snapshot,
360         struct ast_channel_snapshot *new_snapshot);
361
362 /*! \brief Handle channel state changes */
363 static struct snapshot_manager_event *channel_state_change(
364         struct ast_channel_snapshot *old_snapshot,
365         struct ast_channel_snapshot *new_snapshot)
366 {
367         int is_hungup, was_hungup;
368
369         if (!new_snapshot) {
370                 /* Ignore cache clearing events; we'll see the hangup first */
371                 return NULL;
372         }
373
374         /* The Newchannel, Newstate and Hangup events are closely related, in
375          * in that they are mutually exclusive, basically different flavors
376          * of a new channel state event.
377          */
378
379         if (!old_snapshot) {
380                 return snapshot_manager_event_create(
381                         EVENT_FLAG_CALL, "Newchannel", NO_EXTRA_FIELDS);
382         }
383
384         was_hungup = ast_test_flag(&old_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
385         is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
386
387         if (!was_hungup && is_hungup) {
388                 return snapshot_manager_event_create(
389                         EVENT_FLAG_CALL, "Hangup",
390                         "Cause: %d\r\n"
391                         "Cause-txt: %s\r\n",
392                         new_snapshot->hangupcause,
393                         ast_cause2str(new_snapshot->hangupcause));
394         }
395
396         if (old_snapshot->state != new_snapshot->state) {
397                 return snapshot_manager_event_create(
398                         EVENT_FLAG_CALL, "Newstate", NO_EXTRA_FIELDS);
399         }
400
401         /* No event */
402         return NULL;
403 }
404
405 /*!
406  * \brief Compares the context, exten and priority of two snapshots.
407  * \param old_snapshot Old snapshot
408  * \param new_snapshot New snapshot
409  * \return True (non-zero) if context, exten or priority are identical.
410  * \return False (zero) if context, exten and priority changed.
411  */
412 static inline int cep_equal(
413         const struct ast_channel_snapshot *old_snapshot,
414         const struct ast_channel_snapshot *new_snapshot)
415 {
416         ast_assert(old_snapshot != NULL);
417         ast_assert(new_snapshot != NULL);
418
419         /* We actually get some snapshots with CEP set, but before the
420          * application is set. Since empty application is invalid, we treat
421          * setting the application from nothing as a CEP change.
422          */
423         if (ast_strlen_zero(old_snapshot->appl) &&
424             !ast_strlen_zero(new_snapshot->appl)) {
425                 return 0;
426         }
427
428         return old_snapshot->priority == new_snapshot->priority &&
429                 strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
430                 strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
431 }
432
433 static struct snapshot_manager_event *channel_newexten(
434         struct ast_channel_snapshot *old_snapshot,
435         struct ast_channel_snapshot *new_snapshot)
436 {
437         /* No Newexten event on cache clear */
438         if (!new_snapshot) {
439                 return NULL;
440         }
441
442         /* Empty application is not valid for a Newexten event */
443         if (ast_strlen_zero(new_snapshot->appl)) {
444                 return NULL;
445         }
446
447         if (old_snapshot && cep_equal(old_snapshot, new_snapshot)) {
448                 return NULL;
449         }
450
451         /* DEPRECATED: Extension field deprecated in 12; remove in 14 */
452         return snapshot_manager_event_create(
453                 EVENT_FLAG_CALL, "Newexten",
454                 "Extension: %s\r\n"
455                 "Application: %s\r\n"
456                 "AppData: %s\r\n",
457                 new_snapshot->exten,
458                 new_snapshot->appl,
459                 new_snapshot->data);
460 }
461
462 /*!
463  * \brief Compares the callerid info of two snapshots.
464  * \param old_snapshot Old snapshot
465  * \param new_snapshot New snapshot
466  * \return True (non-zero) if callerid are identical.
467  * \return False (zero) if callerid changed.
468  */
469 static inline int caller_id_equal(
470         const struct ast_channel_snapshot *old_snapshot,
471         const struct ast_channel_snapshot *new_snapshot)
472 {
473         ast_assert(old_snapshot != NULL);
474         ast_assert(new_snapshot != NULL);
475         return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
476                 strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
477 }
478
479 static struct snapshot_manager_event *channel_new_callerid(
480         struct ast_channel_snapshot *old_snapshot,
481         struct ast_channel_snapshot *new_snapshot)
482 {
483         /* No NewCallerid event on cache clear or first event */
484         if (!old_snapshot || !new_snapshot) {
485                 return NULL;
486         }
487
488         if (caller_id_equal(old_snapshot, new_snapshot)) {
489                 return NULL;
490         }
491
492         return snapshot_manager_event_create(
493                 EVENT_FLAG_CALL, "NewCallerid",
494                 "CID-CallingPres: %d (%s)\r\n",
495                 new_snapshot->caller_pres,
496                 ast_describe_caller_presentation(new_snapshot->caller_pres));
497 }
498
499 snapshot_monitor monitors[] = {
500         channel_state_change,
501         channel_newexten,
502         channel_new_callerid
503 };
504
505 static void channel_snapshot_update(void *data, struct stasis_subscription *sub,
506                                     struct stasis_topic *topic,
507                                     struct stasis_message *message)
508 {
509         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
510         struct stasis_cache_update *update;
511         struct ast_channel_snapshot *old_snapshot;
512         struct ast_channel_snapshot *new_snapshot;
513         size_t i;
514
515         update = stasis_message_data(message);
516
517         if (ast_channel_snapshot_type() != update->type) {
518                 return;
519         }
520
521         old_snapshot = stasis_message_data(update->old_snapshot);
522         new_snapshot = stasis_message_data(update->new_snapshot);
523
524         for (i = 0; i < ARRAY_LEN(monitors); ++i) {
525                 RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
526                 ev = monitors[i](old_snapshot, new_snapshot);
527
528                 if (!ev) {
529                         continue;
530                 }
531
532                 /* If we haven't already, build the channel event string */
533                 if (!channel_event_string) {
534                         channel_event_string =
535                                 ast_manager_build_channel_state_string(new_snapshot);
536                         if (!channel_event_string) {
537                                 return;
538                         }
539                 }
540
541                 manager_event(ev->event_flags, ev->manager_event, "%s%s",
542                         ast_str_buffer(channel_event_string),
543                         ev->extra_fields);
544         }
545 }
546
547 static void channel_varset_cb(void *data, struct stasis_subscription *sub,
548         struct stasis_topic *topic, struct stasis_message *message)
549 {
550         struct ast_channel_blob *obj = stasis_message_data(message);
551         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
552         const char *variable = ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
553         const char *value = ast_json_string_get(ast_json_object_get(obj->blob, "value"));
554
555         if (obj->snapshot) {
556                 channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
557         } else {
558                 channel_event_string = ast_str_create(35);
559                 ast_str_set(&channel_event_string, 0,
560                             "Channel: none\r\n"
561                             "Uniqueid: none\r\n");
562         }
563
564         if (!channel_event_string) {
565                 return;
566         }
567
568         /*** DOCUMENTATION
569                 <managerEventInstance>
570                         <synopsis>Raised when a variable is set to a particular value.</synopsis>
571                         <syntax>
572                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
573                                 <parameter name="Variable">
574                                         <para>The variable being set.</para>
575                                 </parameter>
576                                 <parameter name="Value">
577                                         <para>The new value of the variable.</para>
578                                 </parameter>
579                         </syntax>
580                 </managerEventInstance>
581         ***/
582         manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
583                       "%s"
584                       "Variable: %s\r\n"
585                       "Value: %s\r\n",
586                       ast_str_buffer(channel_event_string),
587                       variable, value);
588 }
589
590 static void channel_user_event_cb(void *data, struct stasis_subscription *sub,
591         struct stasis_topic *topic, struct stasis_message *message)
592 {
593         struct ast_channel_blob *obj = stasis_message_data(message);
594         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
595         const char *eventname;
596         const char *body;
597
598         eventname = ast_json_string_get(ast_json_object_get(obj->blob, "eventname"));
599         body = ast_json_string_get(ast_json_object_get(obj->blob, "body"));
600         channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
601
602         if (!channel_event_string) {
603                 return;
604         }
605
606         /*** DOCUMENTATION
607                 <managerEventInstance>
608                         <synopsis>A user defined event raised from the dialplan.</synopsis>
609                         <syntax>
610                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
611                                 <parameter name="UserEvent">
612                                         <para>The event name, as specified in the dialplan.</para>
613                                 </parameter>
614                         </syntax>
615                         <see-also>
616                                 <ref type="application">UserEvent</ref>
617                         </see-also>
618                 </managerEventInstance>
619         ***/
620         manager_event(EVENT_FLAG_USER, "UserEvent",
621                       "%s"
622                       "UserEvent: %s\r\n"
623                       "%s",
624                       ast_str_buffer(channel_event_string), eventname, body);
625 }
626
627 static void channel_hangup_request_cb(void *data,
628         struct stasis_subscription *sub, struct stasis_topic *topic,
629         struct stasis_message *message)
630 {
631         struct ast_channel_blob *obj = stasis_message_data(message);
632         RAII_VAR(struct ast_str *, extra, NULL, ast_free);
633         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
634         struct ast_json *cause;
635         int is_soft;
636         char *manager_event = "HangupRequest";
637
638         extra = ast_str_create(20);
639         if (!extra) {
640                 return;
641         }
642
643         channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
644
645         if (!channel_event_string) {
646                 return;
647         }
648
649         cause = ast_json_object_get(obj->blob, "cause");
650         if (cause) {
651                 ast_str_append(&extra, 0,
652                                "Cause: %jd\r\n",
653                                ast_json_integer_get(cause));
654         }
655
656         is_soft = ast_json_is_true(ast_json_object_get(obj->blob, "soft"));
657         if (is_soft) {
658                 manager_event = "SoftHangupRequest";
659         }
660
661         manager_event(EVENT_FLAG_CALL, manager_event,
662                       "%s%s",
663                       ast_str_buffer(channel_event_string),
664                       ast_str_buffer(extra));
665 }
666
667 static void channel_dtmf_begin_cb(void *data, struct stasis_subscription *sub,
668         struct stasis_topic *topic, struct stasis_message *message)
669 {
670         struct ast_channel_blob *obj = stasis_message_data(message);
671         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
672         const char *digit =
673                 ast_json_string_get(ast_json_object_get(obj->blob, "digit"));
674         const char *direction =
675                 ast_json_string_get(ast_json_object_get(obj->blob, "direction"));
676
677         channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
678
679         if (!channel_event_string) {
680                 return;
681         }
682
683         /*** DOCUMENTATION
684                 <managerEventInstance>
685                         <synopsis>Raised when a DTMF digit has started on a channel.</synopsis>
686                                 <syntax>
687                                         <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
688                                         <parameter name="Digit">
689                                                 <para>DTMF digit received or transmitted (0-9, A-E, # or *</para>
690                                         </parameter>
691                                         <parameter name="Direction">
692                                                 <enumlist>
693                                                         <enum name="Received"/>
694                                                         <enum name="Sent"/>
695                                                 </enumlist>
696                                         </parameter>
697                                 </syntax>
698                 </managerEventInstance>
699         ***/
700         manager_event(EVENT_FLAG_DTMF, "DTMFBegin",
701                 "%s"
702                 "Digit: %s\r\n"
703                 "Direction: %s\r\n",
704                 ast_str_buffer(channel_event_string),
705                 digit, direction);
706 }
707
708 static void channel_dtmf_end_cb(void *data, struct stasis_subscription *sub,
709         struct stasis_topic *topic, struct stasis_message *message)
710 {
711         struct ast_channel_blob *obj = stasis_message_data(message);
712         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
713         const char *digit =
714                 ast_json_string_get(ast_json_object_get(obj->blob, "digit"));
715         const char *direction =
716                 ast_json_string_get(ast_json_object_get(obj->blob, "direction"));
717         long duration_ms =
718                 ast_json_integer_get(ast_json_object_get(obj->blob, "duration_ms"));
719
720         channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
721
722         if (!channel_event_string) {
723                 return;
724         }
725
726         /*** DOCUMENTATION
727                 <managerEventInstance>
728                         <synopsis>Raised when a DTMF digit has ended on a channel.</synopsis>
729                                 <syntax>
730                                         <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
731                                         <parameter name="Digit">
732                                                 <para>DTMF digit received or transmitted (0-9, A-E, # or *</para>
733                                         </parameter>
734                                         <parameter name="DurationMs">
735                                                 <para>Duration (in milliseconds) DTMF was sent/received</para>
736                                         </parameter>
737                                         <parameter name="Direction">
738                                                 <enumlist>
739                                                         <enum name="Received"/>
740                                                         <enum name="Sent"/>
741                                                 </enumlist>
742                                         </parameter>
743                                 </syntax>
744                 </managerEventInstance>
745         ***/
746         manager_event(EVENT_FLAG_DTMF, "DTMFEnd",
747                 "%s"
748                 "Digit: %s\r\n"
749                 "DurationMs: %ld\r\n"
750                 "Direction: %s\r\n",
751                 ast_str_buffer(channel_event_string),
752                 digit, duration_ms, direction);
753 }
754
755 /*!
756  * \brief Callback processing messages for channel dialing
757  */
758 static void channel_dial_cb(void *data, struct stasis_subscription *sub,
759         struct stasis_topic *topic, struct stasis_message *message)
760 {
761         struct ast_multi_channel_blob *obj = stasis_message_data(message);
762         const char *dialstatus;
763         const char *dialstring;
764         struct ast_channel_snapshot *caller;
765         struct ast_channel_snapshot *peer;
766         RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
767         RAII_VAR(struct ast_str *, peer_event_string, NULL, ast_free);
768
769         caller = ast_multi_channel_blob_get_channel(obj, "caller");
770         peer = ast_multi_channel_blob_get_channel(obj, "peer");
771
772         /* Peer is required - otherwise, who are we dialing? */
773         ast_assert(peer != NULL);
774         peer_event_string = ast_manager_build_channel_state_string_suffix(peer, "Dest");
775         if (!peer_event_string) {
776                 return;
777         }
778
779         if (caller) {
780                 caller_event_string = ast_manager_build_channel_state_string(caller);
781                 if (!caller_event_string) {
782                         return;
783                 }
784                 dialstatus = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "dialstatus"));
785                 dialstring = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "dialstring"));
786                 if (ast_strlen_zero(dialstatus)) {
787                         manager_event(EVENT_FLAG_CALL, "DialBegin",
788                                         "%s"
789                                         "%s"
790                                         "DialString: %s\r\n",
791                                         ast_str_buffer(caller_event_string),
792                                         ast_str_buffer(peer_event_string),
793                                         S_OR(dialstring, "unknown"));
794                 } else {
795                         manager_event(EVENT_FLAG_CALL, "DialEnd",
796                                         "%s"
797                                         "%s"
798                                         "DialStatus: %s\r\n",
799                                         ast_str_buffer(caller_event_string),
800                                         ast_str_buffer(peer_event_string),
801                                         S_OR(dialstatus, "unknown"));
802                 }
803         } else {
804                 /* TODO: If we don't have a caller, this should be treated as an Originate */
805         }
806 }
807
808 static void manager_channels_shutdown(void)
809 {
810         stasis_message_router_unsubscribe(channel_state_router);
811         channel_state_router = NULL;
812 }
813
814 int manager_channels_init(void)
815 {
816         int ret = 0;
817
818         if (channel_state_router) {
819                 /* Already initialized */
820                 return 0;
821         }
822
823         ast_register_atexit(manager_channels_shutdown);
824
825         channel_state_router = stasis_message_router_create(
826                 stasis_caching_get_topic(ast_channel_topic_all_cached()));
827
828         if (!channel_state_router) {
829                 return -1;
830         }
831
832         ret |= stasis_message_router_add(channel_state_router,
833                                          stasis_cache_update_type(),
834                                          channel_snapshot_update,
835                                          NULL);
836
837         ret |= stasis_message_router_add(channel_state_router,
838                                          ast_channel_varset_type(),
839                                          channel_varset_cb,
840                                          NULL);
841
842         ret |= stasis_message_router_add(channel_state_router,
843                                          ast_channel_user_event_type(),
844                                          channel_user_event_cb,
845                                          NULL);
846
847         ret |= stasis_message_router_add(channel_state_router,
848                                          ast_channel_dtmf_begin_type(),
849                                          channel_dtmf_begin_cb,
850                                          NULL);
851
852         ret |= stasis_message_router_add(channel_state_router,
853                                          ast_channel_dtmf_end_type(),
854                                          channel_dtmf_end_cb,
855                                          NULL);
856
857         ret |= stasis_message_router_add(channel_state_router,
858                                          ast_channel_hangup_request_type(),
859                                          channel_hangup_request_cb,
860                                          NULL);
861
862         ret |= stasis_message_router_add(channel_state_router,
863                                          ast_channel_dial_type(),
864                                          channel_dial_cb,
865                                          NULL);
866
867         /* If somehow we failed to add any routes, just shut down the whole
868          * thing and fail it.
869          */
870         if (ret) {
871                 manager_channels_shutdown();
872                 return -1;
873         }
874
875         return 0;
876 }
877