manager: Add <see-also> tags to relate Bridge related events,actions, and apps
[asterisk/asterisk.git] / main / manager_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 The Asterisk Management Interface - AMI (bridge event handling)
22  *
23  * \author Kinsey Moore <kmoore@digium.com>
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_REGISTER_FILE()
29
30 #include "asterisk/stasis_bridges.h"
31 #include "asterisk/stasis_channels.h"
32 #include "asterisk/manager.h"
33 #include "asterisk/stasis_message_router.h"
34
35 /*! \brief Message router for cached bridge state snapshot updates */
36 static struct stasis_message_router *bridge_state_router;
37
38 /*** DOCUMENTATION
39         <managerEvent language="en_US" name="BridgeCreate">
40                 <managerEventInstance class="EVENT_FLAG_CALL">
41                         <synopsis>Raised when a bridge is created.</synopsis>
42                         <syntax>
43                                 <bridge_snapshot/>
44                         </syntax>
45                         <see-also>
46                                 <ref type="managerEvent">BridgeDestroy</ref>
47                                 <ref type="managerEvent">BridgeEnter</ref>
48                                 <ref type="managerEvent">BridgeLeave</ref>
49                         </see-also>
50                 </managerEventInstance>
51         </managerEvent>
52         <managerEvent language="en_US" name="BridgeDestroy">
53                 <managerEventInstance class="EVENT_FLAG_CALL">
54                         <synopsis>Raised when a bridge is destroyed.</synopsis>
55                         <syntax>
56                                 <bridge_snapshot/>
57                         </syntax>
58                         <see-also>
59                                 <ref type="managerEvent">BridgeCreate</ref>
60                                 <ref type="managerEvent">BridgeEnter</ref>
61                                 <ref type="managerEvent">BridgeLeave</ref>
62                         </see-also>
63                 </managerEventInstance>
64         </managerEvent>
65         <managerEvent language="en_US" name="BridgeEnter">
66                 <managerEventInstance class="EVENT_FLAG_CALL">
67                         <synopsis>Raised when a channel enters a bridge.</synopsis>
68                         <syntax>
69                                 <bridge_snapshot/>
70                                 <channel_snapshot/>
71                                 <parameter name="SwapUniqueid">
72                                         <para>The uniqueid of the channel being swapped out of the bridge</para>
73                                 </parameter>
74                         </syntax>
75                         <see-also>
76                                 <ref type="managerEvent">BridgeCreate</ref>
77                                 <ref type="managerEvent">BridgeDestroy</ref>
78                                 <ref type="managerEvent">BridgeLeave</ref>
79                         </see-also>
80                 </managerEventInstance>
81         </managerEvent>
82         <managerEvent language="en_US" name="BridgeLeave">
83                 <managerEventInstance class="EVENT_FLAG_CALL">
84                         <synopsis>Raised when a channel leaves a bridge.</synopsis>
85                         <syntax>
86                                 <bridge_snapshot/>
87                                 <channel_snapshot/>
88                         </syntax>
89                         <see-also>
90                                 <ref type="managerEvent">BridgeCreate</ref>
91                                 <ref type="managerEvent">BridgeDestroy</ref>
92                                 <ref type="managerEvent">BridgeEnter</ref>
93                         </see-also>
94                 </managerEventInstance>
95         </managerEvent>
96         <manager name="BridgeList" language="en_US">
97                 <synopsis>
98                         Get a list of bridges in the system.
99                 </synopsis>
100                 <syntax>
101                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
102                         <parameter name="BridgeType">
103                                 <para>Optional type for filtering the resulting list of bridges.</para>
104                         </parameter>
105                 </syntax>
106                 <description>
107                         <para>Returns a list of bridges, optionally filtering on a bridge type.</para>
108                 </description>
109                 <see-also>
110                         <ref type="manager">Bridge</ref>
111                         <ref type="manager">BridgeDestroy</ref>
112                         <ref type="manager">BridgeInfo</ref>
113                         <ref type="manager">BridgeKick</ref>
114                 </see-also>
115         </manager>
116         <manager name="BridgeInfo" language="en_US">
117                 <synopsis>
118                         Get information about a bridge.
119                 </synopsis>
120                 <syntax>
121                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
122                         <parameter name="BridgeUniqueid" required="true">
123                                 <para>The unique ID of the bridge about which to retrieve information.</para>
124                         </parameter>
125                 </syntax>
126                 <description>
127                         <para>Returns detailed information about a bridge and the channels in it.</para>
128                 </description>
129                 <see-also>
130                         <ref type="manager">Bridge</ref>
131                         <ref type="manager">BridgeDestroy</ref>
132                         <ref type="manager">BridgeKick</ref>
133                         <ref type="manager">BridgeList</ref>
134                 </see-also>
135                 <responses>
136                         <list-elements>
137                                 <managerEvent language="en_US" name="BridgeInfoChannel">
138                                         <managerEventInstance class="EVENT_FLAG_COMMAND">
139                                                 <synopsis>Information about a channel in a bridge.</synopsis>
140                                                 <syntax>
141                                                         <channel_snapshot/>
142                                                 </syntax>
143                                         </managerEventInstance>
144                                 </managerEvent>
145                         </list-elements>
146                         <managerEvent language="en_US" name="BridgeInfoComplete">
147                                 <managerEventInstance class="EVENT_FLAG_COMMAND">
148                                         <synopsis>Information about a bridge.</synopsis>
149                                         <syntax>
150                                                 <bridge_snapshot/>
151                                         </syntax>
152                                 </managerEventInstance>
153                         </managerEvent>
154                 </responses>
155         </manager>
156         <manager name="BridgeDestroy" language="en_US">
157                 <synopsis>
158                         Destroy a bridge.
159                 </synopsis>
160                 <syntax>
161                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
162                         <parameter name="BridgeUniqueid" required="true">
163                                 <para>The unique ID of the bridge to destroy.</para>
164                         </parameter>
165                 </syntax>
166                 <description>
167                         <para>Deletes the bridge, causing channels to continue or hang up.</para>
168                 </description>
169                 <see-also>
170                         <ref type="manager">Bridge</ref>
171                         <ref type="manager">BridgeInfo</ref>
172                         <ref type="manager">BridgeKick</ref>
173                         <ref type="manager">BridgeList</ref>
174                         <ref type="managerEvent">BridgeDestroy</ref>
175                 </see-also>
176         </manager>
177         <manager name="BridgeKick" language="en_US">
178                 <synopsis>
179                         Kick a channel from a bridge.
180                 </synopsis>
181                 <syntax>
182                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
183                         <parameter name="BridgeUniqueid" required="false">
184                                 <para>The unique ID of the bridge containing the channel to
185                                 destroy.  This parameter can be omitted, or supplied to insure
186                                 that the channel is not removed from the wrong bridge.</para>
187                         </parameter>
188                         <parameter name="Channel" required="true">
189                                 <para>The channel to kick out of a bridge.</para>
190                         </parameter>
191                 </syntax>
192                 <description>
193                         <para>The channel is removed from the bridge.</para>
194                 </description>
195                 <see-also>
196                         <ref type="manager">Bridge</ref>
197                         <ref type="manager">BridgeDestroy</ref>
198                         <ref type="manager">BridgeInfo</ref>
199                         <ref type="manager">BridgeList</ref>
200                         <ref type="managerEvent">BridgeLeave</ref>
201                 </see-also>
202         </manager>
203  ***/
204
205 /*! \brief The \ref stasis subscription returned by the forwarding of the channel topic
206  * to the manager topic
207  */
208 static struct stasis_forward *topic_forwarder;
209
210 struct ast_str *ast_manager_build_bridge_state_string_prefix(
211         const struct ast_bridge_snapshot *snapshot,
212         const char *prefix)
213 {
214         struct ast_str *out = ast_str_create(128);
215         int res;
216
217         if (!out) {
218                 return NULL;
219         }
220
221         res = ast_str_set(&out, 0,
222                 "%sBridgeUniqueid: %s\r\n"
223                 "%sBridgeType: %s\r\n"
224                 "%sBridgeTechnology: %s\r\n"
225                 "%sBridgeCreator: %s\r\n"
226                 "%sBridgeName: %s\r\n"
227                 "%sBridgeNumChannels: %u\r\n",
228                 prefix, snapshot->uniqueid,
229                 prefix, snapshot->subclass,
230                 prefix, snapshot->technology,
231                 prefix, ast_strlen_zero(snapshot->creator) ? "<unknown>": snapshot->creator,
232                 prefix, ast_strlen_zero(snapshot->name) ? "<unknown>": snapshot->name,
233                 prefix, snapshot->num_channels);
234         if (!res) {
235                 ast_free(out);
236                 return NULL;
237         }
238
239         return out;
240 }
241
242 struct ast_str *ast_manager_build_bridge_state_string(
243         const struct ast_bridge_snapshot *snapshot)
244 {
245         return ast_manager_build_bridge_state_string_prefix(snapshot, "");
246 }
247
248 /*! \brief Typedef for callbacks that get called on channel snapshot updates */
249 typedef struct ast_manager_event_blob *(*bridge_snapshot_monitor)(
250         struct ast_bridge_snapshot *old_snapshot,
251         struct ast_bridge_snapshot *new_snapshot);
252
253 /*! \brief Handle bridge creation */
254 static struct ast_manager_event_blob *bridge_create(
255         struct ast_bridge_snapshot *old_snapshot,
256         struct ast_bridge_snapshot *new_snapshot)
257 {
258         if (!new_snapshot || old_snapshot) {
259                 return NULL;
260         }
261
262         return ast_manager_event_blob_create(
263                 EVENT_FLAG_CALL, "BridgeCreate", NO_EXTRA_FIELDS);
264 }
265
266 /*! \brief Handle bridge destruction */
267 static struct ast_manager_event_blob *bridge_destroy(
268         struct ast_bridge_snapshot *old_snapshot,
269         struct ast_bridge_snapshot *new_snapshot)
270 {
271         if (new_snapshot || !old_snapshot) {
272                 return NULL;
273         }
274
275         return ast_manager_event_blob_create(
276                 EVENT_FLAG_CALL, "BridgeDestroy", NO_EXTRA_FIELDS);
277 }
278
279
280 bridge_snapshot_monitor bridge_monitors[] = {
281         bridge_create,
282         bridge_destroy,
283 };
284
285 static void bridge_snapshot_update(void *data, struct stasis_subscription *sub,
286                                     struct stasis_message *message)
287 {
288         RAII_VAR(struct ast_str *, bridge_event_string, NULL, ast_free);
289         struct stasis_cache_update *update;
290         struct ast_bridge_snapshot *old_snapshot;
291         struct ast_bridge_snapshot *new_snapshot;
292         size_t i;
293
294         update = stasis_message_data(message);
295
296         ast_assert(ast_bridge_snapshot_type() == update->type);
297
298         old_snapshot = stasis_message_data(update->old_snapshot);
299         new_snapshot = stasis_message_data(update->new_snapshot);
300
301         for (i = 0; i < ARRAY_LEN(bridge_monitors); ++i) {
302                 RAII_VAR(struct ast_manager_event_blob *, event, NULL, ao2_cleanup);
303
304                 event = bridge_monitors[i](old_snapshot, new_snapshot);
305                 if (!event) {
306                         continue;
307                 }
308
309                 /* If we haven't already, build the channel event string */
310                 if (!bridge_event_string) {
311                         bridge_event_string =
312                                 ast_manager_build_bridge_state_string(
313                                         new_snapshot ? new_snapshot : old_snapshot);
314                         if (!bridge_event_string) {
315                                 return;
316                         }
317                 }
318
319                 manager_event(event->event_flags, event->manager_event, "%s%s",
320                         ast_str_buffer(bridge_event_string),
321                         event->extra_fields);
322         }
323 }
324
325 static void bridge_merge_cb(void *data, struct stasis_subscription *sub,
326                                     struct stasis_message *message)
327 {
328         struct ast_bridge_merge_message *merge_msg = stasis_message_data(message);
329         RAII_VAR(struct ast_str *, to_text, NULL, ast_free);
330         RAII_VAR(struct ast_str *, from_text, NULL, ast_free);
331
332         ast_assert(merge_msg->to != NULL);
333         ast_assert(merge_msg->from != NULL);
334
335         to_text = ast_manager_build_bridge_state_string_prefix(merge_msg->to, "To");
336         from_text = ast_manager_build_bridge_state_string_prefix(merge_msg->from, "From");
337         if (!to_text || !from_text) {
338                 return;
339         }
340
341         /*** DOCUMENTATION
342                 <managerEventInstance>
343                         <synopsis>Raised when two bridges are merged.</synopsis>
344                         <syntax>
345                                 <bridge_snapshot prefix="To"/>
346                                 <bridge_snapshot prefix="From"/>
347                         </syntax>
348                 </managerEventInstance>
349         ***/
350         manager_event(EVENT_FLAG_CALL, "BridgeMerge",
351                 "%s"
352                 "%s",
353                 ast_str_buffer(to_text),
354                 ast_str_buffer(from_text));
355 }
356
357 static void channel_enter_cb(void *data, struct stasis_subscription *sub,
358                                     struct stasis_message *message)
359 {
360         static const char *swap_name = "SwapUniqueid: ";
361         struct ast_bridge_blob *blob = stasis_message_data(message);
362         RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
363         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
364         const char *swap_id;
365
366         bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
367         channel_text = ast_manager_build_channel_state_string(blob->channel);
368         if (!bridge_text || !channel_text) {
369                 return;
370         }
371
372         swap_id = ast_json_string_get(ast_json_object_get(blob->blob, "swap"));
373
374         manager_event(EVENT_FLAG_CALL, "BridgeEnter",
375                 "%s"
376                 "%s"
377                 "%s%s%s",
378                 ast_str_buffer(bridge_text),
379                 ast_str_buffer(channel_text),
380                 swap_id ? swap_name : "",
381                 S_OR(swap_id, ""),
382                 swap_id ? "\r\n" : "");
383 }
384
385 static void channel_leave_cb(void *data, struct stasis_subscription *sub,
386                                     struct stasis_message *message)
387 {
388         struct ast_bridge_blob *blob = stasis_message_data(message);
389         RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
390         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
391
392         bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
393         channel_text = ast_manager_build_channel_state_string(blob->channel);
394         if (!bridge_text || !channel_text) {
395                 return;
396         }
397
398         manager_event(EVENT_FLAG_CALL, "BridgeLeave",
399                 "%s"
400                 "%s",
401                 ast_str_buffer(bridge_text),
402                 ast_str_buffer(channel_text));
403 }
404
405 static int filter_bridge_type_cb(void *obj, void *arg, int flags)
406 {
407         char *bridge_type = arg;
408         struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);
409         /* unlink all the snapshots that do not match the bridge type */
410         return strcmp(bridge_type, snapshot->technology) ? CMP_MATCH : 0;
411 }
412
413 struct bridge_list_data {
414         const char *id_text;
415         int count;
416 };
417
418 static int send_bridge_list_item_cb(void *obj, void *arg, void *data, int flags)
419 {
420         struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);
421         struct mansession *s = arg;
422         struct bridge_list_data *list_data = data;
423         RAII_VAR(struct ast_str *, bridge_info, ast_manager_build_bridge_state_string(snapshot), ast_free);
424
425         if (!bridge_info) {
426                 return 0;
427         }
428
429         astman_append(s,
430                 "Event: BridgeListItem\r\n"
431                 "%s"
432                 "%s"
433                 "\r\n",
434                 list_data->id_text,
435                 ast_str_buffer(bridge_info));
436         ++list_data->count;
437         return 0;
438 }
439
440 static int manager_bridges_list(struct mansession *s, const struct message *m)
441 {
442         const char *id = astman_get_header(m, "ActionID");
443         const char *type_filter = astman_get_header(m, "BridgeType");
444         RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
445         RAII_VAR(struct ao2_container *, bridges, NULL, ao2_cleanup);
446         struct bridge_list_data list_data;
447
448         if (!id_text) {
449                 astman_send_error(s, m, "Internal error");
450                 return -1;
451         }
452
453         if (!ast_strlen_zero(id)) {
454                 ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);
455         }
456
457         bridges = stasis_cache_dump(ast_bridge_cache(), ast_bridge_snapshot_type());
458         if (!bridges) {
459                 astman_send_error(s, m, "Internal error");
460                 return -1;
461         }
462
463         astman_send_listack(s, m, "Bridge listing will follow", "start");
464
465         if (!ast_strlen_zero(type_filter)) {
466                 char *type_filter_dup = ast_strdupa(type_filter);
467
468                 ao2_callback(bridges, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK,
469                         filter_bridge_type_cb, type_filter_dup);
470         }
471
472         list_data.id_text = ast_str_buffer(id_text);
473         list_data.count = 0;
474         ao2_callback_data(bridges, OBJ_NODATA, send_bridge_list_item_cb, s, &list_data);
475
476         astman_send_list_complete_start(s, m, "BridgeListComplete", list_data.count);
477         astman_send_list_complete_end(s);
478
479         return 0;
480 }
481
482 static int send_bridge_info_item_cb(void *obj, void *arg, void *data, int flags)
483 {
484         char *uniqueid = obj;
485         struct mansession *s = arg;
486         struct bridge_list_data *list_data = data;
487         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
488         struct ast_channel_snapshot *snapshot;
489         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
490
491         msg = stasis_cache_get(ast_channel_cache(),
492                 ast_channel_snapshot_type(), uniqueid);
493         if (!msg) {
494                 return 0;
495         }
496
497         snapshot = stasis_message_data(msg);
498         if (snapshot->tech_properties & AST_CHAN_TP_INTERNAL) {
499                 return 0;
500         }
501
502         channel_text = ast_manager_build_channel_state_string(snapshot);
503         if (!channel_text) {
504                 return 0;
505         }
506
507         astman_append(s,
508                 "Event: BridgeInfoChannel\r\n"
509                 "%s"
510                 "%s"
511                 "\r\n",
512                 list_data->id_text,
513                 ast_str_buffer(channel_text));
514         ++list_data->count;
515         return 0;
516 }
517
518 static int manager_bridge_info(struct mansession *s, const struct message *m)
519 {
520         const char *id = astman_get_header(m, "ActionID");
521         const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
522         RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
523         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
524         RAII_VAR(struct ast_str *, bridge_info, NULL, ast_free);
525         struct ast_bridge_snapshot *snapshot;
526         struct bridge_list_data list_data;
527
528         if (!id_text) {
529                 astman_send_error(s, m, "Internal error");
530                 return -1;
531         }
532
533         if (ast_strlen_zero(bridge_uniqueid)) {
534                 astman_send_error(s, m, "BridgeUniqueid must be provided");
535                 return 0;
536         }
537
538         if (!ast_strlen_zero(id)) {
539                 ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);
540         }
541
542         msg = stasis_cache_get(ast_bridge_cache(), ast_bridge_snapshot_type(), bridge_uniqueid);
543         if (!msg) {
544                 astman_send_error(s, m, "Specified BridgeUniqueid not found");
545                 return 0;
546         }
547
548         snapshot = stasis_message_data(msg);
549         bridge_info = ast_manager_build_bridge_state_string(snapshot);
550         if (!bridge_info) {
551                 astman_send_error(s, m, "Internal error");
552                 return -1;
553         }
554
555         astman_send_listack(s, m, "Bridge channel listing will follow", "start");
556
557         list_data.id_text = ast_str_buffer(id_text);
558         list_data.count = 0;
559         ao2_callback_data(snapshot->channels, OBJ_NODATA, send_bridge_info_item_cb, s, &list_data);
560
561         astman_send_list_complete_start(s, m, "BridgeInfoComplete", list_data.count);
562         if (!ast_strlen_zero(ast_str_buffer(bridge_info))) {
563                 astman_append(s, "%s", ast_str_buffer(bridge_info));
564         }
565         astman_send_list_complete_end(s);
566
567         return 0;
568 }
569
570 static int manager_bridge_destroy(struct mansession *s, const struct message *m)
571 {
572         const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
573         struct ast_bridge *bridge;
574
575         if (ast_strlen_zero(bridge_uniqueid)) {
576                 astman_send_error(s, m, "BridgeUniqueid must be provided");
577                 return 0;
578         }
579
580         bridge = ast_bridge_find_by_id(bridge_uniqueid);
581         if (!bridge) {
582                 astman_send_error(s, m, "Specified BridgeUniqueid not found");
583                 return 0;
584         }
585         ast_bridge_destroy(bridge, 0);
586
587         astman_send_ack(s, m, "Bridge has been destroyed");
588
589         return 0;
590 }
591
592 static int manager_bridge_kick(struct mansession *s, const struct message *m)
593 {
594         const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
595         const char *channel_name = astman_get_header(m, "Channel");
596         RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
597         RAII_VAR(struct ast_channel *, channel, NULL, ao2_cleanup);
598
599         if (ast_strlen_zero(channel_name)) {
600                 astman_send_error(s, m, "Channel must be provided");
601                 return 0;
602         }
603
604         channel = ast_channel_get_by_name(channel_name);
605         if (!channel) {
606                 astman_send_error(s, m, "Channel does not exist");
607                 return 0;
608         }
609
610         if (ast_strlen_zero(bridge_uniqueid)) {
611                 /* get the bridge from the channel */
612                 ast_channel_lock(channel);
613                 bridge = ast_channel_get_bridge(channel);
614                 ast_channel_unlock(channel);
615                 if (!bridge) {
616                         astman_send_error(s, m, "Channel is not in a bridge");
617                         return 0;
618                 }
619         } else {
620                 bridge = ast_bridge_find_by_id(bridge_uniqueid);
621                 if (!bridge || ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
622                         astman_send_error(s, m, "Bridge not found");
623                         return 0;
624                 }
625         }
626
627         if (ast_bridge_kick(bridge, channel)) {
628                 astman_send_error(s, m, "Channel kick from bridge failed");
629                 return 0;
630         }
631
632         astman_send_ack(s, m, "Channel has been kicked");
633         return 0;
634 }
635
636 static void manager_bridging_cleanup(void)
637 {
638         stasis_forward_cancel(topic_forwarder);
639         topic_forwarder = NULL;
640
641         ast_manager_unregister("BridgeList");
642         ast_manager_unregister("BridgeInfo");
643         ast_manager_unregister("BridgeDestroy");
644         ast_manager_unregister("BridgeKick");
645 }
646
647 int manager_bridging_init(void)
648 {
649         int ret = 0;
650         struct stasis_topic *manager_topic;
651         struct stasis_topic *bridge_topic;
652
653         if (bridge_state_router) {
654                 /* Already initialized */
655                 return 0;
656         }
657
658         ast_register_cleanup(manager_bridging_cleanup);
659
660         manager_topic = ast_manager_get_topic();
661         if (!manager_topic) {
662                 return -1;
663         }
664
665         bridge_topic = ast_bridge_topic_all_cached();
666         if (!bridge_topic) {
667                 return -1;
668         }
669
670         topic_forwarder = stasis_forward_all(bridge_topic, manager_topic);
671         if (!topic_forwarder) {
672                 return -1;
673         }
674
675         bridge_state_router = ast_manager_get_message_router();
676         if (!bridge_state_router) {
677                 return -1;
678         }
679
680         ret |= stasis_message_router_add_cache_update(bridge_state_router,
681                 ast_bridge_snapshot_type(), bridge_snapshot_update, NULL);
682
683         ret |= stasis_message_router_add(bridge_state_router,
684                 ast_bridge_merge_message_type(), bridge_merge_cb, NULL);
685
686         ret |= stasis_message_router_add(bridge_state_router,
687                 ast_channel_entered_bridge_type(), channel_enter_cb, NULL);
688
689         ret |= stasis_message_router_add(bridge_state_router,
690                 ast_channel_left_bridge_type(), channel_leave_cb, NULL);
691
692         ret |= ast_manager_register_xml_core("BridgeList", 0, manager_bridges_list);
693         ret |= ast_manager_register_xml_core("BridgeInfo", 0, manager_bridge_info);
694         ret |= ast_manager_register_xml_core("BridgeDestroy", 0, manager_bridge_destroy);
695         ret |= ast_manager_register_xml_core("BridgeKick", 0, manager_bridge_kick);
696
697         /* If somehow we failed to add any routes, just shut down the whole
698          * thing and fail it.
699          */
700         if (ret) {
701                 manager_bridging_cleanup();
702                 return -1;
703         }
704
705         return 0;
706 }