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