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