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