d121279d88ce8e63cefc29a2de40b965efaf847e
[asterisk/asterisk.git] / main / stasis_channels.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Matt Jordan <mjordan@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 Stasis Messages and Data Types for Channel Objects
22  *
23  * \author \verbatim Matt Jordan <mjordan@digium.com> \endverbatim
24  *
25  */
26
27 /*** MODULEINFO
28         <support_level>core</support_level>
29  ***/
30
31 #include "asterisk.h"
32
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34
35 #include "asterisk/astobj2.h"
36 #include "asterisk/json.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/stasis.h"
39 #include "asterisk/stasis_channels.h"
40
41 /*** DOCUMENTATION
42         <managerEvent language="en_US" name="VarSet">
43                 <managerEventInstance class="EVENT_FLAG_DIALPLAN">
44                         <synopsis>Raised when a variable is set to a particular value.</synopsis>
45                         <syntax>
46                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
47                                 <parameter name="Variable">
48                                         <para>The variable being set.</para>
49                                 </parameter>
50                                 <parameter name="Value">
51                                         <para>The new value of the variable.</para>
52                                 </parameter>
53                         </syntax>
54                 </managerEventInstance>
55         </managerEvent>
56 ***/
57
58 #define NUM_MULTI_CHANNEL_BLOB_BUCKETS 7
59
60 /*! \brief Topic for all channels */
61 struct stasis_topic *channel_topic_all;
62
63 /*! \brief Caching topic for all channels */
64 struct stasis_caching_topic *channel_topic_all_cached;
65
66 /*! \brief Caching topic for all channels indexed by name */
67 struct stasis_caching_topic *channel_topic_all_cached_by_name;
68
69 struct stasis_topic *ast_channel_topic_all(void)
70 {
71         return channel_topic_all;
72 }
73
74 struct stasis_caching_topic *ast_channel_topic_all_cached(void)
75 {
76         return channel_topic_all_cached;
77 }
78
79 static const char *channel_snapshot_get_id(struct stasis_message *message)
80 {
81         struct ast_channel_snapshot *snapshot;
82         if (ast_channel_snapshot_type() != stasis_message_type(message)) {
83                 return NULL;
84         }
85         snapshot = stasis_message_data(message);
86         return snapshot->uniqueid;
87 }
88
89 struct stasis_caching_topic *ast_channel_topic_all_cached_by_name(void)
90 {
91         return channel_topic_all_cached_by_name;
92 }
93
94 static const char *channel_snapshot_get_name(struct stasis_message *message)
95 {
96         struct ast_channel_snapshot *snapshot;
97         if (ast_channel_snapshot_type() != stasis_message_type(message)) {
98                 return NULL;
99         }
100         snapshot = stasis_message_data(message);
101         return snapshot->name;
102 }
103
104 /*! \internal \brief Hash function for \ref ast_channel_snapshot objects */
105 static int channel_snapshot_hash_cb(const void *obj, const int flags)
106 {
107         const struct ast_channel_snapshot *snapshot = obj;
108         const char *name = (flags & OBJ_KEY) ? obj : snapshot->name;
109         return ast_str_case_hash(name);
110 }
111
112 /*! \internal \brief Comparison function for \ref ast_channel_snapshot objects */
113 static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
114 {
115         struct ast_channel_snapshot *left = obj;
116         struct ast_channel_snapshot *right = arg;
117         const char *match = (flags & OBJ_KEY) ? arg : right->name;
118         return strcasecmp(left->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
119 }
120
121 static void channel_snapshot_dtor(void *obj)
122 {
123         struct ast_channel_snapshot *snapshot = obj;
124         ast_string_field_free_memory(snapshot);
125         ao2_cleanup(snapshot->manager_vars);
126 }
127
128 struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
129 {
130         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
131
132         /* no snapshots for dummy channels */
133         if (!ast_channel_tech(chan)) {
134                 return NULL;
135         }
136
137         snapshot = ao2_alloc(sizeof(*snapshot), channel_snapshot_dtor);
138         if (!snapshot || ast_string_field_init(snapshot, 1024)) {
139                 return NULL;
140         }
141
142         ast_string_field_set(snapshot, name, ast_channel_name(chan));
143         ast_string_field_set(snapshot, accountcode, ast_channel_accountcode(chan));
144         ast_string_field_set(snapshot, peeraccount, ast_channel_peeraccount(chan));
145         ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan));
146         ast_string_field_set(snapshot, uniqueid, ast_channel_uniqueid(chan));
147         ast_string_field_set(snapshot, linkedid, ast_channel_linkedid(chan));
148         ast_string_field_set(snapshot, parkinglot, ast_channel_parkinglot(chan));
149         ast_string_field_set(snapshot, hangupsource, ast_channel_hangupsource(chan));
150         if (ast_channel_appl(chan)) {
151                 ast_string_field_set(snapshot, appl, ast_channel_appl(chan));
152         }
153         if (ast_channel_data(chan)) {
154                 ast_string_field_set(snapshot, data, ast_channel_data(chan));
155         }
156         ast_string_field_set(snapshot, context, ast_channel_context(chan));
157         ast_string_field_set(snapshot, exten, ast_channel_exten(chan));
158
159         ast_string_field_set(snapshot, caller_name,
160                 S_COR(ast_channel_caller(chan)->ani.name.valid, ast_channel_caller(chan)->ani.name.str,
161                 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "")));
162         ast_string_field_set(snapshot, caller_number,
163                 S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str,
164                 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "")));
165         ast_string_field_set(snapshot, caller_dnid, S_OR(ast_channel_dialed(chan)->number.str, ""));
166         ast_string_field_set(snapshot, caller_subaddr,
167                 S_COR(ast_channel_caller(chan)->ani.subaddress.valid, ast_channel_caller(chan)->ani.subaddress.str,
168                 S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, "")));
169         ast_string_field_set(snapshot, dialed_subaddr,
170                 S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, ""));
171         ast_string_field_set(snapshot, caller_ani,
172                 S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""));
173         ast_string_field_set(snapshot, caller_rdnis,
174                 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""));
175         ast_string_field_set(snapshot, caller_dnid,
176                 S_OR(ast_channel_dialed(chan)->number.str, ""));
177
178         ast_string_field_set(snapshot, connected_name,
179                 S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, ""));
180         ast_string_field_set(snapshot, connected_number,
181                 S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, ""));
182         ast_string_field_set(snapshot, language, ast_channel_language(chan));
183
184         snapshot->creationtime = ast_channel_creationtime(chan);
185         snapshot->state = ast_channel_state(chan);
186         snapshot->priority = ast_channel_priority(chan);
187         snapshot->amaflags = ast_channel_amaflags(chan);
188         snapshot->hangupcause = ast_channel_hangupcause(chan);
189         snapshot->flags = *ast_channel_flags(chan);
190         snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
191
192         snapshot->manager_vars = ast_channel_get_manager_vars(chan);
193
194         ao2_ref(snapshot, +1);
195         return snapshot;
196 }
197
198 static void publish_message_for_channel_topics(struct stasis_message *message, struct ast_channel *chan)
199 {
200         if (chan) {
201                 stasis_publish(ast_channel_topic(chan), message);
202         } else {
203                 stasis_publish(ast_channel_topic_all(), message);
204         }
205 }
206
207 static void channel_blob_dtor(void *obj)
208 {
209         struct ast_channel_blob *event = obj;
210         ao2_cleanup(event->snapshot);
211         ast_json_unref(event->blob);
212 }
213
214 void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer,
215         const char *dialstring, const char *dialstatus, const char *forward)
216 {
217         RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
218         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
219         RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
220         RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
221         RAII_VAR(struct ast_channel_snapshot *, peer_snapshot, NULL, ao2_cleanup);
222
223         ast_assert(peer != NULL);
224         blob = ast_json_pack("{s: s, s: s, s: s}",
225                              "dialstatus", S_OR(dialstatus, ""),
226                              "forward", S_OR(forward, ""),
227                              "dialstring", S_OR(dialstring, ""));
228         if (!blob) {
229                 return;
230         }
231         payload = ast_multi_channel_blob_create(blob);
232         if (!payload) {
233                 return;
234         }
235
236         if (caller) {
237                 caller_snapshot = ast_channel_snapshot_create(caller);
238                 if (!caller_snapshot) {
239                         return;
240                 }
241                 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
242         }
243
244         peer_snapshot = ast_channel_snapshot_create(peer);
245         if (!peer_snapshot) {
246                 return;
247         }
248         ast_multi_channel_blob_add_channel(payload, "peer", peer_snapshot);
249
250         msg = stasis_message_create(ast_channel_dial_type(), payload);
251         if (!msg) {
252                 return;
253         }
254
255         publish_message_for_channel_topics(msg, caller);
256 }
257
258 void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer,
259         const char *dialstring, const char *dialstatus)
260 {
261         ast_channel_publish_dial_forward(caller, peer, dialstring, dialstatus, NULL);
262 }
263
264 static struct stasis_message *create_channel_blob_message(struct ast_channel_snapshot *snapshot,
265                 struct stasis_message_type *type,
266                 struct ast_json *blob)
267
268 {
269         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
270         RAII_VAR(struct ast_channel_blob *, obj, NULL, ao2_cleanup);
271
272         if (blob == NULL) {
273                 blob = ast_json_null();
274         }
275
276         obj = ao2_alloc(sizeof(*obj), channel_blob_dtor);
277         if (!obj) {
278                 return NULL;
279         }
280
281         if (snapshot) {
282                 obj->snapshot = snapshot;
283                 ao2_ref(obj->snapshot, +1);
284         }
285         obj->blob = ast_json_ref(blob);
286
287         msg = stasis_message_create(type, obj);
288         if (!msg) {
289                 return NULL;
290         }
291
292         ao2_ref(msg, +1);
293         return msg;
294 }
295
296 struct stasis_message *ast_channel_blob_create_from_cache(const char *channel_id,
297                                                struct stasis_message_type *type,
298                                                struct ast_json *blob)
299 {
300         RAII_VAR(struct ast_channel_snapshot *, snapshot,
301                         ast_channel_snapshot_get_latest(channel_id),
302                         ao2_cleanup);
303
304         return create_channel_blob_message(snapshot, type, blob);
305 }
306
307 struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
308         struct stasis_message_type *type, struct ast_json *blob)
309 {
310         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
311
312         if (chan) {
313                 snapshot = ast_channel_snapshot_create(chan);
314         }
315
316         return create_channel_blob_message(snapshot, type, blob);
317 }
318
319 /*! \brief A channel snapshot wrapper object used in \ref ast_multi_channel_blob objects */
320 struct channel_role_snapshot {
321         struct ast_channel_snapshot *snapshot;  /*!< A channel snapshot */
322         char role[0];                                                   /*!< The role assigned to the channel */
323 };
324
325 /*! \brief A multi channel blob data structure for multi_channel_blob stasis messages */
326 struct ast_multi_channel_blob {
327         struct ao2_container *channel_snapshots;        /*!< A container holding the snapshots */
328         struct ast_json *blob;                                          /*< A blob of JSON data */
329 };
330
331 /*! \internal \brief Standard comparison function for \ref channel_role_snapshot objects */
332 static int channel_role_single_cmp_cb(void *obj, void *arg, int flags)
333 {
334         struct channel_role_snapshot *left = obj;
335         struct channel_role_snapshot *right = arg;
336         const char *match = (flags & OBJ_KEY) ? arg : right->role;
337         return strcasecmp(left->role, match) ? 0 : (CMP_MATCH | CMP_STOP);
338 }
339
340 /*! \internal \brief Multi comparison function for \ref channel_role_snapshot objects */
341 static int channel_role_multi_cmp_cb(void *obj, void *arg, int flags)
342 {
343         struct channel_role_snapshot *left = obj;
344         struct channel_role_snapshot *right = arg;
345         const char *match = (flags & OBJ_KEY) ? arg : right->role;
346         return strcasecmp(left->role, match) ? 0 : (CMP_MATCH);
347 }
348
349 /*! \internal \brief Hash function for \ref channel_role_snapshot objects */
350 static int channel_role_hash_cb(const void *obj, const int flags)
351 {
352         const struct channel_role_snapshot *snapshot = obj;
353         const char *name = (flags & OBJ_KEY) ? obj : snapshot->role;
354         return ast_str_case_hash(name);
355 }
356
357 /*! \internal \brief Destructor for \ref ast_multi_channel_blob objects */
358 static void multi_channel_blob_dtor(void *obj)
359 {
360         struct ast_multi_channel_blob *multi_blob = obj;
361
362         ao2_cleanup(multi_blob->channel_snapshots);
363         ast_json_unref(multi_blob->blob);
364 }
365
366 struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *blob)
367 {
368         RAII_VAR(struct ast_multi_channel_blob *, obj,
369                         ao2_alloc(sizeof(*obj), multi_channel_blob_dtor),
370                         ao2_cleanup);
371
372         ast_assert(blob != NULL);
373
374         if (!obj) {
375                 return NULL;
376         }
377
378         obj->channel_snapshots = ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS,
379                         channel_role_hash_cb, channel_role_single_cmp_cb);
380         if (!obj->channel_snapshots) {
381                 return NULL;
382         }
383
384         obj->blob = ast_json_ref(blob);
385
386         ao2_ref(obj, +1);
387         return obj;
388 }
389
390 struct ast_channel_snapshot *ast_channel_snapshot_get_latest(const char *uniqueid)
391 {
392         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
393         struct ast_channel_snapshot *snapshot;
394
395         ast_assert(!ast_strlen_zero(uniqueid));
396
397         message = stasis_cache_get(ast_channel_topic_all_cached(),
398                         ast_channel_snapshot_type(),
399                         uniqueid);
400         if (!message) {
401                 return NULL;
402         }
403
404         snapshot = stasis_message_data(message);
405         if (!snapshot) {
406                 return NULL;
407         }
408         ao2_ref(snapshot, +1);
409         return snapshot;
410 }
411
412 struct ast_channel_snapshot *ast_channel_snapshot_get_latest_by_name(const char *name)
413 {
414         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
415         struct ast_channel_snapshot *snapshot;
416
417         ast_assert(!ast_strlen_zero(name));
418
419         message = stasis_cache_get(ast_channel_topic_all_cached_by_name(),
420                         ast_channel_snapshot_type(),
421                         name);
422         if (!message) {
423                 return NULL;
424         }
425
426         snapshot = stasis_message_data(message);
427         if (!snapshot) {
428                 return NULL;
429         }
430         ao2_ref(snapshot, +1);
431         return snapshot;
432 }
433
434 static void channel_role_snapshot_dtor(void *obj)
435 {
436         struct channel_role_snapshot *role_snapshot = obj;
437         ao2_cleanup(role_snapshot->snapshot);
438 }
439
440 void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
441 {
442         RAII_VAR(struct channel_role_snapshot *, role_snapshot, NULL, ao2_cleanup);
443         int role_len = strlen(role) + 1;
444
445         if (!obj || ast_strlen_zero(role) || !snapshot) {
446                 return;
447         }
448
449         role_snapshot = ao2_alloc(sizeof(*role_snapshot) + role_len, channel_role_snapshot_dtor);
450         if (!role_snapshot) {
451                 return;
452         }
453         ast_copy_string(role_snapshot->role, role, role_len);
454         role_snapshot->snapshot = snapshot;
455         ao2_ref(role_snapshot->snapshot, +1);
456         ao2_link(obj->channel_snapshots, role_snapshot);
457 }
458
459 struct ast_channel_snapshot *ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
460 {
461         struct channel_role_snapshot *role_snapshot;
462
463         if (!obj || ast_strlen_zero(role)) {
464                 return NULL;
465         }
466         role_snapshot = ao2_find(obj->channel_snapshots, role, OBJ_KEY);
467         /* Note that this function does not increase the ref count on snapshot */
468         if (!role_snapshot) {
469                 return NULL;
470         }
471         ao2_ref(role_snapshot, -1);
472         return role_snapshot->snapshot;
473 }
474
475 struct ao2_container *ast_multi_channel_blob_get_channels(struct ast_multi_channel_blob *obj, const char *role)
476 {
477         RAII_VAR(struct ao2_container *, ret_container,
478                 ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS, channel_snapshot_hash_cb, channel_snapshot_cmp_cb),
479                 ao2_cleanup);
480         struct ao2_iterator *it_role_snapshots;
481         struct channel_role_snapshot *role_snapshot;
482         char *arg;
483
484         if (!obj || ast_strlen_zero(role) || !ret_container) {
485                 return NULL;
486         }
487         arg = ast_strdupa(role);
488
489         it_role_snapshots = ao2_callback(obj->channel_snapshots, OBJ_MULTIPLE | OBJ_KEY, channel_role_multi_cmp_cb, arg);
490         if (!it_role_snapshots) {
491                 return NULL;
492         }
493
494         while ((role_snapshot = ao2_iterator_next(it_role_snapshots))) {
495                 ao2_link(ret_container, role_snapshot->snapshot);
496                 ao2_ref(role_snapshot, -1);
497         }
498         ao2_iterator_destroy(it_role_snapshots);
499
500         ao2_ref(ret_container, +1);
501         return ret_container;
502 }
503
504 struct ast_json *ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
505 {
506         if (!obj) {
507                 return NULL;
508         }
509         return obj->blob;
510 }
511
512 void ast_channel_publish_snapshot(struct ast_channel *chan)
513 {
514         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
515         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
516
517         snapshot = ast_channel_snapshot_create(chan);
518         if (!snapshot) {
519                 return;
520         }
521
522         message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
523         if (!message) {
524                 return;
525         }
526
527         ast_assert(ast_channel_topic(chan) != NULL);
528         stasis_publish(ast_channel_topic(chan), message);
529 }
530
531 void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
532 {
533         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
534
535         if (!blob) {
536                 blob = ast_json_null();
537         }
538
539         message = ast_channel_blob_create(chan, type, blob);
540         if (message) {
541                 stasis_publish(ast_channel_topic(chan), message);
542         }
543 }
544
545 void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
546 {
547         RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
548
549         ast_assert(name != NULL);
550         ast_assert(value != NULL);
551
552         blob = ast_json_pack("{s: s, s: s}",
553                              "variable", name,
554                              "value", value);
555         if (!blob) {
556                 ast_log(LOG_ERROR, "Error creating message\n");
557                 return;
558         }
559
560         ast_channel_publish_blob(chan, ast_channel_varset_type(), blob);
561 }
562
563 static struct ast_manager_event_blob *varset_to_ami(struct stasis_message *msg)
564 {
565         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
566         struct ast_channel_blob *obj = stasis_message_data(msg);
567         const char *variable =
568                 ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
569         const char *value =
570                 ast_json_string_get(ast_json_object_get(obj->blob, "value"));
571
572         if (obj->snapshot) {
573                 channel_event_string =
574                         ast_manager_build_channel_state_string(obj->snapshot);
575         } else {
576                 channel_event_string = ast_str_create(35);
577                 ast_str_set(&channel_event_string, 0,
578                             "Channel: none\r\n"
579                             "Uniqueid: none\r\n");
580         }
581
582         if (!channel_event_string) {
583                 return NULL;
584         }
585
586         return ast_manager_event_blob_create(EVENT_FLAG_DIALPLAN, "VarSet",
587                 "%s"
588                 "Variable: %s\r\n"
589                 "Value: %s\r\n",
590                 ast_str_buffer(channel_event_string), variable, value);
591 }
592
593 void ast_publish_channel_state(struct ast_channel *chan)
594 {
595         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
596         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
597
598         ast_assert(chan != NULL);
599         if (!chan) {
600                 return;
601         }
602
603         snapshot = ast_channel_snapshot_create(chan);
604         if (!snapshot) {
605                 return;
606         }
607
608         message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
609         if (!message) {
610                 return;
611         }
612
613         ast_assert(ast_channel_topic(chan) != NULL);
614         stasis_publish(ast_channel_topic(chan), message);
615 }
616
617 struct ast_json *ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot)
618 {
619         RAII_VAR(struct ast_json *, json_chan, NULL, ast_json_unref);
620
621         if (snapshot == NULL) {
622                 return NULL;
623         }
624
625         json_chan = ast_json_pack(
626                 /* Broken up into groups of three for readability */
627                 "{ s: s, s: s, s: s,"
628                 "  s: o, s: o, s: s,"
629                 "  s: o, s: o }",
630                 /* First line */
631                 "id", snapshot->uniqueid,
632                 "name", snapshot->name,
633                 "state", ast_state2str(snapshot->state),
634                 /* Second line */
635                 "caller", ast_json_name_number(
636                         snapshot->caller_name, snapshot->caller_number),
637                 "connected", ast_json_name_number(
638                         snapshot->connected_name, snapshot->connected_number),
639                 "accountcode", snapshot->accountcode,
640                 /* Third line */
641                 "dialplan", ast_json_dialplan_cep(
642                         snapshot->context, snapshot->exten, snapshot->priority),
643                 "creationtime", ast_json_timeval(snapshot->creationtime, NULL));
644
645         return ast_json_ref(json_chan);
646 }
647
648 int ast_channel_snapshot_cep_equal(
649         const struct ast_channel_snapshot *old_snapshot,
650         const struct ast_channel_snapshot *new_snapshot)
651 {
652         ast_assert(old_snapshot != NULL);
653         ast_assert(new_snapshot != NULL);
654
655         /* We actually get some snapshots with CEP set, but before the
656          * application is set. Since empty application is invalid, we treat
657          * setting the application from nothing as a CEP change.
658          */
659         if (ast_strlen_zero(old_snapshot->appl) &&
660             !ast_strlen_zero(new_snapshot->appl)) {
661                 return 0;
662         }
663
664         return old_snapshot->priority == new_snapshot->priority &&
665                 strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
666                 strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
667 }
668
669 int ast_channel_snapshot_caller_id_equal(
670         const struct ast_channel_snapshot *old_snapshot,
671         const struct ast_channel_snapshot *new_snapshot)
672 {
673         ast_assert(old_snapshot != NULL);
674         ast_assert(new_snapshot != NULL);
675         return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
676                 strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
677 }
678
679 static struct ast_json *channel_blob_to_json(struct stasis_message *message,
680         const char *type)
681 {
682         RAII_VAR(struct ast_json *, out, NULL, ast_json_unref);
683         struct ast_channel_blob *channel_blob = stasis_message_data(message);
684         struct ast_json *blob = channel_blob->blob;
685         struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
686         const struct timeval *tv = stasis_message_timestamp(message);
687         int res = 0;
688
689         if (blob == NULL || ast_json_is_null(blob)) {
690                 out = ast_json_object_create();
691         } else {
692                 /* blobs are immutable, so shallow copies are fine */
693                 out = ast_json_copy(blob);
694         }
695
696         if (!out) {
697                 return NULL;
698         }
699
700         res |= ast_json_object_set(out, "type", ast_json_string_create(type));
701         res |= ast_json_object_set(out, "timestamp",
702                 ast_json_timeval(*tv, NULL));
703
704         /* For global channel messages, the snapshot is optional */
705         if (snapshot) {
706                 res |= ast_json_object_set(out, "channel",
707                         ast_channel_snapshot_to_json(snapshot));
708         }
709
710         if (res != 0) {
711                 return NULL;
712         }
713
714         return ast_json_ref(out);
715 }
716
717 static struct ast_json *dtmf_end_to_json(struct stasis_message *message)
718 {
719         struct ast_channel_blob *channel_blob = stasis_message_data(message);
720         struct ast_json *blob = channel_blob->blob;
721         struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
722         const char *direction =
723                 ast_json_string_get(ast_json_object_get(blob, "direction"));
724         const struct timeval *tv = stasis_message_timestamp(message);
725
726         /* Only present received DTMF end events as JSON */
727         if (strcasecmp("Received", direction) != 0) {
728                 return NULL;
729         }
730
731         return ast_json_pack("{s: s, s: o, s: O, s: O, s: o}",
732                 "type", "ChannelDtmfReceived",
733                 "timestamp", ast_json_timeval(*tv, NULL),
734                 "digit", ast_json_object_get(blob, "digit"),
735                 "duration_ms", ast_json_object_get(blob, "duration_ms"),
736                 "channel", ast_channel_snapshot_to_json(snapshot));
737 }
738
739 static struct ast_json *user_event_to_json(struct stasis_message *message)
740 {
741         struct ast_channel_blob *channel_blob = stasis_message_data(message);
742         struct ast_json *blob = channel_blob->blob;
743         struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
744         const struct timeval *tv = stasis_message_timestamp(message);
745
746         return ast_json_pack("{s: s, s: o, s: O, s: O, s: o}",
747                 "type", "ChannelUserevent",
748                 "timestamp", ast_json_timeval(*tv, NULL),
749                 "eventname", ast_json_object_get(blob, "eventname"),
750                 "userevent", blob,
751                 "channel", ast_channel_snapshot_to_json(snapshot));
752 }
753
754 static struct ast_json *varset_to_json(struct stasis_message *message)
755 {
756         return channel_blob_to_json(message, "ChannelVarset");
757 }
758
759 static struct ast_json *hangup_request_to_json(struct stasis_message *message)
760 {
761         return channel_blob_to_json(message, "ChannelHangupRequest");
762 }
763
764 /*!
765  * @{ \brief Define channel message types.
766  */
767 STASIS_MESSAGE_TYPE_DEFN(ast_channel_snapshot_type);
768 STASIS_MESSAGE_TYPE_DEFN(ast_channel_dial_type);
769 STASIS_MESSAGE_TYPE_DEFN(ast_channel_varset_type,
770         .to_ami = varset_to_ami,
771         .to_json = varset_to_json,
772         );
773 STASIS_MESSAGE_TYPE_DEFN(ast_channel_user_event_type,
774         .to_json = user_event_to_json,
775         );
776 STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_request_type,
777         .to_json = hangup_request_to_json,
778         );
779 STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_begin_type);
780 STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_end_type,
781         .to_json = dtmf_end_to_json,
782         );
783 STASIS_MESSAGE_TYPE_DEFN(ast_channel_hold_type);
784 STASIS_MESSAGE_TYPE_DEFN(ast_channel_unhold_type);
785 STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_start_type);
786 STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_stop_type);
787 STASIS_MESSAGE_TYPE_DEFN(ast_channel_fax_type);
788 STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_handler_type);
789 STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_start_type);
790 STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_stop_type);
791 STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_start_type);
792 STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_stop_type);
793
794 /*! @} */
795
796 static void stasis_channels_cleanup(void)
797 {
798         channel_topic_all_cached = stasis_caching_unsubscribe_and_join(channel_topic_all_cached);
799         channel_topic_all_cached_by_name = stasis_caching_unsubscribe_and_join(channel_topic_all_cached_by_name);
800         ao2_cleanup(channel_topic_all);
801         channel_topic_all = NULL;
802         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_snapshot_type);
803         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dial_type);
804         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_varset_type);
805         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_user_event_type);
806         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_request_type);
807         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_begin_type);
808         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_end_type);
809         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hold_type);
810         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_unhold_type);
811         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_start_type);
812         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_stop_type);
813         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_fax_type);
814         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_handler_type);
815         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_moh_start_type);
816         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_moh_stop_type);
817         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_monitor_start_type);
818         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_monitor_stop_type);
819 }
820
821 void ast_stasis_channels_init(void)
822 {
823         ast_register_cleanup(stasis_channels_cleanup);
824
825         STASIS_MESSAGE_TYPE_INIT(ast_channel_snapshot_type);
826         STASIS_MESSAGE_TYPE_INIT(ast_channel_dial_type);
827         STASIS_MESSAGE_TYPE_INIT(ast_channel_varset_type);
828         STASIS_MESSAGE_TYPE_INIT(ast_channel_user_event_type);
829         STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_request_type);
830         STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_begin_type);
831         STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_end_type);
832         STASIS_MESSAGE_TYPE_INIT(ast_channel_hold_type);
833         STASIS_MESSAGE_TYPE_INIT(ast_channel_unhold_type);
834         STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_start_type);
835         STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_stop_type);
836         STASIS_MESSAGE_TYPE_INIT(ast_channel_fax_type);
837         STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_handler_type);
838         STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_start_type);
839         STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_stop_type);
840         STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_start_type);
841         STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_stop_type);
842
843         channel_topic_all = stasis_topic_create("ast_channel_topic_all");
844         channel_topic_all_cached = stasis_caching_topic_create(channel_topic_all, channel_snapshot_get_id);
845         channel_topic_all_cached_by_name = stasis_caching_topic_create(channel_topic_all, channel_snapshot_get_name);
846 }