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