Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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
155{
157}
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);
472 strcpy(snapshot->source, hangupsource); /* Safe */
473
474 return snapshot;
475}
476
478{
479 struct ast_channel_snapshot *old_snapshot;
480 struct ast_channel_snapshot *snapshot;
481
482 /* no snapshots for dummy channels */
483 if (!ast_channel_tech(chan)) {
484 return NULL;
485 }
486
487 snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dtor,
489 if (!snapshot) {
490 return NULL;
491 }
492
493 old_snapshot = ast_channel_snapshot(chan);
494
495 /* Channels automatically have all segments invalidated on them initially so a check for an old
496 * snapshot existing before usage is not done here, as it can not happen. If the stored snapshot
497 * on the channel is updated as a result of this then all segments marked as invalidated will be
498 * cleared.
499 */
501 /* The base information has changed so update our snapshot */
502 snapshot->base = channel_snapshot_base_create(chan);
503 if (!snapshot->base) {
504 ao2_ref(snapshot, -1);
505 return NULL;
506 }
507 } else {
508 snapshot->base = ao2_bump(old_snapshot->base);
509 }
510
512 /* The peer information has changed so update our snapshot */
513 snapshot->peer = channel_snapshot_peer_create(chan);
514 if (!snapshot->peer) {
515 ao2_ref(snapshot, -1);
516 return NULL;
517 }
518 } else {
519 snapshot->peer = ao2_bump(old_snapshot->peer);
520 }
521
522 /* Unfortunately both caller and connected information do not have an enforced contract with
523 * the channel API. This has allowed consumers to directly get the caller or connected structure
524 * and manipulate it. Until such time as there is an enforced contract (which is being tracked under
525 * ASTERISK-28164) they are each regenerated every time a channel snapshot is created.
526 */
527 snapshot->caller = channel_snapshot_caller_create(chan);
528 if (!snapshot->caller) {
529 ao2_ref(snapshot, -1);
530 return NULL;
531 }
532
534 if (!snapshot->connected) {
535 ao2_ref(snapshot, -1);
536 return NULL;
537 }
538
540 /* The bridge has changed so update our snapshot */
541 snapshot->bridge = channel_snapshot_bridge_create(chan);
542 if (!snapshot->bridge) {
543 ao2_ref(snapshot, -1);
544 return NULL;
545 }
546 } else {
547 snapshot->bridge = ao2_bump(old_snapshot->bridge);
548 }
549
551 /* The dialplan information has changed so update our snapshot */
553 if (!snapshot->dialplan) {
554 ao2_ref(snapshot, -1);
555 return NULL;
556 }
557 } else {
558 snapshot->dialplan = ao2_bump(old_snapshot->dialplan);
559 }
560
562 /* The hangup information has changed so update our snapshot */
563 snapshot->hangup = channel_snapshot_hangup_create(chan);
564 if (!snapshot->hangup) {
565 ao2_ref(snapshot, -1);
566 return NULL;
567 }
568 } else {
569 snapshot->hangup = ao2_bump(old_snapshot->hangup);
570 }
571
572 snapshot->state = ast_channel_state(chan);
573 snapshot->amaflags = ast_channel_amaflags(chan);
574 ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF);
576
577 /* These have to be recreated as they may have changed, unfortunately */
579 snapshot->ari_vars = ast_channel_get_ari_vars(chan);
580
581 return snapshot;
582}
583
584static void channel_snapshot_update_dtor(void *obj)
585{
587
588 ao2_cleanup(update->old_snapshot);
589 ao2_cleanup(update->new_snapshot);
590}
591
593{
595
598 if (!update) {
599 return NULL;
600 }
601
602 update->old_snapshot = ao2_bump(ast_channel_snapshot(chan));
603 update->new_snapshot = ast_channel_snapshot_create(chan);
604 if (!update->new_snapshot) {
605 ao2_ref(update, -1);
606 return NULL;
607 }
608
609 return update;
610}
611
613{
614 if (chan) {
616 } else {
618 }
619}
620
621static void channel_blob_dtor(void *obj)
622{
623 struct ast_channel_blob *event = obj;
624 ao2_cleanup(event->snapshot);
625 ast_json_unref(event->blob);
626}
627
629 struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring,
630 const char *dialstatus, const char *forward)
631{
632 struct ast_multi_channel_blob *payload;
633 struct stasis_message *msg;
634 struct ast_json *blob;
635 struct ast_channel_snapshot *peer_snapshot;
636
637 if (!ast_channel_dial_type()) {
638 return;
639 }
640
641 ast_assert(peer != NULL);
642
643 blob = ast_json_pack("{s: s, s: s, s: s}",
644 "dialstatus", S_OR(dialstatus, ""),
645 "forward", S_OR(forward, ""),
646 "dialstring", S_OR(dialstring, ""));
647 if (!blob) {
648 return;
649 }
650 payload = ast_multi_channel_blob_create(blob);
651 ast_json_unref(blob);
652 if (!payload) {
653 return;
654 }
655
656 if (caller) {
657 struct ast_channel_snapshot *caller_snapshot;
658
660 if (ast_strlen_zero(dialstatus)) {
662 } else {
663 caller_snapshot = ast_channel_snapshot_create(caller);
664 }
666 if (!caller_snapshot) {
667 ao2_ref(payload, -1);
668 return;
669 }
670 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
671 ao2_ref(caller_snapshot, -1);
672 }
673
675 if (ast_strlen_zero(dialstatus)) {
677 } else {
678 peer_snapshot = ast_channel_snapshot_create(peer);
679 }
681 if (!peer_snapshot) {
682 ao2_ref(payload, -1);
683 return;
684 }
685 ast_multi_channel_blob_add_channel(payload, "peer", peer_snapshot);
686 ao2_ref(peer_snapshot, -1);
687
688 if (forwarded) {
689 struct ast_channel_snapshot *forwarded_snapshot;
690
691 ast_channel_lock(forwarded);
692 forwarded_snapshot = ast_channel_snapshot_create(forwarded);
693 ast_channel_unlock(forwarded);
694 if (!forwarded_snapshot) {
695 ao2_ref(payload, -1);
696 return;
697 }
698 ast_multi_channel_blob_add_channel(payload, "forwarded", forwarded_snapshot);
699 ao2_ref(forwarded_snapshot, -1);
700 }
701
703 ao2_ref(payload, -1);
704 if (msg) {
706 ao2_ref(msg, -1);
707 }
708}
709
710static void remove_dial_masquerade(struct ast_channel *peer);
712static int set_dial_masquerade(struct ast_channel *caller,
713 struct ast_channel *peer, const char *dialstring);
714
716 struct ast_channel *forwarded, const char *dialstring, const char *dialstatus,
717 const char *forward)
718{
719 ast_assert(peer != NULL);
720
721 /* XXX With an early bridge the below dial masquerade datastore code could, theoretically,
722 * go away as the act of changing the channel during dialing would be done using the bridge
723 * API itself and not a masquerade.
724 */
725
726 if (caller) {
727 /*
728 * Lock two or three channels.
729 *
730 * We need to hold the locks to hold off a potential masquerade
731 * messing up the stasis dial event ordering.
732 */
733 for (;; ast_channel_unlock(caller), sched_yield()) {
736 continue;
737 }
738 if (forwarded && ast_channel_trylock(forwarded)) {
740 continue;
741 }
742 break;
743 }
744
745 if (ast_strlen_zero(dialstatus)) {
746 set_dial_masquerade(caller, peer, dialstring);
747 } else {
749 }
750 }
751
752 ast_channel_publish_dial_internal(caller, peer, forwarded, dialstring, dialstatus,
753 forward);
754
755 if (caller) {
756 if (forwarded) {
757 ast_channel_unlock(forwarded);
758 }
762 }
763}
764
766 const char *dialstring, const char *dialstatus)
767{
768 ast_channel_publish_dial_forward(caller, peer, NULL, dialstring, dialstatus, NULL);
769}
770
773 struct ast_json *blob)
774{
775 struct stasis_message *msg;
776 struct ast_channel_blob *obj;
777
778 obj = ao2_alloc(sizeof(*obj), channel_blob_dtor);
779 if (!obj) {
780 return NULL;
781 }
782
783 if (snapshot) {
784 obj->snapshot = snapshot;
785 ao2_ref(obj->snapshot, +1);
786 }
787 if (!blob) {
789 }
790 obj->blob = ast_json_ref(blob);
791
792 msg = stasis_message_create(type, obj);
793 ao2_cleanup(obj);
794 return msg;
795}
796
799 struct ast_json *blob)
800{
801 struct ast_channel_snapshot *snapshot;
802 struct stasis_message *msg;
803
804 if (!type) {
805 return NULL;
806 }
807
808 snapshot = ast_channel_snapshot_get_latest(channel_id);
809 msg = create_channel_blob_message(snapshot, type, blob);
810 ao2_cleanup(snapshot);
811 return msg;
812}
813
815 struct stasis_message_type *type, struct ast_json *blob)
816{
817 struct ast_channel_snapshot *snapshot;
818 struct stasis_message *msg;
819
820 if (!type) {
821 return NULL;
822 }
823
824 snapshot = chan ? ao2_bump(ast_channel_snapshot(chan)) : NULL;
825 msg = create_channel_blob_message(snapshot, type, blob);
826 ao2_cleanup(snapshot);
827 return msg;
828}
829
830/*! \brief A channel snapshot wrapper object used in \ref ast_multi_channel_blob objects */
832 struct ast_channel_snapshot *snapshot; /*!< A channel snapshot */
833 char role[0]; /*!< The role assigned to the channel */
834};
835
836/*! \brief A multi channel blob data structure for multi_channel_blob stasis messages */
838 struct ao2_container *channel_snapshots; /*!< A container holding the snapshots */
839 struct ast_json *blob; /*!< A blob of JSON data */
840};
841
842/*!
843 * \internal
844 * \brief Comparison function for \ref channel_role_snapshot objects
845 */
846static int channel_role_cmp_cb(void *obj, void *arg, int flags)
847{
848 const struct channel_role_snapshot *object_left = obj;
849 const struct channel_role_snapshot *object_right = arg;
850 const char *right_key = arg;
851 int cmp;
852
853 switch (flags & OBJ_SEARCH_MASK) {
855 right_key = object_right->role;
856 case OBJ_SEARCH_KEY:
857 cmp = strcasecmp(object_left->role, right_key);
858 break;
860 cmp = strncasecmp(object_left->role, right_key, strlen(right_key));
861 break;
862 default:
863 cmp = 0;
864 break;
865 }
866 if (cmp) {
867 return 0;
868 }
869 return CMP_MATCH;
870}
871
872/*!
873 * \internal
874 * \brief Hash function for \ref channel_role_snapshot objects
875 */
876static int channel_role_hash_cb(const void *obj, const int flags)
877{
878 const struct channel_role_snapshot *object = obj;
879 const char *key;
880
881 switch (flags & OBJ_SEARCH_MASK) {
882 case OBJ_SEARCH_KEY:
883 key = obj;
884 break;
886 key = object->role;
887 break;
888 default:
889 ast_assert(0);
890 return 0;
891 }
892 return ast_str_case_hash(key);
893}
894
895/*!
896 * \internal
897 * \brief Destructor for \ref ast_multi_channel_blob objects
898 */
899static void multi_channel_blob_dtor(void *obj)
900{
901 struct ast_multi_channel_blob *multi_blob = obj;
902
903 ao2_cleanup(multi_blob->channel_snapshots);
904 ast_json_unref(multi_blob->blob);
905}
906
908{
909 struct ast_multi_channel_blob *obj;
910
911 ast_assert(blob != NULL);
912
913 obj = ao2_alloc(sizeof(*obj), multi_channel_blob_dtor);
914 if (!obj) {
915 return NULL;
916 }
917
920 if (!obj->channel_snapshots) {
921 ao2_ref(obj, -1);
922 return NULL;
923 }
924
925 obj->blob = ast_json_ref(blob);
926 return obj;
927}
928
930{
931 ast_assert(!ast_strlen_zero(uniqueid));
932
933 return ao2_find(channel_cache, uniqueid, OBJ_SEARCH_KEY);
934}
935
937{
939
941}
942
944{
946 struct stasis_message *message;
947
949 return;
950 }
951
953 if (!update) {
954 return;
955 }
956
958 /* In the success path message holds a reference to update so it will be valid
959 * for the lifetime of this function until the end.
960 */
961 ao2_ref(update, -1);
962 if (!message) {
963 return;
964 }
965
968
970
972 ao2_ref(message, -1);
973}
974
975static void channel_role_snapshot_dtor(void *obj)
976{
977 struct channel_role_snapshot *role_snapshot = obj;
978
979 ao2_cleanup(role_snapshot->snapshot);
980}
981
983{
984 struct channel_role_snapshot *role_snapshot;
985 int role_len = strlen(role) + 1;
986
987 if (!obj || ast_strlen_zero(role) || !snapshot) {
988 return;
989 }
990
991 role_snapshot = ao2_alloc_options(sizeof(*role_snapshot) + role_len,
993 if (!role_snapshot) {
994 return;
995 }
996 ast_copy_string(role_snapshot->role, role, role_len);
997 role_snapshot->snapshot = snapshot;
998 ao2_ref(role_snapshot->snapshot, +1);
999 ao2_link(obj->channel_snapshots, role_snapshot);
1000 ao2_ref(role_snapshot, -1);
1001}
1002
1004{
1005 struct channel_role_snapshot *role_snapshot;
1006 struct ast_channel_snapshot *snapshot;
1007
1008 if (!obj || ast_strlen_zero(role)) {
1009 return NULL;
1010 }
1011 role_snapshot = ao2_find(obj->channel_snapshots, role, OBJ_SEARCH_KEY);
1012 /* Note that this function does not increase the ref count on snapshot */
1013 if (!role_snapshot) {
1014 return NULL;
1015 }
1016 snapshot = role_snapshot->snapshot;
1017 ao2_ref(role_snapshot, -1);
1018 return snapshot;
1019}
1020
1022{
1023 struct ao2_container *ret_container;
1024 struct ao2_iterator *it_role_snapshots;
1025 struct channel_role_snapshot *role_snapshot;
1026 char *arg;
1027
1028 if (!obj || ast_strlen_zero(role)) {
1029 return NULL;
1030 }
1031
1035 if (!ret_container) {
1036 return NULL;
1037 }
1038
1039 arg = ast_strdupa(role);
1040 it_role_snapshots = ao2_callback(obj->channel_snapshots,
1042 if (!it_role_snapshots) {
1043 ao2_ref(ret_container, -1);
1044 return NULL;
1045 }
1046
1047 while ((role_snapshot = ao2_iterator_next(it_role_snapshots))) {
1048 ao2_link(ret_container, role_snapshot->snapshot);
1049 ao2_ref(role_snapshot, -1);
1050 }
1051 ao2_iterator_destroy(it_role_snapshots);
1052
1053 return ret_container;
1054}
1055
1057{
1058 if (!obj) {
1059 return NULL;
1060 }
1061 return obj->blob;
1062}
1063
1065{
1067}
1068
1070{
1073}
1074
1077{
1079}
1080
1082{
1084 struct stasis_message *message;
1085
1087 return;
1088 }
1089
1091 return;
1092 }
1093
1095 if (!update) {
1096 return;
1097 }
1098
1099 /* If an old snapshot exists and is the same as this newly created one don't bother
1100 * raising a message as it hasn't changed.
1101 */
1102 if (update->old_snapshot && !memcmp(update->old_snapshot, update->new_snapshot, sizeof(struct ast_channel_snapshot))) {
1103 ao2_ref(update, -1);
1104 return;
1105 }
1106
1108 /* In the success path message holds a reference to update so it will be valid
1109 * for the lifetime of this function until the end.
1110 */
1111 ao2_ref(update, -1);
1112 if (!message) {
1113 return;
1114 }
1115
1116 /* We lock these ourselves so that the update is atomic and there isn't time where a
1117 * snapshot is not in the cache.
1118 */
1121
1124
1125 /* The same applies here. */
1128
1131
1132 ast_channel_snapshot_set(chan, update->new_snapshot);
1133
1134 /* As this is now the new snapshot any existing invalidated segments have been
1135 * created fresh and are up to date.
1136 */
1138
1141 ao2_ref(message, -1);
1142}
1143
1145{
1146 struct stasis_message *message;
1147
1148 if (!blob) {
1149 blob = ast_json_null();
1150 }
1151
1153 if (message) {
1155 ao2_ref(message, -1);
1156 }
1157}
1158
1160{
1161 struct stasis_message *message;
1162
1163 if (!blob) {
1164 blob = ast_json_null();
1165 }
1166
1167 message = ast_channel_blob_create(chan, type, blob);
1168 if (message) {
1170 ao2_ref(message, -1);
1171 }
1172}
1173
1174void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
1175{
1176 struct ast_json *blob;
1178 char *new_value = NULL;
1179 size_t new_value_size = 0;
1180
1181 ast_assert(name != NULL);
1182 ast_assert(value != NULL);
1183
1184 /*
1185 * Call with new-value == NULL to just check for invalid UTF-8
1186 * sequences and get size of buffer needed.
1187 */
1188 result = ast_utf8_replace_invalid_chars(new_value, &new_value_size,
1189 value, strlen(value));
1190
1192 /*
1193 * If there were no invalid sequences, we can use
1194 * the value directly.
1195 */
1196 new_value = (char *)value;
1197 } else {
1198 /*
1199 * If there were invalid sequences, we need to replace
1200 * them with the UTF-8 U+FFFD replacement character.
1201 */
1202 new_value = ast_alloca(new_value_size);
1203
1204 result = ast_utf8_replace_invalid_chars(new_value, &new_value_size,
1205 value, strlen(value));
1206
1207 ast_log(LOG_WARNING, "%s: The contents of variable '%s' had invalid UTF-8 sequences which were replaced",
1208 chan ? ast_channel_name(chan) : "GLOBAL", name);
1209 }
1210
1211 blob = ast_json_pack("{s: s, s: s}",
1212 "variable", name,
1213 "value", new_value);
1214 if (!blob) {
1215 ast_log(LOG_ERROR, "Error creating message\n");
1216 return;
1217 }
1218
1219 /*! If there are manager variables, force a cache update */
1220 if (chan && ast_channel_has_manager_vars()) {
1222 }
1223
1224 /* This function is NULL safe for global variables */
1226 ast_json_unref(blob);
1227}
1228
1230{
1231 struct ast_str *channel_event_string;
1232 struct ast_channel_blob *obj = stasis_message_data(msg);
1233 const char *variable =
1234 ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
1235 char *value;
1236 struct ast_manager_event_blob *ev;
1237
1239 "value")));
1240 if (!value) {
1241 return NULL;
1242 }
1243
1244 if (obj->snapshot) {
1245 channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
1246 } else {
1247 channel_event_string = ast_str_create(35);
1248 ast_str_set(&channel_event_string, 0,
1249 "Channel: none\r\n"
1250 "Uniqueid: none\r\n");
1251 }
1252 if (!channel_event_string) {
1253 ast_free(value);
1254 return NULL;
1255 }
1256
1258 "%s"
1259 "Variable: %s\r\n"
1260 "Value: %s\r\n",
1261 ast_str_buffer(channel_event_string), variable, value);
1262 ast_free(channel_event_string);
1263 ast_free(value);
1264 return ev;
1265}
1266
1268{
1269 struct ast_str *channel_string;
1270 struct ast_channel_blob *obj = stasis_message_data(msg);
1271 const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
1272 struct ast_manager_event_blob *ev;
1273
1274 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1275 if (!channel_string) {
1276 return NULL;
1277 }
1278
1280 "%s"
1281 "Agent: %s\r\n",
1282 ast_str_buffer(channel_string), agent);
1283 ast_free(channel_string);
1284 return ev;
1285}
1286
1288{
1289 struct ast_str *channel_string;
1290 struct ast_channel_blob *obj = stasis_message_data(msg);
1291 const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
1292 long logintime = ast_json_integer_get(ast_json_object_get(obj->blob, "logintime"));
1293 struct ast_manager_event_blob *ev;
1294
1295 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1296 if (!channel_string) {
1297 return NULL;
1298 }
1299
1301 "%s"
1302 "Agent: %s\r\n"
1303 "Logintime: %ld\r\n",
1304 ast_str_buffer(channel_string), agent, logintime);
1305 ast_free(channel_string);
1306 return ev;
1307}
1308
1310 const struct ast_channel_snapshot *snapshot,
1311 const struct stasis_message_sanitizer *sanitize)
1312{
1313 struct ast_json *json_chan;
1314
1315 if (snapshot == NULL
1316 || (sanitize
1317 && sanitize->channel_snapshot
1318 && sanitize->channel_snapshot(snapshot))) {
1319 return NULL;
1320 }
1321
1322 json_chan = ast_json_pack(
1323 /* Broken up into groups for readability */
1324 "{ s: s, s: s, s: s, s: s,"
1325 " s: o, s: o, s: s,"
1326 " s: o, s: o, s: s }",
1327 /* First line */
1328 "id", snapshot->base->uniqueid,
1329 "name", snapshot->base->name,
1330 "state", ast_state2str(snapshot->state),
1331 "protocol_id", snapshot->base->protocol_id,
1332 /* Second line */
1333 "caller", ast_json_name_number(
1334 snapshot->caller->name, snapshot->caller->number),
1335 "connected", ast_json_name_number(
1336 snapshot->connected->name, snapshot->connected->number),
1337 "accountcode", snapshot->base->accountcode,
1338 /* Third line */
1339 "dialplan", ast_json_dialplan_cep_app(
1340 snapshot->dialplan->context, snapshot->dialplan->exten, snapshot->dialplan->priority,
1341 snapshot->dialplan->appl, snapshot->dialplan->data),
1342 "creationtime", ast_json_timeval(snapshot->base->creationtime, NULL),
1343 "language", snapshot->base->language);
1344
1345 if (!ast_strlen_zero(snapshot->caller->rdnis)) {
1346 ast_json_object_set(json_chan, "caller_rdnis", ast_json_string_create(snapshot->caller->rdnis));
1347 }
1348
1349 if (snapshot->ari_vars && !AST_LIST_EMPTY(snapshot->ari_vars)) {
1350 ast_json_object_set(json_chan, "channelvars", ast_json_channel_vars(snapshot->ari_vars));
1351 }
1352
1353 if (!ast_strlen_zero(snapshot->base->tenantid)) {
1354 ast_json_object_set(json_chan, "tenantid", ast_json_string_create(snapshot->base->tenantid));
1355 }
1356
1357 return json_chan;
1358}
1359
1361 const struct ast_channel_snapshot *old_snapshot,
1362 const struct ast_channel_snapshot *new_snapshot)
1363{
1364 ast_assert(old_snapshot != NULL);
1365 ast_assert(new_snapshot != NULL);
1366
1367 /* We actually get some snapshots with CEP set, but before the
1368 * application is set. Since empty application is invalid, we treat
1369 * setting the application from nothing as a CEP change.
1370 */
1371 if (ast_strlen_zero(old_snapshot->dialplan->appl) &&
1372 !ast_strlen_zero(new_snapshot->dialplan->appl)) {
1373 return 0;
1374 }
1375
1376 return old_snapshot->dialplan->priority == new_snapshot->dialplan->priority &&
1377 strcmp(old_snapshot->dialplan->context, new_snapshot->dialplan->context) == 0 &&
1378 strcmp(old_snapshot->dialplan->exten, new_snapshot->dialplan->exten) == 0;
1379}
1380
1382 const struct ast_channel_snapshot *old_snapshot,
1383 const struct ast_channel_snapshot *new_snapshot)
1384{
1385 ast_assert(old_snapshot != NULL);
1386 ast_assert(new_snapshot != NULL);
1387 return strcmp(old_snapshot->caller->number, new_snapshot->caller->number) == 0 &&
1388 strcmp(old_snapshot->caller->name, new_snapshot->caller->name) == 0;
1389}
1390
1392 const struct ast_channel_snapshot *old_snapshot,
1393 const struct ast_channel_snapshot *new_snapshot)
1394{
1395 ast_assert(old_snapshot != NULL);
1396 ast_assert(new_snapshot != NULL);
1397 return strcmp(old_snapshot->connected->number, new_snapshot->connected->number) == 0 &&
1398 strcmp(old_snapshot->connected->name, new_snapshot->connected->name) == 0;
1399}
1400
1402 struct stasis_message *message,
1403 const char *type,
1404 const struct stasis_message_sanitizer *sanitize)
1405{
1406 struct ast_json *to_json;
1407 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1408 struct ast_json *blob = channel_blob->blob;
1409 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1410 const struct timeval *tv = stasis_message_timestamp(message);
1411 int res = 0;
1412
1413 if (blob == NULL || ast_json_is_null(blob)) {
1414 to_json = ast_json_object_create();
1415 } else {
1416 /* blobs are immutable, so shallow copies are fine */
1417 to_json = ast_json_copy(blob);
1418 }
1419 if (!to_json) {
1420 return NULL;
1421 }
1422
1423 res |= ast_json_object_set(to_json, "type", ast_json_string_create(type));
1424 res |= ast_json_object_set(to_json, "timestamp",
1425 ast_json_timeval(*tv, NULL));
1426
1427 /* For global channel messages, the snapshot is optional */
1428 if (snapshot) {
1429 struct ast_json *json_channel;
1430
1431 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1432 if (!json_channel) {
1433 ast_json_unref(to_json);
1434 return NULL;
1435 }
1436
1437 res |= ast_json_object_set(to_json, "channel", json_channel);
1438 }
1439
1440 if (res != 0) {
1441 ast_json_unref(to_json);
1442 return NULL;
1443 }
1444
1445 return to_json;
1446}
1447
1449 struct stasis_message *message,
1450 const struct stasis_message_sanitizer *sanitize)
1451{
1452 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1453 struct ast_json *blob = channel_blob->blob;
1454 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1455 const char *direction =
1456 ast_json_string_get(ast_json_object_get(blob, "direction"));
1457 const char *digit =
1459 long duration_ms =
1460 ast_json_integer_get(ast_json_object_get(blob, "duration_ms"));
1461 const struct timeval *tv = stasis_message_timestamp(message);
1462 struct ast_json *json_channel;
1463
1464 /* Only present received DTMF end events as JSON */
1465 if (strcasecmp("Received", direction) != 0) {
1466 return NULL;
1467 }
1468
1469 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1470 if (!json_channel) {
1471 return NULL;
1472 }
1473
1474 return ast_json_pack("{s: s, s: o, s: s, s: I, s: o}",
1475 "type", "ChannelDtmfReceived",
1476 "timestamp", ast_json_timeval(*tv, NULL),
1477 "digit", digit,
1478 "duration_ms", (ast_json_int_t)duration_ms,
1479 "channel", json_channel);
1480}
1481
1483 struct stasis_message *message,
1484 const struct stasis_message_sanitizer *sanitize)
1485{
1486 return channel_blob_to_json(message, "ChannelVarset", sanitize);
1487}
1488
1490 struct stasis_message *message,
1491 const struct stasis_message_sanitizer *sanitize)
1492{
1493 return channel_blob_to_json(message, "ChannelHangupRequest", sanitize);
1494}
1495
1496static struct ast_json *dial_to_json(
1497 struct stasis_message *message,
1498 const struct stasis_message_sanitizer *sanitize)
1499{
1501 struct ast_json *blob = ast_multi_channel_blob_get_json(payload);
1502 const char *dialstatus =
1503 ast_json_string_get(ast_json_object_get(blob, "dialstatus"));
1504 const char *forward =
1505 ast_json_string_get(ast_json_object_get(blob, "forward"));
1506 const char *dialstring =
1507 ast_json_string_get(ast_json_object_get(blob, "dialstring"));
1508 struct ast_json *caller_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "caller"), sanitize);
1509 struct ast_json *peer_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "peer"), sanitize);
1510 struct ast_json *forwarded_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "forwarded"), sanitize);
1511 struct ast_json *json;
1512 const struct timeval *tv = stasis_message_timestamp(message);
1513 int res = 0;
1514
1515 json = ast_json_pack("{s: s, s: o, s: s, s: s, s: s}",
1516 "type", "Dial",
1517 "timestamp", ast_json_timeval(*tv, NULL),
1518 "dialstatus", dialstatus,
1519 "forward", forward,
1520 "dialstring", dialstring);
1521 if (!json) {
1522 ast_json_unref(caller_json);
1523 ast_json_unref(peer_json);
1524 ast_json_unref(forwarded_json);
1525 return NULL;
1526 }
1527
1528 if (caller_json) {
1529 res |= ast_json_object_set(json, "caller", caller_json);
1530 }
1531 if (peer_json) {
1532 res |= ast_json_object_set(json, "peer", peer_json);
1533 }
1534 if (forwarded_json) {
1535 res |= ast_json_object_set(json, "forwarded", forwarded_json);
1536 }
1537
1538 if (res) {
1539 ast_json_unref(json);
1540 return NULL;
1541 }
1542
1543 return json;
1544}
1545
1547{
1548 struct ast_str *channel_string;
1549 struct ast_channel_blob *obj = stasis_message_data(msg);
1550 struct ast_manager_event_blob *blob;
1551
1552 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1553 if (!channel_string) {
1554 return NULL;
1555 }
1556
1557 blob = ast_manager_event_blob_create(EVENT_FLAG_CALL, "ChannelTalkingStart",
1558 "%s", ast_str_buffer(channel_string));
1559 ast_free(channel_string);
1560
1561 return blob;
1562}
1563
1565 const struct stasis_message_sanitizer *sanitize)
1566{
1567 return channel_blob_to_json(message, "ChannelTalkingStarted", sanitize);
1568}
1569
1571{
1572 struct ast_str *channel_string;
1573 struct ast_channel_blob *obj = stasis_message_data(msg);
1574 int duration = ast_json_integer_get(ast_json_object_get(obj->blob, "duration"));
1575 struct ast_manager_event_blob *blob;
1576
1577 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1578 if (!channel_string) {
1579 return NULL;
1580 }
1581
1582 blob = ast_manager_event_blob_create(EVENT_FLAG_CALL, "ChannelTalkingStop",
1583 "%s"
1584 "Duration: %d\r\n",
1585 ast_str_buffer(channel_string),
1586 duration);
1587 ast_free(channel_string);
1588
1589 return blob;
1590}
1591
1593 const struct stasis_message_sanitizer *sanitize)
1594{
1595 return channel_blob_to_json(message, "ChannelTalkingFinished", sanitize);
1596}
1597
1599 const struct stasis_message_sanitizer *sanitize)
1600{
1601 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1602 struct ast_json *blob = channel_blob->blob;
1603 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1604 const char *musicclass = ast_json_string_get(ast_json_object_get(blob, "musicclass"));
1605 const struct timeval *tv = stasis_message_timestamp(message);
1606 struct ast_json *json_channel;
1607
1608 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1609 if (!json_channel) {
1610 return NULL;
1611 }
1612
1613 return ast_json_pack("{s: s, s: o, s: s, s: o}",
1614 "type", "ChannelHold",
1615 "timestamp", ast_json_timeval(*tv, NULL),
1616 "musicclass", S_OR(musicclass, "N/A"),
1617 "channel", json_channel);
1618}
1619
1620
1622 const struct stasis_message_sanitizer *sanitize)
1623{
1624 return channel_blob_to_json(message, "ChannelToneDetected", sanitize);
1625}
1626
1628 const struct stasis_message_sanitizer *sanitize)
1629{
1630 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1631 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1632 const struct timeval *tv = stasis_message_timestamp(message);
1633 struct ast_json *json_channel;
1634
1635 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1636 if (!json_channel) {
1637 return NULL;
1638 }
1639
1640 return ast_json_pack("{s: s, s: o, s: o}",
1641 "type", "ChannelUnhold",
1642 "timestamp", ast_json_timeval(*tv, NULL),
1643 "channel", json_channel);
1644}
1645
1646static const char *state2str(enum ast_control_transfer state) {
1647 switch (state) {
1649 return "channel_declined";
1651 return "channel_answered";
1653 return "channel_progress";
1655 return "channel_declined";
1656 default:
1657 return "invalid";
1658 }
1659}
1660
1662 const struct stasis_message_sanitizer *sanitize)
1663{
1664 struct ast_json *json_channel, *res;
1665 struct ast_json *refer_json, *referred_json, *dest_json;
1666 const struct timeval *tv = stasis_message_timestamp(msg);
1667 struct ast_ari_transfer_message *transfer_msg = stasis_message_data(msg);
1668
1669 dest_json = ast_json_pack("{s: s, s: s}",
1670 "protocol_id", transfer_msg->protocol_id,
1671 "destination", transfer_msg->destination);
1672 if (!dest_json) {
1673 return NULL;
1674 }
1675
1676 if (AST_VECTOR_SIZE(transfer_msg->refer_params) > 0) {
1677 struct ast_json *params = ast_json_array_create();
1678 if (!params) {
1679 return NULL;
1680 }
1681 for (int i = 0; i < AST_VECTOR_SIZE(transfer_msg->refer_params); ++i) {
1682 struct ast_refer_param param = AST_VECTOR_GET(transfer_msg->refer_params, i);
1683 ast_json_array_append(params, ast_json_pack("{s: s, s: s}",
1684 "parameter_name", param.param_name,
1685 "parameter_value", param.param_value));
1686 }
1687 ast_json_object_set(dest_json, "additional_protocol_params", params);
1688 }
1689
1690 refer_json = ast_json_pack("{s: o}",
1691 "requested_destination", dest_json);
1692 if (!refer_json) {
1693 return NULL;
1694 }
1695 if (transfer_msg->dest) {
1696 struct ast_json *dest_chan_json;
1697
1698 dest_chan_json = ast_channel_snapshot_to_json(transfer_msg->dest, sanitize);
1699 ast_json_object_set(refer_json, "destination_channel", dest_chan_json);
1700 }
1701 if (transfer_msg->dest_peer) {
1702 struct ast_json *peer_chan_json;
1703
1704 peer_chan_json = ast_channel_snapshot_to_json(transfer_msg->dest_peer, sanitize);
1705 ast_json_object_set(refer_json, "connected_channel", peer_chan_json);
1706 }
1707 if (transfer_msg->dest_bridge) {
1708 struct ast_json *dest_bridge_json;
1709
1710 dest_bridge_json = ast_bridge_snapshot_to_json(transfer_msg->dest_bridge, sanitize);
1711 ast_json_object_set(refer_json, "bridge", dest_bridge_json);
1712 }
1713
1714 json_channel = ast_channel_snapshot_to_json(transfer_msg->source, sanitize);
1715 if (!json_channel) {
1716 return NULL;
1717 }
1718
1719 referred_json = ast_json_pack("{s: o}",
1720 "source_channel", json_channel);
1721 if (!referred_json) {
1722 return NULL;
1723 }
1724 if (transfer_msg->source_peer) {
1725 struct ast_json *peer_chan_json;
1726
1727 peer_chan_json = ast_channel_snapshot_to_json(transfer_msg->source_peer, sanitize);
1728 ast_json_object_set(referred_json, "connected_channel", peer_chan_json);
1729 }
1730 if (transfer_msg->source_bridge) {
1731 struct ast_json *source_bridge_json;
1732
1733 source_bridge_json = ast_bridge_snapshot_to_json(transfer_msg->source_bridge, sanitize);
1734 ast_json_object_set(referred_json, "bridge", source_bridge_json);
1735 }
1736
1737 res = ast_json_pack("{s: s, s: o, s: o, s: o}",
1738 "type", "ChannelTransfer",
1739 "timestamp", ast_json_timeval(*tv, NULL),
1740 "refer_to", refer_json,
1741 "referred_by", referred_json);
1742 if (!res) {
1743 return NULL;
1744 }
1745
1746 if (transfer_msg->state != AST_TRANSFER_INVALID) {
1747 ast_json_object_set(res, "state", ast_json_string_create(state2str(transfer_msg->state)));
1748 }
1749 return res;
1750}
1751
1752static void ari_transfer_dtor(void *obj)
1753{
1754 struct ast_ari_transfer_message *msg = obj;
1755
1756 ao2_cleanup(msg->source);
1759 ao2_cleanup(msg->dest);
1761 ao2_cleanup(msg->dest_peer);
1763 ast_free(msg->referred_by);
1764 ast_free(msg->protocol_id);
1765}
1766
1768 const char *exten, const char *protocol_id, struct ast_channel *dest,
1769 struct ast_refer_params *params, enum ast_control_transfer state)
1770{
1771 struct ast_ari_transfer_message *msg;
1772 msg = ao2_alloc(sizeof(*msg), ari_transfer_dtor);
1773 if (!msg) {
1774 return NULL;
1775 }
1776
1777 msg->refer_params = params;
1778 ao2_ref(msg->refer_params, +1);
1779
1780 msg->state = state;
1781
1782 ast_channel_lock(originating_chan);
1783 msg->source = ao2_bump(ast_channel_snapshot(originating_chan));
1784 ast_channel_unlock(originating_chan);
1785 if (!msg->source) {
1786 ao2_cleanup(msg);
1787 return NULL;
1788 }
1789
1790 if (dest) {
1794 if (!msg->dest) {
1795 ao2_cleanup(msg);
1796 return NULL;
1797 }
1798 }
1799
1801 if (!msg->referred_by) {
1802 ao2_cleanup(msg);
1803 return NULL;
1804 }
1805 ast_copy_string(msg->destination, exten, sizeof(msg->destination));
1807 if (!msg->protocol_id) {
1808 ao2_cleanup(msg);
1809 return NULL;
1810 }
1811
1812 return msg;
1813}
1814
1815/*!
1816 * @{ \brief Define channel message types.
1817 */
1820 .to_json = dial_to_json,
1821 );
1824 .to_json = varset_to_json,
1825 );
1827 .to_json = hangup_request_to_json,
1828 );
1832 .to_json = dtmf_end_to_json,
1833 );
1835 .to_json = hold_to_json,
1836 );
1838 .to_json = unhold_to_json,
1839 );
1853 );
1856 );
1859 .to_json = talking_start_to_json,
1860 );
1863 .to_json = talking_stop_to_json,
1864 );
1866 .to_json = tone_detect_to_json,
1867 );
1869 .to_json = ari_transfer_to_json,
1870 );
1871
1872/*! @} */
1873
1875{
1882
1909}
1910
1912{
1913 int res = 0;
1914
1916
1917 channel_topic_all = stasis_topic_create("channel:all");
1918 if (!channel_topic_all) {
1919 return -1;
1920 }
1921
1925 if (!channel_cache) {
1926 return -1;
1927 }
1928
1932 if (!channel_cache_by_name) {
1933 return -1;
1934 }
1935
1962
1963 return res;
1964}
1965
1966/*!
1967 * \internal
1968 * \brief A list element for the dial_masquerade_datastore -- stores data about a dialed peer
1969 */
1971 /*! Called party channel. */
1973 /*! Dialstring used to call the peer. */
1975 /*! Next entry in the list. */
1977};
1978
1979static void dial_target_free(struct dial_target *doomed)
1980{
1981 if (!doomed) {
1982 return;
1983 }
1984 ast_free(doomed->dialstring);
1985 ast_channel_cleanup(doomed->peer);
1986 ast_free(doomed);
1987}
1988
1989/*!
1990 * \internal
1991 * \brief Datastore used for advancing dial state in the case of a masquerade
1992 * against a channel in the process of dialing.
1993 */
1995 /*! Calling party channel. */
1997 /*! List of called peers. */
1999};
2000
2002{
2003 struct dial_target *cur;
2004
2005 while ((cur = AST_LIST_REMOVE_HEAD(&masq_data->dialed_peers, list))) {
2006 dial_target_free(cur);
2007 }
2008}
2009
2011{
2012 struct dial_target *cur;
2013
2014 ao2_lock(masq_data);
2015 if (masq_data->caller == chan) {
2017 } else {
2019 if (cur->peer == chan) {
2021 dial_target_free(cur);
2022 break;
2023 }
2024 }
2026 }
2027 ao2_unlock(masq_data);
2028}
2029
2030static void dial_masquerade_datastore_dtor(void *vdoomed)
2031{
2033}
2034
2036{
2037 struct dial_masquerade_datastore *masq_data;
2038
2039 masq_data = ao2_alloc(sizeof(struct dial_masquerade_datastore),
2041 if (!masq_data) {
2042 return NULL;
2043 }
2045 return masq_data;
2046}
2047
2048/*!
2049 * \internal
2050 * \brief Datastore destructor for dial_masquerade_datastore
2051 */
2053{
2054 ao2_ref(data, -1);
2055}
2056
2057/*!
2058 * \internal
2059 * \brief Datastore destructor for dial_masquerade_datastore
2060 */
2062{
2064 ao2_ref(data, -1);
2065}
2066
2067static struct ast_datastore *dial_masquerade_datastore_find(struct ast_channel *chan);
2068
2069static void dial_masquerade_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
2070{
2071 struct dial_masquerade_datastore *masq_data = data;
2072 struct dial_target *cur;
2073 struct ast_datastore *datastore;
2074
2075 ao2_lock(masq_data);
2076 if (!masq_data->caller) {
2077 /* Nothing to do but remove the datastore */
2078 } else if (masq_data->caller == old_chan) {
2079 /* The caller channel is being masqueraded out. */
2080 ast_debug(1, "Caller channel %s being masqueraded out to %s (is_empty:%d)\n",
2081 ast_channel_name(new_chan), ast_channel_name(old_chan),
2082 AST_LIST_EMPTY(&masq_data->dialed_peers));
2083 AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
2085 cur->dialstring, "NOANSWER", NULL);
2087 cur->dialstring, NULL, NULL);
2088 }
2090 } else {
2091 /* One of the peer channels is being masqueraded out. */
2092 AST_LIST_TRAVERSE_SAFE_BEGIN(&masq_data->dialed_peers, cur, list) {
2093 if (cur->peer == old_chan) {
2094 ast_debug(1, "Peer channel %s being masqueraded out to %s\n",
2095 ast_channel_name(new_chan), ast_channel_name(old_chan));
2096 ast_channel_publish_dial_internal(masq_data->caller, new_chan, NULL,
2097 cur->dialstring, "CANCEL", NULL);
2098 ast_channel_publish_dial_internal(masq_data->caller, old_chan, NULL,
2099 cur->dialstring, NULL, NULL);
2100
2102 dial_target_free(cur);
2103 break;
2104 }
2105 }
2107 }
2108 ao2_unlock(masq_data);
2109
2110 /* Remove the datastore from the channel. */
2111 datastore = dial_masquerade_datastore_find(old_chan);
2112 if (!datastore) {
2113 return;
2114 }
2115 ast_channel_datastore_remove(old_chan, datastore);
2116 ast_datastore_free(datastore);
2117}
2118
2119/*!
2120 * \internal
2121 * \brief Primary purpose for dial_masquerade_datastore, publishes
2122 * the channel dial event needed to set the incoming channel into the
2123 * dial state during a masquerade.
2124 * \param data pointer to the dial_masquerade_datastore
2125 * \param old_chan Channel being replaced
2126 * \param new_chan Channel being pushed to dial mode
2127 */
2128static void dial_masquerade_breakdown(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
2129{
2130 struct dial_masquerade_datastore *masq_data = data;
2131 struct dial_target *cur;
2132
2133 ao2_lock(masq_data);
2134
2135 if (!masq_data->caller) {
2136 ao2_unlock(masq_data);
2137 return;
2138 }
2139
2140 if (masq_data->caller == new_chan) {
2141 /*
2142 * The caller channel is being masqueraded into.
2143 * The masquerade is likely because of a blonde transfer.
2144 */
2145 ast_debug(1, "Caller channel %s being masqueraded into by %s (is_empty:%d)\n",
2146 ast_channel_name(old_chan), ast_channel_name(new_chan),
2147 AST_LIST_EMPTY(&masq_data->dialed_peers));
2148 AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
2150 cur->dialstring, "NOANSWER", NULL);
2152 cur->dialstring, NULL, NULL);
2153 }
2154
2155 ao2_unlock(masq_data);
2156 return;
2157 }
2158
2159 /*
2160 * One of the peer channels is being masqueraded into.
2161 * The masquerade is likely because of a call pickup.
2162 */
2163 AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
2164 if (cur->peer == new_chan) {
2165 ast_debug(1, "Peer channel %s being masqueraded into by %s\n",
2166 ast_channel_name(old_chan), ast_channel_name(new_chan));
2167 ast_channel_publish_dial_internal(masq_data->caller, old_chan, NULL,
2168 cur->dialstring, "CANCEL", NULL);
2169 ast_channel_publish_dial_internal(masq_data->caller, new_chan, NULL,
2170 cur->dialstring, NULL, NULL);
2171 break;
2172 }
2173 }
2174
2175 ao2_unlock(masq_data);
2176}
2177
2179 .type = "stasis-chan-dial-masq",
2181 .chan_fixup = dial_masquerade_fixup,
2182 .chan_breakdown = dial_masquerade_breakdown,
2183};
2184
2186 .type = "stasis-chan-dial-masq",
2188 .chan_fixup = dial_masquerade_fixup,
2189 .chan_breakdown = dial_masquerade_breakdown,
2190};
2191
2192/*!
2193 * \internal
2194 * \brief Find the dial masquerade datastore on the given channel.
2195 *
2196 * \param chan Channel a datastore data is wanted from
2197 *
2198 * \return A pointer to the datastore if it exists.
2199 */
2201{
2202 struct ast_datastore *datastore;
2203
2205 if (!datastore) {
2207 }
2208
2209 return datastore;
2210}
2211
2212/*!
2213 * \internal
2214 * \brief Add the dial masquerade datastore to a channel.
2215 *
2216 * \param chan Channel to setup dial masquerade datastore on.
2217 * \param masq_data NULL to setup caller datastore otherwise steals the ref on success.
2218 *
2219 * \retval masq_data given or created on success.
2220 * (A ref is not returned but can be obtained before chan is unlocked.)
2221 * \retval NULL on error. masq_data ref is not stolen.
2222 */
2224 struct ast_channel *chan, struct dial_masquerade_datastore *masq_data)
2225{
2226 struct ast_datastore *datastore;
2227
2229 if (!datastore) {
2230 return NULL;
2231 }
2232
2233 if (!masq_data) {
2234 masq_data = dial_masquerade_datastore_alloc();
2235 if (!masq_data) {
2236 ast_datastore_free(datastore);
2237 return NULL;
2238 }
2239 masq_data->caller = chan;
2240 }
2241
2242 datastore->data = masq_data;
2243 ast_channel_datastore_add(chan, datastore);
2244
2245 return masq_data;
2246}
2247
2248static int set_dial_masquerade(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring)
2249{
2250 struct ast_datastore *datastore;
2251 struct dial_masquerade_datastore *masq_data;
2252 struct dial_target *target;
2253
2254 /* Find or create caller datastore */
2255 datastore = dial_masquerade_datastore_find(caller);
2256 if (!datastore) {
2257 masq_data = dial_masquerade_datastore_add(caller, NULL);
2258 } else {
2259 masq_data = datastore->data;
2260 }
2261 if (!masq_data) {
2262 return -1;
2263 }
2264 ao2_ref(masq_data, +1);
2265
2266 /*
2267 * Someone likely forgot to do an ast_channel_publish_dial()
2268 * or ast_channel_publish_dial_forward() with a final dial
2269 * status on the channel.
2270 */
2271 ast_assert(masq_data->caller == caller);
2272
2273 /* Create peer target to put into datastore */
2274 target = ast_calloc(1, sizeof(*target));
2275 if (!target) {
2276 ao2_ref(masq_data, -1);
2277 return -1;
2278 }
2279 if (dialstring) {
2280 target->dialstring = ast_strdup(dialstring);
2281 if (!target->dialstring) {
2282 ast_free(target);
2283 ao2_ref(masq_data, -1);
2284 return -1;
2285 }
2286 }
2287 target->peer = ast_channel_ref(peer);
2288
2289 /* Put peer target into datastore */
2290 ao2_lock(masq_data);
2292 AST_LIST_INSERT_HEAD(&masq_data->dialed_peers, target, list);
2293 ao2_unlock(masq_data);
2294
2296 if (datastore) {
2297 if (datastore->data == masq_data) {
2298 /*
2299 * Peer already had the datastore for this dial masquerade.
2300 * This was a redundant peer dial masquerade setup.
2301 */
2302 ao2_ref(masq_data, -1);
2303 return 0;
2304 }
2305
2306 /* Something is wrong. Try to fix if the assert doesn't abort. */
2307 ast_assert(0);
2308
2309 /* Remove the stale dial masquerade datastore */
2312 ast_datastore_free(datastore);
2313 }
2314
2315 /* Create the peer dial masquerade datastore */
2316 if (dial_masquerade_datastore_add(peer, masq_data)) {
2317 /* Success */
2318 return 0;
2319 }
2320
2321 /* Failed to create the peer datastore */
2323 ao2_ref(masq_data, -1);
2324 return -1;
2325}
2326
2328{
2329 struct ast_datastore *datastore;
2330 struct dial_masquerade_datastore *masq_data;
2331
2332 datastore = dial_masquerade_datastore_find(peer);
2333 if (!datastore) {
2334 return;
2335 }
2336
2337 masq_data = datastore->data;
2338 if (masq_data) {
2340 }
2341
2342 ast_channel_datastore_remove(peer, datastore);
2343 ast_datastore_free(datastore);
2344}
2345
2347{
2348 struct ast_datastore *datastore;
2349 struct dial_masquerade_datastore *masq_data;
2350
2352 if (!datastore) {
2353 return;
2354 }
2355
2356 masq_data = datastore->data;
2357 if (!masq_data || !AST_LIST_EMPTY(&masq_data->dialed_peers)) {
2358 return;
2359 }
2360
2362
2364 ast_datastore_free(datastore);
2365}
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
enum cc_state state
Definition: ccss.c:399
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[]
Definition: chan_ooh323.c:109
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:8009
const char * ast_channel_linkedid(const struct ast_channel *chan)
const char * ast_channel_name(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:2414
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2423
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:1848
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:2970
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:8014
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:2995
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:2972
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)
struct ast_channel_snapshot * ast_channel_snapshot(const 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:10560
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:7881
@ AST_FLAG_SNAPSHOT_STAGE
Definition: channel.h:1070
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
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3017
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2971
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:2428
ast_channel_state
ast_channel states
Definition: channelstate.h:35
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_control_transfer
@ 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.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
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:10237
#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:644
#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.
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:1538
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)
STASIS_MESSAGE_TYPE_DEFN(ast_channel_snapshot_type)
Define channel message types.
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.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_init_extended(x, field)
Initialize an extended string field.
Definition: stringfields.h:401
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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
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:2140
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
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::@401 dialed_peers
struct ast_channel * peer
struct dial_target::@400 list
Definition: astman.c:222
Number structure.
Definition: app_followme.c:157
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:63
#define ast_assert(a)
Definition: utils.h:739
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ast_copy_flags(dest, src, flagz)
Definition: utils.h:84
#define AST_FLAGS_ALL
Definition: utils.h:196
Vector container support.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680