Moved core logic from app_stasis to res_stasis
[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(struct ast_channel_blob *obj)
548 {
549         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
550         const char *variable = ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
551         const char *value = ast_json_string_get(ast_json_object_get(obj->blob, "value"));
552
553         if (obj->snapshot) {
554                 channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
555         } else {
556                 channel_event_string = ast_str_create(35);
557                 ast_str_set(&channel_event_string, 0,
558                             "Channel: none\r\n"
559                             "Uniqueid: none\r\n");
560         }
561
562         if (!channel_event_string) {
563                 return;
564         }
565
566         /*** DOCUMENTATION
567                 <managerEventInstance>
568                         <synopsis>Raised when a variable is set to a particular value.</synopsis>
569                         <syntax>
570                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
571                                 <parameter name="Variable">
572                                         <para>The variable being set.</para>
573                                 </parameter>
574                                 <parameter name="Value">
575                                         <para>The new value of the variable.</para>
576                                 </parameter>
577                         </syntax>
578                 </managerEventInstance>
579         ***/
580         manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
581                       "%s"
582                       "Variable: %s\r\n"
583                       "Value: %s\r\n",
584                       ast_str_buffer(channel_event_string),
585                       variable, value);
586 }
587
588 static void channel_userevent(struct ast_channel_blob *obj)
589 {
590         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
591         const char *eventname;
592         const char *body;
593
594         eventname = ast_json_string_get(ast_json_object_get(obj->blob, "eventname"));
595         body = ast_json_string_get(ast_json_object_get(obj->blob, "body"));
596         channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
597
598         if (!channel_event_string) {
599                 return;
600         }
601
602         /*** DOCUMENTATION
603                 <managerEventInstance>
604                         <synopsis>A user defined event raised from the dialplan.</synopsis>
605                         <syntax>
606                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
607                                 <parameter name="UserEvent">
608                                         <para>The event name, as specified in the dialplan.</para>
609                                 </parameter>
610                         </syntax>
611                         <see-also>
612                                 <ref type="application">UserEvent</ref>
613                         </see-also>
614                 </managerEventInstance>
615         ***/
616         manager_event(EVENT_FLAG_USER, "UserEvent",
617                       "%s"
618                       "UserEvent: %s\r\n"
619                       "%s",
620                       ast_str_buffer(channel_event_string), eventname, body);
621 }
622
623 static void channel_hangup_request(struct ast_channel_blob *obj)
624 {
625         RAII_VAR(struct ast_str *, extra, NULL, ast_free);
626         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
627         struct ast_json *cause;
628         int is_soft;
629         char *manager_event = "HangupRequest";
630
631         extra = ast_str_create(20);
632         if (!extra) {
633                 return;
634         }
635
636         channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
637
638         if (!channel_event_string) {
639                 return;
640         }
641
642         cause = ast_json_object_get(obj->blob, "cause");
643         if (cause) {
644                 ast_str_append(&extra, 0,
645                                "Cause: %jd\r\n",
646                                ast_json_integer_get(cause));
647         }
648
649         is_soft = ast_json_is_true(ast_json_object_get(obj->blob, "soft"));
650         if (is_soft) {
651                 manager_event = "SoftHangupRequest";
652         }
653
654         manager_event(EVENT_FLAG_CALL, manager_event,
655                       "%s%s",
656                       ast_str_buffer(channel_event_string),
657                       ast_str_buffer(extra));
658 }
659
660 static void channel_dtmf_begin(struct ast_channel_blob *obj)
661 {
662         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
663         const char *digit =
664                 ast_json_string_get(ast_json_object_get(obj->blob, "digit"));
665         const char *direction =
666                 ast_json_string_get(ast_json_object_get(obj->blob, "direction"));
667
668         channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
669
670         if (!channel_event_string) {
671                 return;
672         }
673
674         /*** DOCUMENTATION
675                 <managerEventInstance>
676                         <synopsis>Raised when a DTMF digit has started on a channel.</synopsis>
677                                 <syntax>
678                                         <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
679                                         <parameter name="Digit">
680                                                 <para>DTMF digit received or transmitted (0-9, A-E, # or *</para>
681                                         </parameter>
682                                         <parameter name="Direction">
683                                                 <enumlist>
684                                                         <enum name="Received"/>
685                                                         <enum name="Sent"/>
686                                                 </enumlist>
687                                         </parameter>
688                                 </syntax>
689                 </managerEventInstance>
690         ***/
691         manager_event(EVENT_FLAG_DTMF, "DTMFBegin",
692                 "%s"
693                 "Digit: %s\r\n"
694                 "Direction: %s\r\n",
695                 ast_str_buffer(channel_event_string),
696                 digit, direction);
697 }
698
699 static void channel_dtmf_end(struct ast_channel_blob *obj)
700 {
701         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
702         const char *digit =
703                 ast_json_string_get(ast_json_object_get(obj->blob, "digit"));
704         const char *direction =
705                 ast_json_string_get(ast_json_object_get(obj->blob, "direction"));
706         long duration_ms =
707                 ast_json_integer_get(ast_json_object_get(obj->blob, "duration_ms"));
708
709         channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
710
711         if (!channel_event_string) {
712                 return;
713         }
714
715         /*** DOCUMENTATION
716                 <managerEventInstance>
717                         <synopsis>Raised when a DTMF digit has ended on a channel.</synopsis>
718                                 <syntax>
719                                         <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
720                                         <parameter name="Digit">
721                                                 <para>DTMF digit received or transmitted (0-9, A-E, # or *</para>
722                                         </parameter>
723                                         <parameter name="DurationMs">
724                                                 <para>Duration (in milliseconds) DTMF was sent/received</para>
725                                         </parameter>
726                                         <parameter name="Direction">
727                                                 <enumlist>
728                                                         <enum name="Received"/>
729                                                         <enum name="Sent"/>
730                                                 </enumlist>
731                                         </parameter>
732                                 </syntax>
733                 </managerEventInstance>
734         ***/
735         manager_event(EVENT_FLAG_DTMF, "DTMFEnd",
736                 "%s"
737                 "Digit: %s\r\n"
738                 "DurationMs: %ld\r\n"
739                 "Direction: %s\r\n",
740                 ast_str_buffer(channel_event_string),
741                 digit, duration_ms, direction);
742 }
743
744 /*!
745  * \brief Callback processing messages on the channel topic.
746  */
747 static void channel_blob_cb(void *data, struct stasis_subscription *sub,
748                             struct stasis_topic *topic,
749                             struct stasis_message *message)
750 {
751         struct ast_channel_blob *obj = stasis_message_data(message);
752
753         if (strcmp("varset", ast_channel_blob_json_type(obj)) == 0) {
754                 channel_varset(obj);
755         } else if (strcmp("userevent", ast_channel_blob_json_type(obj)) == 0) {
756                 channel_userevent(obj);
757         } else if (strcmp("hangup_request", ast_channel_blob_json_type(obj)) == 0) {
758                 channel_hangup_request(obj);
759         } else if (strcmp("dtmf_begin", ast_channel_blob_json_type(obj)) == 0) {
760                 channel_dtmf_begin(obj);
761         } else if (strcmp("dtmf_end", ast_channel_blob_json_type(obj)) == 0) {
762                 channel_dtmf_end(obj);
763         }
764 }
765
766 /*!
767  * \brief Callback processing messages for channel dialing
768  */
769 static void channel_dial_cb(void *data, struct stasis_subscription *sub,
770                                 struct stasis_topic *topic,
771                                 struct stasis_message *message)
772 {
773         struct ast_multi_channel_blob *obj = stasis_message_data(message);
774         const char *dialstatus;
775         const char *dialstring;
776         struct ast_channel_snapshot *caller;
777         struct ast_channel_snapshot *peer;
778         RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
779         RAII_VAR(struct ast_str *, peer_event_string, NULL, ast_free);
780
781         if (strcmp("dial", ast_multi_channel_blob_get_type(obj))) {
782                 ast_assert(0);
783                 return;
784         }
785
786         caller = ast_multi_channel_blob_get_channel(obj, "caller");
787         peer = ast_multi_channel_blob_get_channel(obj, "peer");
788
789         /* Peer is required - otherwise, who are we dialing? */
790         ast_assert(peer != NULL);
791         peer_event_string = ast_manager_build_channel_state_string_suffix(peer, "Dest");
792         if (!peer_event_string) {
793                 return;
794         }
795
796         if (caller) {
797                 caller_event_string = ast_manager_build_channel_state_string(caller);
798                 if (!caller_event_string) {
799                         return;
800                 }
801                 dialstatus = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "dialstatus"));
802                 dialstring = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "dialstring"));
803                 if (ast_strlen_zero(dialstatus)) {
804                         manager_event(EVENT_FLAG_CALL, "DialBegin",
805                                         "%s"
806                                         "%s"
807                                         "DialString: %s\r\n",
808                                         ast_str_buffer(caller_event_string),
809                                         ast_str_buffer(peer_event_string),
810                                         S_OR(dialstring, "unknown"));
811                 } else {
812                         manager_event(EVENT_FLAG_CALL, "DialEnd",
813                                         "%s"
814                                         "%s"
815                                         "DialStatus: %s\r\n",
816                                         ast_str_buffer(caller_event_string),
817                                         ast_str_buffer(peer_event_string),
818                                         S_OR(dialstatus, "unknown"));
819                 }
820         } else {
821                 /* TODO: If we don't have a caller, this should be treated as an Originate */
822         }
823 }
824
825 static void manager_channels_shutdown(void)
826 {
827         stasis_message_router_unsubscribe(channel_state_router);
828         channel_state_router = NULL;
829 }
830
831 int manager_channels_init(void)
832 {
833         int ret = 0;
834
835         if (channel_state_router) {
836                 /* Already initialized */
837                 return 0;
838         }
839
840         ast_register_atexit(manager_channels_shutdown);
841
842         channel_state_router = stasis_message_router_create(
843                 stasis_caching_get_topic(ast_channel_topic_all_cached()));
844
845         if (!channel_state_router) {
846                 return -1;
847         }
848
849         ret |= stasis_message_router_add(channel_state_router,
850                                          stasis_cache_update_type(),
851                                          channel_snapshot_update,
852                                          NULL);
853
854         ret |= stasis_message_router_add(channel_state_router,
855                                          ast_channel_blob_type(),
856                                          channel_blob_cb,
857                                          NULL);
858
859         ret |= stasis_message_router_add(channel_state_router,
860                                          ast_channel_dial_type(),
861                                          channel_dial_cb,
862                                          NULL);
863
864         /* If somehow we failed to add any routes, just shut down the whole
865          * thing and fail it.
866          */
867         if (ret) {
868                 manager_channels_shutdown();
869                 return -1;
870         }
871
872         return 0;
873 }
874