Fix documentation replication issues
[asterisk/asterisk.git] / main / stasis_bridges.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Kinsey Moore <kmoore@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 Bridge Objects
22  *
23  * \author Kinsey Moore <kmoore@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include "asterisk/astobj2.h"
35 #include "asterisk/stasis.h"
36 #include "asterisk/stasis_cache_pattern.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/stasis_bridges.h"
39 #include "asterisk/stasis_channels.h"
40 #include "asterisk/bridge.h"
41 #include "asterisk/bridge_technology.h"
42
43 #define SNAPSHOT_CHANNELS_BUCKETS 13
44
45 /*** DOCUMENTATION
46         <managerEvent language="en_US" name="BlindTransfer">
47                 <managerEventInstance class="EVENT_FLAG_CALL">
48                         <synopsis>Raised when a blind transfer is complete.</synopsis>
49                         <syntax>
50                                 <parameter name="Result">
51                                         <para>Indicates if the transfer was successful or if it failed.</para>
52                                         <enumlist>
53                                                 <enum name="Fail"><para>An internal error occurred.</para></enum>
54                                                 <enum name="Invalid"><para>Invalid configuration for transfer (e.g. Not bridged)</para></enum>
55                                                 <enum name="Not Permitted"><para>Bridge does not permit transfers</para></enum>
56                                                 <enum name="Success"><para>Transfer completed successfully</para></enum>
57                                         </enumlist>
58                                         <note><para>A result of <literal>Success</literal> does not necessarily mean that a target was succesfully
59                                         contacted. It means that a party was succesfully placed into the dialplan at the expected location.</para></note>
60                                 </parameter>
61                                 <channel_snapshot prefix="Transferer"/>
62                                 <bridge_snapshot/>
63                                 <parameter name="IsExternal">
64                                         <para>Indicates if the transfer was performed outside of Asterisk. For instance,
65                                         a channel protocol native transfer is external. A DTMF transfer is internal.</para>
66                                                 <enumlist>
67                                                         <enum name="Yes" />
68                                                         <enum name="No" />
69                                                 </enumlist>
70                                 </parameter>
71                                 <parameter name="Context">
72                                         <para>Destination context for the blind transfer.</para>
73                                 </parameter>
74                                 <parameter name="Extension">
75                                         <para>Destination extension for the blind transfer.</para>
76                                 </parameter>
77                         </syntax>
78                 </managerEventInstance>
79         </managerEvent>
80         <managerEvent language="en_US" name="AttendedTransfer">
81                 <managerEventInstance class="EVENT_FLAG_CALL">
82                         <synopsis>Raised when an attended transfer is complete.</synopsis>
83                         <syntax>
84                                 <xi:include xpointer="xpointer(docs/managerEvent[@name='BlindTransfer']/managerEventInstance/syntax/parameter[@name='Result'])" />
85                                 <channel_snapshot prefix="OrigTransferer"/>
86                                 <bridge_snapshot prefix="Orig"/>
87                                 <channel_snapshot prefix="SecondTransferer"/>
88                                 <bridge_snapshot prefix="Second"/>
89                                 <parameter name="DestType">
90                                         <para>Indicates the method by which the attended transfer completed.</para>
91                                         <enumlist>
92                                                 <enum name="Bridge"><para>The transfer was accomplished by merging two bridges into one.</para></enum>
93                                                 <enum name="App"><para>The transfer was accomplished by having a channel or bridge run a dialplan application.</para></enum>
94                                                 <enum name="Link"><para>The transfer was accomplished by linking two bridges together using a local channel pair.</para></enum>
95                                                 <enum name="Threeway"><para>The transfer was accomplished by placing all parties into a threeway call.</para></enum>
96                                                 <enum name="Fail"><para>The transfer failed.</para></enum>
97                                         </enumlist>
98                                 </parameter>
99                                 <parameter name="DestBridgeUniqueid">
100                                         <para>Indicates the surviving bridge when bridges were merged to complete the transfer</para>
101                                         <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Bridge</literal> or <literal>Threeway</literal></para></note>
102                                 </parameter>
103                                 <parameter name="DestApp">
104                                         <para>Indicates the application that is running when the transfer completes</para>
105                                         <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>App</literal></para></note>
106                                 </parameter>
107                                 <channel_snapshot prefix="LocalOne"/>
108                                 <channel_snapshot prefix="LocalTwo"/>
109                                 <parameter name="DestTransfererChannel">
110                                         <para>The name of the surviving transferer channel when a transfer results in a threeway call</para>
111                                         <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Threeway</literal></para></note>
112                                 </parameter>
113                         </syntax>
114                         <description>
115                                 <para>The headers in this event attempt to describe all the major details of the attended transfer. The two transferer channels
116                                 and the two bridges are determined based on their chronological establishment. So consider that Alice calls Bob, and then Alice
117                                 transfers the call to Voicemail. The transferer and bridge headers would be arranged as follows:</para>
118                                 <para>  <replaceable>OrigTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
119                                 <para>  <replaceable>OrigBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
120                                 <para>  <replaceable>SecondTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
121                                 <para>  <replaceable>SecondBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
122                                 <para>Now consider if the order were reversed; instead of having Alice call Bob and transfer him to Voicemail, Alice instead
123                                 calls her Voicemail and transfers that to Bob. The transferer and bridge headers would be arranged as follows:</para>
124                                 <para>  <replaceable>OrigTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
125                                 <para>  <replaceable>OrigBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
126                                 <para>  <replaceable>SecondTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
127                                 <para>  <replaceable>SecondBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
128                         </description>
129                 </managerEventInstance>
130         </managerEvent>
131  ***/
132
133 static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *message);
134 static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *message);
135
136 static struct stasis_cp_all *bridge_cache_all;
137
138 /*!
139  * @{ \brief Define bridge message types.
140  */
141 STASIS_MESSAGE_TYPE_DEFN(ast_bridge_snapshot_type);
142 STASIS_MESSAGE_TYPE_DEFN(ast_bridge_merge_message_type);
143 STASIS_MESSAGE_TYPE_DEFN(ast_channel_entered_bridge_type);
144 STASIS_MESSAGE_TYPE_DEFN(ast_channel_left_bridge_type);
145 STASIS_MESSAGE_TYPE_DEFN(ast_blind_transfer_type, .to_ami = blind_transfer_to_ami);
146 STASIS_MESSAGE_TYPE_DEFN(ast_attended_transfer_type, .to_ami = attended_transfer_to_ami);
147 /*! @} */
148
149 struct stasis_cache *ast_bridge_cache(void)
150 {
151         return stasis_cp_all_cache(bridge_cache_all);
152 }
153
154 struct stasis_topic *ast_bridge_topic_all(void)
155 {
156         return stasis_cp_all_topic(bridge_cache_all);
157 }
158
159 struct stasis_topic *ast_bridge_topic_all_cached(void)
160 {
161         return stasis_cp_all_topic_cached(bridge_cache_all);
162 }
163
164 int bridge_topics_init(struct ast_bridge *bridge)
165 {
166         if (ast_strlen_zero(bridge->uniqueid)) {
167                 ast_log(LOG_ERROR, "Bridge id initialization required\n");
168                 return -1;
169         }
170         bridge->topics = stasis_cp_single_create(bridge_cache_all,
171                 bridge->uniqueid);
172         if (!bridge->topics) {
173                 return -1;
174         }
175         return 0;
176 }
177
178 struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge)
179 {
180         if (!bridge) {
181                 return ast_bridge_topic_all();
182         }
183
184         return stasis_cp_single_topic(bridge->topics);
185 }
186
187 struct stasis_topic *ast_bridge_topic_cached(struct ast_bridge *bridge)
188 {
189         if (!bridge) {
190                 return ast_bridge_topic_all_cached();
191         }
192
193         return stasis_cp_single_topic_cached(bridge->topics);
194 }
195
196 /*! \brief Destructor for bridge snapshots */
197 static void bridge_snapshot_dtor(void *obj)
198 {
199         struct ast_bridge_snapshot *snapshot = obj;
200         ast_string_field_free_memory(snapshot);
201         ao2_cleanup(snapshot->channels);
202         snapshot->channels = NULL;
203 }
204
205 struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge)
206 {
207         RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
208         struct ast_bridge_channel *bridge_channel;
209
210         snapshot = ao2_alloc(sizeof(*snapshot), bridge_snapshot_dtor);
211         if (!snapshot || ast_string_field_init(snapshot, 128)) {
212                 return NULL;
213         }
214
215         snapshot->channels = ast_str_container_alloc(SNAPSHOT_CHANNELS_BUCKETS);
216         if (!snapshot->channels) {
217                 return NULL;
218         }
219
220         AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
221                 if (ast_str_container_add(snapshot->channels,
222                                 ast_channel_uniqueid(bridge_channel->chan))) {
223                         return NULL;
224                 }
225         }
226
227         ast_string_field_set(snapshot, uniqueid, bridge->uniqueid);
228         ast_string_field_set(snapshot, technology, bridge->technology->name);
229         ast_string_field_set(snapshot, subclass, bridge->v_table->name);
230
231         snapshot->feature_flags = bridge->feature_flags;
232         snapshot->capabilities = bridge->technology->capabilities;
233         snapshot->num_channels = bridge->num_channels;
234         snapshot->num_active = bridge->num_active;
235
236         ao2_ref(snapshot, +1);
237         return snapshot;
238 }
239
240 void ast_bridge_publish_state(struct ast_bridge *bridge)
241 {
242         RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
243         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
244
245         ast_assert(bridge != NULL);
246
247         snapshot = ast_bridge_snapshot_create(bridge);
248         if (!snapshot) {
249                 return;
250         }
251
252         msg = stasis_message_create(ast_bridge_snapshot_type(), snapshot);
253         if (!msg) {
254                 return;
255         }
256
257         stasis_publish(ast_bridge_topic(bridge), msg);
258 }
259
260 static void bridge_publish_state_from_blob(struct ast_bridge *bridge,
261         struct ast_bridge_blob *obj)
262 {
263         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
264
265         ast_assert(obj != NULL);
266
267         msg = stasis_message_create(ast_bridge_snapshot_type(), obj->bridge);
268         if (!msg) {
269                 return;
270         }
271
272         stasis_publish(ast_bridge_topic(bridge), msg);
273 }
274
275 /*! \brief Destructor for bridge merge messages */
276 static void bridge_merge_message_dtor(void *obj)
277 {
278         struct ast_bridge_merge_message *msg = obj;
279
280         ao2_cleanup(msg->to);
281         msg->to = NULL;
282         ao2_cleanup(msg->from);
283         msg->from = NULL;
284 }
285
286 /*! \brief Bridge merge message creation helper */
287 static struct ast_bridge_merge_message *bridge_merge_message_create(struct ast_bridge *to, struct ast_bridge *from)
288 {
289         RAII_VAR(struct ast_bridge_merge_message *, msg, NULL, ao2_cleanup);
290
291         msg = ao2_alloc(sizeof(*msg), bridge_merge_message_dtor);
292         if (!msg) {
293                 return NULL;
294         }
295
296         msg->to = ast_bridge_snapshot_create(to);
297         if (!msg->to) {
298                 return NULL;
299         }
300
301         msg->from = ast_bridge_snapshot_create(from);
302         if (!msg->from) {
303                 return NULL;
304         }
305
306         ao2_ref(msg, +1);
307         return msg;
308 }
309
310 void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
311 {
312         RAII_VAR(struct ast_bridge_merge_message *, merge_msg, NULL, ao2_cleanup);
313         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
314
315         ast_assert(to != NULL);
316         ast_assert(from != NULL);
317
318         merge_msg = bridge_merge_message_create(to, from);
319         if (!merge_msg) {
320                 return;
321         }
322
323         msg = stasis_message_create(ast_bridge_merge_message_type(), merge_msg);
324         if (!msg) {
325                 return;
326         }
327
328         stasis_publish(ast_bridge_topic_all(), msg);
329 }
330
331 static void bridge_blob_dtor(void *obj)
332 {
333         struct ast_bridge_blob *event = obj;
334         ao2_cleanup(event->bridge);
335         event->bridge = NULL;
336         ao2_cleanup(event->channel);
337         event->channel = NULL;
338         ast_json_unref(event->blob);
339         event->blob = NULL;
340 }
341
342 struct stasis_message *ast_bridge_blob_create(
343         struct stasis_message_type *message_type,
344         struct ast_bridge *bridge,
345         struct ast_channel *chan,
346         struct ast_json *blob)
347 {
348         RAII_VAR(struct ast_bridge_blob *, obj, NULL, ao2_cleanup);
349         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
350
351         obj = ao2_alloc(sizeof(*obj), bridge_blob_dtor);
352         if (!obj) {
353                 return NULL;
354         }
355
356         if (bridge) {
357                 obj->bridge = ast_bridge_snapshot_create(bridge);
358                 if (obj->bridge == NULL) {
359                         return NULL;
360                 }
361         }
362
363         if (chan) {
364                 obj->channel = ast_channel_snapshot_create(chan);
365                 if (obj->channel == NULL) {
366                         return NULL;
367                 }
368         }
369
370         if (blob) {
371                 obj->blob = ast_json_ref(blob);
372         }
373
374         msg = stasis_message_create(message_type, obj);
375         if (!msg) {
376                 return NULL;
377         }
378
379         ao2_ref(msg, +1);
380         return msg;
381 }
382
383 void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan)
384 {
385         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
386
387         msg = ast_bridge_blob_create(ast_channel_entered_bridge_type(), bridge, chan, NULL);
388         if (!msg) {
389                 return;
390         }
391
392         /* enter blob first, then state */
393         stasis_publish(ast_bridge_topic(bridge), msg);
394         bridge_publish_state_from_blob(bridge, stasis_message_data(msg));
395 }
396
397 void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan)
398 {
399         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
400
401         msg = ast_bridge_blob_create(ast_channel_left_bridge_type(), bridge, chan, NULL);
402         if (!msg) {
403                 return;
404         }
405
406         /* state first, then leave blob (opposite of enter, preserves nesting of events) */
407         bridge_publish_state_from_blob(bridge, stasis_message_data(msg));
408         stasis_publish(ast_bridge_topic(bridge), msg);
409 }
410
411 typedef struct ast_json *(*json_item_serializer_cb)(void *obj);
412
413 static struct ast_json *container_to_json_array(struct ao2_container *items, json_item_serializer_cb item_cb)
414 {
415         RAII_VAR(struct ast_json *, json_items, ast_json_array_create(), ast_json_unref);
416         void *item;
417         struct ao2_iterator it;
418         if (!json_items) {
419                 return NULL;
420         }
421
422         it = ao2_iterator_init(items, 0);
423         while ((item = ao2_iterator_next(&it))) {
424                 if (ast_json_array_append(json_items, item_cb(item))) {
425                         ao2_iterator_destroy(&it);
426                         return NULL;
427                 }
428         }
429         ao2_iterator_destroy(&it);
430
431         return ast_json_ref(json_items);
432 }
433
434 static const char *capability2str(uint32_t capabilities)
435 {
436         if (capabilities & AST_BRIDGE_CAPABILITY_HOLDING) {
437                 return "holding";
438         } else {
439                 return "mixing";
440         }
441 }
442
443 struct ast_json *ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *snapshot)
444 {
445         RAII_VAR(struct ast_json *, json_bridge, NULL, ast_json_unref);
446         struct ast_json *json_channels;
447
448         if (snapshot == NULL) {
449                 return NULL;
450         }
451
452         json_channels = container_to_json_array(snapshot->channels,
453                 (json_item_serializer_cb)ast_json_string_create);
454         if (!json_channels) {
455                 return NULL;
456         }
457
458         json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: o}",
459                 "id", snapshot->uniqueid,
460                 "technology", snapshot->technology,
461                 "bridge_type", capability2str(snapshot->capabilities),
462                 "bridge_class", snapshot->subclass,
463                 "channels", json_channels);
464         if (!json_bridge) {
465                 return NULL;
466         }
467
468         return ast_json_ref(json_bridge);
469 }
470
471 /*!
472  * \internal
473  * \brief Allocate the fields of an \ref ast_bridge_channel_snapshot_pair.
474  *
475  * \param pair A bridge and channel to get snapshots of
476  * \param[out] snapshot_pair An allocated snapshot pair.
477  * \retval 0 Success
478  * \retval non-zero Failure
479  */
480 static int bridge_channel_snapshot_pair_init(struct ast_bridge_channel_pair *pair, struct ast_bridge_channel_snapshot_pair *snapshot_pair)
481 {
482         if (pair->bridge) {
483                 snapshot_pair->bridge_snapshot = ast_bridge_snapshot_create(pair->bridge);
484                 if (!snapshot_pair->bridge_snapshot) {
485                         return -1;
486                 }
487         }
488
489         snapshot_pair->channel_snapshot = ast_channel_snapshot_create(pair->channel);
490         if (!snapshot_pair->channel_snapshot) {
491                 return -1;
492         }
493
494         return 0;
495 }
496
497 /*!
498  * \internal
499  * \brief Free the fields of an \ref ast_bridge_channel_snapshot_pair.
500  *
501  * \param pair The snapshot pair whose fields are to be cleaned up
502  */
503 static void bridge_channel_snapshot_pair_cleanup(struct ast_bridge_channel_snapshot_pair *pair)
504 {
505         ao2_cleanup(pair->bridge_snapshot);
506         ao2_cleanup(pair->channel_snapshot);
507 }
508
509 static const char *result_strs[] = {
510         [AST_BRIDGE_TRANSFER_FAIL] = "Fail",
511         [AST_BRIDGE_TRANSFER_INVALID] = "Invalid",
512         [AST_BRIDGE_TRANSFER_NOT_PERMITTED] = "Not Permitted",
513         [AST_BRIDGE_TRANSFER_SUCCESS] = "Success",
514 };
515
516 static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *msg)
517 {
518         RAII_VAR(struct ast_str *, channel_state, NULL, ast_free_ptr);
519         RAII_VAR(struct ast_str *, bridge_state, NULL, ast_free_ptr);
520         struct ast_bridge_blob *blob = stasis_message_data(msg);
521         const char *exten;
522         const char *context;
523         enum ast_transfer_result result;
524         int is_external;
525
526         if (!blob) {
527                 return NULL;
528         }
529
530         channel_state = ast_manager_build_channel_state_string_prefix(blob->channel, "Transferer");
531         bridge_state = ast_manager_build_bridge_state_string(blob->bridge, "");
532
533         if (!channel_state || !bridge_state) {
534                 return NULL;
535         }
536
537         exten = ast_json_string_get(ast_json_object_get(blob->blob, "exten"));
538         context = ast_json_string_get(ast_json_object_get(blob->blob, "context"));
539         result = ast_json_integer_get(ast_json_object_get(blob->blob, "result"));
540         is_external = ast_json_integer_get(ast_json_object_get(blob->blob, "is_external"));
541
542         return ast_manager_event_blob_create(EVENT_FLAG_CALL, "BlindTransfer",
543                         "Result: %s\r\n"
544                         "%s"
545                         "%s"
546                         "IsExternal: %s\r\n"
547                         "Context: %s\r\n"
548                         "Extension: %s\r\n",
549                         result_strs[result],
550                         ast_str_buffer(channel_state),
551                         ast_str_buffer(bridge_state),
552                         is_external ? "Yes" : "No",
553                         context,
554                         exten);
555 }
556
557 void ast_bridge_publish_blind_transfer(int is_external, enum ast_transfer_result result,
558                 struct ast_bridge_channel_pair *transferer, const char *context, const char *exten)
559 {
560         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
561         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
562
563         json_object = ast_json_pack("{s: s, s: s, s: i, s: i}",
564                         "context", context, "exten", exten, "result", result, "is_external", is_external);
565
566         if (!json_object) {
567                 ast_log(LOG_NOTICE, "Failed to create json bridge blob\n");
568                 return;
569         }
570
571         msg = ast_bridge_blob_create(ast_blind_transfer_type(),
572                         transferer->bridge, transferer->channel, json_object);
573
574         if (!msg) {
575                 ast_log(LOG_NOTICE, "Failed to create blob msg\n");
576                 return;
577         }
578
579         stasis_publish(ast_bridge_topic_all(), msg);
580 }
581
582 static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *msg)
583 {
584         RAII_VAR(struct ast_str *, variable_data, ast_str_create(64), ast_free_ptr);
585         RAII_VAR(struct ast_str *, transferer1_state, NULL, ast_free_ptr);
586         RAII_VAR(struct ast_str *, bridge1_state, NULL, ast_free_ptr);
587         RAII_VAR(struct ast_str *, transferer2_state, NULL, ast_free_ptr);
588         RAII_VAR(struct ast_str *, bridge2_state, NULL, ast_free_ptr);
589         RAII_VAR(struct ast_str *, local1_state, NULL, ast_free_ptr);
590         RAII_VAR(struct ast_str *, local2_state, NULL, ast_free_ptr);
591         struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
592
593         if (!variable_data) {
594                 return NULL;
595         }
596
597         transferer1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transferee.channel_snapshot, "OrigTransferer");
598         transferer2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transfer_target.channel_snapshot, "SecondTransferer");
599
600         if (!transferer1_state || !transferer2_state) {
601                 return NULL;
602         }
603
604         if (transfer_msg->to_transferee.bridge_snapshot) {
605                 bridge1_state = ast_manager_build_bridge_state_string(transfer_msg->to_transferee.bridge_snapshot, "Orig");
606                 if (!bridge1_state) {
607                         return NULL;
608                 }
609         }
610
611         if (transfer_msg->to_transfer_target.bridge_snapshot) {
612                 bridge2_state = ast_manager_build_bridge_state_string(transfer_msg->to_transfer_target.bridge_snapshot, "Second");
613                 if (!bridge2_state) {
614                         return NULL;
615                 }
616         }
617
618         switch (transfer_msg->dest_type) {
619         case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
620                 ast_str_append(&variable_data, 0, "DestType: Bridge\r\n");
621                 ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.bridge);
622                 break;
623         case AST_ATTENDED_TRANSFER_DEST_APP:
624                 ast_str_append(&variable_data, 0, "DestType: App\r\n");
625                 ast_str_append(&variable_data, 0, "DestApp: %s\r\n", transfer_msg->dest.app);
626                 break;
627         case AST_ATTENDED_TRANSFER_DEST_LINK:
628                 local1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[0], "LocalOne");
629                 local2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[1], "LocalTwo");
630                 if (!local1_state || !local2_state) {
631                         return NULL;
632                 }
633                 ast_str_append(&variable_data, 0, "DestType: Link\r\n");
634                 ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local1_state));
635                 ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local2_state));
636                 break;
637         case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
638                 ast_str_append(&variable_data, 0, "DestType: Threeway\r\n");
639                 ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.threeway.bridge_snapshot->uniqueid);
640                 ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->name);
641                 break;
642         case AST_ATTENDED_TRANSFER_DEST_FAIL:
643                 ast_str_append(&variable_data, 0, "DestType: Fail\r\n");
644                 break;
645         }
646
647         return ast_manager_event_blob_create(EVENT_FLAG_CALL, "AttendedTransfer",
648                         "Result: %s\r\n"
649                         "%s"
650                         "%s"
651                         "%s"
652                         "%s"
653                         "IsExternal: %s\r\n"
654                         "%s\r\n",
655                         result_strs[transfer_msg->result],
656                         ast_str_buffer(transferer1_state),
657                         bridge1_state ? ast_str_buffer(bridge1_state) : "",
658                         ast_str_buffer(transferer2_state),
659                         bridge2_state ? ast_str_buffer(bridge2_state) : "",
660                         transfer_msg->is_external ? "Yes" : "No",
661                         ast_str_buffer(variable_data));
662 }
663
664 static void attended_transfer_dtor(void *obj)
665 {
666         struct ast_attended_transfer_message *msg = obj;
667         int i;
668
669         bridge_channel_snapshot_pair_cleanup(&msg->to_transferee);
670         bridge_channel_snapshot_pair_cleanup(&msg->to_transfer_target);
671
672         if (msg->dest_type != AST_ATTENDED_TRANSFER_DEST_LINK) {
673                 return;
674         }
675
676         for (i = 0; i < ARRAY_LEN(msg->dest.links); ++i) {
677                 ao2_cleanup(msg->dest.links[i]);
678         }
679 }
680
681 static struct ast_attended_transfer_message *attended_transfer_message_create(int is_external, enum ast_transfer_result result,
682                 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target)
683 {
684         RAII_VAR(struct ast_attended_transfer_message *, msg, NULL, ao2_cleanup);
685
686         msg = ao2_alloc(sizeof(*msg), attended_transfer_dtor);
687         if (!msg) {
688                 return NULL;
689         }
690
691         if (bridge_channel_snapshot_pair_init(transferee, &msg->to_transferee) ||
692                         bridge_channel_snapshot_pair_init(target, &msg->to_transfer_target)) {
693                 return NULL;
694         }
695
696         msg->is_external = is_external;
697         msg->result = result;
698
699         ao2_ref(msg, +1);
700         return msg;
701 }
702
703 void ast_bridge_publish_attended_transfer_fail(int is_external, enum ast_transfer_result result,
704                 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target)
705 {
706         RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
707         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
708
709         transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
710         if (!transfer_msg) {
711                 return;
712         }
713
714         transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_FAIL;
715
716         msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
717         if (!msg) {
718                 return;
719         }
720
721         stasis_publish(ast_bridge_topic_all(), msg);
722 }
723
724 void ast_bridge_publish_attended_transfer_bridge_merge(int is_external, enum ast_transfer_result result,
725                 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
726                 struct ast_bridge *final_bridge)
727 {
728         RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
729         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
730
731         transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
732         if (!transfer_msg) {
733                 return;
734         }
735
736         transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE;
737         ast_copy_string(transfer_msg->dest.bridge, final_bridge->uniqueid,
738                         sizeof(transfer_msg->dest.bridge));
739
740         msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
741         if (!msg) {
742                 return;
743         }
744
745         stasis_publish(ast_bridge_topic_all(), msg);
746 }
747
748 void ast_bridge_publish_attended_transfer_threeway(int is_external, enum ast_transfer_result result,
749                 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
750                 struct ast_bridge_channel_pair *final_pair)
751 {
752         RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
753         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
754
755         transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
756         if (!transfer_msg) {
757                 return;
758         }
759
760         transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_THREEWAY;
761         if (final_pair->channel == transferee->channel) {
762                 transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transferee.channel_snapshot;
763         } else {
764                 transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transfer_target.channel_snapshot;
765         }
766
767         if (final_pair->bridge == transferee->bridge) {
768                 transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transferee.bridge_snapshot;
769         } else {
770                 transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transfer_target.bridge_snapshot;
771         }
772
773         msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
774         if (!msg) {
775                 return;
776         }
777
778         stasis_publish(ast_bridge_topic_all(), msg);
779 }
780
781 void ast_bridge_publish_attended_transfer_app(int is_external, enum ast_transfer_result result,
782                 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
783                 const char *dest_app)
784 {
785         RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
786         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
787
788         transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
789         if (!transfer_msg) {
790                 return;
791         }
792
793         transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_APP;
794         ast_copy_string(transfer_msg->dest.app, dest_app, sizeof(transfer_msg->dest.app));
795
796         msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
797         if (!msg) {
798                 return;
799         }
800
801         stasis_publish(ast_bridge_topic_all(), msg);
802 }
803
804 void ast_bridge_publish_attended_transfer_link(int is_external, enum ast_transfer_result result,
805                 struct ast_bridge_channel_pair *transferee, struct ast_bridge_channel_pair *target,
806                 struct ast_channel *locals[2])
807 {
808         RAII_VAR(struct ast_attended_transfer_message *, transfer_msg, NULL, ao2_cleanup);
809         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
810         int i;
811
812         transfer_msg = attended_transfer_message_create(is_external, result, transferee, target);
813         if (!transfer_msg) {
814                 return;
815         }
816
817         transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_LINK;
818         for (i = 0; i < 2; ++i) {
819                 transfer_msg->dest.links[i] = ast_channel_snapshot_create(locals[i]);
820                 if (!transfer_msg->dest.links[i]) {
821                         return;
822                 }
823         }
824
825         msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
826         if (!msg) {
827                 return;
828         }
829
830         stasis_publish(ast_bridge_topic_all(), msg);
831 }
832
833 struct ast_bridge_snapshot *ast_bridge_snapshot_get_latest(const char *uniqueid)
834 {
835         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
836         struct ast_bridge_snapshot *snapshot;
837
838         ast_assert(!ast_strlen_zero(uniqueid));
839
840         message = stasis_cache_get(ast_bridge_cache(),
841                         ast_bridge_snapshot_type(),
842                         uniqueid);
843         if (!message) {
844                 return NULL;
845         }
846
847         snapshot = stasis_message_data(message);
848         if (!snapshot) {
849                 return NULL;
850         }
851         ao2_ref(snapshot, +1);
852         return snapshot;
853 }
854
855 /*! \brief snapshot ID getter for caching topic */
856 static const char *bridge_snapshot_get_id(struct stasis_message *msg)
857 {
858         struct ast_bridge_snapshot *snapshot;
859         if (stasis_message_type(msg) != ast_bridge_snapshot_type()) {
860                 return NULL;
861         }
862         snapshot = stasis_message_data(msg);
863         return snapshot->uniqueid;
864 }
865
866 static void stasis_bridging_cleanup(void)
867 {
868         STASIS_MESSAGE_TYPE_CLEANUP(ast_bridge_snapshot_type);
869         STASIS_MESSAGE_TYPE_CLEANUP(ast_bridge_merge_message_type);
870         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_entered_bridge_type);
871         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_left_bridge_type);
872         STASIS_MESSAGE_TYPE_CLEANUP(ast_blind_transfer_type);
873         STASIS_MESSAGE_TYPE_CLEANUP(ast_attended_transfer_type);
874
875         ao2_cleanup(bridge_cache_all);
876         bridge_cache_all = NULL;
877 }
878
879 int ast_stasis_bridging_init(void)
880 {
881         int res = 0;
882
883         ast_register_cleanup(stasis_bridging_cleanup);
884
885         bridge_cache_all = stasis_cp_all_create("ast_bridge_topic_all",
886                 bridge_snapshot_get_id);
887
888         if (!bridge_cache_all) {
889                 return -1;
890         }
891
892         res |= STASIS_MESSAGE_TYPE_INIT(ast_bridge_snapshot_type);
893         res |= STASIS_MESSAGE_TYPE_INIT(ast_bridge_merge_message_type);
894         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_entered_bridge_type);
895         res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_left_bridge_type);
896         res |= STASIS_MESSAGE_TYPE_INIT(ast_blind_transfer_type);
897         res |= STASIS_MESSAGE_TYPE_INIT(ast_attended_transfer_type);
898
899         return res;
900 }