Asterisk - The Open Source Telephony Project GIT-master-27fb039
Loading...
Searching...
No Matches
stasis_channels.c
Go to the documentation of this file.
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#include "asterisk/astobj2.h"
34#include "asterisk/json.h"
35#include "asterisk/pbx.h"
36#include "asterisk/bridge.h"
38#include "asterisk/translate.h"
39#include "asterisk/stasis.h"
41#include "asterisk/dial.h"
43#include "asterisk/utf8.h"
44#include "asterisk/vector.h"
45
46/*** DOCUMENTATION
47 <managerEvent language="en_US" name="VarSet">
48 <managerEventInstance class="EVENT_FLAG_DIALPLAN">
49 <since>
50 <version>12.0.0</version>
51 </since>
52 <synopsis>Raised when a variable is set to a particular value.</synopsis>
53 <syntax>
54 <channel_snapshot/>
55 <parameter name="Variable">
56 <para>The variable being set.</para>
57 </parameter>
58 <parameter name="Value">
59 <para>The new value of the variable.</para>
60 </parameter>
61 </syntax>
62 </managerEventInstance>
63 </managerEvent>
64 <managerEvent language="en_US" name="AgentLogin">
65 <managerEventInstance class="EVENT_FLAG_AGENT">
66 <since>
67 <version>12.0.0</version>
68 </since>
69 <synopsis>Raised when an Agent has logged in.</synopsis>
70 <syntax>
71 <channel_snapshot/>
72 <parameter name="Agent">
73 <para>Agent ID of the agent.</para>
74 </parameter>
75 </syntax>
76 <see-also>
77 <ref type="application">AgentLogin</ref>
78 <ref type="managerEvent">AgentLogoff</ref>
79 </see-also>
80 </managerEventInstance>
81 </managerEvent>
82 <managerEvent language="en_US" name="AgentLogoff">
83 <managerEventInstance class="EVENT_FLAG_AGENT">
84 <since>
85 <version>12.0.0</version>
86 </since>
87 <synopsis>Raised when an Agent has logged off.</synopsis>
88 <syntax>
89 <channel_snapshot/>
90 <parameter name="Agent">
91 <para>Agent ID of the agent.</para>
92 </parameter>
93 <parameter name="Logintime">
94 <para>The number of seconds the agent was logged in.</para>
95 </parameter>
96 </syntax>
97 <see-also>
98 <ref type="managerEvent">AgentLogin</ref>
99 </see-also>
100 </managerEventInstance>
101 </managerEvent>
102 <managerEvent language="en_US" name="ChannelTalkingStart">
103 <managerEventInstance class="EVENT_FLAG_CLASS">
104 <since>
105 <version>12.4.0</version>
106 </since>
107 <synopsis>Raised when talking is detected on a channel.</synopsis>
108 <syntax>
109 <channel_snapshot/>
110 </syntax>
111 <see-also>
112 <ref type="function">TALK_DETECT</ref>
113 <ref type="managerEvent">ChannelTalkingStop</ref>
114 </see-also>
115 </managerEventInstance>
116 </managerEvent>
117 <managerEvent language="en_US" name="ChannelTalkingStop">
118 <managerEventInstance class="EVENT_FLAG_CLASS">
119 <since>
120 <version>12.4.0</version>
121 </since>
122 <synopsis>Raised when talking is no longer detected on a channel.</synopsis>
123 <syntax>
124 <channel_snapshot/>
125 <parameter name="Duration">
126 <para>The length in time, in milliseconds, that talking was
127 detected on the channel.</para>
128 </parameter>
129 </syntax>
130 <see-also>
131 <ref type="function">TALK_DETECT</ref>
132 <ref type="managerEvent">ChannelTalkingStart</ref>
133 </see-also>
134 </managerEventInstance>
135 </managerEvent>
136***/
137
138#define NUM_MULTI_CHANNEL_BLOB_BUCKETS 7
139
143
145{
146 return ao2_bump(channel_cache);
147}
148
150{
151 return channel_topic_all;
152}
153
158
159/*!
160 * \internal
161 * \brief Hash function for \ref ast_channel_snapshot objects
162 */
163static int channel_snapshot_hash_cb(const void *obj, const int flags)
164{
165 const struct ast_channel_snapshot *object = obj;
166 const char *key;
167
168 switch (flags & OBJ_SEARCH_MASK) {
169 case OBJ_SEARCH_KEY:
170 key = obj;
171 break;
173 key = object->base->name;
174 break;
175 default:
176 ast_assert(0);
177 return 0;
178 }
179 return ast_str_case_hash(key);
180}
181
182/*!
183 * \internal
184 * \brief Comparison function for \ref ast_channel_snapshot objects
185 */
186static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
187{
188 const struct ast_channel_snapshot *object_left = obj;
189 const struct ast_channel_snapshot *object_right = arg;
190 const char *right_key = arg;
191 int cmp;
192
193 switch (flags & OBJ_SEARCH_MASK) {
195 right_key = object_right->base->name;
196 case OBJ_SEARCH_KEY:
197 cmp = strcasecmp(object_left->base->name, right_key);
198 break;
200 cmp = strncasecmp(object_left->base->name, right_key, strlen(right_key));
201 break;
202 default:
203 cmp = 0;
204 break;
205 }
206 if (cmp) {
207 return 0;
208 }
209 return CMP_MATCH;
210}
211
212/*!
213 * \internal
214 * \brief Hash function (using uniqueid) for \ref ast_channel_snapshot objects
215 */
216static int channel_snapshot_uniqueid_hash_cb(const void *obj, const int flags)
217{
218 const struct ast_channel_snapshot *object = obj;
219 const char *key;
220
221 switch (flags & OBJ_SEARCH_MASK) {
222 case OBJ_SEARCH_KEY:
223 key = obj;
224 break;
226 key = object->base->uniqueid;
227 break;
228 default:
229 ast_assert(0);
230 return 0;
231 }
232 return ast_str_case_hash(key);
233}
234
235/*!
236 * \internal
237 * \brief Comparison function (using uniqueid) for \ref ast_channel_snapshot objects
238 */
239static int channel_snapshot_uniqueid_cmp_cb(void *obj, void *arg, int flags)
240{
241 const struct ast_channel_snapshot *object_left = obj;
242 const struct ast_channel_snapshot *object_right = arg;
243 const char *right_key = arg;
244 int cmp;
245
246 switch (flags & OBJ_SEARCH_MASK) {
248 right_key = object_right->base->uniqueid;
249 case OBJ_SEARCH_KEY:
250 cmp = strcasecmp(object_left->base->uniqueid, right_key);
251 break;
253 cmp = strncasecmp(object_left->base->uniqueid, right_key, strlen(right_key));
254 break;
255 default:
256 cmp = 0;
257 break;
258 }
259 if (cmp) {
260 return 0;
261 }
262 return CMP_MATCH;
263}
264
265static void channel_snapshot_dtor(void *obj)
266{
267 struct ast_channel_snapshot *snapshot = obj;
268
269 ao2_cleanup(snapshot->base);
270 ao2_cleanup(snapshot->peer);
271 ao2_cleanup(snapshot->caller);
272 ao2_cleanup(snapshot->connected);
273 ao2_cleanup(snapshot->bridge);
274 ao2_cleanup(snapshot->dialplan);
275 ao2_cleanup(snapshot->hangup);
276 ao2_cleanup(snapshot->manager_vars);
277 ao2_cleanup(snapshot->ari_vars);
278}
279
280static void channel_snapshot_base_dtor(void *obj)
281{
282 struct ast_channel_snapshot_base *snapshot = obj;
283
285}
286
288{
289 struct ast_channel_snapshot_base *snapshot;
290
291 snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_base_dtor,
293 if (!snapshot) {
294 return NULL;
295 }
296
297 if (ast_string_field_init(snapshot, 256) || ast_string_field_init_extended(snapshot, protocol_id)) {
298 ao2_ref(snapshot, -1);
299 return NULL;
300 }
301
309
310 snapshot->creationtime = ast_channel_creationtime(chan);
312
313 if (ast_channel_tech(chan)->get_pvt_uniqueid) {
314 ast_string_field_set(snapshot, protocol_id, ast_channel_tech(chan)->get_pvt_uniqueid(chan));
315 }
316
317 return snapshot;
318}
319
321{
322 const char *linkedid = S_OR(ast_channel_linkedid(chan), "");
323 const char *peeraccount = S_OR(ast_channel_peeraccount(chan), "");
324 size_t linkedid_len = strlen(linkedid) + 1;
325 size_t peeraccount_len = strlen(peeraccount) + 1;
326 struct ast_channel_snapshot_peer *snapshot;
327
328 snapshot = ao2_alloc_options(sizeof(*snapshot) + linkedid_len + peeraccount_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
329 if (!snapshot) {
330 return NULL;
331 }
332
333 strcpy(snapshot->account, peeraccount); /* Safe */
334 snapshot->linkedid = snapshot->account + peeraccount_len;
335 ast_copy_string(snapshot->linkedid, linkedid, linkedid_len); /* Safe */
336
337 return snapshot;
338}
339
340static void channel_snapshot_caller_dtor(void *obj)
341{
342 struct ast_channel_snapshot_caller *snapshot = obj;
343
345}
346
348{
349 struct ast_channel_snapshot_caller *snapshot;
350
351 snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_caller_dtor,
353 if (!snapshot) {
354 return NULL;
355 }
356
357 if (ast_string_field_init(snapshot, 256)) {
358 ao2_ref(snapshot, -1);
359 return NULL;
360 }
361
362 ast_string_field_set(snapshot, name,
363 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""));
365 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
367 S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, ""));
368 ast_string_field_set(snapshot, ani,
369 S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""));
370
371 ast_string_field_set(snapshot, rdnis,
372 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""));
373
374 ast_string_field_set(snapshot, dnid,
375 S_OR(ast_channel_dialed(chan)->number.str, ""));
377 S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, ""));
378
379 snapshot->pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
380
381 return snapshot;
382}
383
385{
386 const char *name = S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "");
387 const char *number = S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "");
388 size_t name_len = strlen(name) + 1;
389 size_t number_len = strlen(number) + 1;
390 struct ast_channel_snapshot_connected *snapshot;
391
392 snapshot = ao2_alloc_options(sizeof(*snapshot) + name_len + number_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
393 if (!snapshot) {
394 return NULL;
395 }
396
397 strcpy(snapshot->name, name); /* Safe */
398 snapshot->number = snapshot->name + name_len;
399 ast_copy_string(snapshot->number, number, number_len); /* Safe */
400
401 return snapshot;
402}
403
405{
406 const char *uniqueid = "";
407 struct ast_bridge *bridge;
408 struct ast_channel_snapshot_bridge *snapshot;
409
410 bridge = ast_channel_get_bridge(chan);
411 if (bridge && !ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
412 uniqueid = bridge->uniqueid;
413 }
414 ao2_cleanup(bridge);
415
416 snapshot = ao2_alloc_options(sizeof(*snapshot) + strlen(uniqueid) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
417 if (!snapshot) {
418 return NULL;
419 }
420
421 strcpy(snapshot->id, uniqueid); /* Safe */
422
423 return snapshot;
424}
425
426static void channel_snapshot_dialplan_dtor(void *obj)
427{
428 struct ast_channel_snapshot_dialplan *snapshot = obj;
429
431}
432
434{
435 struct ast_channel_snapshot_dialplan *snapshot;
436
437 snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dialplan_dtor,
439 if (!snapshot) {
440 return NULL;
441 }
442
443 if (ast_string_field_init(snapshot, 256)) {
444 ao2_ref(snapshot, -1);
445 return NULL;
446 }
447
448 if (ast_channel_appl(chan)) {
450 }
451 if (ast_channel_data(chan)) {
453 }
456 snapshot->priority = ast_channel_priority(chan);
457
458 return snapshot;
459}
460
462{
463 const char *hangupsource = S_OR(ast_channel_hangupsource(chan), "");
464 struct ast_channel_snapshot_hangup *snapshot;
465
466 snapshot = ao2_alloc_options(sizeof(*snapshot) + strlen(hangupsource) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
467 if (!snapshot) {
468 return NULL;
469 }
470
471 snapshot->cause = ast_channel_hangupcause(chan);
473 snapshot->source = snapshot->buffer;
474 strcpy(snapshot->source, hangupsource); /* Safe */
475
476 return snapshot;
477}
478
480{
481 struct ast_channel_snapshot *old_snapshot;
482 struct ast_channel_snapshot *snapshot;
483
484 /* no snapshots for dummy channels */
485 if (!ast_channel_tech(chan)) {
486 return NULL;
487 }
488
489 snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dtor,
491 if (!snapshot) {
492 return NULL;
493 }
494
495 old_snapshot = ast_channel_snapshot(chan);
496
497 /* Channels automatically have all segments invalidated on them initially so a check for an old
498 * snapshot existing before usage is not done here, as it can not happen. If the stored snapshot
499 * on the channel is updated as a result of this then all segments marked as invalidated will be
500 * cleared.
501 */
503 /* The base information has changed so update our snapshot */
504 snapshot->base = channel_snapshot_base_create(chan);
505 if (!snapshot->base) {
506 ao2_ref(snapshot, -1);
507 return NULL;
508 }
509 } else {
510 snapshot->base = ao2_bump(old_snapshot->base);
511 }
512
514 /* The peer information has changed so update our snapshot */
515 snapshot->peer = channel_snapshot_peer_create(chan);
516 if (!snapshot->peer) {
517 ao2_ref(snapshot, -1);
518 return NULL;
519 }
520 } else {
521 snapshot->peer = ao2_bump(old_snapshot->peer);
522 }
523
524 /* Unfortunately both caller and connected information do not have an enforced contract with
525 * the channel API. This has allowed consumers to directly get the caller or connected structure
526 * and manipulate it. Until such time as there is an enforced contract (which is being tracked under
527 * ASTERISK-28164) they are each regenerated every time a channel snapshot is created.
528 */
529 snapshot->caller = channel_snapshot_caller_create(chan);
530 if (!snapshot->caller) {
531 ao2_ref(snapshot, -1);
532 return NULL;
533 }
534
536 if (!snapshot->connected) {
537 ao2_ref(snapshot, -1);
538 return NULL;
539 }
540
542 /* The bridge has changed so update our snapshot */
543 snapshot->bridge = channel_snapshot_bridge_create(chan);
544 if (!snapshot->bridge) {
545 ao2_ref(snapshot, -1);
546 return NULL;
547 }
548 } else {
549 snapshot->bridge = ao2_bump(old_snapshot->bridge);
550 }
551
553 /* The dialplan information has changed so update our snapshot */
555 if (!snapshot->dialplan) {
556 ao2_ref(snapshot, -1);
557 return NULL;
558 }
559 } else {
560 snapshot->dialplan = ao2_bump(old_snapshot->dialplan);
561 }
562
564 /* The hangup information has changed so update our snapshot */
565 snapshot->hangup = channel_snapshot_hangup_create(chan);
566 if (!snapshot->hangup) {
567 ao2_ref(snapshot, -1);
568 return NULL;
569 }
570 } else {
571 snapshot->hangup = ao2_bump(old_snapshot->hangup);
572 }
573
574 snapshot->state = ast_channel_state(chan);
575 snapshot->amaflags = ast_channel_amaflags(chan);
576 ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF);
578
579 /* These have to be recreated as they may have changed, unfortunately */
581 snapshot->ari_vars = ast_channel_get_ari_vars(chan);
582
583 return snapshot;
584}
585
586static void channel_snapshot_update_dtor(void *obj)
587{
589
590 ao2_cleanup(update->old_snapshot);
591 ao2_cleanup(update->new_snapshot);
592}
593
595{
597
600 if (!update) {
601 return NULL;
602 }
603
604 update->old_snapshot = ao2_bump(ast_channel_snapshot(chan));
605 update->new_snapshot = ast_channel_snapshot_create(chan);
606 if (!update->new_snapshot) {
607 ao2_ref(update, -1);
608 return NULL;
609 }
610
611 return update;
612}
613
615{
616 if (chan) {
618 } else {
620 }
621}
622
623static void channel_blob_dtor(void *obj)
624{
625 struct ast_channel_blob *event = obj;
626 ao2_cleanup(event->snapshot);
627 ast_json_unref(event->blob);
628}
629
631 struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring,
632 const char *dialstatus, const char *forward)
633{
634 struct ast_multi_channel_blob *payload;
635 struct stasis_message *msg;
636 struct ast_json *blob;
637 struct ast_channel_snapshot *peer_snapshot;
638
639 if (!ast_channel_dial_type()) {
640 return;
641 }
642
643 ast_assert(peer != NULL);
644
645 blob = ast_json_pack("{s: s, s: s, s: s}",
646 "dialstatus", S_OR(dialstatus, ""),
647 "forward", S_OR(forward, ""),
648 "dialstring", S_OR(dialstring, ""));
649 if (!blob) {
650 return;
651 }
652 payload = ast_multi_channel_blob_create(blob);
653 ast_json_unref(blob);
654 if (!payload) {
655 return;
656 }
657
658 if (caller) {
659 struct ast_channel_snapshot *caller_snapshot;
660
662 if (ast_strlen_zero(dialstatus)) {
664 } else {
665 caller_snapshot = ast_channel_snapshot_create(caller);
666 }
668 if (!caller_snapshot) {
669 ao2_ref(payload, -1);
670 return;
671 }
672 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
673 ao2_ref(caller_snapshot, -1);
674 }
675
677 if (ast_strlen_zero(dialstatus)) {
679 } else {
680 peer_snapshot = ast_channel_snapshot_create(peer);
681 }
683 if (!peer_snapshot) {
684 ao2_ref(payload, -1);
685 return;
686 }
687 ast_multi_channel_blob_add_channel(payload, "peer", peer_snapshot);
688 ao2_ref(peer_snapshot, -1);
689
690 if (forwarded) {
691 struct ast_channel_snapshot *forwarded_snapshot;
692
693 ast_channel_lock(forwarded);
694 forwarded_snapshot = ast_channel_snapshot_create(forwarded);
695 ast_channel_unlock(forwarded);
696 if (!forwarded_snapshot) {
697 ao2_ref(payload, -1);
698 return;
699 }
700 ast_multi_channel_blob_add_channel(payload, "forwarded", forwarded_snapshot);
701 ao2_ref(forwarded_snapshot, -1);
702 }
703
705 ao2_ref(payload, -1);
706 if (msg) {
708 ao2_ref(msg, -1);
709 }
710}
711
712static void remove_dial_masquerade(struct ast_channel *peer);
714static int set_dial_masquerade(struct ast_channel *caller,
715 struct ast_channel *peer, const char *dialstring);
716
718 struct ast_channel *forwarded, const char *dialstring, const char *dialstatus,
719 const char *forward)
720{
721 ast_assert(peer != NULL);
722
723 /* XXX With an early bridge the below dial masquerade datastore code could, theoretically,
724 * go away as the act of changing the channel during dialing would be done using the bridge
725 * API itself and not a masquerade.
726 */
727
728 if (caller) {
729 /*
730 * Lock two or three channels.
731 *
732 * We need to hold the locks to hold off a potential masquerade
733 * messing up the stasis dial event ordering.
734 */
735 for (;; ast_channel_unlock(caller), sched_yield()) {
738 continue;
739 }
740 if (forwarded && ast_channel_trylock(forwarded)) {
742 continue;
743 }
744 break;
745 }
746
747 if (ast_strlen_zero(dialstatus)) {
748 set_dial_masquerade(caller, peer, dialstring);
749 } else {
751 }
752 }
753
754 ast_channel_publish_dial_internal(caller, peer, forwarded, dialstring, dialstatus,
755 forward);
756
757 if (caller) {
758 if (forwarded) {
759 ast_channel_unlock(forwarded);
760 }
764 }
765}
766
768 const char *dialstring, const char *dialstatus)
769{
770 ast_channel_publish_dial_forward(caller, peer, NULL, dialstring, dialstatus, NULL);
771}
772
775 struct ast_json *blob)
776{
777 struct stasis_message *msg;
778 struct ast_channel_blob *obj;
779
780 obj = ao2_alloc(sizeof(*obj), channel_blob_dtor);
781 if (!obj) {
782 return NULL;
783 }
784
785 if (snapshot) {
786 obj->snapshot = snapshot;
787 ao2_ref(obj->snapshot, +1);
788 }
789 if (!blob) {
791 }
792 obj->blob = ast_json_ref(blob);
793
794 msg = stasis_message_create(type, obj);
795 ao2_cleanup(obj);
796 return msg;
797}
798
801 struct ast_json *blob)
802{
803 struct ast_channel_snapshot *snapshot;
804 struct stasis_message *msg;
805
806 if (!type) {
807 return NULL;
808 }
809
810 snapshot = ast_channel_snapshot_get_latest(channel_id);
811 msg = create_channel_blob_message(snapshot, type, blob);
812 ao2_cleanup(snapshot);
813 return msg;
814}
815
817 struct stasis_message_type *type, struct ast_json *blob)
818{
819 struct ast_channel_snapshot *snapshot;
820 struct stasis_message *msg;
821
822 if (!type) {
823 return NULL;
824 }
825
826 snapshot = chan ? ao2_bump(ast_channel_snapshot(chan)) : NULL;
827 msg = create_channel_blob_message(snapshot, type, blob);
828 ao2_cleanup(snapshot);
829 return msg;
830}
831
832/*! \brief A channel snapshot wrapper object used in \ref ast_multi_channel_blob objects */
834 struct ast_channel_snapshot *snapshot; /*!< A channel snapshot */
835 char role[0]; /*!< The role assigned to the channel */
836};
837
838/*! \brief A multi channel blob data structure for multi_channel_blob stasis messages */
840 struct ao2_container *channel_snapshots; /*!< A container holding the snapshots */
841 struct ast_json *blob; /*!< A blob of JSON data */
842};
843
844/*!
845 * \internal
846 * \brief Comparison function for \ref channel_role_snapshot objects
847 */
848static int channel_role_cmp_cb(void *obj, void *arg, int flags)
849{
850 const struct channel_role_snapshot *object_left = obj;
851 const struct channel_role_snapshot *object_right = arg;
852 const char *right_key = arg;
853 int cmp;
854
855 switch (flags & OBJ_SEARCH_MASK) {
857 right_key = object_right->role;
858 case OBJ_SEARCH_KEY:
859 cmp = strcasecmp(object_left->role, right_key);
860 break;
862 cmp = strncasecmp(object_left->role, right_key, strlen(right_key));
863 break;
864 default:
865 cmp = 0;
866 break;
867 }
868 if (cmp) {
869 return 0;
870 }
871 return CMP_MATCH;
872}
873
874/*!
875 * \internal
876 * \brief Hash function for \ref channel_role_snapshot objects
877 */
878static int channel_role_hash_cb(const void *obj, const int flags)
879{
880 const struct channel_role_snapshot *object = obj;
881 const char *key;
882
883 switch (flags & OBJ_SEARCH_MASK) {
884 case OBJ_SEARCH_KEY:
885 key = obj;
886 break;
888 key = object->role;
889 break;
890 default:
891 ast_assert(0);
892 return 0;
893 }
894 return ast_str_case_hash(key);
895}
896
897/*!
898 * \internal
899 * \brief Destructor for \ref ast_multi_channel_blob objects
900 */
901static void multi_channel_blob_dtor(void *obj)
902{
903 struct ast_multi_channel_blob *multi_blob = obj;
904
905 ao2_cleanup(multi_blob->channel_snapshots);
906 ast_json_unref(multi_blob->blob);
907}
908
910{
911 struct ast_multi_channel_blob *obj;
912
913 ast_assert(blob != NULL);
914
915 obj = ao2_alloc(sizeof(*obj), multi_channel_blob_dtor);
916 if (!obj) {
917 return NULL;
918 }
919
922 if (!obj->channel_snapshots) {
923 ao2_ref(obj, -1);
924 return NULL;
925 }
926
927 obj->blob = ast_json_ref(blob);
928 return obj;
929}
930
932{
933 ast_assert(!ast_strlen_zero(uniqueid));
934
935 return ao2_find(channel_cache, uniqueid, OBJ_SEARCH_KEY);
936}
937
944
946{
948 struct stasis_message *message;
949
951 return;
952 }
953
955 if (!update) {
956 return;
957 }
958
960 /* In the success path message holds a reference to update so it will be valid
961 * for the lifetime of this function until the end.
962 */
963 ao2_ref(update, -1);
964 if (!message) {
965 return;
966 }
967
970
972
974 ao2_ref(message, -1);
975}
976
977static void channel_role_snapshot_dtor(void *obj)
978{
979 struct channel_role_snapshot *role_snapshot = obj;
980
981 ao2_cleanup(role_snapshot->snapshot);
982}
983
985{
986 struct channel_role_snapshot *role_snapshot;
987 int role_len = strlen(role) + 1;
988
989 if (!obj || ast_strlen_zero(role) || !snapshot) {
990 return;
991 }
992
993 role_snapshot = ao2_alloc_options(sizeof(*role_snapshot) + role_len,
995 if (!role_snapshot) {
996 return;
997 }
998 ast_copy_string(role_snapshot->role, role, role_len);
999 role_snapshot->snapshot = snapshot;
1000 ao2_ref(role_snapshot->snapshot, +1);
1001 ao2_link(obj->channel_snapshots, role_snapshot);
1002 ao2_ref(role_snapshot, -1);
1003}
1004
1006{
1007 struct channel_role_snapshot *role_snapshot;
1008 struct ast_channel_snapshot *snapshot;
1009
1010 if (!obj || ast_strlen_zero(role)) {
1011 return NULL;
1012 }
1013 role_snapshot = ao2_find(obj->channel_snapshots, role, OBJ_SEARCH_KEY);
1014 /* Note that this function does not increase the ref count on snapshot */
1015 if (!role_snapshot) {
1016 return NULL;
1017 }
1018 snapshot = role_snapshot->snapshot;
1019 ao2_ref(role_snapshot, -1);
1020 return snapshot;
1021}
1022
1024{
1025 struct ao2_container *ret_container;
1026 struct ao2_iterator *it_role_snapshots;
1027 struct channel_role_snapshot *role_snapshot;
1028 char *arg;
1029
1030 if (!obj || ast_strlen_zero(role)) {
1031 return NULL;
1032 }
1033
1037 if (!ret_container) {
1038 return NULL;
1039 }
1040
1041 arg = ast_strdupa(role);
1042 it_role_snapshots = ao2_callback(obj->channel_snapshots,
1044 if (!it_role_snapshots) {
1045 ao2_ref(ret_container, -1);
1046 return NULL;
1047 }
1048
1049 while ((role_snapshot = ao2_iterator_next(it_role_snapshots))) {
1050 ao2_link(ret_container, role_snapshot->snapshot);
1051 ao2_ref(role_snapshot, -1);
1052 }
1053 ao2_iterator_destroy(it_role_snapshots);
1054
1055 return ret_container;
1056}
1057
1059{
1060 if (!obj) {
1061 return NULL;
1062 }
1063 return obj->blob;
1064}
1065
1070
1076
1082
1084{
1086 struct stasis_message *message;
1087
1089 return;
1090 }
1091
1093 return;
1094 }
1095
1097 if (!update) {
1098 return;
1099 }
1100
1101 /* If an old snapshot exists and is the same as this newly created one don't bother
1102 * raising a message as it hasn't changed.
1103 */
1104 if (update->old_snapshot && !memcmp(update->old_snapshot, update->new_snapshot, sizeof(struct ast_channel_snapshot))) {
1105 ao2_ref(update, -1);
1106 return;
1107 }
1108
1110 /* In the success path message holds a reference to update so it will be valid
1111 * for the lifetime of this function until the end.
1112 */
1113 ao2_ref(update, -1);
1114 if (!message) {
1115 return;
1116 }
1117
1118 /* We lock these ourselves so that the update is atomic and there isn't time where a
1119 * snapshot is not in the cache.
1120 */
1123
1126
1127 /* The same applies here. */
1130
1133
1134 ast_channel_snapshot_set(chan, update->new_snapshot);
1135
1136 /* As this is now the new snapshot any existing invalidated segments have been
1137 * created fresh and are up to date.
1138 */
1140
1143 ao2_ref(message, -1);
1144}
1145
1147{
1148 struct stasis_message *message;
1149
1150 if (!blob) {
1151 blob = ast_json_null();
1152 }
1153
1155 if (message) {
1157 ao2_ref(message, -1);
1158 }
1159}
1160
1162{
1163 struct stasis_message *message;
1164
1165 if (!blob) {
1166 blob = ast_json_null();
1167 }
1168
1169 message = ast_channel_blob_create(chan, type, blob);
1170 if (message) {
1172 ao2_ref(message, -1);
1173 }
1174}
1175
1176void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
1177{
1178 struct ast_json *blob;
1180 char *new_value = NULL;
1181 size_t new_value_size = 0;
1182
1183 ast_assert(name != NULL);
1184 ast_assert(value != NULL);
1185
1186 /*
1187 * Call with new-value == NULL to just check for invalid UTF-8
1188 * sequences and get size of buffer needed.
1189 */
1190 result = ast_utf8_replace_invalid_chars(new_value, &new_value_size,
1191 value, strlen(value));
1192
1194 /*
1195 * If there were no invalid sequences, we can use
1196 * the value directly.
1197 */
1198 new_value = (char *)value;
1199 } else {
1200 /*
1201 * If there were invalid sequences, we need to replace
1202 * them with the UTF-8 U+FFFD replacement character.
1203 */
1204 new_value = ast_alloca(new_value_size);
1205
1206 result = ast_utf8_replace_invalid_chars(new_value, &new_value_size,
1207 value, strlen(value));
1208
1209 ast_log(LOG_WARNING, "%s: The contents of variable '%s' had invalid UTF-8 sequences which were replaced",
1210 chan ? ast_channel_name(chan) : "GLOBAL", name);
1211 }
1212
1213 blob = ast_json_pack("{s: s, s: s}",
1214 "variable", name,
1215 "value", new_value);
1216 if (!blob) {
1217 ast_log(LOG_ERROR, "Error creating message\n");
1218 return;
1219 }
1220
1221 /*! If there are manager variables, force a cache update */
1222 if (chan && ast_channel_has_manager_vars()) {
1224 }
1225
1226 /* This function is NULL safe for global variables */
1228 ast_json_unref(blob);
1229}
1230
1232{
1233 struct ast_str *channel_event_string;
1234 struct ast_channel_blob *obj = stasis_message_data(msg);
1235 const char *variable =
1236 ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
1237 char *value;
1238 struct ast_manager_event_blob *ev;
1239
1241 "value")));
1242 if (!value) {
1243 return NULL;
1244 }
1245
1246 if (obj->snapshot) {
1247 channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
1248 } else {
1249 channel_event_string = ast_str_create(35);
1250 ast_str_set(&channel_event_string, 0,
1251 "Channel: none\r\n"
1252 "Uniqueid: none\r\n");
1253 }
1254 if (!channel_event_string) {
1255 ast_free(value);
1256 return NULL;
1257 }
1258
1260 "%s"
1261 "Variable: %s\r\n"
1262 "Value: %s\r\n",
1263 ast_str_buffer(channel_event_string), variable, value);
1264 ast_free(channel_event_string);
1265 ast_free(value);
1266 return ev;
1267}
1268
1270{
1271 struct ast_str *channel_string;
1272 struct ast_channel_blob *obj = stasis_message_data(msg);
1273 const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
1274 struct ast_manager_event_blob *ev;
1275
1276 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1277 if (!channel_string) {
1278 return NULL;
1279 }
1280
1282 "%s"
1283 "Agent: %s\r\n",
1284 ast_str_buffer(channel_string), agent);
1285 ast_free(channel_string);
1286 return ev;
1287}
1288
1290{
1291 struct ast_str *channel_string;
1292 struct ast_channel_blob *obj = stasis_message_data(msg);
1293 const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
1294 long logintime = ast_json_integer_get(ast_json_object_get(obj->blob, "logintime"));
1295 struct ast_manager_event_blob *ev;
1296
1297 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1298 if (!channel_string) {
1299 return NULL;
1300 }
1301
1303 "%s"
1304 "Agent: %s\r\n"
1305 "Logintime: %ld\r\n",
1306 ast_str_buffer(channel_string), agent, logintime);
1307 ast_free(channel_string);
1308 return ev;
1309}
1310
1312 const struct ast_channel_snapshot *snapshot,
1313 const struct stasis_message_sanitizer *sanitize)
1314{
1315 struct ast_json *json_chan;
1316
1317 if (snapshot == NULL
1318 || (sanitize
1319 && sanitize->channel_snapshot
1320 && sanitize->channel_snapshot(snapshot))) {
1321 return NULL;
1322 }
1323
1324 json_chan = ast_json_pack(
1325 /* Broken up into groups for readability */
1326 "{ s: s, s: s, s: s, s: s,"
1327 " s: o, s: o, s: s,"
1328 " s: o, s: o, s: s }",
1329 /* First line */
1330 "id", snapshot->base->uniqueid,
1331 "name", snapshot->base->name,
1332 "state", ast_state2str(snapshot->state),
1333 "protocol_id", snapshot->base->protocol_id,
1334 /* Second line */
1335 "caller", ast_json_name_number(
1336 snapshot->caller->name, snapshot->caller->number),
1337 "connected", ast_json_name_number(
1338 snapshot->connected->name, snapshot->connected->number),
1339 "accountcode", snapshot->base->accountcode,
1340 /* Third line */
1341 "dialplan", ast_json_dialplan_cep_app(
1342 snapshot->dialplan->context, snapshot->dialplan->exten, snapshot->dialplan->priority,
1343 snapshot->dialplan->appl, snapshot->dialplan->data),
1344 "creationtime", ast_json_timeval(snapshot->base->creationtime, NULL),
1345 "language", snapshot->base->language);
1346
1347 if (!ast_strlen_zero(snapshot->caller->rdnis)) {
1348 ast_json_object_set(json_chan, "caller_rdnis", ast_json_string_create(snapshot->caller->rdnis));
1349 }
1350
1351 if (snapshot->ari_vars && !AST_LIST_EMPTY(snapshot->ari_vars)) {
1352 ast_json_object_set(json_chan, "channelvars", ast_json_channel_vars(snapshot->ari_vars));
1353 }
1354
1355 if (!ast_strlen_zero(snapshot->base->tenantid)) {
1356 ast_json_object_set(json_chan, "tenantid", ast_json_string_create(snapshot->base->tenantid));
1357 }
1358
1359 return json_chan;
1360}
1361
1363 const struct ast_channel_snapshot *old_snapshot,
1364 const struct ast_channel_snapshot *new_snapshot)
1365{
1366 ast_assert(old_snapshot != NULL);
1367 ast_assert(new_snapshot != NULL);
1368
1369 /* We actually get some snapshots with CEP set, but before the
1370 * application is set. Since empty application is invalid, we treat
1371 * setting the application from nothing as a CEP change.
1372 */
1373 if (ast_strlen_zero(old_snapshot->dialplan->appl) &&
1374 !ast_strlen_zero(new_snapshot->dialplan->appl)) {
1375 return 0;
1376 }
1377
1378 return old_snapshot->dialplan->priority == new_snapshot->dialplan->priority &&
1379 strcmp(old_snapshot->dialplan->context, new_snapshot->dialplan->context) == 0 &&
1380 strcmp(old_snapshot->dialplan->exten, new_snapshot->dialplan->exten) == 0;
1381}
1382
1384 const struct ast_channel_snapshot *old_snapshot,
1385 const struct ast_channel_snapshot *new_snapshot)
1386{
1387 ast_assert(old_snapshot != NULL);
1388 ast_assert(new_snapshot != NULL);
1389 return strcmp(old_snapshot->caller->number, new_snapshot->caller->number) == 0 &&
1390 strcmp(old_snapshot->caller->name, new_snapshot->caller->name) == 0;
1391}
1392
1394 const struct ast_channel_snapshot *old_snapshot,
1395 const struct ast_channel_snapshot *new_snapshot)
1396{
1397 ast_assert(old_snapshot != NULL);
1398 ast_assert(new_snapshot != NULL);
1399 return strcmp(old_snapshot->connected->number, new_snapshot->connected->number) == 0 &&
1400 strcmp(old_snapshot->connected->name, new_snapshot->connected->name) == 0;
1401}
1402
1404 struct stasis_message *message,
1405 const char *type,
1406 const struct stasis_message_sanitizer *sanitize)
1407{
1408 struct ast_json *to_json;
1409 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1410 struct ast_json *blob = channel_blob->blob;
1411 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1412 const struct timeval *tv = stasis_message_timestamp(message);
1413 int res = 0;
1414
1415 if (blob == NULL || ast_json_is_null(blob)) {
1416 to_json = ast_json_object_create();
1417 } else {
1418 /* blobs are immutable, so shallow copies are fine */
1419 to_json = ast_json_copy(blob);
1420 }
1421 if (!to_json) {
1422 return NULL;
1423 }
1424
1425 res |= ast_json_object_set(to_json, "type", ast_json_string_create(type));
1426 res |= ast_json_object_set(to_json, "timestamp",
1427 ast_json_timeval(*tv, NULL));
1428
1429 /* For global channel messages, the snapshot is optional */
1430 if (snapshot) {
1431 struct ast_json *json_channel;
1432
1433 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1434 if (!json_channel) {
1435 ast_json_unref(to_json);
1436 return NULL;
1437 }
1438
1439 res |= ast_json_object_set(to_json, "channel", json_channel);
1440 }
1441
1442 if (res != 0) {
1443 ast_json_unref(to_json);
1444 return NULL;
1445 }
1446
1447 return to_json;
1448}
1449
1451 struct stasis_message *message,
1452 const struct stasis_message_sanitizer *sanitize)
1453{
1454 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1455 struct ast_json *blob = channel_blob->blob;
1456 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1457 const char *direction =
1458 ast_json_string_get(ast_json_object_get(blob, "direction"));
1459 const char *digit =
1461 long duration_ms =
1462 ast_json_integer_get(ast_json_object_get(blob, "duration_ms"));
1463 const struct timeval *tv = stasis_message_timestamp(message);
1464 struct ast_json *json_channel;
1465
1466 /* Only present received DTMF end events as JSON */
1467 if (strcasecmp("Received", direction) != 0) {
1468 return NULL;
1469 }
1470
1471 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1472 if (!json_channel) {
1473 return NULL;
1474 }
1475
1476 return ast_json_pack("{s: s, s: o, s: s, s: I, s: o}",
1477 "type", "ChannelDtmfReceived",
1478 "timestamp", ast_json_timeval(*tv, NULL),
1479 "digit", digit,
1480 "duration_ms", (ast_json_int_t)duration_ms,
1481 "channel", json_channel);
1482}
1483
1485 struct stasis_message *message,
1486 const struct stasis_message_sanitizer *sanitize)
1487{
1488 return channel_blob_to_json(message, "ChannelVarset", sanitize);
1489}
1490
1492 struct stasis_message *message,
1493 const struct stasis_message_sanitizer *sanitize)
1494{
1495 return channel_blob_to_json(message, "ChannelHangupRequest", sanitize);
1496}
1497
1498static struct ast_json *dial_to_json(
1499 struct stasis_message *message,
1500 const struct stasis_message_sanitizer *sanitize)
1501{
1503 struct ast_json *blob = ast_multi_channel_blob_get_json(payload);
1504 const char *dialstatus =
1505 ast_json_string_get(ast_json_object_get(blob, "dialstatus"));
1506 const char *forward =
1507 ast_json_string_get(ast_json_object_get(blob, "forward"));
1508 const char *dialstring =
1509 ast_json_string_get(ast_json_object_get(blob, "dialstring"));
1510 struct ast_json *caller_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "caller"), sanitize);
1511 struct ast_json *peer_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "peer"), sanitize);
1512 struct ast_json *forwarded_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "forwarded"), sanitize);
1513 struct ast_json *json;
1514 const struct timeval *tv = stasis_message_timestamp(message);
1515 int res = 0;
1516
1517 json = ast_json_pack("{s: s, s: o, s: s, s: s, s: s}",
1518 "type", "Dial",
1519 "timestamp", ast_json_timeval(*tv, NULL),
1520 "dialstatus", dialstatus,
1521 "forward", forward,
1522 "dialstring", dialstring);
1523 if (!json) {
1524 ast_json_unref(caller_json);
1525 ast_json_unref(peer_json);
1526 ast_json_unref(forwarded_json);
1527 return NULL;
1528 }
1529
1530 if (caller_json) {
1531 res |= ast_json_object_set(json, "caller", caller_json);
1532 }
1533 if (peer_json) {
1534 res |= ast_json_object_set(json, "peer", peer_json);
1535 }
1536 if (forwarded_json) {
1537 res |= ast_json_object_set(json, "forwarded", forwarded_json);
1538 }
1539
1540 if (res) {
1541 ast_json_unref(json);
1542 return NULL;
1543 }
1544
1545 return json;
1546}
1547
1549{
1550 struct ast_str *channel_string;
1551 struct ast_channel_blob *obj = stasis_message_data(msg);
1552 struct ast_manager_event_blob *blob;
1553
1554 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1555 if (!channel_string) {
1556 return NULL;
1557 }
1558
1559 blob = ast_manager_event_blob_create(EVENT_FLAG_CALL, "ChannelTalkingStart",
1560 "%s", ast_str_buffer(channel_string));
1561 ast_free(channel_string);
1562
1563 return blob;
1564}
1565
1567 const struct stasis_message_sanitizer *sanitize)
1568{
1569 return channel_blob_to_json(message, "ChannelTalkingStarted", sanitize);
1570}
1571
1573{
1574 struct ast_str *channel_string;
1575 struct ast_channel_blob *obj = stasis_message_data(msg);
1576 int duration = ast_json_integer_get(ast_json_object_get(obj->blob, "duration"));
1577 struct ast_manager_event_blob *blob;
1578
1579 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1580 if (!channel_string) {
1581 return NULL;
1582 }
1583
1584 blob = ast_manager_event_blob_create(EVENT_FLAG_CALL, "ChannelTalkingStop",
1585 "%s"
1586 "Duration: %d\r\n",
1587 ast_str_buffer(channel_string),
1588 duration);
1589 ast_free(channel_string);
1590
1591 return blob;
1592}
1593
1595 const struct stasis_message_sanitizer *sanitize)
1596{
1597 return channel_blob_to_json(message, "ChannelTalkingFinished", sanitize);
1598}
1599
1601 const struct stasis_message_sanitizer *sanitize)
1602{
1603 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1604 struct ast_json *blob = channel_blob->blob;
1605 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1606 const char *musicclass = ast_json_string_get(ast_json_object_get(blob, "musicclass"));
1607 const struct timeval *tv = stasis_message_timestamp(message);
1608 struct ast_json *json_channel;
1609
1610 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1611 if (!json_channel) {
1612 return NULL;
1613 }
1614
1615 return ast_json_pack("{s: s, s: o, s: s, s: o}",
1616 "type", "ChannelHold",
1617 "timestamp", ast_json_timeval(*tv, NULL),
1618 "musicclass", S_OR(musicclass, "N/A"),
1619 "channel", json_channel);
1620}
1621
1622
1624 const struct stasis_message_sanitizer *sanitize)
1625{
1626 return channel_blob_to_json(message, "ChannelToneDetected", sanitize);
1627}
1628
1630 const struct stasis_message_sanitizer *sanitize)
1631{
1632 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1633 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1634 const struct timeval *tv = stasis_message_timestamp(message);
1635 struct ast_json *json_channel;
1636
1637 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1638 if (!json_channel) {
1639 return NULL;
1640 }
1641
1642 return ast_json_pack("{s: s, s: o, s: o}",
1643 "type", "ChannelUnhold",
1644 "timestamp", ast_json_timeval(*tv, NULL),
1645 "channel", json_channel);
1646}
1647
1648static const char *state2str(enum ast_control_transfer state) {
1649 switch (state) {
1651 return "channel_declined";
1653 return "channel_answered";
1655 return "channel_progress";
1657 return "channel_declined";
1658 default:
1659 return "invalid";
1660 }
1661}
1662
1664 const struct stasis_message_sanitizer *sanitize)
1665{
1666 struct ast_json *json_channel, *res;
1667 struct ast_json *refer_json, *referred_json, *dest_json;
1668 const struct timeval *tv = stasis_message_timestamp(msg);
1669 struct ast_ari_transfer_message *transfer_msg = stasis_message_data(msg);
1670
1671 dest_json = ast_json_pack("{s: s}", "destination", transfer_msg->destination);
1672 if (!dest_json) {
1673 return NULL;
1674 }
1675
1676 if (transfer_msg->protocol_id) {
1677 ast_json_object_set(dest_json, "protocol_id",
1678 ast_json_string_create(transfer_msg->protocol_id));
1679 }
1680
1681 if (AST_VECTOR_SIZE(transfer_msg->refer_params) > 0) {
1682 struct ast_json *params = ast_json_array_create();
1683 if (!params) {
1684 return NULL;
1685 }
1686 for (int i = 0; i < AST_VECTOR_SIZE(transfer_msg->refer_params); ++i) {
1687 struct ast_refer_param param = AST_VECTOR_GET(transfer_msg->refer_params, i);
1688 ast_json_array_append(params, ast_json_pack("{s: s, s: s}",
1689 "parameter_name", param.param_name,
1690 "parameter_value", param.param_value));
1691 }
1692 ast_json_object_set(dest_json, "additional_protocol_params", params);
1693 }
1694
1695 refer_json = ast_json_pack("{s: o}",
1696 "requested_destination", dest_json);
1697 if (!refer_json) {
1698 return NULL;
1699 }
1700 if (transfer_msg->dest) {
1701 struct ast_json *dest_chan_json;
1702
1703 dest_chan_json = ast_channel_snapshot_to_json(transfer_msg->dest, sanitize);
1704 ast_json_object_set(refer_json, "destination_channel", dest_chan_json);
1705 }
1706 if (transfer_msg->dest_peer) {
1707 struct ast_json *peer_chan_json;
1708
1709 peer_chan_json = ast_channel_snapshot_to_json(transfer_msg->dest_peer, sanitize);
1710 ast_json_object_set(refer_json, "connected_channel", peer_chan_json);
1711 }
1712 if (transfer_msg->dest_bridge) {
1713 struct ast_json *dest_bridge_json;
1714
1715 dest_bridge_json = ast_bridge_snapshot_to_json(transfer_msg->dest_bridge, sanitize);
1716 ast_json_object_set(refer_json, "bridge", dest_bridge_json);
1717 }
1718
1719 json_channel = ast_channel_snapshot_to_json(transfer_msg->source, sanitize);
1720 if (!json_channel) {
1721 return NULL;
1722 }
1723
1724 referred_json = ast_json_pack("{s: o}",
1725 "source_channel", json_channel);
1726 if (!referred_json) {
1727 return NULL;
1728 }
1729 if (transfer_msg->source_peer) {
1730 struct ast_json *peer_chan_json;
1731
1732 peer_chan_json = ast_channel_snapshot_to_json(transfer_msg->source_peer, sanitize);
1733 ast_json_object_set(referred_json, "connected_channel", peer_chan_json);
1734 }
1735 if (transfer_msg->source_bridge) {
1736 struct ast_json *source_bridge_json;
1737
1738 source_bridge_json = ast_bridge_snapshot_to_json(transfer_msg->source_bridge, sanitize);
1739 ast_json_object_set(referred_json, "bridge", source_bridge_json);
1740 }
1741
1742 res = ast_json_pack("{s: s, s: o, s: o, s: o}",
1743 "type", "ChannelTransfer",
1744 "timestamp", ast_json_timeval(*tv, NULL),
1745 "refer_to", refer_json,
1746 "referred_by", referred_json);
1747 if (!res) {
1748 return NULL;
1749 }
1750
1751 if (transfer_msg->state != AST_TRANSFER_INVALID) {
1752 ast_json_object_set(res, "state", ast_json_string_create(state2str(transfer_msg->state)));
1753 }
1754 return res;
1755}
1756
1757static void ari_transfer_dtor(void *obj)
1758{
1759 struct ast_ari_transfer_message *msg = obj;
1760
1761 ao2_cleanup(msg->source);
1764 ao2_cleanup(msg->dest);
1766 ao2_cleanup(msg->dest_peer);
1768 ast_free(msg->referred_by);
1769 ast_free(msg->protocol_id);
1770}
1771
1773 const char *exten, const char *protocol_id, struct ast_channel *dest,
1774 struct ast_refer_params *params, enum ast_control_transfer state)
1775{
1776 struct ast_ari_transfer_message *msg;
1777 msg = ao2_alloc(sizeof(*msg), ari_transfer_dtor);
1778 if (!msg) {
1779 return NULL;
1780 }
1781
1782 msg->refer_params = params;
1783 ao2_ref(msg->refer_params, +1);
1784
1785 msg->state = state;
1786
1787 ast_channel_lock(originating_chan);
1788 msg->source = ao2_bump(ast_channel_snapshot(originating_chan));
1789 ast_channel_unlock(originating_chan);
1790 if (!msg->source) {
1791 ao2_cleanup(msg);
1792 return NULL;
1793 }
1794
1795 if (dest) {
1799 if (!msg->dest) {
1800 ao2_cleanup(msg);
1801 return NULL;
1802 }
1803 }
1804
1805 if (referred_by) {
1807 if (!msg->referred_by) {
1808 ao2_cleanup(msg);
1809 return NULL;
1810 }
1811 }
1812
1813 ast_copy_string(msg->destination, exten, sizeof(msg->destination));
1814
1815 if (protocol_id) {
1817 if (!msg->protocol_id) {
1818 ao2_cleanup(msg);
1819 return NULL;
1820 }
1821 }
1822
1823 return msg;
1824}
1825
1826/*!
1827 * @{ \brief Define channel message types.
1828 */
1831 .to_json = dial_to_json,
1832 );
1835 .to_json = varset_to_json,
1836 );
1838 .to_json = hangup_request_to_json,
1839 );
1843 .to_json = dtmf_end_to_json,
1844 );
1846 .to_json = hold_to_json,
1847 );
1849 .to_json = unhold_to_json,
1850 );
1864 );
1867 );
1870 .to_json = talking_start_to_json,
1871 );
1874 .to_json = talking_stop_to_json,
1875 );
1877 .to_json = tone_detect_to_json,
1878 );
1880 .to_json = ari_transfer_to_json,
1881 );
1882
1883/*! @} */
1884
1886{
1893
1920}
1921
1923{
1924 int res = 0;
1925
1927
1928 channel_topic_all = stasis_topic_create("channel:all");
1929 if (!channel_topic_all) {
1930 return -1;
1931 }
1932
1936 if (!channel_cache) {
1937 return -1;
1938 }
1939
1943 if (!channel_cache_by_name) {
1944 return -1;
1945 }
1946
1973
1974 return res;
1975}
1976
1977/*!
1978 * \internal
1979 * \brief A list element for the dial_masquerade_datastore -- stores data about a dialed peer
1980 */
1982 /*! Called party channel. */
1984 /*! Dialstring used to call the peer. */
1986 /*! Next entry in the list. */
1988};
1989
1990static void dial_target_free(struct dial_target *doomed)
1991{
1992 if (!doomed) {
1993 return;
1994 }
1995 ast_free(doomed->dialstring);
1996 ast_channel_cleanup(doomed->peer);
1997 ast_free(doomed);
1998}
1999
2000/*!
2001 * \internal
2002 * \brief Datastore used for advancing dial state in the case of a masquerade
2003 * against a channel in the process of dialing.
2004 */
2006 /*! Calling party channel. */
2008 /*! List of called peers. */
2010};
2011
2013{
2014 struct dial_target *cur;
2015
2016 while ((cur = AST_LIST_REMOVE_HEAD(&masq_data->dialed_peers, list))) {
2017 dial_target_free(cur);
2018 }
2019}
2020
2022{
2023 struct dial_target *cur;
2024
2025 ao2_lock(masq_data);
2026 if (masq_data->caller == chan) {
2028 } else {
2030 if (cur->peer == chan) {
2032 dial_target_free(cur);
2033 break;
2034 }
2035 }
2037 }
2038 ao2_unlock(masq_data);
2039}
2040
2041static void dial_masquerade_datastore_dtor(void *vdoomed)
2042{
2044}
2045
2047{
2048 struct dial_masquerade_datastore *masq_data;
2049
2050 masq_data = ao2_alloc(sizeof(struct dial_masquerade_datastore),
2052 if (!masq_data) {
2053 return NULL;
2054 }
2056 return masq_data;
2057}
2058
2059/*!
2060 * \internal
2061 * \brief Datastore destructor for dial_masquerade_datastore
2062 */
2064{
2065 ao2_ref(data, -1);
2066}
2067
2068/*!
2069 * \internal
2070 * \brief Datastore destructor for dial_masquerade_datastore
2071 */
2073{
2075 ao2_ref(data, -1);
2076}
2077
2078static struct ast_datastore *dial_masquerade_datastore_find(struct ast_channel *chan);
2079
2080static void dial_masquerade_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
2081{
2082 struct dial_masquerade_datastore *masq_data = data;
2083 struct dial_target *cur;
2084 struct ast_datastore *datastore;
2085
2086 ao2_lock(masq_data);
2087 if (!masq_data->caller) {
2088 /* Nothing to do but remove the datastore */
2089 } else if (masq_data->caller == old_chan) {
2090 /* The caller channel is being masqueraded out. */
2091 ast_debug(1, "Caller channel %s being masqueraded out to %s (is_empty:%d)\n",
2092 ast_channel_name(new_chan), ast_channel_name(old_chan),
2093 AST_LIST_EMPTY(&masq_data->dialed_peers));
2094 AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
2096 cur->dialstring, "NOANSWER", NULL);
2098 cur->dialstring, NULL, NULL);
2099 }
2101 } else {
2102 /* One of the peer channels is being masqueraded out. */
2103 AST_LIST_TRAVERSE_SAFE_BEGIN(&masq_data->dialed_peers, cur, list) {
2104 if (cur->peer == old_chan) {
2105 ast_debug(1, "Peer channel %s being masqueraded out to %s\n",
2106 ast_channel_name(new_chan), ast_channel_name(old_chan));
2107 ast_channel_publish_dial_internal(masq_data->caller, new_chan, NULL,
2108 cur->dialstring, "CANCEL", NULL);
2109 ast_channel_publish_dial_internal(masq_data->caller, old_chan, NULL,
2110 cur->dialstring, NULL, NULL);
2111
2113 dial_target_free(cur);
2114 break;
2115 }
2116 }
2118 }
2119 ao2_unlock(masq_data);
2120
2121 /* Remove the datastore from the channel. */
2122 datastore = dial_masquerade_datastore_find(old_chan);
2123 if (!datastore) {
2124 return;
2125 }
2126 ast_channel_datastore_remove(old_chan, datastore);
2127 ast_datastore_free(datastore);
2128}
2129
2130/*!
2131 * \internal
2132 * \brief Primary purpose for dial_masquerade_datastore, publishes
2133 * the channel dial event needed to set the incoming channel into the
2134 * dial state during a masquerade.
2135 * \param data pointer to the dial_masquerade_datastore
2136 * \param old_chan Channel being replaced
2137 * \param new_chan Channel being pushed to dial mode
2138 */
2139static void dial_masquerade_breakdown(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
2140{
2141 struct dial_masquerade_datastore *masq_data = data;
2142 struct dial_target *cur;
2143
2144 ao2_lock(masq_data);
2145
2146 if (!masq_data->caller) {
2147 ao2_unlock(masq_data);
2148 return;
2149 }
2150
2151 if (masq_data->caller == new_chan) {
2152 /*
2153 * The caller channel is being masqueraded into.
2154 * The masquerade is likely because of a blonde transfer.
2155 */
2156 ast_debug(1, "Caller channel %s being masqueraded into by %s (is_empty:%d)\n",
2157 ast_channel_name(old_chan), ast_channel_name(new_chan),
2158 AST_LIST_EMPTY(&masq_data->dialed_peers));
2159 AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
2161 cur->dialstring, "NOANSWER", NULL);
2163 cur->dialstring, NULL, NULL);
2164 }
2165
2166 ao2_unlock(masq_data);
2167 return;
2168 }
2169
2170 /*
2171 * One of the peer channels is being masqueraded into.
2172 * The masquerade is likely because of a call pickup.
2173 */
2174 AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
2175 if (cur->peer == new_chan) {
2176 ast_debug(1, "Peer channel %s being masqueraded into by %s\n",
2177 ast_channel_name(old_chan), ast_channel_name(new_chan));
2178 ast_channel_publish_dial_internal(masq_data->caller, old_chan, NULL,
2179 cur->dialstring, "CANCEL", NULL);
2180 ast_channel_publish_dial_internal(masq_data->caller, new_chan, NULL,
2181 cur->dialstring, NULL, NULL);
2182 break;
2183 }
2184 }
2185
2186 ao2_unlock(masq_data);
2187}
2188
2190 .type = "stasis-chan-dial-masq",
2192 .chan_fixup = dial_masquerade_fixup,
2193 .chan_breakdown = dial_masquerade_breakdown,
2194};
2195
2197 .type = "stasis-chan-dial-masq",
2199 .chan_fixup = dial_masquerade_fixup,
2200 .chan_breakdown = dial_masquerade_breakdown,
2201};
2202
2203/*!
2204 * \internal
2205 * \brief Find the dial masquerade datastore on the given channel.
2206 *
2207 * \param chan Channel a datastore data is wanted from
2208 *
2209 * \return A pointer to the datastore if it exists.
2210 */
2212{
2213 struct ast_datastore *datastore;
2214
2216 if (!datastore) {
2218 }
2219
2220 return datastore;
2221}
2222
2223/*!
2224 * \internal
2225 * \brief Add the dial masquerade datastore to a channel.
2226 *
2227 * \param chan Channel to setup dial masquerade datastore on.
2228 * \param masq_data NULL to setup caller datastore otherwise steals the ref on success.
2229 *
2230 * \retval masq_data given or created on success.
2231 * (A ref is not returned but can be obtained before chan is unlocked.)
2232 * \retval NULL on error. masq_data ref is not stolen.
2233 */
2235 struct ast_channel *chan, struct dial_masquerade_datastore *masq_data)
2236{
2237 struct ast_datastore *datastore;
2238
2240 if (!datastore) {
2241 return NULL;
2242 }
2243
2244 if (!masq_data) {
2245 masq_data = dial_masquerade_datastore_alloc();
2246 if (!masq_data) {
2247 ast_datastore_free(datastore);
2248 return NULL;
2249 }
2250 masq_data->caller = chan;
2251 }
2252
2253 datastore->data = masq_data;
2254 ast_channel_datastore_add(chan, datastore);
2255
2256 return masq_data;
2257}
2258
2259static int set_dial_masquerade(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring)
2260{
2261 struct ast_datastore *datastore;
2262 struct dial_masquerade_datastore *masq_data;
2263 struct dial_target *target;
2264
2265 /* Find or create caller datastore */
2266 datastore = dial_masquerade_datastore_find(caller);
2267 if (!datastore) {
2268 masq_data = dial_masquerade_datastore_add(caller, NULL);
2269 } else {
2270 masq_data = datastore->data;
2271 }
2272 if (!masq_data) {
2273 return -1;
2274 }
2275 ao2_ref(masq_data, +1);
2276
2277 /*
2278 * Someone likely forgot to do an ast_channel_publish_dial()
2279 * or ast_channel_publish_dial_forward() with a final dial
2280 * status on the channel.
2281 */
2282 ast_assert(masq_data->caller == caller);
2283
2284 /* Create peer target to put into datastore */
2285 target = ast_calloc(1, sizeof(*target));
2286 if (!target) {
2287 ao2_ref(masq_data, -1);
2288 return -1;
2289 }
2290 if (dialstring) {
2291 target->dialstring = ast_strdup(dialstring);
2292 if (!target->dialstring) {
2293 ast_free(target);
2294 ao2_ref(masq_data, -1);
2295 return -1;
2296 }
2297 }
2298 target->peer = ast_channel_ref(peer);
2299
2300 /* Put peer target into datastore */
2301 ao2_lock(masq_data);
2303 AST_LIST_INSERT_HEAD(&masq_data->dialed_peers, target, list);
2304 ao2_unlock(masq_data);
2305
2307 if (datastore) {
2308 if (datastore->data == masq_data) {
2309 /*
2310 * Peer already had the datastore for this dial masquerade.
2311 * This was a redundant peer dial masquerade setup.
2312 */
2313 ao2_ref(masq_data, -1);
2314 return 0;
2315 }
2316
2317 /* Something is wrong. Try to fix if the assert doesn't abort. */
2318 ast_assert(0);
2319
2320 /* Remove the stale dial masquerade datastore */
2323 ast_datastore_free(datastore);
2324 }
2325
2326 /* Create the peer dial masquerade datastore */
2327 if (dial_masquerade_datastore_add(peer, masq_data)) {
2328 /* Success */
2329 return 0;
2330 }
2331
2332 /* Failed to create the peer datastore */
2334 ao2_ref(masq_data, -1);
2335 return -1;
2336}
2337
2339{
2340 struct ast_datastore *datastore;
2341 struct dial_masquerade_datastore *masq_data;
2342
2343 datastore = dial_masquerade_datastore_find(peer);
2344 if (!datastore) {
2345 return;
2346 }
2347
2348 masq_data = datastore->data;
2349 if (masq_data) {
2351 }
2352
2353 ast_channel_datastore_remove(peer, datastore);
2354 ast_datastore_free(datastore);
2355}
2356
2358{
2359 struct ast_datastore *datastore;
2360 struct dial_masquerade_datastore *masq_data;
2361
2363 if (!datastore) {
2364 return;
2365 }
2366
2367 masq_data = datastore->data;
2368 if (!masq_data || !AST_LIST_EMPTY(&masq_data->dialed_peers)) {
2369 return;
2370 }
2371
2373
2375 ast_datastore_free(datastore);
2376}
char digit
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition clicompat.c:19
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_log
Definition astobj2.c:42
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
@ CMP_MATCH
Definition astobj2.h:1027
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_RWLOCK
Definition astobj2.h:365
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
#define ao2_wrlock(a)
Definition astobj2.h:719
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition astobj2.h:1554
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition astobj2.h:404
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition astobj2.h:1063
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition astobj2.h:1072
@ OBJ_MULTIPLE
Definition astobj2.h:1049
@ OBJ_UNLINK
Definition astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition astobj2.h:1303
Bridging API.
@ AST_BRIDGE_FLAG_INVISIBLE
static PGresult * result
Definition cel_pgsql.c:84
static char language[MAX_LANGUAGE]
Definition chan_iax2.c:348
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition chan_iax2.c:497
static const char type[]
struct varshead * ast_channel_get_manager_vars(struct ast_channel *chan)
Gets the variables for a given channel, as specified by ast_channel_set_manager_vars().
Definition channel.c:7968
const char * ast_channel_linkedid(const struct ast_channel *chan)
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_tech_hangupcause(const struct ast_channel *chan)
const char * ast_channel_data(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition channel.c:2375
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition channel.c:2384
const char * ast_channel_tenantid(const struct ast_channel *chan)
struct ast_flags * ast_channel_snapshot_segment_flags(struct ast_channel *chan)
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition channel.c:1807
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
#define ast_channel_lock(chan)
Definition channel.h:2982
struct varshead * ast_channel_get_ari_vars(struct ast_channel *chan)
Gets the variables for a given channel, as specified by ast_channel_set_ari_vars().
Definition channel.c:7973
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
void ast_channel_snapshot_set(struct ast_channel *chan, struct ast_channel_snapshot *snapshot)
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
#define ast_channel_ref(c)
Increase channel reference count.
Definition channel.h:3007
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_accountcode(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
const char * ast_channel_userfield(const struct ast_channel *chan)
#define ast_channel_trylock(chan)
Definition channel.h:2984
const char * ast_channel_appl(const struct ast_channel *chan)
const char * ast_channel_peeraccount(const struct ast_channel *chan)
struct timeval ast_channel_creationtime(struct ast_channel *chan)
enum ama_flags ast_channel_amaflags(const struct ast_channel *chan)
const char * ast_channel_hangupsource(const struct ast_channel *chan)
#define AST_NUM_CHANNEL_BUCKETS
Definition channel.h:157
int ast_channel_hangupcause(const struct ast_channel *chan)
struct ast_bridge * ast_channel_get_bridge(const struct ast_channel *chan)
Get the bridge associated with a channel.
Definition channel.c:10578
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
int ast_channel_has_manager_vars(void)
Return whether or not any manager variables have been set.
Definition channel.c:7840
const char * ast_channel_language(const struct ast_channel *chan)
const char * ast_state2str(enum ast_channel_state state)
Gives the string form of a given channel state.
Definition channel.c:636
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
@ AST_FLAG_SNAPSHOT_STAGE
Definition channel.h:1070
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition channel.h:3029
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition channel.h:2983
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition channel.c:2389
ast_channel_state
ast_channel states
static void update(int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, struct g726_state *state_ptr)
Definition codec_g726.c:367
#define ast_datastore_alloc(info, uid)
Definition datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition datastore.c:68
Dialing API.
static const char name[]
Definition format_mp3.c:68
direction
struct stasis_message_type * ast_channel_mixmonitor_mute_type(void)
Message type for muting or unmuting mixmonitor on a channel.
struct stasis_message_type * ast_channel_masquerade_type(void)
Message type for when a channel is being masqueraded.
struct ao2_container * ast_channel_cache_all(void)
void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
Publish a ast_channel_publish_varset for a channel.
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
struct stasis_message_type * ast_channel_hold_type(void)
Message type for when a channel is placed on hold.
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
struct stasis_message_type * ast_channel_talking_start(void)
Message type for a channel starting talking.
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
struct stasis_message_type * ast_channel_chanspy_start_type(void)
Message type for when a channel starts spying on another channel.
struct stasis_message_type * ast_channel_chanspy_stop_type(void)
Message type for when a channel stops spying on another channel.
struct stasis_message_type * ast_channel_talking_stop(void)
Message type for a channel stopping talking.
struct stasis_message_type * ast_channel_dtmf_begin_type(void)
Message type for when DTMF begins on a channel.
struct stasis_message_type * ast_channel_mixmonitor_stop_type(void)
Message type for stopping mixmonitor on a channel.
struct stasis_message_type * ast_channel_tone_detect(void)
Message type for a channel tone detection.
struct stasis_message_type * ast_channel_varset_type(void)
Message type for when a variable is set on a channel.
struct stasis_message_type * ast_channel_hangup_handler_type(void)
Message type for hangup handler related actions.
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
void ast_channel_snapshot_invalidate_segment(struct ast_channel *chan, enum ast_channel_snapshot_segment_invalidation segment)
Invalidate a channel snapshot segment from being reused.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
struct stasis_message_type * ast_channel_agent_logoff_type(void)
Message type for agent logoff on a channel.
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest_by_name(const char *name)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring, const char *dialstatus)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
struct ao2_container * ast_multi_channel_blob_get_channels(struct ast_multi_channel_blob *obj, const char *role)
Retrieve all channel snapshots associated with a specific role from a ast_multi_channel_blob.
void ast_channel_publish_final_snapshot(struct ast_channel *chan)
Send the final channel snapshot for a channel, thus removing it from cache.
struct stasis_message_type * ast_channel_dial_type(void)
Message type for when a channel dials another channel.
struct stasis_message_type * ast_channel_moh_stop_type(void)
Message type for stopping music on hold on a channel.
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
struct stasis_message_type * ast_channel_unhold_type(void)
Message type for when a channel is removed from hold.
struct stasis_message_type * ast_channel_hangup_request_type(void)
Message type for when a hangup is requested on a channel.
struct stasis_message_type * ast_channel_agent_login_type(void)
Message type for agent login on a channel.
struct stasis_message_type * ast_channel_flash_type(void)
Message type for when a hook flash occurs on a channel.
struct stasis_message_type * ast_channel_snapshot_type(void)
Message type for ast_channel_snapshot_update.
struct stasis_message * ast_channel_blob_create_from_cache(const char *channel_id, struct stasis_message_type *type, struct ast_json *blob)
Create a ast_channel_blob message, pulling channel state from the cache.
struct stasis_message_type * ast_channel_fax_type(void)
Message type for a fax operation.
struct stasis_message_type * ast_channel_dtmf_end_type(void)
Message type for when DTMF ends on a channel.
struct stasis_message_type * ast_channel_wink_type(void)
Message type for when a wink occurs on a channel.
struct stasis_message_type * ast_channel_transfer_request_type(void)
struct ast_json * ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
Retrieve the JSON blob from a ast_multi_channel_blob. Returned ast_json is still owned by obj.
ast_channel_snapshot_segment_invalidation
Channel snapshot invalidation flags, used to force generation of segments.
void ast_channel_publish_snapshot(struct ast_channel *chan)
Publish a ast_channel_snapshot for a channel.
struct ao2_container * ast_channel_cache_by_name(void)
Secondary channel cache, indexed by name.
void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message.
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring, const char *dialstatus, const char *forward)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
struct stasis_message_type * ast_channel_moh_start_type(void)
Message type for starting music on hold on a channel.
struct stasis_message * ast_channel_blob_create(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Creates a ast_channel_blob message.
struct stasis_message_type * ast_channel_mixmonitor_start_type(void)
Message type for starting mixmonitor on a channel.
@ AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER
@ AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP
@ AST_CHANNEL_SNAPSHOT_INVALIDATE_BRIDGE
@ AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE
@ AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN
@ AST_TRANSFER_FAILED
@ AST_TRANSFER_UNAVAILABLE
@ AST_TRANSFER_SUCCESS
@ AST_TRANSFER_PROGRESS
@ AST_TRANSFER_INVALID
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
Asterisk JSON abstraction layer.
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition json.c:278
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition json.c:248
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition json.c:378
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
Definition json.c:399
struct ast_json * ast_json_name_number(const char *name, const char *number)
Common JSON rendering functions for common 'objects'.
Definition json.c:646
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition json.c:670
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition json.c:362
struct ast_json * ast_json_dialplan_cep_app(const char *context, const char *exten, int priority, const char *app_name, const char *app_data)
Construct a context/exten/priority/application/application_data as JSON.
Definition json.c:653
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition json.c:67
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition json.c:414
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition json.c:283
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition json.c:407
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition json.c:332
struct ast_json * ast_json_channel_vars(struct varshead *channelvars)
Construct a JSON object from a ast_var_t list.
Definition json.c:941
struct ast_json * ast_json_copy(const struct ast_json *value)
Copy a JSON value, but not its children.
Definition json.c:637
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition json.h:87
int ast_json_is_null(const struct ast_json *value)
Check if value is JSON null.
Definition json.c:273
A set of macros to manage forward-linked lists.
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition manager.c:10144
#define EVENT_FLAG_CALL
Definition manager.h:76
#define EVENT_FLAG_AGENT
Definition manager.h:80
#define EVENT_FLAG_DIALPLAN
Definition manager.h:86
Core PBX routines and definitions.
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
#define NULL
Definition resample.c:96
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition stasis.h:1515
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition stasis.c:684
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define STASIS_MESSAGE_TYPE_DEFN(name,...)
Boiler-plate messaging macro for defining public message types.
Definition stasis.h:1440
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition stasis.c:1578
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
struct ast_json * ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_bridge_snapshot.
struct ast_ari_transfer_message * ast_ari_transfer_message_create(struct ast_channel *originating_chan, const char *referred_by, const char *exten, const char *protocol_id, struct ast_channel *dest, struct ast_refer_params *params, enum ast_control_transfer state)
static void channel_snapshot_dialplan_dtor(void *obj)
int ast_channel_snapshot_connected_line_equal(const struct ast_channel_snapshot *old_snapshot, const struct ast_channel_snapshot *new_snapshot)
Compares the connected line info of two snapshots.
static struct ast_manager_event_blob * varset_to_ami(struct stasis_message *msg)
struct ast_json * ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_channel_snapshot.
static const struct ast_datastore_info dial_masquerade_caller_info
static struct ast_json * dtmf_end_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static struct ast_json * channel_blob_to_json(struct stasis_message *message, const char *type, const struct stasis_message_sanitizer *sanitize)
static void dial_masquerade_datastore_cleanup(struct dial_masquerade_datastore *masq_data)
static int set_dial_masquerade(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring)
static struct ast_json * ari_transfer_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize)
static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
static void channel_blob_dtor(void *obj)
static int channel_role_cmp_cb(void *obj, void *arg, int flags)
static struct ast_channel_snapshot_caller * channel_snapshot_caller_create(struct ast_channel *chan)
static void publish_message_for_channel_topics(struct stasis_message *message, struct ast_channel *chan)
static void dial_target_free(struct dial_target *doomed)
static void dial_masquerade_caller_datastore_destroy(void *data)
static const struct ast_datastore_info dial_masquerade_info
static void ari_transfer_dtor(void *obj)
static int channel_snapshot_uniqueid_cmp_cb(void *obj, void *arg, int flags)
static struct ast_json * tone_detect_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static void dial_masquerade_datastore_remove_chan(struct dial_masquerade_datastore *masq_data, struct ast_channel *chan)
static struct ast_json * talking_start_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static struct stasis_message * create_channel_blob_message(struct ast_channel_snapshot *snapshot, struct stasis_message_type *type, struct ast_json *blob)
static struct ast_channel_snapshot_base * channel_snapshot_base_create(struct ast_channel *chan)
static const char * state2str(enum ast_control_transfer state)
static void ast_channel_publish_dial_internal(struct ast_channel *caller, struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring, const char *dialstatus, const char *forward)
static struct ao2_container * channel_cache_by_name
#define NUM_MULTI_CHANNEL_BLOB_BUCKETS
static void dial_masquerade_breakdown(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
static void dial_masquerade_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
static struct ast_channel_snapshot_update * channel_snapshot_update_create(struct ast_channel *chan)
static struct dial_masquerade_datastore * dial_masquerade_datastore_add(struct ast_channel *chan, struct dial_masquerade_datastore *masq_data)
int ast_channel_snapshot_caller_id_equal(const struct ast_channel_snapshot *old_snapshot, const struct ast_channel_snapshot *new_snapshot)
Compares the callerid info of two snapshots.
static struct ast_channel_snapshot_peer * channel_snapshot_peer_create(struct ast_channel *chan)
static struct ast_datastore * dial_masquerade_datastore_find(struct ast_channel *chan)
static struct ast_json * varset_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static void channel_snapshot_update_dtor(void *obj)
static struct ast_json * dial_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
int ast_stasis_channels_init(void)
Initialize the stasis channel topic and message types.
static struct ast_manager_event_blob * talking_stop_to_ami(struct stasis_message *msg)
int ast_channel_snapshot_cep_equal(const struct ast_channel_snapshot *old_snapshot, const struct ast_channel_snapshot *new_snapshot)
Compares the context, exten and priority of two snapshots.
static struct stasis_topic * channel_topic_all
static void dial_masquerade_datastore_destroy(void *data)
static void remove_dial_masquerade_caller(struct ast_channel *caller)
static struct ast_channel_snapshot_connected * channel_snapshot_connected_create(struct ast_channel *chan)
static struct ast_manager_event_blob * talking_start_to_ami(struct stasis_message *msg)
static struct ast_channel_snapshot_dialplan * channel_snapshot_dialplan_create(struct ast_channel *chan)
static struct dial_masquerade_datastore * dial_masquerade_datastore_alloc(void)
static void dial_masquerade_datastore_dtor(void *vdoomed)
static void channel_role_snapshot_dtor(void *obj)
static struct ast_channel_snapshot_hangup * channel_snapshot_hangup_create(struct ast_channel *chan)
static int channel_snapshot_uniqueid_hash_cb(const void *obj, const int flags)
static void channel_snapshot_caller_dtor(void *obj)
static void channel_snapshot_dtor(void *obj)
static struct ao2_container * channel_cache
static void channel_snapshot_base_dtor(void *obj)
static struct ast_json * hold_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static void remove_dial_masquerade(struct ast_channel *peer)
static struct ast_manager_event_blob * agent_logoff_to_ami(struct stasis_message *msg)
static struct ast_json * unhold_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static int channel_snapshot_hash_cb(const void *obj, const int flags)
static int channel_role_hash_cb(const void *obj, const int flags)
static struct ast_json * hangup_request_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static void multi_channel_blob_dtor(void *obj)
static struct ast_json * talking_stop_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static struct ast_manager_event_blob * agent_login_to_ami(struct stasis_message *msg)
static struct ast_channel_snapshot_bridge * channel_snapshot_bridge_create(struct ast_channel *chan)
static void stasis_channels_cleanup(void)
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_init_extended(x, field)
Initialize an extended string field.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition strings.h:1303
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
char * ast_escape_c_alloc(const char *s)
Escape standard 'C' sequences in the given string.
Definition utils.c:2176
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
Message published during an "ARI" transfer.
char destination[AST_MAX_EXTENSION]
struct ast_refer_params * refer_params
struct ast_channel_snapshot * dest_peer
enum ast_control_transfer state
struct ast_bridge_snapshot * dest_bridge
struct ast_channel_snapshot * source_peer
struct ast_bridge_snapshot * source_bridge
struct ast_channel_snapshot * dest
struct ast_channel_snapshot * source
Structure that contains information about a bridge.
Definition bridge.h:353
const ast_string_field uniqueid
Definition bridge.h:405
struct ast_flags feature_flags
Definition bridge.h:373
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
Structure containing base information for a channel snapshot.
const ast_string_field language
const ast_string_field tenantid
const ast_string_field accountcode
const ast_string_field userfield
const ast_string_field uniqueid
const ast_string_field name
Structure containing bridge information for a channel snapshot.
Structure containing caller information for a channel snapshot.
const ast_string_field dialed_subaddr
const ast_string_field number
const ast_string_field rdnis
const ast_string_field ani
const ast_string_field name
const ast_string_field subaddr
const ast_string_field dnid
Structure containing connected information for a channel snapshot.
Structure containing dialplan information for a channel snapshot.
const ast_string_field data
const ast_string_field context
const ast_string_field exten
const ast_string_field appl
Structure containing hangup information for a channel snapshot.
Structure containing peer information for a channel snapshot.
Structure representing a change of snapshot of channel state.
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_connected * connected
struct varshead * manager_vars
struct varshead * ari_vars
struct ast_channel_snapshot_dialplan * dialplan
struct ast_channel_snapshot_peer * peer
struct ast_channel_snapshot_bridge * bridge
struct ast_channel_snapshot_base * base
enum ast_channel_state state
struct ast_flags softhangup_flags
struct ast_channel_snapshot_caller * caller
struct ast_flags flags
struct ast_channel_snapshot_hangup * hangup
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition channel.h:648
Main Channel structure associated with a channel.
Structure for a data store type.
Definition datastore.h:31
const char * type
Definition datastore.h:32
Structure for a data store object.
Definition datastore.h:64
void * data
Definition datastore.h:66
Abstract JSON element (object, array, string, int, ...).
Struct containing info for an AMI event to send out.
Definition manager.h:503
A multi channel blob data structure for multi_channel_blob stasis messages.
struct ast_json * blob
struct ao2_container * channel_snapshots
char * str
Subscriber phone number (Malloced)
Definition channel.h:388
const char * param_value
Definition refer.h:83
const char * param_name
Definition refer.h:82
Support for dynamic strings.
Definition strings.h:623
A channel snapshot wrapper object used in ast_multi_channel_blob objects.
struct ast_channel_snapshot * snapshot
struct ast_channel * caller
struct dial_masquerade_datastore::@431 dialed_peers
struct ast_channel * peer
struct dial_target::@430 list
Number structure.
Structure containing callbacks for Stasis message sanitization.
Definition stasis.h:200
int(* channel_snapshot)(const struct ast_channel_snapshot *snapshot)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
Definition stasis.h:221
int value
Definition syslog.c:37
Support for translation of data formats. translate.c.
UTF-8 information and validation functions.
ast_utf8_replace_result
Definition utf8.h:70
@ AST_UTF8_REPLACE_VALID
Source contained fully valid UTF-8.
Definition utf8.h:76
enum ast_utf8_replace_result ast_utf8_replace_invalid_chars(char *dst, size_t *dst_size, const char *src, size_t src_len)
Copy a string safely replacing any invalid UTF-8 sequences.
Definition utf8.c:173
#define ast_test_flag(p, flag)
Definition utils.h:64
#define ast_assert(a)
Definition utils.h:779
#define ast_clear_flag(p, flag)
Definition utils.h:78
#define ast_set_flag(p, flag)
Definition utils.h:71
#define ast_copy_flags(dest, src, flagz)
Definition utils.h:85
#define AST_FLAGS_ALL
Definition utils.h:217
Vector container support.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691