89ccd4af89c8cce7026a3481ee48f280d2cb8ed6
[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 /*!
236  * \brief Generate the AMI message body from a channel snapshot
237  * \internal
238  *
239  * \param snapshot the channel snapshot for which to generate an AMI message
240  *                 body
241  * \param suffix the suffix to append to the channel fields
242  *
243  * \retval NULL on error
244  * \retval ast_str* on success (must be ast_freed by caller)
245  */
246 static struct ast_str *manager_build_channel_state_string_suffix(
247                 const struct ast_channel_snapshot *snapshot,
248                 const char *suffix)
249 {
250         struct ast_str *out = ast_str_create(1024);
251         int res = 0;
252         if (!out) {
253                 return NULL;
254         }
255         res = ast_str_set(&out, 0,
256                 "Channel%s: %s\r\n"
257                 "ChannelState%s: %d\r\n"
258                 "ChannelStateDesc%s: %s\r\n"
259                 "CallerIDNum%s: %s\r\n"
260                 "CallerIDName%s: %s\r\n"
261                 "ConnectedLineNum%s: %s\r\n"
262                 "ConnectedLineName%s: %s\r\n"
263                 "AccountCode%s: %s\r\n"
264                 "Context%s: %s\r\n"
265                 "Exten%s: %s\r\n"
266                 "Priority%s: %d\r\n"
267                 "Uniqueid%s: %s\r\n",
268                 suffix, snapshot->name,
269                 suffix, snapshot->state,
270                 suffix, ast_state2str(snapshot->state),
271                 suffix, S_OR(snapshot->caller_number, "<unknown>"),
272                 suffix, S_OR(snapshot->caller_name, "<unknown>"),
273                 suffix, S_OR(snapshot->connected_number, "<unknown>"),
274                 suffix, S_OR(snapshot->connected_name, "<unknown>"),
275                 suffix, snapshot->accountcode,
276                 suffix, snapshot->context,
277                 suffix, snapshot->exten,
278                 suffix, snapshot->priority,
279                 suffix, snapshot->uniqueid);
280
281         if (!res) {
282                 return NULL;
283         }
284
285         if (snapshot->manager_vars) {
286                 struct ast_var_t *var;
287                 AST_LIST_TRAVERSE(snapshot->manager_vars, var, entries) {
288                         ast_str_append(&out, 0, "ChanVariable%s: %s=%s\r\n",
289                                                    suffix,
290                                                    var->name, var->value);
291                 }
292         }
293
294         return out;
295 }
296
297 /*!
298  * \brief Generate the AMI message body from a channel snapshot
299  * \internal
300  *
301  * \param snapshot the channel snapshot for which to generate an AMI message
302  *                 body
303  *
304  * \retval NULL on error
305  * \retval ast_str* on success (must be ast_freed by caller)
306  */
307 static struct ast_str *manager_build_channel_state_string(
308         const struct ast_channel_snapshot *snapshot)
309 {
310         return manager_build_channel_state_string_suffix(snapshot, "");
311 }
312
313 /*! \brief Struct containing info for an AMI channel event to send out. */
314 struct snapshot_manager_event {
315         /*! event_flags manager_event() flags parameter. */
316         int event_flags;
317         /*!  manager_event manager_event() category. */
318         const char *manager_event;
319         AST_DECLARE_STRING_FIELDS(
320                 /* extra fields to include in the event. */
321                 AST_STRING_FIELD(extra_fields);
322                 );
323 };
324
325 static void snapshot_manager_event_dtor(void *obj)
326 {
327         struct snapshot_manager_event *ev = obj;
328         ast_string_field_free_memory(ev);
329 }
330
331 /*!
332  * \brief Construct a \ref snapshot_manager_event.
333  * \param event_flags manager_event() flags parameter.
334  * \param manager_event manager_event() category.
335  * \param extra_fields_fmt Format string for extra fields to include.
336  *                         Or NO_EXTRA_FIELDS for no extra fields.
337  * \return New \ref snapshot_manager_event object.
338  * \return \c NULL on error.
339  */
340 static struct snapshot_manager_event *
341 __attribute__((format(printf, 3, 4)))
342 snapshot_manager_event_create(
343         int event_flags,
344         const char *manager_event,
345         const char *extra_fields_fmt,
346         ...)
347 {
348         RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
349         va_list argp;
350
351         ast_assert(extra_fields_fmt != NULL);
352         ast_assert(manager_event != NULL);
353
354         ev = ao2_alloc(sizeof(*ev), snapshot_manager_event_dtor);
355         if (!ev) {
356                 return NULL;
357         }
358
359         if (ast_string_field_init(ev, 20)) {
360                 return NULL;
361         }
362
363         ev->manager_event = manager_event;
364         ev->event_flags = event_flags;
365
366         va_start(argp, extra_fields_fmt);
367         ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt,
368                                       argp);
369         va_end(argp);
370
371         ao2_ref(ev, +1);
372         return ev;
373 }
374
375 /*! GCC warns about blank or NULL format strings. So, shenanigans! */
376 #define NO_EXTRA_FIELDS "%s", ""
377
378 /*! \brief Typedef for callbacks that get called on channel snapshot updates */
379 typedef struct snapshot_manager_event *(*snapshot_monitor)(
380         struct ast_channel_snapshot *old_snapshot,
381         struct ast_channel_snapshot *new_snapshot);
382
383 /*! \brief Handle channel state changes */
384 static struct snapshot_manager_event *channel_state_change(
385         struct ast_channel_snapshot *old_snapshot,
386         struct ast_channel_snapshot *new_snapshot)
387 {
388         int is_hungup, was_hungup;
389
390         if (!new_snapshot) {
391                 /* Ignore cache clearing events; we'll see the hangup first */
392                 return NULL;
393         }
394
395         /* The Newchannel, Newstate and Hangup events are closely related, in
396          * in that they are mutually exclusive, basically different flavors
397          * of a new channel state event.
398          */
399
400         if (!old_snapshot) {
401                 return snapshot_manager_event_create(
402                         EVENT_FLAG_CALL, "Newchannel", NO_EXTRA_FIELDS);
403         }
404
405         was_hungup = ast_test_flag(&old_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
406         is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
407
408         if (!was_hungup && is_hungup) {
409                 return snapshot_manager_event_create(
410                         EVENT_FLAG_CALL, "Hangup",
411                         "Cause: %d\r\n"
412                         "Cause-txt: %s\r\n",
413                         new_snapshot->hangupcause,
414                         ast_cause2str(new_snapshot->hangupcause));
415         }
416
417         if (old_snapshot->state != new_snapshot->state) {
418                 return snapshot_manager_event_create(
419                         EVENT_FLAG_CALL, "Newstate", NO_EXTRA_FIELDS);
420         }
421
422         /* No event */
423         return NULL;
424 }
425
426 /*!
427  * \brief Compares the context, exten and priority of two snapshots.
428  * \param old_snapshot Old snapshot
429  * \param new_snapshot New snapshot
430  * \return True (non-zero) if context, exten or priority are identical.
431  * \return False (zero) if context, exten and priority changed.
432  */
433 static inline int cep_equal(
434         const struct ast_channel_snapshot *old_snapshot,
435         const struct ast_channel_snapshot *new_snapshot)
436 {
437         ast_assert(old_snapshot != NULL);
438         ast_assert(new_snapshot != NULL);
439
440         /* We actually get some snapshots with CEP set, but before the
441          * application is set. Since empty application is invalid, we treat
442          * setting the application from nothing as a CEP change.
443          */
444         if (ast_strlen_zero(old_snapshot->appl) &&
445             !ast_strlen_zero(new_snapshot->appl)) {
446                 return 0;
447         }
448
449         return old_snapshot->priority == new_snapshot->priority &&
450                 strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
451                 strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
452 }
453
454 static struct snapshot_manager_event *channel_newexten(
455         struct ast_channel_snapshot *old_snapshot,
456         struct ast_channel_snapshot *new_snapshot)
457 {
458         /* No Newexten event on cache clear */
459         if (!new_snapshot) {
460                 return NULL;
461         }
462
463         /* Empty application is not valid for a Newexten event */
464         if (ast_strlen_zero(new_snapshot->appl)) {
465                 return NULL;
466         }
467
468         if (old_snapshot && cep_equal(old_snapshot, new_snapshot)) {
469                 return NULL;
470         }
471
472         /* DEPRECATED: Extension field deprecated in 12; remove in 14 */
473         return snapshot_manager_event_create(
474                 EVENT_FLAG_CALL, "Newexten",
475                 "Extension: %s\r\n"
476                 "Application: %s\r\n"
477                 "AppData: %s\r\n",
478                 new_snapshot->exten,
479                 new_snapshot->appl,
480                 new_snapshot->data);
481 }
482
483 /*!
484  * \brief Compares the callerid info of two snapshots.
485  * \param old_snapshot Old snapshot
486  * \param new_snapshot New snapshot
487  * \return True (non-zero) if callerid are identical.
488  * \return False (zero) if callerid changed.
489  */
490 static inline int caller_id_equal(
491         const struct ast_channel_snapshot *old_snapshot,
492         const struct ast_channel_snapshot *new_snapshot)
493 {
494         ast_assert(old_snapshot != NULL);
495         ast_assert(new_snapshot != NULL);
496         return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
497                 strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
498 }
499
500 static struct snapshot_manager_event *channel_new_callerid(
501         struct ast_channel_snapshot *old_snapshot,
502         struct ast_channel_snapshot *new_snapshot)
503 {
504         /* No NewCallerid event on cache clear or first event */
505         if (!old_snapshot || !new_snapshot) {
506                 return NULL;
507         }
508
509         if (caller_id_equal(old_snapshot, new_snapshot)) {
510                 return NULL;
511         }
512
513         return snapshot_manager_event_create(
514                 EVENT_FLAG_CALL, "NewCallerid",
515                 "CID-CallingPres: %d (%s)\r\n",
516                 new_snapshot->caller_pres,
517                 ast_describe_caller_presentation(new_snapshot->caller_pres));
518 }
519
520 snapshot_monitor monitors[] = {
521         channel_state_change,
522         channel_newexten,
523         channel_new_callerid
524 };
525
526 static void channel_snapshot_update(void *data, struct stasis_subscription *sub,
527                                     struct stasis_topic *topic,
528                                     struct stasis_message *message)
529 {
530         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
531         struct stasis_cache_update *update;
532         struct ast_channel_snapshot *old_snapshot;
533         struct ast_channel_snapshot *new_snapshot;
534         size_t i;
535
536         update = stasis_message_data(message);
537
538         if (ast_channel_snapshot_type() != update->type) {
539                 return;
540         }
541
542         old_snapshot = stasis_message_data(update->old_snapshot);
543         new_snapshot = stasis_message_data(update->new_snapshot);
544
545         for (i = 0; i < ARRAY_LEN(monitors); ++i) {
546                 RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
547                 ev = monitors[i](old_snapshot, new_snapshot);
548
549                 if (!ev) {
550                         continue;
551                 }
552
553                 /* If we haven't already, build the channel event string */
554                 if (!channel_event_string) {
555                         channel_event_string =
556                                 manager_build_channel_state_string(new_snapshot);
557                         if (!channel_event_string) {
558                                 return;
559                         }
560                 }
561
562                 manager_event(ev->event_flags, ev->manager_event, "%s%s",
563                         ast_str_buffer(channel_event_string),
564                         ev->extra_fields);
565         }
566 }
567
568 static void channel_varset(struct ast_channel_blob *obj)
569 {
570         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
571         const char *variable = ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
572         const char *value = ast_json_string_get(ast_json_object_get(obj->blob, "value"));
573
574         if (obj->snapshot) {
575                 channel_event_string = manager_build_channel_state_string(obj->snapshot);
576         } else {
577                 channel_event_string = ast_str_create(35);
578                 ast_str_set(&channel_event_string, 0,
579                             "Channel: none\r\n"
580                             "Uniqueid: none\r\n");
581         }
582
583         if (!channel_event_string) {
584                 return;
585         }
586
587         /*** DOCUMENTATION
588                 <managerEventInstance>
589                         <synopsis>Raised when a variable is set to a particular value.</synopsis>
590                         <syntax>
591                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
592                                 <parameter name="Variable">
593                                         <para>The variable being set.</para>
594                                 </parameter>
595                                 <parameter name="Value">
596                                         <para>The new value of the variable.</para>
597                                 </parameter>
598                         </syntax>
599                 </managerEventInstance>
600         ***/
601         manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
602                       "%s"
603                       "Variable: %s\r\n"
604                       "Value: %s\r\n",
605                       ast_str_buffer(channel_event_string),
606                       variable, value);
607 }
608
609 static void channel_userevent(struct ast_channel_blob *obj)
610 {
611         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
612         const char *eventname;
613         const char *body;
614
615         eventname = ast_json_string_get(ast_json_object_get(obj->blob, "eventname"));
616         body = ast_json_string_get(ast_json_object_get(obj->blob, "body"));
617         channel_event_string = manager_build_channel_state_string(obj->snapshot);
618
619         if (!channel_event_string) {
620                 return;
621         }
622
623         /*** DOCUMENTATION
624                 <managerEventInstance>
625                         <synopsis>A user defined event raised from the dialplan.</synopsis>
626                         <syntax>
627                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
628                                 <parameter name="UserEvent">
629                                         <para>The event name, as specified in the dialplan.</para>
630                                 </parameter>
631                         </syntax>
632                         <see-also>
633                                 <ref type="application">UserEvent</ref>
634                         </see-also>
635                 </managerEventInstance>
636         ***/
637         manager_event(EVENT_FLAG_USER, "UserEvent",
638                       "%s"
639                       "UserEvent: %s\r\n"
640                       "%s",
641                       ast_str_buffer(channel_event_string), eventname, body);
642 }
643
644 static void channel_hangup_request(struct ast_channel_blob *obj)
645 {
646         RAII_VAR(struct ast_str *, extra, NULL, ast_free);
647         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
648         struct ast_json *cause;
649         int is_soft;
650         char *manager_event = "HangupRequest";
651
652         extra = ast_str_create(20);
653         if (!extra) {
654                 return;
655         }
656
657         channel_event_string = manager_build_channel_state_string(obj->snapshot);
658
659         if (!channel_event_string) {
660                 return;
661         }
662
663         cause = ast_json_object_get(obj->blob, "cause");
664         if (cause) {
665                 ast_str_append(&extra, 0,
666                                "Cause: %jd\r\n",
667                                ast_json_integer_get(cause));
668         }
669
670         is_soft = ast_json_is_true(ast_json_object_get(obj->blob, "soft"));
671         if (is_soft) {
672                 manager_event = "SoftHangupRequest";
673         }
674
675         manager_event(EVENT_FLAG_CALL, manager_event,
676                       "%s%s",
677                       ast_str_buffer(channel_event_string),
678                       ast_str_buffer(extra));
679 }
680
681 /*!
682  * \brief Callback processing messages on the channel topic.
683  */
684 static void channel_blob_cb(void *data, struct stasis_subscription *sub,
685                             struct stasis_topic *topic,
686                             struct stasis_message *message)
687 {
688         struct ast_channel_blob *obj = stasis_message_data(message);
689
690         if (strcmp("varset", ast_channel_blob_json_type(obj)) == 0) {
691                 channel_varset(obj);
692         } else if (strcmp("userevent", ast_channel_blob_json_type(obj)) == 0) {
693                 channel_userevent(obj);
694         } else if (strcmp("hangup_request", ast_channel_blob_json_type(obj)) == 0) {
695                 channel_hangup_request(obj);
696         }
697 }
698
699 /*!
700  * \brief Callback processing messages for channel dialing
701  */
702 static void channel_dial_cb(void *data, struct stasis_subscription *sub,
703                                 struct stasis_topic *topic,
704                                 struct stasis_message *message)
705 {
706         struct ast_multi_channel_blob *obj = stasis_message_data(message);
707         const char *dialstatus;
708         const char *dialstring;
709         struct ast_channel_snapshot *caller;
710         struct ast_channel_snapshot *peer;
711         RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
712         RAII_VAR(struct ast_str *, peer_event_string, NULL, ast_free);
713
714         if (strcmp("dial", ast_multi_channel_blob_get_type(obj))) {
715                 ast_assert(0);
716                 return;
717         }
718
719         caller = ast_multi_channel_blob_get_channel(obj, "caller");
720         peer = ast_multi_channel_blob_get_channel(obj, "peer");
721
722         /* Peer is required - otherwise, who are we dialing? */
723         ast_assert(peer != NULL);
724         peer_event_string = manager_build_channel_state_string_suffix(peer, "Dest");
725         if (!peer_event_string) {
726                 return;
727         }
728
729         if (caller) {
730                 caller_event_string = manager_build_channel_state_string(caller);
731                 if (!caller_event_string) {
732                         return;
733                 }
734                 dialstatus = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "dialstatus"));
735                 dialstring = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "dialstring"));
736                 if (ast_strlen_zero(dialstatus)) {
737                         manager_event(EVENT_FLAG_CALL, "DialBegin",
738                                         "%s"
739                                         "%s"
740                                         "DialString: %s\r\n",
741                                         ast_str_buffer(caller_event_string),
742                                         ast_str_buffer(peer_event_string),
743                                         S_OR(dialstring, "unknown"));
744                 } else {
745                         manager_event(EVENT_FLAG_CALL, "DialEnd",
746                                         "%s"
747                                         "%s"
748                                         "DialStatus: %s\r\n",
749                                         ast_str_buffer(caller_event_string),
750                                         ast_str_buffer(peer_event_string),
751                                         S_OR(dialstatus, "unknown"));
752                 }
753         } else {
754                 /* TODO: If we don't have a caller, this should be treated as an Originate */
755         }
756 }
757
758 static void manager_channels_shutdown(void)
759 {
760         stasis_message_router_unsubscribe(channel_state_router);
761         channel_state_router = NULL;
762 }
763
764 int manager_channels_init(void)
765 {
766         int ret = 0;
767
768         if (channel_state_router) {
769                 /* Already initialized */
770                 return 0;
771         }
772
773         ast_register_atexit(manager_channels_shutdown);
774
775         channel_state_router = stasis_message_router_create(
776                 stasis_caching_get_topic(ast_channel_topic_all_cached()));
777
778         if (!channel_state_router) {
779                 return -1;
780         }
781
782         ret |= stasis_message_router_add(channel_state_router,
783                                          stasis_cache_update_type(),
784                                          channel_snapshot_update,
785                                          NULL);
786
787         ret |= stasis_message_router_add(channel_state_router,
788                                          ast_channel_blob_type(),
789                                          channel_blob_cb,
790                                          NULL);
791
792         ret |= stasis_message_router_add(channel_state_router,
793                                          ast_channel_dial_type(),
794                                          channel_dial_cb,
795                                          NULL);
796
797         /* If somehow we failed to add any routes, just shut down the whole
798          * thing and fail it.
799          */
800         if (ret) {
801                 manager_channels_shutdown();
802                 return -1;
803         }
804
805         return 0;
806 }
807