Play conf-placeintoconf message to the correct channel
[asterisk/asterisk.git] / apps / app_confbridge.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2007-2008, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  * David Vossel <dvossel@digium.com>
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19
20 /*! \file
21  *
22  * \brief Conference Bridge application
23  *
24  * \author\verbatim Joshua Colp <jcolp@digium.com> \endverbatim
25  * \author\verbatim David Vossel <dvossel@digium.com> \endverbatim
26  *
27  * This is a conference bridge application utilizing the bridging core.
28  * \ingroup applications
29  */
30
31 /*** MODULEINFO
32         <support_level>core</support_level>
33  ***/
34
35 #include "asterisk.h"
36
37 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <signal.h>
44
45 #include "asterisk/cli.h"
46 #include "asterisk/file.h"
47 #include "asterisk/channel.h"
48 #include "asterisk/pbx.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/module.h"
51 #include "asterisk/lock.h"
52 #include "asterisk/bridging.h"
53 #include "asterisk/musiconhold.h"
54 #include "asterisk/say.h"
55 #include "asterisk/audiohook.h"
56 #include "asterisk/astobj2.h"
57 #include "confbridge/include/confbridge.h"
58 #include "asterisk/paths.h"
59 #include "asterisk/manager.h"
60 #include "asterisk/test.h"
61
62 /*** DOCUMENTATION
63     <application name="ConfBridge" language="en_US">
64             <synopsis>
65                     Conference bridge application.
66             </synopsis>
67             <syntax>
68                     <parameter name="confno">
69                             <para>The conference number</para>
70                     </parameter>
71                     <parameter name="bridge_profile">
72                             <para>The bridge profile name from confbridge.conf.  When left blank, a dynamically built bridge profile created by the CONFBRIDGE dialplan function is searched for on the channel and used.  If no dynamic profile is present, the 'default_bridge' profile found in confbridge.conf is used. </para>
73                             <para>It is important to note that while user profiles may be unique for each participant, mixing bridge profiles on a single conference is _NOT_ recommended and will produce undefined results.</para>
74                     </parameter>
75                     <parameter name="user_profile">
76                             <para>The user profile name from confbridge.conf.  When left blank, a dynamically built user profile created by the CONFBRIDGE dialplan function is searched for on the channel and used.  If no dynamic profile is present, the 'default_user' profile found in confbridge.conf is used.</para>
77                     </parameter>
78                     <parameter name="menu">
79                             <para>The name of the DTMF menu in confbridge.conf to be applied to this channel.  No menu is applied by default if this option is left blank.</para>
80                     </parameter>
81             </syntax>
82             <description>
83                     <para>Enters the user into a specified conference bridge. The user can exit the conference by hangup or DTMF menu option.</para>
84             </description>
85                         <see-also>
86                                 <ref type="application">ConfBridge</ref>
87                                 <ref type="function">CONFBRIDGE</ref>
88                                 <ref type="function">CONFBRIDGE_INFO</ref>
89                         </see-also>
90     </application>
91         <function name="CONFBRIDGE" language="en_US">
92                 <synopsis>
93                         Set a custom dynamic bridge and user profile on a channel for the ConfBridge application using the same options defined in confbridge.conf.
94                 </synopsis>
95                 <syntax>
96                         <parameter name="type" required="true">
97                                 <para>Type refers to which type of profile the option belongs too.  Type can be <literal>bridge</literal> or <literal>user</literal>.</para>
98                         </parameter>
99             <parameter name="option" required="true">
100                                 <para>Option refers to <filename>confbridge.conf</filename> option that is being set dynamically on this channel.</para>
101                         </parameter>
102                 </syntax>
103                 <description>
104                         <para>---- Example 1 ----</para>
105                         <para>In this example the custom set user profile on this channel will automatically be used by the ConfBridge app.</para> 
106                         <para>exten => 1,1,Answer() </para>
107                         <para>exten => 1,n,Set(CONFBRIDGE(user,announce_join_leave)=yes)</para>
108                         <para>exten => 1,n,Set(CONFBRIDGE(user,startmuted)=yes)</para>
109                         <para>exten => 1,n,ConfBridge(1) </para>
110                         <para>---- Example 2 ----</para>
111                         <para>This example shows how to use a predefined user or bridge profile in confbridge.conf as a template for a dynamic profile. Here we make a admin/marked user out of the default_user profile that is already defined in confbridge.conf.</para> 
112                         <para>exten => 1,1,Answer() </para>
113                         <para>exten => 1,n,Set(CONFBRIDGE(user,template)=default_user)</para>
114                         <para>exten => 1,n,Set(CONFBRIDGE(user,admin)=yes)</para>
115                         <para>exten => 1,n,Set(CONFBRIDGE(user,marked)=yes)</para>
116                         <para>exten => 1,n,ConfBridge(1)</para>
117                 </description>
118         </function>
119         <function name="CONFBRIDGE_INFO" language="en_US">
120                 <synopsis>
121                         Get information about a ConfBridge conference.
122                 </synopsis>
123                 <syntax>
124                         <parameter name="type" required="true">
125                                 <para>Type can be <literal>parties</literal>, <literal>admins</literal>, <literal>marked</literal>, or <literal>locked</literal>.</para>
126                         </parameter>
127                         <parameter name="conf" required="true">
128                                 <para>Conf refers to the name of the conference being referenced.</para>
129                         </parameter>
130                 </syntax>
131                 <description>
132                         <para>This function returns a non-negative integer for valid conference identifiers (0 or 1 for <literal>locked</literal>) and "" for invalid conference identifiers.</para> 
133                 </description>
134         </function>
135         <manager name="ConfbridgeList" language="en_US">
136                 <synopsis>
137                         List participants in a conference.
138                 </synopsis>
139                 <syntax>
140                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
141                         <parameter name="Conference" required="false">
142                                 <para>Conference number.</para>
143                         </parameter>
144                 </syntax>
145                 <description>
146                         <para>Lists all users in a particular ConfBridge conference.
147                         ConfbridgeList will follow as separate events, followed by a final event called
148                         ConfbridgeListComplete.</para>
149                 </description>
150         </manager>
151         <manager name="ConfbridgeListRooms" language="en_US">
152                 <synopsis>
153                         List active conferences.
154                 </synopsis>
155                 <syntax>
156                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
157                 </syntax>
158                 <description>
159                         <para>Lists data about all active conferences.
160                                 ConfbridgeListRooms will follow as separate events, followed by a final event called
161                                 ConfbridgeListRoomsComplete.</para>
162                 </description>
163         </manager>
164         <manager name="ConfbridgeMute" language="en_US">
165                 <synopsis>
166                         Mute a Confbridge user.
167                 </synopsis>
168                 <syntax>
169                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
170                         <parameter name="Conference" required="true" />
171                         <parameter name="Channel" required="true" />
172                 </syntax>
173                 <description>
174                 </description>
175         </manager>
176         <manager name="ConfbridgeUnmute" language="en_US">
177                 <synopsis>
178                         Unmute a Confbridge user.
179                 </synopsis>
180                 <syntax>
181                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
182                         <parameter name="Conference" required="true" />
183                         <parameter name="Channel" required="true" />
184                 </syntax>
185                 <description>
186                 </description>
187         </manager>
188         <manager name="ConfbridgeKick" language="en_US">
189                 <synopsis>
190                         Kick a Confbridge user.
191                 </synopsis>
192                 <syntax>
193                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
194                         <parameter name="Conference" required="true" />
195                         <parameter name="Channel" required="true" />
196                 </syntax>
197                 <description>
198                 </description>
199         </manager>
200         <manager name="ConfbridgeLock" language="en_US">
201                 <synopsis>
202                         Lock a Confbridge conference.
203                 </synopsis>
204                 <syntax>
205                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
206                         <parameter name="Conference" required="true" />
207                 </syntax>
208                 <description>
209                 </description>
210         </manager>
211         <manager name="ConfbridgeUnlock" language="en_US">
212                 <synopsis>
213                         Unlock a Confbridge conference.
214                 </synopsis>
215                 <syntax>
216                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
217                         <parameter name="Conference" required="true" />
218                 </syntax>
219                 <description>
220                 </description>
221         </manager>
222         <manager name="ConfbridgeStartRecord" language="en_US">
223                 <synopsis>
224                         Start recording a Confbridge conference.
225                 </synopsis>
226                 <syntax>
227                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
228                         <parameter name="Conference" required="true" />
229                         <parameter name="RecordFile" required="false" />
230                 </syntax>
231                 <description>
232                         <para>Start recording a conference. If recording is already present an error will be returned. If RecordFile is not provided, the default record file specified in the conference's bridge profile will be used, if that is not present either a file will automatically be generated in the monitor directory.</para>
233                 </description>
234         </manager>
235         <manager name="ConfbridgeStopRecord" language="en_US">
236                 <synopsis>
237                         Stop recording a Confbridge conference.
238                 </synopsis>
239                 <syntax>
240                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
241                         <parameter name="Conference" required="true" />
242                 </syntax>
243                 <description>
244                 </description>
245         </manager>
246         <manager name="ConfbridgeSetSingleVideoSrc" language="en_US">
247                 <synopsis>
248                         Set a conference user as the single video source distributed to all other participants.
249                 </synopsis>
250                 <syntax>
251                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
252                         <parameter name="Conference" required="true" />
253                         <parameter name="Channel" required="true" />
254                 </syntax>
255                 <description>
256                 </description>
257         </manager>
258
259 ***/
260
261 /*!
262  * \par Playing back a file to a channel in a conference
263  * You might notice in this application that while playing a sound file
264  * to a channel the actual conference bridge lock is not held. This is done so
265  * that other channels are not blocked from interacting with the conference bridge.
266  * Unfortunately because of this it is possible for things to change after the sound file
267  * is done being played. Data must therefore be checked after reacquiring the conference
268  * bridge lock if it is important.
269  */
270
271 static const char app[] = "ConfBridge";
272
273 /* Number of buckets our conference bridges container can have */
274 #define CONFERENCE_BRIDGE_BUCKETS 53
275
276 /*! \brief Container to hold all conference bridges in progress */
277 static struct ao2_container *conference_bridges;
278
279 static int play_sound_file(struct conference_bridge *conference_bridge, const char *filename);
280 static int play_sound_number(struct conference_bridge *conference_bridge, int say_number);
281 static int execute_menu_entry(struct conference_bridge *conference_bridge,
282         struct conference_bridge_user *conference_bridge_user,
283         struct ast_bridge_channel *bridge_channel,
284         struct conf_menu_entry *menu_entry,
285         struct conf_menu *menu);
286
287 /*! \brief Hashing function used for conference bridges container */
288 static int conference_bridge_hash_cb(const void *obj, const int flags)
289 {
290         const struct conference_bridge *conference_bridge = obj;
291         return ast_str_case_hash(conference_bridge->name);
292 }
293
294 /*! \brief Comparison function used for conference bridges container */
295 static int conference_bridge_cmp_cb(void *obj, void *arg, int flags)
296 {
297         const struct conference_bridge *conference_bridge0 = obj, *conference_bridge1 = arg;
298         return (!strcasecmp(conference_bridge0->name, conference_bridge1->name) ? CMP_MATCH | CMP_STOP : 0);
299 }
300
301 const char *conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds *custom_sounds)
302 {
303         switch (sound) {
304         case CONF_SOUND_HAS_JOINED:
305                 return S_OR(custom_sounds->hasjoin, "conf-hasjoin");
306         case CONF_SOUND_HAS_LEFT:
307                 return S_OR(custom_sounds->hasleft, "conf-hasleft");
308         case CONF_SOUND_KICKED:
309                 return S_OR(custom_sounds->kicked, "conf-kicked");
310         case CONF_SOUND_MUTED:
311                 return S_OR(custom_sounds->muted, "conf-muted");
312         case CONF_SOUND_UNMUTED:
313                 return S_OR(custom_sounds->unmuted, "conf-unmuted");
314         case CONF_SOUND_ONLY_ONE:
315                 return S_OR(custom_sounds->onlyone, "conf-onlyone");
316         case CONF_SOUND_THERE_ARE:
317                 return S_OR(custom_sounds->thereare, "conf-thereare");
318         case CONF_SOUND_OTHER_IN_PARTY:
319                 return S_OR(custom_sounds->otherinparty, "conf-otherinparty");
320         case CONF_SOUND_PLACE_IN_CONF:
321                 return S_OR(custom_sounds->placeintoconf, "conf-placeintoconf");
322         case CONF_SOUND_WAIT_FOR_LEADER:
323                 return S_OR(custom_sounds->waitforleader, "conf-waitforleader");
324         case CONF_SOUND_LEADER_HAS_LEFT:
325                 return S_OR(custom_sounds->leaderhasleft, "conf-leaderhasleft");
326         case CONF_SOUND_GET_PIN:
327                 return S_OR(custom_sounds->getpin, "conf-getpin");
328         case CONF_SOUND_INVALID_PIN:
329                 return S_OR(custom_sounds->invalidpin, "conf-invalidpin");
330         case CONF_SOUND_ONLY_PERSON:
331                 return S_OR(custom_sounds->onlyperson, "conf-onlyperson");
332         case CONF_SOUND_LOCKED:
333                 return S_OR(custom_sounds->locked, "conf-locked");
334         case CONF_SOUND_LOCKED_NOW:
335                 return S_OR(custom_sounds->lockednow, "conf-lockednow");
336         case CONF_SOUND_UNLOCKED_NOW:
337                 return S_OR(custom_sounds->unlockednow, "conf-unlockednow");
338         case CONF_SOUND_ERROR_MENU:
339                 return S_OR(custom_sounds->errormenu, "conf-errormenu");
340         case CONF_SOUND_JOIN:
341                 return S_OR(custom_sounds->join, "confbridge-join");
342         case CONF_SOUND_LEAVE:
343                 return S_OR(custom_sounds->leave, "confbridge-leave");
344         case CONF_SOUND_PARTICIPANTS_MUTED:
345                 return S_OR(custom_sounds->participantsmuted, "conf-now-muted");
346         case CONF_SOUND_PARTICIPANTS_UNMUTED:
347                 return S_OR(custom_sounds->participantsunmuted, "conf-now-unmuted");
348         }
349
350         return "";
351 }
352
353 static struct ast_frame *rec_read(struct ast_channel *ast)
354 {
355         return &ast_null_frame;
356 }
357 static int rec_write(struct ast_channel *ast, struct ast_frame *f)
358 {
359         return 0;
360 }
361 static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
362 static struct ast_channel_tech record_tech = {
363         .type = "ConfBridgeRec",
364         .description = "Conference Bridge Recording Channel",
365         .requester = rec_request,
366         .read = rec_read,
367         .write = rec_write,
368 };
369 static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
370 {
371         struct ast_channel *tmp;
372         struct ast_format fmt;
373         const char *conf_name = data;
374         if (!(tmp = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", NULL, 0,
375                 "ConfBridgeRecorder/conf-%s-uid-%d",
376                 conf_name,
377                 (int) ast_random()))) {
378                 return NULL;
379         }
380         ast_format_set(&fmt, AST_FORMAT_SLINEAR, 0);
381         ast_channel_tech_set(tmp, &record_tech);
382         ast_format_cap_add_all(ast_channel_nativeformats(tmp));
383         ast_format_copy(ast_channel_writeformat(tmp), &fmt);
384         ast_format_copy(ast_channel_rawwriteformat(tmp), &fmt);
385         ast_format_copy(ast_channel_readformat(tmp), &fmt);
386         ast_format_copy(ast_channel_rawreadformat(tmp), &fmt);
387         return tmp;
388 }
389
390 static void *record_thread(void *obj)
391 {
392         struct conference_bridge *conference_bridge = obj;
393         struct ast_app *mixmonapp = pbx_findapp("MixMonitor");
394         struct ast_channel *chan;
395         struct ast_str *filename = ast_str_alloca(PATH_MAX);
396
397         if (!mixmonapp) {
398                 ao2_ref(conference_bridge, -1);
399                 return NULL;
400         }
401
402         ao2_lock(conference_bridge);
403         if (!(conference_bridge->record_chan)) {
404                 conference_bridge->record_thread = AST_PTHREADT_NULL;
405                 ao2_unlock(conference_bridge);
406                 ao2_ref(conference_bridge, -1);
407                 return NULL;
408         }
409         chan = ast_channel_ref(conference_bridge->record_chan);
410
411         if (!(ast_strlen_zero(conference_bridge->b_profile.rec_file))) {
412                 ast_str_append(&filename, 0, "%s", conference_bridge->b_profile.rec_file);
413         } else {
414                 time_t now;
415                 time(&now);
416                 ast_str_append(&filename, 0, "confbridge-%s-%u.wav",
417                         conference_bridge->name,
418                         (unsigned int) now);
419         }
420         ao2_unlock(conference_bridge);
421
422         ast_answer(chan);
423         pbx_exec(chan, mixmonapp, ast_str_buffer(filename));
424         ast_bridge_join(conference_bridge->bridge, chan, NULL, NULL, NULL);
425
426         ao2_lock(conference_bridge);
427         conference_bridge->record_thread = AST_PTHREADT_NULL;
428         ao2_unlock(conference_bridge);
429
430         ast_hangup(chan); /* This will eat this threads reference to the channel as well */
431         ao2_ref(conference_bridge, -1);
432         return NULL;
433 }
434
435 /*!
436  * \internal
437  * \brief Returns whether or not conference is being recorded.
438  * \retval 1, conference is recording.
439  * \retval 0, conference is NOT recording.
440  */
441 static int conf_is_recording(struct conference_bridge *conference_bridge)
442 {
443         int res = 0;
444         ao2_lock(conference_bridge);
445         if (conference_bridge->record_chan || conference_bridge->record_thread != AST_PTHREADT_NULL) {
446                 res = 1;
447         }
448         ao2_unlock(conference_bridge);
449         return res;
450 }
451
452 /*!
453  * \internal
454  * \brief Stops the confbridge recording thread.
455  *
456  * \note do not call this function with any locks
457  */
458 static int conf_stop_record(struct conference_bridge *conference_bridge)
459 {
460         ao2_lock(conference_bridge);
461
462         if (conference_bridge->record_thread != AST_PTHREADT_NULL) {
463                 struct ast_channel *chan = ast_channel_ref(conference_bridge->record_chan);
464                 pthread_t thread = conference_bridge->record_thread;
465                 ao2_unlock(conference_bridge);
466
467                 ast_bridge_remove(conference_bridge->bridge, chan);
468                 ast_queue_frame(chan, &ast_null_frame);
469
470                 chan = ast_channel_unref(chan);
471                 pthread_join(thread, NULL);
472                 ast_test_suite_event_notify("CONF_STOP_RECORD", "Message: stopped conference recording channel\r\nConference: %s", conference_bridge->b_profile.name);
473
474                 ao2_lock(conference_bridge);
475         }
476
477         /* this is the reference given to the channel during the channel alloc */
478         if (conference_bridge->record_chan) {
479                 conference_bridge->record_chan = ast_channel_unref(conference_bridge->record_chan);
480         }
481
482         ao2_unlock(conference_bridge);
483         return 0;
484 }
485
486 static int conf_start_record(struct conference_bridge *conference_bridge)
487 {
488         struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
489         struct ast_format tmpfmt;
490         int cause;
491
492         ao2_lock(conference_bridge);
493         if (conference_bridge->record_chan || conference_bridge->record_thread != AST_PTHREADT_NULL) {
494                 ao2_unlock(conference_bridge);
495                 return -1; /* already recording */
496         }
497         if (!cap) {
498                 ao2_unlock(conference_bridge);
499                 return -1;
500         }
501         if (!pbx_findapp("MixMonitor")) {
502                 ast_log(LOG_WARNING, "Can not record ConfBridge, MixMonitor app is not installed\n");
503                 cap = ast_format_cap_destroy(cap);
504                 ao2_unlock(conference_bridge);
505                 return -1;
506         }
507         ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
508         if (!(conference_bridge->record_chan = ast_request("ConfBridgeRec", cap, NULL, conference_bridge->name, &cause))) {
509                 cap = ast_format_cap_destroy(cap);
510                 ao2_unlock(conference_bridge);
511                 return -1;
512         }
513
514         cap = ast_format_cap_destroy(cap);
515         ao2_ref(conference_bridge, +1); /* give the record thread a ref */
516
517         if (ast_pthread_create_background(&conference_bridge->record_thread, NULL, record_thread, conference_bridge)) {
518                 ast_log(LOG_WARNING, "Failed to create recording channel for conference %s\n", conference_bridge->name);
519
520                 ao2_unlock(conference_bridge);
521                 ao2_ref(conference_bridge, -1); /* error so remove ref */
522                 return -1;
523         }
524
525         ast_test_suite_event_notify("CONF_START_RECORD", "Message: started conference recording channel\r\nConference: %s", conference_bridge->b_profile.name);
526         ao2_unlock(conference_bridge);
527         return 0;
528 }
529
530 static void send_conf_start_event(const char *conf_name)
531 {
532         manager_event(EVENT_FLAG_CALL, "ConfbridgeStart", "Conference: %s\r\n", conf_name);
533 }
534
535 static void send_conf_end_event(const char *conf_name)
536 {
537         manager_event(EVENT_FLAG_CALL, "ConfbridgeEnd", "Conference: %s\r\n", conf_name);
538 }
539
540 static void send_join_event(struct ast_channel *chan, const char *conf_name)
541 {
542         ast_manager_event(chan, EVENT_FLAG_CALL, "ConfbridgeJoin",
543                 "Channel: %s\r\n"
544                 "Uniqueid: %s\r\n"
545                 "Conference: %s\r\n"
546                 "CallerIDnum: %s\r\n"
547                 "CallerIDname: %s\r\n",
548                 ast_channel_name(chan),
549                 ast_channel_uniqueid(chan),
550                 conf_name,
551                 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<unknown>"),
552                 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>")
553         );
554 }
555
556 static void send_leave_event(struct ast_channel *chan, const char *conf_name)
557 {
558         ast_manager_event(chan, EVENT_FLAG_CALL, "ConfbridgeLeave",
559                 "Channel: %s\r\n"
560                 "Uniqueid: %s\r\n"
561                 "Conference: %s\r\n"
562                 "CallerIDnum: %s\r\n"
563                 "CallerIDname: %s\r\n",
564                 ast_channel_name(chan),
565                 ast_channel_uniqueid(chan),
566                 conf_name,
567                 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<unknown>"),
568                 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>")
569         );
570 }
571
572 /*!
573  * \brief Announce number of users in the conference bridge to the caller
574  *
575  * \param conference_bridge Conference bridge to peek at
576  * \param (OPTIONAL) conference_bridge_user Caller
577  *
578  * \note if caller is NULL, the announcment will be sent to all participants in the conference.
579  * \return Returns 0 on success, -1 if the user hung up
580  */
581 static int announce_user_count(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
582 {
583         const char *other_in_party = conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, conference_bridge->b_profile.sounds);
584         const char *only_one = conf_get_sound(CONF_SOUND_ONLY_ONE, conference_bridge->b_profile.sounds);
585         const char *there_are = conf_get_sound(CONF_SOUND_THERE_ARE, conference_bridge->b_profile.sounds);
586
587         if (conference_bridge->users == 1) {
588                 /* Awww we are the only person in the conference bridge */
589                 return 0;
590         } else if (conference_bridge->users == 2) {
591                 if (conference_bridge_user) {
592                         /* Eep, there is one other person */
593                         if (ast_stream_and_wait(conference_bridge_user->chan,
594                                 only_one,
595                                 "")) {
596                                 return -1;
597                         }
598                 } else {
599                         play_sound_file(conference_bridge, only_one);
600                 }
601         } else {
602                 /* Alas multiple others in here */
603                 if (conference_bridge_user) {
604                         if (ast_stream_and_wait(conference_bridge_user->chan,
605                                 there_are,
606                                 "")) {
607                                 return -1;
608                         }
609                         if (ast_say_number(conference_bridge_user->chan, conference_bridge->users - 1, "", ast_channel_language(conference_bridge_user->chan), NULL)) {
610                                 return -1;
611                         }
612                         if (ast_stream_and_wait(conference_bridge_user->chan,
613                                 other_in_party,
614                                 "")) {
615                                 return -1;
616                         }
617                 } else if (ast_fileexists(there_are, NULL, NULL) && ast_fileexists(other_in_party, NULL, NULL)) {
618                         play_sound_file(conference_bridge, there_are);
619                         play_sound_number(conference_bridge, conference_bridge->users - 1);
620                         play_sound_file(conference_bridge, other_in_party);
621                 }
622         }
623         return 0;
624 }
625
626 /*!
627  * \brief Play back an audio file to a channel
628  *
629  * \param conference_bridge Conference bridge they are in
630  * \param chan Channel to play audio prompt to
631  * \param file Prompt to play
632  *
633  * \return Returns 0 on success, -1 if the user hung up
634  *
635  * \note This function assumes that conference_bridge is locked
636  */
637 static int play_prompt_to_channel(struct conference_bridge *conference_bridge, struct ast_channel *chan, const char *file)
638 {
639         int res;
640         ao2_unlock(conference_bridge);
641         res = ast_stream_and_wait(chan, file, "");
642         ao2_lock(conference_bridge);
643         return res;
644 }
645
646 static void handle_video_on_join(struct conference_bridge *conference_bridge, struct ast_channel *chan, int marked)
647 {
648         /* Right now, only marked users are automatically set as the single src of video.*/
649         if (!marked) {
650                 return;
651         }
652
653         if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED)) {
654                 int set = 1;
655                 struct conference_bridge_user *tmp_user = NULL;
656                 ao2_lock(conference_bridge);
657                 /* see if anyone is already the video src */
658                 AST_LIST_TRAVERSE(&conference_bridge->users_list, tmp_user, list) {
659                         if (tmp_user->chan == chan) {
660                                 continue;
661                         }
662                         if (ast_bridge_is_video_src(conference_bridge->bridge, tmp_user->chan)) {
663                                 set = 0;
664                                 break;
665                         }
666                 }
667                 ao2_unlock(conference_bridge);
668                 if (set) {
669                         ast_bridge_set_single_src_video_mode(conference_bridge->bridge, chan);
670                 }
671         } else if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
672                 /* we joined and are video capable, we override anyone else that may have already been the video feed */
673                 ast_bridge_set_single_src_video_mode(conference_bridge->bridge, chan);
674         }
675 }
676
677 static void handle_video_on_exit(struct conference_bridge *conference_bridge, struct ast_channel *chan)
678 {
679         struct conference_bridge_user *tmp_user = NULL;
680
681         /* if this isn't a video source, nothing to update */
682         if (!ast_bridge_is_video_src(conference_bridge->bridge, chan)) {
683                 return;
684         }
685
686         ast_bridge_remove_video_src(conference_bridge->bridge, chan);
687
688         /* If in follow talker mode, make sure to restore this mode on the
689          * bridge when a source is removed.  It is possible this channel was
690          * only set temporarily as a video source by an AMI or DTMF action. */
691         if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
692                 ast_bridge_set_talker_src_video_mode(conference_bridge->bridge);
693         }
694
695         /* if the video_mode isn't set to automatically pick the video source, do nothing on exit. */
696         if (!ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED) &&
697                 !ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
698                 return;
699         }
700
701         /* Make the next available marked user the video src.  */
702         ao2_lock(conference_bridge);
703         AST_LIST_TRAVERSE(&conference_bridge->users_list, tmp_user, list) {
704                 if (tmp_user->chan == chan) {
705                         continue;
706                 }
707                 if (ast_test_flag(&tmp_user->u_profile, USER_OPT_MARKEDUSER)) {
708                         ast_bridge_set_single_src_video_mode(conference_bridge->bridge, tmp_user->chan);
709                         break;
710                 }
711         }
712         ao2_unlock(conference_bridge);
713 }
714
715 /*!
716  * \brief Perform post-joining marked specific actions
717  *
718  * \param conference_bridge Conference bridge being joined
719  * \param conference_bridge_user Conference bridge user joining
720  *
721  * \return Returns 0 on success, -1 if the user hung up
722  */
723 static int post_join_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
724 {
725         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER)) {
726                 struct conference_bridge_user *other_conference_bridge_user = NULL;
727
728                 /* If we are not the first user to join, then the users are already
729                  * in the conference so we do not need to update them. */
730                 if (conference_bridge->markedusers >= 2) {
731                         return 0;
732                 }
733
734                 /* Iterate through every participant stopping MOH on them if need be */
735                 AST_LIST_TRAVERSE(&conference_bridge->users_list, other_conference_bridge_user, list) {
736                         if (other_conference_bridge_user == conference_bridge_user) {
737                                 continue;
738                         }
739                         if (other_conference_bridge_user->playing_moh && !ast_bridge_suspend(conference_bridge->bridge, other_conference_bridge_user->chan)) {
740                                 other_conference_bridge_user->playing_moh = 0;
741                                 ast_moh_stop(other_conference_bridge_user->chan);
742                                 ast_bridge_unsuspend(conference_bridge->bridge, other_conference_bridge_user->chan);
743                         }
744                 }
745
746                 /* Next play the audio file stating they are going to be placed into the conference */
747                 if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET)) {
748                         if (play_prompt_to_channel(conference_bridge,
749                                 conference_bridge_user->chan,
750                                 conf_get_sound(CONF_SOUND_PLACE_IN_CONF, conference_bridge_user->b_profile.sounds))) {
751                                 /* user hungup while the sound was playing */
752                                 return -1;
753                         }
754                 }
755
756                 /* Finally iterate through and unmute them all */
757                 AST_LIST_TRAVERSE(&conference_bridge->users_list, other_conference_bridge_user, list) {
758                         if (other_conference_bridge_user == conference_bridge_user) {
759                                 continue;
760                         }
761                         /* only unmute them if they are not supposed to start muted */
762                         if (!ast_test_flag(&other_conference_bridge_user->u_profile, USER_OPT_STARTMUTED)) {
763                                 other_conference_bridge_user->features.mute = 0;
764                         }
765                 }
766         } else {
767                 /* If a marked user already exists in the conference bridge we can just bail out now */
768                 if (conference_bridge->markedusers) {
769                         return 0;
770                 }
771                 /* Be sure we are muted so we can't talk to anybody else waiting */
772                 conference_bridge_user->features.mute = 1;
773                 /* If we have not been quieted play back that they are waiting for the leader */
774                 if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET)) {
775                         if (play_prompt_to_channel(conference_bridge,
776                                 conference_bridge_user->chan,
777                                 conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, conference_bridge_user->b_profile.sounds))) {
778                                 /* user hungup while the sound was playing */
779                                 return -1;
780                         }
781                 }
782                 /* Start music on hold if needed */
783                 /* We need to recheck the markedusers value here. play_prompt_to_channel unlocks the conference bridge, potentially
784                  * allowing a marked user to enter while the prompt was playing
785                  */
786                 if (!conference_bridge->markedusers && ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MUSICONHOLD)) {
787                         ast_moh_start(conference_bridge_user->chan, conference_bridge_user->u_profile.moh_class, NULL);
788                         conference_bridge_user->playing_moh = 1;
789                 }
790         }
791         return 0;
792 }
793
794 /*!
795  * \brief Perform post-joining non-marked specific actions
796  *
797  * \param conference_bridge Conference bridge being joined
798  * \param conference_bridge_user Conference bridge user joining
799  *
800  * \return Returns 0 on success, -1 if the user hung up
801  */
802 static int post_join_unmarked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
803 {
804         /* Play back audio prompt and start MOH if need be if we are the first participant */
805         if (conference_bridge->users == 1) {
806                 /* If audio prompts have not been quieted or this prompt quieted play it on out */
807                 if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET | USER_OPT_NOONLYPERSON)) {
808                         if (play_prompt_to_channel(conference_bridge,
809                                 conference_bridge_user->chan,
810                                 conf_get_sound(CONF_SOUND_ONLY_PERSON, conference_bridge_user->b_profile.sounds))) {
811                                 /* user hungup while the sound was playing */
812                                 return -1;
813                         }
814                 }
815                 /* If we need to start music on hold on the channel do so now */
816                 /* We need to re-check the number of users in the conference bridge here because another conference bridge
817                  * participant could have joined while the above prompt was playing for the first user.
818                  */
819                 if (conference_bridge->users == 1 && ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MUSICONHOLD)) {
820                         ast_moh_start(conference_bridge_user->chan, conference_bridge_user->u_profile.moh_class, NULL);
821                         conference_bridge_user->playing_moh = 1;
822                 }
823                 return 0;
824         }
825
826         /* Announce number of users if need be */
827         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ANNOUNCEUSERCOUNT)) {
828                 ao2_unlock(conference_bridge);
829                 if (announce_user_count(conference_bridge, conference_bridge_user)) {
830                         ao2_lock(conference_bridge);
831                         return -1;
832                 }
833                 ao2_lock(conference_bridge);
834         }
835
836         /* If we are the second participant we may need to stop music on hold on the first */
837         if (conference_bridge->users == 2) {
838                 struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->users_list);
839
840                 /* Temporarily suspend the above participant from the bridge so we have control to stop MOH if needed */
841                 if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) {
842                         first_participant->playing_moh = 0;
843                         ast_moh_stop(first_participant->chan);
844                         ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan);
845                 }
846         }
847
848         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ANNOUNCEUSERCOUNTALL) &&
849                 (conference_bridge->users > conference_bridge_user->u_profile.announce_user_count_all_after)) {
850                 ao2_unlock(conference_bridge);
851                 if (announce_user_count(conference_bridge, NULL)) {
852                         ao2_lock(conference_bridge);
853                         return -1;
854                 }
855                 ao2_lock(conference_bridge);
856         }
857         return 0;
858 }
859
860 /*!
861  * \brief Destroy a conference bridge
862  *
863  * \param obj The conference bridge object
864  *
865  * \return Returns nothing
866  */
867 static void destroy_conference_bridge(void *obj)
868 {
869         struct conference_bridge *conference_bridge = obj;
870
871         ast_debug(1, "Destroying conference bridge '%s'\n", conference_bridge->name);
872
873         ast_mutex_destroy(&conference_bridge->playback_lock);
874
875         if (conference_bridge->playback_chan) {
876                 struct ast_channel *underlying_channel = ast_channel_tech(conference_bridge->playback_chan)->bridged_channel(conference_bridge->playback_chan, NULL);
877                 if (underlying_channel) {
878                         ast_hangup(underlying_channel);
879                 }
880                 ast_hangup(conference_bridge->playback_chan);
881                 conference_bridge->playback_chan = NULL;
882         }
883
884         /* Destroying a conference bridge is simple, all we have to do is destroy the bridging object */
885         if (conference_bridge->bridge) {
886                 ast_bridge_destroy(conference_bridge->bridge);
887                 conference_bridge->bridge = NULL;
888         }
889         conf_bridge_profile_destroy(&conference_bridge->b_profile);
890 }
891
892 static void leave_conference_bridge(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user);
893
894 /*!
895  * \brief Join a conference bridge
896  *
897  * \param name The conference name
898  * \param conference_bridge_user Conference bridge user structure
899  *
900  * \return A pointer to the conference bridge struct, or NULL if the conference room wasn't found.
901  */
902 static struct conference_bridge *join_conference_bridge(const char *name, struct conference_bridge_user *conference_bridge_user)
903 {
904         struct conference_bridge *conference_bridge = NULL;
905         struct conference_bridge tmp;
906         int start_record = 0;
907         int max_members_reached = 0;
908
909         ast_copy_string(tmp.name, name, sizeof(tmp.name));
910
911         /* We explictly lock the conference bridges container ourselves so that other callers can not create duplicate conferences at the same */
912         ao2_lock(conference_bridges);
913
914         ast_debug(1, "Trying to find conference bridge '%s'\n", name);
915
916         /* Attempt to find an existing conference bridge */
917         conference_bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
918
919         if (conference_bridge && conference_bridge->b_profile.max_members) {
920                 max_members_reached = conference_bridge->b_profile.max_members > conference_bridge->users ? 0 : 1;
921         }
922
923         /* When finding a conference bridge that already exists make sure that it is not locked, and if so that we are not an admin */
924         if (conference_bridge && (max_members_reached || conference_bridge->locked) && !ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN)) {
925                 ao2_unlock(conference_bridges);
926                 ao2_ref(conference_bridge, -1);
927                 ast_debug(1, "Conference bridge '%s' is locked and caller is not an admin\n", name);
928                 ast_stream_and_wait(conference_bridge_user->chan,
929                                 conf_get_sound(CONF_SOUND_LOCKED, conference_bridge_user->b_profile.sounds),
930                                 "");
931                 return NULL;
932         }
933
934         /* If no conference bridge was found see if we can create one */
935         if (!conference_bridge) {
936                 /* Try to allocate memory for a new conference bridge, if we fail... this won't end well. */
937                 if (!(conference_bridge = ao2_alloc(sizeof(*conference_bridge), destroy_conference_bridge))) {
938                         ao2_unlock(conference_bridges);
939                         ast_log(LOG_ERROR, "Conference bridge '%s' does not exist.\n", name);
940                         return NULL;
941                 }
942
943                 /* Setup conference bridge parameters */
944                 conference_bridge->record_thread = AST_PTHREADT_NULL;
945                 ast_copy_string(conference_bridge->name, name, sizeof(conference_bridge->name));
946                 conf_bridge_profile_copy(&conference_bridge->b_profile, &conference_bridge_user->b_profile);
947
948                 /* Create an actual bridge that will do the audio mixing */
949                 if (!(conference_bridge->bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_MULTIMIX, 0))) {
950                         ao2_ref(conference_bridge, -1);
951                         conference_bridge = NULL;
952                         ao2_unlock(conference_bridges);
953                         ast_log(LOG_ERROR, "Conference bridge '%s' could not be created.\n", name);
954                         return NULL;
955                 }
956
957                 /* Set the internal sample rate on the bridge from the bridge profile */
958                 ast_bridge_set_internal_sample_rate(conference_bridge->bridge, conference_bridge->b_profile.internal_sample_rate);
959                 /* Set the internal mixing interval on the bridge from the bridge profile */
960                 ast_bridge_set_mixing_interval(conference_bridge->bridge, conference_bridge->b_profile.mix_interval);
961
962                 if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
963                         ast_bridge_set_talker_src_video_mode(conference_bridge->bridge);
964                 }
965
966                 /* Setup lock for playback channel */
967                 ast_mutex_init(&conference_bridge->playback_lock);
968
969                 /* Link it into the conference bridges container */
970                 ao2_link(conference_bridges, conference_bridge);
971
972
973                 send_conf_start_event(conference_bridge->name);
974                 ast_debug(1, "Created conference bridge '%s' and linked to container '%p'\n", name, conference_bridges);
975         }
976
977         ao2_unlock(conference_bridges);
978
979         /* Setup conference bridge user parameters */
980         conference_bridge_user->conference_bridge = conference_bridge;
981
982         ao2_lock(conference_bridge);
983
984         /* All good to go, add them in */
985         AST_LIST_INSERT_TAIL(&conference_bridge->users_list, conference_bridge_user, list);
986
987         /* Increment the users count on the bridge, but record it as it is going to need to be known right after this */
988         conference_bridge->users++;
989
990         /* If the caller is a marked user bump up the count */
991         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER)) {
992                 conference_bridge->markedusers++;
993         }
994
995         /* Set the device state for this conference */
996         if (conference_bridge->users == 1) {
997                 ast_devstate_changed(AST_DEVICE_INUSE, "confbridge:%s", conference_bridge->name);
998         }
999
1000         /* If an announcement is to be played play it */
1001         if (!ast_strlen_zero(conference_bridge_user->u_profile.announcement)) {
1002                 if (play_prompt_to_channel(conference_bridge,
1003                                            conference_bridge_user->chan,
1004                                            conference_bridge_user->u_profile.announcement)) {
1005                         ao2_unlock(conference_bridge);
1006                         leave_conference_bridge(conference_bridge, conference_bridge_user);
1007                         return NULL;
1008                 }
1009         }
1010
1011         /* If the caller is a marked user or is waiting for a marked user to enter pass 'em off, otherwise pass them off to do regular joining stuff */
1012         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER | USER_OPT_WAITMARKED)) {
1013                 if (post_join_marked(conference_bridge, conference_bridge_user)) {
1014                         ao2_unlock(conference_bridge);
1015                         leave_conference_bridge(conference_bridge, conference_bridge_user);
1016                         return NULL;
1017                 }
1018         } else {
1019                 if (post_join_unmarked(conference_bridge, conference_bridge_user)) {
1020                         ao2_unlock(conference_bridge);
1021                         leave_conference_bridge(conference_bridge, conference_bridge_user);
1022                         return NULL;
1023                 }
1024         }
1025
1026         /* check to see if recording needs to be started or not */
1027         if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_RECORD_CONFERENCE) && !conf_is_recording(conference_bridge)) {
1028                 start_record = 1;
1029         }
1030
1031         ao2_unlock(conference_bridge);
1032
1033         if (start_record) {
1034                 conf_start_record(conference_bridge);
1035         }
1036
1037         return conference_bridge;
1038 }
1039
1040 /*!
1041  * \brief Leave a conference bridge
1042  *
1043  * \param conference_bridge The conference bridge to leave
1044  * \param conference_bridge_user The conference bridge user structure
1045  *
1046  */
1047 static void leave_conference_bridge(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
1048 {
1049         ao2_lock(conference_bridge);
1050
1051         /* If this caller is a marked user bump down the count */
1052         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER)) {
1053                 conference_bridge->markedusers--;
1054         }
1055
1056         /* Decrement the users count while keeping the previous participant count */
1057         conference_bridge->users--;
1058
1059         /* Drop conference bridge user from the list, they be going bye bye */
1060         AST_LIST_REMOVE(&conference_bridge->users_list, conference_bridge_user, list);
1061
1062         /* If there are still users in the conference bridge we may need to do things (such as start MOH on them) */
1063         if (conference_bridge->users) {
1064                 if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER) && !conference_bridge->markedusers) {
1065                         struct conference_bridge_user *other_participant = NULL;
1066
1067                         /* Start out with muting everyone */
1068                         AST_LIST_TRAVERSE(&conference_bridge->users_list, other_participant, list) {
1069                                 other_participant->features.mute = 1;
1070                         }
1071
1072                         /* Play back the audio prompt saying the leader has left the conference */
1073                         if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET)) {
1074                                 ao2_unlock(conference_bridge);
1075                                 ast_autoservice_start(conference_bridge_user->chan);
1076                                 play_sound_file(conference_bridge,
1077                                         conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, conference_bridge_user->b_profile.sounds));
1078                                 ast_autoservice_stop(conference_bridge_user->chan);
1079                                 ao2_lock(conference_bridge);
1080                         }
1081
1082                         /* Now on to starting MOH or kick if needed */
1083                         AST_LIST_TRAVERSE(&conference_bridge->users_list, other_participant, list) {
1084                                 if (ast_test_flag(&other_participant->u_profile, USER_OPT_ENDMARKED)) {
1085                                         other_participant->kicked = 1;
1086                                         ast_bridge_remove(conference_bridge->bridge, other_participant->chan);
1087                                 } else if (ast_test_flag(&other_participant->u_profile, USER_OPT_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, other_participant->chan)) {
1088                                         ast_moh_start(other_participant->chan, other_participant->u_profile.moh_class, NULL);
1089                                         other_participant->playing_moh = 1;
1090                                         ast_bridge_unsuspend(conference_bridge->bridge, other_participant->chan);
1091                                 }
1092                         }
1093                 } else if (conference_bridge->users == 1) {
1094                         /* Of course if there is one other person in here we may need to start up MOH on them */
1095                         struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->users_list);
1096
1097                         if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) {
1098                                 ast_moh_start(first_participant->chan, first_participant->u_profile.moh_class, NULL);
1099                                 first_participant->playing_moh = 1;
1100                                 ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan);
1101                         }
1102                 }
1103         } else {
1104                 /* Set device state to "not in use" */
1105                 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "confbridge:%s", conference_bridge->name);
1106
1107                 ao2_unlink(conference_bridges, conference_bridge);
1108                 send_conf_end_event(conference_bridge->name);
1109         }
1110
1111         /* Done mucking with the conference bridge, huzzah */
1112         ao2_unlock(conference_bridge);
1113
1114         if (!conference_bridge->users) {
1115                 conf_stop_record(conference_bridge);
1116         }
1117
1118         ao2_ref(conference_bridge, -1);
1119 }
1120
1121 /*!
1122  * \internal
1123  * \brief allocates playback chan on a channel
1124  * \pre expects conference to be locked before calling this function
1125  */
1126 static int alloc_playback_chan(struct conference_bridge *conference_bridge)
1127 {
1128         int cause;
1129         struct ast_format_cap *cap;
1130         struct ast_format tmpfmt;
1131
1132         if (conference_bridge->playback_chan) {
1133                 return 0;
1134         }
1135         if (!(cap = ast_format_cap_alloc_nolock())) {
1136                 return -1;
1137         }
1138         ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
1139         if (!(conference_bridge->playback_chan = ast_request("Bridge", cap, NULL, "", &cause))) {
1140                 cap = ast_format_cap_destroy(cap);
1141                 return -1;
1142         }
1143         cap = ast_format_cap_destroy(cap);
1144
1145         ast_channel_internal_bridge_set(conference_bridge->playback_chan, conference_bridge->bridge);
1146
1147         if (ast_call(conference_bridge->playback_chan, "", 0)) {
1148                 ast_hangup(conference_bridge->playback_chan);
1149                 conference_bridge->playback_chan = NULL;
1150                 return -1;
1151         }
1152
1153         ast_debug(1, "Created a playback channel to conference bridge '%s'\n", conference_bridge->name);
1154         return 0;
1155 }
1156
1157 static int play_sound_helper(struct conference_bridge *conference_bridge, const char *filename, int say_number)
1158 {
1159         struct ast_channel *underlying_channel;
1160
1161         /* Do not waste resources trying to play files that do not exist */
1162         if (!ast_fileexists(filename, NULL, NULL)) {
1163                 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
1164                 return 0;
1165         }
1166
1167         ast_mutex_lock(&conference_bridge->playback_lock);
1168         if (!(conference_bridge->playback_chan)) {
1169                 if (alloc_playback_chan(conference_bridge)) {
1170                         ast_mutex_unlock(&conference_bridge->playback_lock);
1171                         return -1;
1172                 }
1173                 underlying_channel = ast_channel_tech(conference_bridge->playback_chan)->bridged_channel(conference_bridge->playback_chan, NULL);
1174         } else {
1175                 /* Channel was already available so we just need to add it back into the bridge */
1176                 underlying_channel = ast_channel_tech(conference_bridge->playback_chan)->bridged_channel(conference_bridge->playback_chan, NULL);
1177                 ast_bridge_impart(conference_bridge->bridge, underlying_channel, NULL, NULL, 0);
1178         }
1179
1180         /* The channel is all under our control, in goes the prompt */
1181         if (!ast_strlen_zero(filename)) {
1182                 ast_stream_and_wait(conference_bridge->playback_chan, filename, "");
1183         } else {
1184                 ast_say_number(conference_bridge->playback_chan, say_number, "", ast_channel_language(conference_bridge->playback_chan), NULL);
1185         }
1186
1187         ast_debug(1, "Departing underlying channel '%s' from bridge '%p'\n", ast_channel_name(underlying_channel), conference_bridge->bridge);
1188         ast_bridge_depart(conference_bridge->bridge, underlying_channel);
1189
1190         ast_mutex_unlock(&conference_bridge->playback_lock);
1191
1192         return 0;
1193 }
1194
1195 /*!
1196  * \brief Play sound file into conference bridge
1197  *
1198  * \param conference_bridge The conference bridge to play sound file into
1199  * \param filename Sound file to play
1200  *
1201  * \retval 0 success
1202  * \retval -1 failure
1203  */
1204 static int play_sound_file(struct conference_bridge *conference_bridge, const char *filename)
1205 {
1206         return play_sound_helper(conference_bridge, filename, 0);
1207 }
1208
1209 /*!
1210  * \brief Play number into the conference bridge
1211  *
1212  * \param conference_bridge The conference bridge to say the number into
1213  * \param number to say
1214  *
1215  * \retval 0 success
1216  * \retval -1 failure
1217  */
1218 static int play_sound_number(struct conference_bridge *conference_bridge, int say_number)
1219 {
1220         return play_sound_helper(conference_bridge, NULL, say_number);
1221 }
1222
1223 static void conf_handle_talker_destructor(void *pvt_data)
1224 {
1225         ast_free(pvt_data);
1226 }
1227
1228 static void conf_handle_talker_cb(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *pvt_data)
1229 {
1230         char *conf_name = pvt_data;
1231         int talking;
1232
1233         switch (bridge_channel->state) {
1234         case AST_BRIDGE_CHANNEL_STATE_START_TALKING:
1235                 talking = 1;
1236                 break;
1237         case AST_BRIDGE_CHANNEL_STATE_STOP_TALKING:
1238                 talking = 0;
1239                 break;
1240         default:
1241                 return; /* uhh this shouldn't happen, but bail if it does. */
1242         }
1243
1244         /* notify AMI someone is has either started or stopped talking */
1245         ast_manager_event(bridge_channel->chan, EVENT_FLAG_CALL, "ConfbridgeTalking",
1246               "Channel: %s\r\n"
1247               "Uniqueid: %s\r\n"
1248               "Conference: %s\r\n"
1249               "TalkingStatus: %s\r\n",
1250               ast_channel_name(bridge_channel->chan), ast_channel_uniqueid(bridge_channel->chan), conf_name, talking ? "on" : "off");
1251 }
1252
1253 static int conf_get_pin(struct ast_channel *chan, struct conference_bridge_user *conference_bridge_user)
1254 {
1255         char pin_guess[MAX_PIN+1] = { 0, };
1256         const char *pin = conference_bridge_user->u_profile.pin;
1257         char *tmp = pin_guess;
1258         int i, res;
1259         unsigned int len = MAX_PIN ;
1260
1261         /* give them three tries to get the pin right */
1262         for (i = 0; i < 3; i++) {
1263                 if (ast_app_getdata(chan,
1264                         conf_get_sound(CONF_SOUND_GET_PIN, conference_bridge_user->b_profile.sounds),
1265                         tmp, len, 0) >= 0) {
1266                         if (!strcasecmp(pin, pin_guess)) {
1267                                 return 0;
1268                         }
1269                 }
1270                 ast_streamfile(chan,
1271                         conf_get_sound(CONF_SOUND_INVALID_PIN, conference_bridge_user->b_profile.sounds),
1272                         ast_channel_language(chan));
1273                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1274                 if (res > 0) {
1275                         /* Account for digit already read during ivalid pin playback
1276                          * resetting pin buf. */
1277                         pin_guess[0] = res;
1278                         pin_guess[1] = '\0';
1279                         tmp = pin_guess + 1;
1280                         len = MAX_PIN - 1;
1281                 } else {
1282                         /* reset pin buf as empty buffer. */
1283                         tmp = pin_guess;
1284                         len = MAX_PIN;
1285                 }
1286         }
1287         return -1;
1288 }
1289
1290 static int conf_rec_name(struct conference_bridge_user *user, const char *conf_name)
1291 {
1292         char destdir[PATH_MAX];
1293         int res;
1294         int duration = 20;
1295
1296         snprintf(destdir, sizeof(destdir), "%s/confbridge", ast_config_AST_SPOOL_DIR);
1297
1298         if (ast_mkdir(destdir, 0777) != 0) {
1299                 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
1300                 return -1;
1301         }
1302         snprintf(user->name_rec_location, sizeof(user->name_rec_location),
1303                  "%s/confbridge-name-%s-%s", destdir,
1304                  conf_name, ast_channel_uniqueid(user->chan));
1305
1306         res = ast_play_and_record(user->chan,
1307                 "vm-rec-name",
1308                 user->name_rec_location,
1309                 10,
1310                 "sln",
1311                 &duration,
1312                 NULL,
1313                 ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE),
1314                 0,
1315                 NULL);
1316
1317         if (res == -1) {
1318                 user->name_rec_location[0] = '\0';
1319                 return -1;
1320         }
1321         return 0;
1322 }
1323
1324 /*! \brief The ConfBridge application */
1325 static int confbridge_exec(struct ast_channel *chan, const char *data)
1326 {
1327         int res = 0, volume_adjustments[2];
1328         int quiet = 0;
1329         char *parse;
1330         const char *b_profile_name = DEFAULT_BRIDGE_PROFILE;
1331         const char *u_profile_name = DEFAULT_USER_PROFILE;
1332         struct conference_bridge *conference_bridge = NULL;
1333         struct conference_bridge_user conference_bridge_user = {
1334                 .chan = chan,
1335                 .tech_args.talking_threshold = DEFAULT_TALKING_THRESHOLD,
1336                 .tech_args.silence_threshold = DEFAULT_SILENCE_THRESHOLD,
1337                 .tech_args.drop_silence = 0,
1338         };
1339         AST_DECLARE_APP_ARGS(args,
1340                 AST_APP_ARG(conf_name);
1341                 AST_APP_ARG(b_profile_name);
1342                 AST_APP_ARG(u_profile_name);
1343                 AST_APP_ARG(menu_name);
1344         );
1345         ast_bridge_features_init(&conference_bridge_user.features);
1346
1347         if (ast_channel_state(chan) != AST_STATE_UP) {
1348                 ast_answer(chan);
1349         }
1350
1351         if (ast_strlen_zero(data)) {
1352                 ast_log(LOG_WARNING, "%s requires an argument (conference name[,options])\n", app);
1353                 res = -1; /* invalid PIN */
1354                 goto confbridge_cleanup;
1355         }
1356
1357         /* We need to make a copy of the input string if we are going to modify it! */
1358         parse = ast_strdupa(data);
1359
1360         AST_STANDARD_APP_ARGS(args, parse);
1361
1362         /* bridge profile name */
1363         if (args.argc > 1 && !ast_strlen_zero(args.b_profile_name)) {
1364                 b_profile_name = args.b_profile_name;
1365         }
1366         if (!conf_find_bridge_profile(chan, b_profile_name, &conference_bridge_user.b_profile)) {
1367                 ast_log(LOG_WARNING, "Conference bridge profile %s does not exist\n", b_profile_name);
1368                 res = -1;
1369                 goto confbridge_cleanup;
1370         }
1371
1372         /* user profile name */
1373         if (args.argc > 2 && !ast_strlen_zero(args.u_profile_name)) {
1374                 u_profile_name = args.u_profile_name;
1375         }
1376
1377         if (!conf_find_user_profile(chan, u_profile_name, &conference_bridge_user.u_profile)) {
1378                 ast_log(LOG_WARNING, "Conference user profile %s does not exist\n", u_profile_name);
1379                 res = -1;
1380                 goto confbridge_cleanup;
1381         }
1382         quiet = ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_QUIET);
1383
1384         /* ask for a PIN immediately after finding user profile.  This has to be
1385          * prompted for requardless of quiet setting. */
1386         if (!ast_strlen_zero(conference_bridge_user.u_profile.pin)) {
1387                 if (conf_get_pin(chan, &conference_bridge_user)) {
1388                         res = -1; /* invalid PIN */
1389                         goto confbridge_cleanup;
1390                 }
1391         }
1392
1393         /* See if we need them to record a intro name */
1394         if (!quiet && ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE)) {
1395                 conf_rec_name(&conference_bridge_user, args.conf_name);
1396         }
1397
1398         /* menu name */
1399         if (args.argc > 3 && !ast_strlen_zero(args.menu_name)) {
1400                 ast_copy_string(conference_bridge_user.menu_name, args.menu_name, sizeof(conference_bridge_user.menu_name));
1401                 if (conf_set_menu_to_user(conference_bridge_user.menu_name, &conference_bridge_user)) {
1402                         ast_log(LOG_WARNING, "Conference menu %s does not exist and can not be applied to confbridge user.\n",
1403                                 args.menu_name);
1404                         res = -1; /* invalid PIN */
1405                         goto confbridge_cleanup;
1406                 }
1407         }
1408
1409         /* Set if DTMF should pass through for this user or not */
1410         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DTMF_PASS)) {
1411                 conference_bridge_user.features.dtmf_passthrough = 1;
1412         }
1413
1414         /* Set dsp threshold values if present */
1415         if (conference_bridge_user.u_profile.talking_threshold) {
1416                 conference_bridge_user.tech_args.talking_threshold = conference_bridge_user.u_profile.talking_threshold;
1417         }
1418         if (conference_bridge_user.u_profile.silence_threshold) {
1419                 conference_bridge_user.tech_args.silence_threshold = conference_bridge_user.u_profile.silence_threshold;
1420         }
1421
1422         /* Set a talker indicate call back if talking detection is requested */
1423         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_TALKER_DETECT)) {
1424                 char *conf_name = ast_strdup(args.conf_name); /* this is freed during feature cleanup */
1425                 if (!(conf_name)) {
1426                         res = -1; /* invalid PIN */
1427                         goto confbridge_cleanup;
1428                 }
1429                 ast_bridge_features_set_talk_detector(&conference_bridge_user.features,
1430                         conf_handle_talker_cb,
1431                         conf_handle_talker_destructor,
1432                         conf_name);
1433         }
1434
1435         /* Look for a conference bridge matching the provided name */
1436         if (!(conference_bridge = join_conference_bridge(args.conf_name, &conference_bridge_user))) {
1437                 res = -1; /* invalid PIN */
1438                 goto confbridge_cleanup;
1439         }
1440
1441         /* Keep a copy of volume adjustments so we can restore them later if need be */
1442         volume_adjustments[0] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_READ);
1443         volume_adjustments[1] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_WRITE);
1444
1445         /* If the caller should be joined already muted, make it so */
1446         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_STARTMUTED)) {
1447                 conference_bridge_user.features.mute = 1;
1448         }
1449
1450         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DROP_SILENCE)) {
1451                 conference_bridge_user.tech_args.drop_silence = 1;
1452         }
1453
1454         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_JITTERBUFFER)) {
1455                 char *func_jb;
1456                 if ((func_jb = ast_module_helper("", "func_jitterbuffer", 0, 0, 0, 0))) {
1457                         ast_free(func_jb);
1458                         ast_func_write(chan, "JITTERBUFFER(adaptive)", "default");
1459                 }
1460         }
1461
1462         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DENOISE)) {
1463                 char *mod_speex;
1464                 /* Reduce background noise from each participant */
1465                 if ((mod_speex = ast_module_helper("", "codec_speex", 0, 0, 0, 0))) {
1466                         ast_free(mod_speex);
1467                         ast_func_write(chan, "DENOISE(rx)", "on");
1468                 }
1469         }
1470
1471         /* if this user has a intro, play it before entering */
1472         if (!ast_strlen_zero(conference_bridge_user.name_rec_location)) {
1473                 ast_autoservice_start(chan);
1474                 play_sound_file(conference_bridge, conference_bridge_user.name_rec_location);
1475                 play_sound_file(conference_bridge,
1476                         conf_get_sound(CONF_SOUND_HAS_JOINED, conference_bridge_user.b_profile.sounds));
1477                 ast_autoservice_stop(chan);
1478         }
1479
1480         /* Play the Join sound to both the conference and the user entering. */
1481         if (!quiet) {
1482                 const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, conference_bridge_user.b_profile.sounds);
1483                 if (conference_bridge_user.playing_moh) {
1484                         ast_moh_stop(chan);
1485                 }
1486                 ast_stream_and_wait(chan, join_sound, "");
1487                 ast_autoservice_start(chan);
1488                 play_sound_file(conference_bridge, join_sound);
1489                 ast_autoservice_stop(chan);
1490                 if (conference_bridge_user.playing_moh) {
1491                         ast_moh_start(chan, conference_bridge_user.u_profile.moh_class, NULL);
1492                 }
1493         }
1494
1495         /* See if we need to automatically set this user as a video source or not */
1496         handle_video_on_join(conference_bridge, conference_bridge_user.chan, ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_MARKEDUSER));
1497
1498         /* Join our conference bridge for real */
1499         send_join_event(conference_bridge_user.chan, conference_bridge->name);
1500         ast_bridge_join(conference_bridge->bridge,
1501                 chan,
1502                 NULL,
1503                 &conference_bridge_user.features,
1504                 &conference_bridge_user.tech_args);
1505         send_leave_event(conference_bridge_user.chan, conference_bridge->name);
1506
1507         /* if we're shutting down, don't attempt to do further processing */
1508         if (ast_shutting_down()) {
1509                 leave_conference_bridge(conference_bridge, &conference_bridge_user);
1510                 conference_bridge = NULL;
1511                 goto confbridge_cleanup;
1512         }
1513
1514         /* If this user was a video source, we need to clean up and possibly pick a new source. */
1515         handle_video_on_exit(conference_bridge, conference_bridge_user.chan);
1516
1517         /* if this user has a intro, play it when leaving */
1518         if (!quiet && !ast_strlen_zero(conference_bridge_user.name_rec_location)) {
1519                 ast_autoservice_start(chan);
1520                 play_sound_file(conference_bridge, conference_bridge_user.name_rec_location);
1521                 play_sound_file(conference_bridge,
1522                         conf_get_sound(CONF_SOUND_HAS_LEFT, conference_bridge_user.b_profile.sounds));
1523                 ast_autoservice_stop(chan);
1524         }
1525
1526         /* play the leave sound */
1527         if (!quiet) {
1528                 const char *leave_sound = conf_get_sound(CONF_SOUND_LEAVE, conference_bridge_user.b_profile.sounds);
1529                 ast_autoservice_start(chan);
1530                 play_sound_file(conference_bridge, leave_sound);
1531                 ast_autoservice_stop(chan);
1532         }
1533
1534         /* Easy as pie, depart this channel from the conference bridge */
1535         leave_conference_bridge(conference_bridge, &conference_bridge_user);
1536         conference_bridge = NULL;
1537
1538         /* If the user was kicked from the conference play back the audio prompt for it */
1539         if (!quiet && conference_bridge_user.kicked) {
1540                 res = ast_stream_and_wait(chan,
1541                         conf_get_sound(CONF_SOUND_KICKED, conference_bridge_user.b_profile.sounds),
1542                         "");
1543         }
1544
1545         /* Restore volume adjustments to previous values in case they were changed */
1546         if (volume_adjustments[0]) {
1547                 ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_READ, volume_adjustments[0]);
1548         }
1549         if (volume_adjustments[1]) {
1550                 ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_WRITE, volume_adjustments[1]);
1551         }
1552
1553         if (!ast_strlen_zero(conference_bridge_user.name_rec_location)) {
1554                 ast_filedelete(conference_bridge_user.name_rec_location, NULL);
1555         }
1556
1557 confbridge_cleanup:
1558         ast_bridge_features_cleanup(&conference_bridge_user.features);
1559         conf_bridge_profile_destroy(&conference_bridge_user.b_profile);
1560         return res;
1561 }
1562
1563 static int action_toggle_mute(struct conference_bridge *conference_bridge,
1564         struct conference_bridge_user *conference_bridge_user,
1565         struct ast_channel *chan)
1566 {
1567         /* Mute or unmute yourself, note we only allow manipulation if they aren't waiting for a marked user or if marked users exist */
1568         if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_WAITMARKED) || conference_bridge->markedusers) {
1569                 conference_bridge_user->features.mute = (!conference_bridge_user->features.mute ? 1 : 0);
1570                 ast_test_suite_event_notify("CONF_MUTE", "Message: participant %s %s\r\nConference: %s\r\nChannel: %s", ast_channel_name(chan), conference_bridge_user->features.mute ? "muted" : "unmuted", conference_bridge_user->b_profile.name, ast_channel_name(chan));
1571         }
1572         return ast_stream_and_wait(chan, (conference_bridge_user->features.mute ?
1573                 conf_get_sound(CONF_SOUND_MUTED, conference_bridge_user->b_profile.sounds) :
1574                 conf_get_sound(CONF_SOUND_UNMUTED, conference_bridge_user->b_profile.sounds)),
1575                 "");
1576 }
1577
1578 static int action_toggle_mute_participants(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
1579 {
1580         struct conference_bridge_user *participant = NULL;
1581         const char *sound_to_play;
1582
1583         ao2_lock(conference_bridge);
1584
1585         /* If already muted, then unmute */
1586         conference_bridge->muted = conference_bridge->muted ? 0 : 1;
1587         sound_to_play = conf_get_sound((conference_bridge->muted ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED),
1588                 conference_bridge_user->b_profile.sounds);
1589
1590         AST_LIST_TRAVERSE(&conference_bridge->users_list, participant, list) {
1591                 if (!ast_test_flag(&participant->u_profile, USER_OPT_ADMIN)) {
1592                         participant->features.mute = conference_bridge->muted;
1593                 }
1594         }
1595
1596         ao2_unlock(conference_bridge);
1597
1598         /* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */
1599         ast_stream_and_wait(conference_bridge_user->chan, sound_to_play, "");
1600
1601         /* Announce to the group that all participants are muted */
1602         ast_autoservice_start(conference_bridge_user->chan);
1603         play_sound_helper(conference_bridge, sound_to_play, 0);
1604         ast_autoservice_stop(conference_bridge_user->chan);
1605
1606         return 0;
1607 }
1608
1609 static int action_playback(struct ast_bridge_channel *bridge_channel, const char *playback_file)
1610 {
1611         char *file_copy = ast_strdupa(playback_file);
1612         char *file = NULL;
1613
1614         while ((file = strsep(&file_copy, "&"))) {
1615                 if (ast_stream_and_wait(bridge_channel->chan, file, "")) {
1616                         ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
1617                         return -1;
1618                 }
1619         }
1620         return 0;
1621 }
1622
1623 static int action_playback_and_continue(struct conference_bridge *conference_bridge,
1624         struct conference_bridge_user *conference_bridge_user,
1625         struct ast_bridge_channel *bridge_channel,
1626         struct conf_menu *menu,
1627         const char *playback_file,
1628         const char *cur_dtmf,
1629         int *stop_prompts)
1630 {
1631         int i;
1632         int digit = 0;
1633         char dtmf[MAXIMUM_DTMF_FEATURE_STRING];
1634         struct conf_menu_entry new_menu_entry = { { 0, }, };
1635         char *file_copy = ast_strdupa(playback_file);
1636         char *file = NULL;
1637
1638         while ((file = strsep(&file_copy, "&"))) {
1639                 if (ast_streamfile(bridge_channel->chan, file, ast_channel_language(bridge_channel->chan))) {
1640                         ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
1641                         return -1;
1642                 }
1643
1644                 /* now wait for more digits. */
1645                 if (!(digit = ast_waitstream(bridge_channel->chan, AST_DIGIT_ANY))) {
1646                         /* streaming finished and no DTMF was entered */
1647                         continue;
1648                 } else if (digit == -1) {
1649                         /* error */
1650                         return -1;
1651                 } else {
1652                         break; /* dtmf was entered */
1653                 }
1654         }
1655         if (!digit) {
1656                 /* streaming finished on all files and no DTMF was entered */
1657                 return -1;
1658         }
1659         ast_stopstream(bridge_channel->chan);
1660
1661         /* If we get here, then DTMF has been entered, This means no
1662          * additional prompts should be played for this menu entry */
1663         *stop_prompts = 1;
1664
1665         /* If a digit was pressed during the payback, update
1666          * the dtmf string and look for a new menu entry in the
1667          * menu structure */
1668         ast_copy_string(dtmf, cur_dtmf, sizeof(dtmf));
1669         for (i = 0; i < (MAXIMUM_DTMF_FEATURE_STRING - 1); i++) {
1670                 dtmf[i] = cur_dtmf[i];
1671                 if (!dtmf[i]) {
1672                         dtmf[i] = (char) digit;
1673                         dtmf[i + 1] = '\0';
1674                         i = -1;
1675                         break;
1676                 }
1677         }
1678         /* If i is not -1 then the new dtmf digit was _NOT_ added to the string.
1679          * If this is the case, no new DTMF sequence should be looked for. */
1680         if (i != -1) {
1681                 return 0;
1682         }
1683
1684         if (conf_find_menu_entry_by_sequence(dtmf, menu, &new_menu_entry)) {
1685                 execute_menu_entry(conference_bridge,
1686                         conference_bridge_user,
1687                         bridge_channel,
1688                         &new_menu_entry, menu);
1689                 conf_menu_entry_destroy(&new_menu_entry);
1690         }
1691         return 0;
1692 }
1693
1694 static int action_kick_last(struct conference_bridge *conference_bridge,
1695         struct ast_bridge_channel *bridge_channel,
1696         struct conference_bridge_user *conference_bridge_user)
1697 {
1698         struct conference_bridge_user *last_participant = NULL;
1699         int isadmin = ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN);
1700
1701         if (!isadmin) {
1702                 ast_stream_and_wait(bridge_channel->chan,
1703                         conf_get_sound(CONF_SOUND_ERROR_MENU, conference_bridge_user->b_profile.sounds),
1704                         "");
1705                 ast_log(LOG_WARNING, "Only admin users can use the kick_last menu action. Channel %s of conf %s is not an admin.\n",
1706                         ast_channel_name(bridge_channel->chan),
1707                         conference_bridge->name);
1708                 return -1;
1709         }
1710
1711         ao2_lock(conference_bridge);
1712         if (((last_participant = AST_LIST_LAST(&conference_bridge->users_list)) == conference_bridge_user)
1713                 || (ast_test_flag(&last_participant->u_profile, USER_OPT_ADMIN))) {
1714                 ao2_unlock(conference_bridge);
1715                 ast_stream_and_wait(bridge_channel->chan,
1716                         conf_get_sound(CONF_SOUND_ERROR_MENU, conference_bridge_user->b_profile.sounds),
1717                         "");
1718         } else if (last_participant) {
1719                 last_participant->kicked = 1;
1720                 ast_bridge_remove(conference_bridge->bridge, last_participant->chan);
1721                 ao2_unlock(conference_bridge);
1722         }
1723         return 0;
1724 }
1725
1726 static int action_dialplan_exec(struct ast_bridge_channel *bridge_channel, struct conf_menu_action *menu_action)
1727 {
1728         struct ast_pbx_args args;
1729         struct ast_pbx *pbx;
1730         char *exten;
1731         char *context;
1732         int priority;
1733         int res;
1734
1735         memset(&args, 0, sizeof(args));
1736         args.no_hangup_chan = 1;
1737
1738         ast_channel_lock(bridge_channel->chan);
1739
1740         /*save off*/
1741         exten = ast_strdupa(ast_channel_exten(bridge_channel->chan));
1742         context = ast_strdupa(ast_channel_context(bridge_channel->chan));
1743         priority = ast_channel_priority(bridge_channel->chan);
1744         pbx = ast_channel_pbx(bridge_channel->chan);
1745         ast_channel_pbx_set(bridge_channel->chan, NULL);
1746
1747         /*set new*/
1748         ast_channel_exten_set(bridge_channel->chan, menu_action->data.dialplan_args.exten);
1749         ast_channel_context_set(bridge_channel->chan, menu_action->data.dialplan_args.context);
1750         ast_channel_priority_set(bridge_channel->chan, menu_action->data.dialplan_args.priority);
1751
1752         ast_channel_unlock(bridge_channel->chan);
1753
1754         /*execute*/
1755         res = ast_pbx_run_args(bridge_channel->chan, &args);
1756
1757         /*restore*/
1758         ast_channel_lock(bridge_channel->chan);
1759
1760         ast_channel_exten_set(bridge_channel->chan, exten);
1761         ast_channel_context_set(bridge_channel->chan, context);
1762         ast_channel_priority_set(bridge_channel->chan, priority);
1763         ast_channel_pbx_set(bridge_channel->chan, pbx);
1764
1765         ast_channel_unlock(bridge_channel->chan);
1766
1767         return res;
1768 }
1769
1770 static int execute_menu_entry(struct conference_bridge *conference_bridge,
1771         struct conference_bridge_user *conference_bridge_user,
1772         struct ast_bridge_channel *bridge_channel,
1773         struct conf_menu_entry *menu_entry,
1774         struct conf_menu *menu)
1775 {
1776         struct conf_menu_action *menu_action;
1777         int isadmin = ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN);
1778         int stop_prompts = 0;
1779         int res = 0;
1780
1781         AST_LIST_TRAVERSE(&menu_entry->actions, menu_action, action) {
1782                 switch (menu_action->id) {
1783                 case MENU_ACTION_TOGGLE_MUTE:
1784                         res |= action_toggle_mute(conference_bridge,
1785                                 conference_bridge_user,
1786                                 bridge_channel->chan);
1787                         break;
1788                 case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS:
1789                         if (!isadmin) {
1790                                 break;
1791                         }
1792                         action_toggle_mute_participants(conference_bridge, conference_bridge_user);
1793                         break;
1794                 case MENU_ACTION_PARTICIPANT_COUNT:
1795                         announce_user_count(conference_bridge, conference_bridge_user);
1796                         break;
1797                 case MENU_ACTION_PLAYBACK:
1798                         if (!stop_prompts) {
1799                                 res |= action_playback(bridge_channel, menu_action->data.playback_file);
1800                         }
1801                         break;
1802                 case MENU_ACTION_RESET_LISTENING:
1803                         ast_audiohook_volume_set(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_WRITE, 0);
1804                         break;
1805                 case MENU_ACTION_RESET_TALKING:
1806                         ast_audiohook_volume_set(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_READ, 0);
1807                         break;
1808                 case MENU_ACTION_INCREASE_LISTENING:
1809                         ast_audiohook_volume_adjust(conference_bridge_user->chan,
1810                                 AST_AUDIOHOOK_DIRECTION_WRITE, 1);
1811                         break;
1812                 case MENU_ACTION_DECREASE_LISTENING:
1813                         ast_audiohook_volume_adjust(conference_bridge_user->chan,
1814                                 AST_AUDIOHOOK_DIRECTION_WRITE, -1);
1815                         break;
1816                 case MENU_ACTION_INCREASE_TALKING:
1817                         ast_audiohook_volume_adjust(conference_bridge_user->chan,
1818                                 AST_AUDIOHOOK_DIRECTION_READ, 1);
1819                         break;
1820                 case MENU_ACTION_DECREASE_TALKING:
1821                         ast_audiohook_volume_adjust(conference_bridge_user->chan,
1822                                 AST_AUDIOHOOK_DIRECTION_READ, -1);
1823                         break;
1824                 case MENU_ACTION_PLAYBACK_AND_CONTINUE:
1825                         if (!(stop_prompts)) {
1826                                 res |= action_playback_and_continue(conference_bridge,
1827                                         conference_bridge_user,
1828                                         bridge_channel,
1829                                         menu,
1830                                         menu_action->data.playback_file,
1831                                         menu_entry->dtmf,
1832                                         &stop_prompts);
1833                         }
1834                         break;
1835                 case MENU_ACTION_DIALPLAN_EXEC:
1836                         res |= action_dialplan_exec(bridge_channel, menu_action);
1837                         break;
1838                 case MENU_ACTION_ADMIN_TOGGLE_LOCK:
1839                         if (!isadmin) {
1840                                 break;
1841                         }
1842                         conference_bridge->locked = (!conference_bridge->locked ? 1 : 0);
1843                         res |= ast_stream_and_wait(bridge_channel->chan,
1844                                 (conference_bridge->locked ?
1845                                 conf_get_sound(CONF_SOUND_LOCKED_NOW, conference_bridge_user->b_profile.sounds) :
1846                                 conf_get_sound(CONF_SOUND_UNLOCKED_NOW, conference_bridge_user->b_profile.sounds)),
1847                                 "");
1848
1849                         break;
1850                 case MENU_ACTION_ADMIN_KICK_LAST:
1851                         res |= action_kick_last(conference_bridge, bridge_channel, conference_bridge_user);
1852                         break;
1853                 case MENU_ACTION_LEAVE:
1854                         ao2_lock(conference_bridge);
1855                         ast_bridge_remove(conference_bridge->bridge, bridge_channel->chan);
1856                         ao2_unlock(conference_bridge);
1857                         break;
1858                 case MENU_ACTION_NOOP:
1859                         break;
1860                 case MENU_ACTION_SET_SINGLE_VIDEO_SRC:
1861                         ao2_lock(conference_bridge);
1862                         ast_bridge_set_single_src_video_mode(conference_bridge->bridge, bridge_channel->chan);
1863                         ao2_unlock(conference_bridge);
1864                         break;
1865                 case MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC:
1866                         handle_video_on_exit(conference_bridge, bridge_channel->chan);
1867                         break;
1868                 }
1869         }
1870         return res;
1871 }
1872
1873 int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel,
1874         struct conference_bridge_user *conference_bridge_user,
1875         struct conf_menu_entry *menu_entry,
1876         struct conf_menu *menu)
1877 {
1878         struct conference_bridge *conference_bridge = conference_bridge_user->conference_bridge;
1879
1880         /* See if music on hold is playing */
1881         ao2_lock(conference_bridge);
1882         if (conference_bridge_user->playing_moh) {
1883                 /* MOH is going, let's stop it */
1884                 ast_moh_stop(bridge_channel->chan);
1885         }
1886         ao2_unlock(conference_bridge);
1887
1888         /* execute the list of actions associated with this menu entry */
1889         execute_menu_entry(conference_bridge, conference_bridge_user, bridge_channel, menu_entry, menu);
1890
1891         /* See if music on hold needs to be started back up again */
1892         ao2_lock(conference_bridge);
1893         if (conference_bridge_user->playing_moh) {
1894                 ast_moh_start(bridge_channel->chan, conference_bridge_user->u_profile.moh_class, NULL);
1895         }
1896         ao2_unlock(conference_bridge);
1897
1898         return 0;
1899 }
1900
1901 static char *complete_confbridge_name(const char *line, const char *word, int pos, int state)
1902 {
1903         int which = 0;
1904         struct conference_bridge *bridge = NULL;
1905         char *res = NULL;
1906         int wordlen = strlen(word);
1907         struct ao2_iterator i;
1908
1909         i = ao2_iterator_init(conference_bridges, 0);
1910         while ((bridge = ao2_iterator_next(&i))) {
1911                 if (!strncasecmp(bridge->name, word, wordlen) && ++which > state) {
1912                         res = ast_strdup(bridge->name);
1913                         ao2_ref(bridge, -1);
1914                         break;
1915                 }
1916                 ao2_ref(bridge, -1);
1917         }
1918         ao2_iterator_destroy(&i);
1919
1920         return res;
1921 }
1922
1923 static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1924 {
1925         struct conference_bridge *bridge = NULL;
1926         struct conference_bridge tmp;
1927         struct conference_bridge_user *participant = NULL;
1928
1929         switch (cmd) {
1930         case CLI_INIT:
1931                 e->command = "confbridge kick";
1932                 e->usage =
1933                         "Usage: confbridge kick <conference> <channel>\n"
1934                         "       Kicks a channel out of the conference bridge.\n";
1935                 return NULL;
1936         case CLI_GENERATE:
1937                 if (a->pos == 2) {
1938                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
1939                 }
1940                 /*
1941                 if (a->pos == 3) {
1942                         return complete_confbridge_channel(a->line, a->word, a->pos, a->n);
1943                 }
1944                 */
1945                 return NULL;
1946         }
1947
1948         if (a->argc != 4) {
1949                 return CLI_SHOWUSAGE;
1950         }
1951
1952         ast_copy_string(tmp.name, a->argv[2], sizeof(tmp.name));
1953         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
1954         if (!bridge) {
1955                 ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
1956                 return CLI_SUCCESS;
1957         }
1958         ao2_lock(bridge);
1959         AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
1960                 if (!strncmp(a->argv[3], ast_channel_name(participant->chan), strlen(ast_channel_name(participant->chan)))) {
1961                         break;
1962                 }
1963         }
1964         if (participant) {
1965                 ast_cli(a->fd, "Kicking %s from confbridge %s\n", ast_channel_name(participant->chan), bridge->name);
1966                 participant->kicked = 1;
1967                 ast_bridge_remove(bridge->bridge, participant->chan);
1968         }
1969         ao2_unlock(bridge);
1970         ao2_ref(bridge, -1);
1971         return CLI_SUCCESS;
1972 }
1973
1974 static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1975 {
1976         struct ao2_iterator i;
1977         struct conference_bridge *bridge = NULL;
1978         struct conference_bridge tmp;
1979         struct conference_bridge_user *participant = NULL;
1980
1981         switch (cmd) {
1982         case CLI_INIT:
1983                 e->command = "confbridge list";
1984                 e->usage =
1985                         "Usage: confbridge list [<name>]\n"
1986                         "       Lists all currently active conference bridges.\n";
1987                 return NULL;
1988         case CLI_GENERATE:
1989                 if (a->pos == 2) {
1990                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
1991                 }
1992                 return NULL;
1993         }
1994
1995         if (a->argc == 2) {
1996                 ast_cli(a->fd, "Conference Bridge Name           Users  Marked Locked?\n");
1997                 ast_cli(a->fd, "================================ ====== ====== ========\n");
1998                 i = ao2_iterator_init(conference_bridges, 0);
1999                 while ((bridge = ao2_iterator_next(&i))) {
2000                         ast_cli(a->fd, "%-32s %6i %6i %s\n", bridge->name, bridge->users, bridge->markedusers, (bridge->locked ? "locked" : "unlocked"));
2001                         ao2_ref(bridge, -1);
2002                 }
2003                 ao2_iterator_destroy(&i);
2004                 return CLI_SUCCESS;
2005         }
2006
2007         if (a->argc == 3) {
2008                 ast_copy_string(tmp.name, a->argv[2], sizeof(tmp.name));
2009                 bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2010                 if (!bridge) {
2011                         ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
2012                         return CLI_SUCCESS;
2013                 }
2014                 ast_cli(a->fd, "Channel                       User Profile     Bridge Profile   Menu             CallerID\n");
2015                 ast_cli(a->fd, "============================= ================ ================ ================ ================\n");
2016                 ao2_lock(bridge);
2017                 AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2018                         ast_cli(a->fd, "%-29s ", ast_channel_name(participant->chan));
2019                         ast_cli(a->fd, "%-17s", participant->u_profile.name);
2020                         ast_cli(a->fd, "%-17s", participant->b_profile.name);
2021                         ast_cli(a->fd, "%-17s", participant->menu_name);
2022                         ast_cli(a->fd, "%-17s", S_COR(ast_channel_caller(participant->chan)->id.number.valid, ast_channel_caller(participant->chan)->id.number.str, "<unknown>"));
2023                         ast_cli(a->fd, "\n");
2024                 }
2025                 ao2_unlock(bridge);
2026                 ao2_ref(bridge, -1);
2027                 return CLI_SUCCESS;
2028         }
2029
2030         return CLI_SHOWUSAGE;
2031 }
2032
2033 /* \internal
2034  * \brief finds a conference by name and locks/unlocks.
2035  *
2036  * \retval 0 success
2037  * \retval -1 conference not found
2038  */
2039 static int generic_lock_unlock_helper(int lock, const char *conference)
2040 {
2041         struct conference_bridge *bridge = NULL;
2042         struct conference_bridge tmp;
2043         int res = 0;
2044
2045         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2046         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2047         if (!bridge) {
2048                 return -1;
2049         }
2050         ao2_lock(bridge);
2051         bridge->locked = lock;
2052         ast_test_suite_event_notify("CONF_LOCK", "Message: conference %s\r\nConference: %s", bridge->locked ? "locked" : "unlocked", bridge->b_profile.name);
2053         ao2_unlock(bridge);
2054         ao2_ref(bridge, -1);
2055
2056         return res;
2057 }
2058
2059 /* \internal
2060  * \brief finds a conference user by channel name and mutes/unmutes them.
2061  *
2062  * \retval 0 success
2063  * \retval -1 conference not found
2064  * \retval -2 user not found
2065  */
2066 static int generic_mute_unmute_helper(int mute, const char *conference, const char *user)
2067 {
2068         struct conference_bridge *bridge = NULL;
2069         struct conference_bridge tmp;
2070         struct conference_bridge_user *participant = NULL;
2071         int res = 0;
2072         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2073         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2074         if (!bridge) {
2075                 return -1;
2076         }
2077         ao2_lock(bridge);
2078         AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2079                 if (!strncmp(user, ast_channel_name(participant->chan), strlen(user))) {
2080                         break;
2081                 }
2082         }
2083         if (participant) {
2084                 participant->features.mute = mute;
2085                 ast_test_suite_event_notify("CONF_MUTE", "Message: participant %s %s\r\nConference: %s\r\nChannel: %s", ast_channel_name(participant->chan), participant->features.mute ? "muted" : "unmuted", bridge->b_profile.name, ast_channel_name(participant->chan));
2086         } else {
2087                 res = -2;;
2088         }
2089         ao2_unlock(bridge);
2090         ao2_ref(bridge, -1);
2091
2092         return res;
2093 }
2094
2095 static int cli_mute_unmute_helper(int mute, struct ast_cli_args *a)
2096 {
2097         int res = generic_mute_unmute_helper(mute, a->argv[2], a->argv[3]);
2098
2099         if (res == -1) {
2100                 ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
2101                 return -1;
2102         } else if (res == -2) {
2103                 ast_cli(a->fd, "No channel named '%s' found in conference %s\n", a->argv[3], a->argv[2]);
2104                 return -1;
2105         }
2106         ast_cli(a->fd, "%s %s from confbridge %s\n", mute ? "Muting" : "Unmuting", a->argv[3], a->argv[2]);
2107         return 0;
2108 }
2109
2110 static char *handle_cli_confbridge_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2111 {
2112         switch (cmd) {
2113         case CLI_INIT:
2114                 e->command = "confbridge mute";
2115                 e->usage =
2116                         "Usage: confbridge mute <conference> <channel>\n";
2117                 return NULL;
2118         case CLI_GENERATE:
2119                 if (a->pos == 2) {
2120                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2121                 }
2122                 return NULL;
2123         }
2124         if (a->argc != 4) {
2125                 return CLI_SHOWUSAGE;
2126         }
2127
2128         cli_mute_unmute_helper(1, a);
2129
2130         return CLI_SUCCESS;
2131 }
2132
2133 static char *handle_cli_confbridge_unmute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2134 {
2135         switch (cmd) {
2136         case CLI_INIT:
2137                 e->command = "confbridge unmute";
2138                 e->usage =
2139                         "Usage: confbridge unmute <conference> <channel>\n";
2140                 return NULL;
2141         case CLI_GENERATE:
2142                 if (a->pos == 2) {
2143                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2144                 }
2145                 return NULL;
2146         }
2147         if (a->argc != 4) {
2148                 return CLI_SHOWUSAGE;
2149         }
2150
2151         cli_mute_unmute_helper(0, a);
2152
2153         return CLI_SUCCESS;
2154 }
2155
2156 static char *handle_cli_confbridge_lock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2157 {
2158         switch (cmd) {
2159         case CLI_INIT:
2160                 e->command = "confbridge lock";
2161                 e->usage =
2162                         "Usage: confbridge lock <conference>\n";
2163                 return NULL;
2164         case CLI_GENERATE:
2165                 if (a->pos == 2) {
2166                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2167                 }
2168                 return NULL;
2169         }
2170         if (a->argc != 3) {
2171                 return CLI_SHOWUSAGE;
2172         }
2173         if (generic_lock_unlock_helper(1, a->argv[2])) {
2174                 ast_cli(a->fd, "Conference %s is not found\n", a->argv[2]);
2175         } else {
2176                 ast_cli(a->fd, "Conference %s is locked.\n", a->argv[2]);
2177         }
2178         return CLI_SUCCESS;
2179 }
2180
2181 static char *handle_cli_confbridge_unlock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2182 {
2183         switch (cmd) {
2184         case CLI_INIT:
2185                 e->command = "confbridge unlock";
2186                 e->usage =
2187                         "Usage: confbridge unlock <conference>\n";
2188                 return NULL;
2189         case CLI_GENERATE:
2190                 if (a->pos == 2) {
2191                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2192                 }
2193                 return NULL;
2194         }
2195         if (a->argc != 3) {
2196                 return CLI_SHOWUSAGE;
2197         }
2198         if (generic_lock_unlock_helper(0, a->argv[2])) {
2199                 ast_cli(a->fd, "Conference %s is not found\n", a->argv[2]);
2200         } else {
2201                 ast_cli(a->fd, "Conference %s is unlocked.\n", a->argv[2]);
2202         }
2203         return CLI_SUCCESS;
2204 }
2205
2206 static char *handle_cli_confbridge_start_record(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2207 {
2208         const char *rec_file = NULL;
2209         struct conference_bridge *bridge = NULL;
2210         struct conference_bridge tmp;
2211
2212         switch (cmd) {
2213         case CLI_INIT:
2214                 e->command = "confbridge record start";
2215                 e->usage =
2216                         "Usage: confbridge record start <conference> <file>\n"
2217                         "       <file> is optional, Otherwise the bridge profile\n"
2218                         "       record file will be used.  If the bridge profile\n"
2219                         "       has no record file specified, a file will automatically\n"
2220                         "       be generated in the monitor directory\n";
2221                 return NULL;
2222         case CLI_GENERATE:
2223                 if (a->pos == 3) {
2224                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2225                 }
2226                 return NULL;
2227         }
2228         if (a->argc < 4) {
2229                 return CLI_SHOWUSAGE;
2230         }
2231         if (a->argc == 5) {
2232                 rec_file = a->argv[4];
2233         }
2234
2235         ast_copy_string(tmp.name, a->argv[3], sizeof(tmp.name));
2236         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2237         if (!bridge) {
2238                 ast_cli(a->fd, "Conference not found.\n");
2239                 return CLI_FAILURE;
2240         }
2241         if (conf_is_recording(bridge)) {
2242                 ast_cli(a->fd, "Conference is already being recorded.\n");
2243                 ao2_ref(bridge, -1);
2244                 return CLI_SUCCESS;
2245         }
2246         if (!ast_strlen_zero(rec_file)) {
2247                 ao2_lock(bridge);
2248                 ast_copy_string(bridge->b_profile.rec_file, rec_file, sizeof(bridge->b_profile.rec_file));
2249                 ao2_unlock(bridge);
2250         }
2251         if (conf_start_record(bridge)) {
2252                 ast_cli(a->fd, "Could not start recording due to internal error.\n");
2253                 ao2_ref(bridge, -1);
2254                 return CLI_FAILURE;
2255         }
2256         ast_cli(a->fd, "Recording started\n");
2257         ao2_ref(bridge, -1);
2258         return CLI_SUCCESS;
2259 }
2260
2261 static char *handle_cli_confbridge_stop_record(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2262 {
2263         struct conference_bridge *bridge = NULL;
2264         struct conference_bridge tmp;
2265
2266         switch (cmd) {
2267         case CLI_INIT:
2268                 e->command = "confbridge record stop";
2269                 e->usage =
2270                         "Usage: confbridge record stop <conference>\n";
2271                 return NULL;
2272         case CLI_GENERATE:
2273                 if (a->pos == 3) {
2274                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2275                 }
2276                 return NULL;
2277         }
2278         if (a->argc != 4) {
2279                 return CLI_SHOWUSAGE;
2280         }
2281
2282         ast_copy_string(tmp.name, a->argv[3], sizeof(tmp.name));
2283         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2284         if (!bridge) {
2285                 ast_cli(a->fd, "Conference not found.\n");
2286                 return CLI_SUCCESS;
2287         }
2288         conf_stop_record(bridge);
2289         ast_cli(a->fd, "Recording stopped.\n");
2290         ao2_ref(bridge, -1);
2291         return CLI_SUCCESS;
2292 }
2293
2294 static struct ast_cli_entry cli_confbridge[] = {
2295         AST_CLI_DEFINE(handle_cli_confbridge_list, "List conference bridges and participants."),
2296         AST_CLI_DEFINE(handle_cli_confbridge_kick, "Kick participants out of conference bridges."),
2297         AST_CLI_DEFINE(handle_cli_confbridge_mute, "Mute a participant."),
2298         AST_CLI_DEFINE(handle_cli_confbridge_unmute, "Unmute a participant."),
2299         AST_CLI_DEFINE(handle_cli_confbridge_lock, "Lock a conference."),
2300         AST_CLI_DEFINE(handle_cli_confbridge_unlock, "Unlock a conference."),
2301         AST_CLI_DEFINE(handle_cli_confbridge_start_record, "Start recording a conference"),
2302         AST_CLI_DEFINE(handle_cli_confbridge_stop_record, "Stop recording a conference."),
2303 };
2304 static struct ast_custom_function confbridge_function = {
2305         .name = "CONFBRIDGE",
2306         .write = func_confbridge_helper,
2307 };
2308
2309 static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
2310 static struct ast_custom_function confbridge_info_function = {
2311         .name = "CONFBRIDGE_INFO",
2312         .read = func_confbridge_info,
2313 };
2314
2315 static int action_confbridgelist(struct mansession *s, const struct message *m)
2316 {
2317         const char *actionid = astman_get_header(m, "ActionID");
2318         const char *conference = astman_get_header(m, "Conference");
2319         struct conference_bridge_user *participant = NULL;
2320         struct conference_bridge *bridge = NULL;
2321         struct conference_bridge tmp;
2322         char id_text[80] = "";
2323         int total = 0;
2324
2325         if (!ast_strlen_zero(actionid)) {
2326                 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", actionid);
2327         }
2328         if (ast_strlen_zero(conference)) {
2329                 astman_send_error(s, m, "No Conference name provided.");
2330                 return 0;
2331         }
2332         if (!ao2_container_count(conference_bridges)) {
2333                 astman_send_error(s, m, "No active conferences.");
2334                 return 0;
2335         }
2336         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2337         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2338         if (!bridge) {
2339                 astman_send_error(s, m, "No Conference by that name found.");
2340                 return 0;
2341         }
2342
2343         astman_send_listack(s, m, "Confbridge user list will follow", "start");
2344
2345         ao2_lock(bridge);
2346         AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2347                 total++;
2348                 astman_append(s,
2349                         "Event: ConfbridgeList\r\n"
2350                         "%s"
2351                         "Conference: %s\r\n"
2352                         "CallerIDNum: %s\r\n"
2353                         "CallerIDName: %s\r\n"
2354                         "Channel: %s\r\n"
2355                         "Admin: %s\r\n"
2356                         "MarkedUser: %s\r\n"
2357                         "\r\n",
2358                         id_text,
2359                         bridge->name,
2360                         S_COR(ast_channel_caller(participant->chan)->id.number.valid, ast_channel_caller(participant->chan)->id.number.str, "<unknown>"),
2361                         S_COR(ast_channel_caller(participant->chan)->id.name.valid, ast_channel_caller(participant->chan)->id.name.str, "<no name>"),
2362                         ast_channel_name(participant->chan),
2363                         ast_test_flag(&participant->u_profile, USER_OPT_ADMIN) ? "Yes" : "No",
2364                         ast_test_flag(&participant->u_profile, USER_OPT_MARKEDUSER) ? "Yes" : "No");
2365         }
2366         ao2_unlock(bridge);
2367         ao2_ref(bridge, -1);
2368
2369         astman_append(s,
2370         "Event: ConfbridgeListComplete\r\n"
2371         "EventList: Complete\r\n"
2372         "ListItems: %d\r\n"
2373         "%s"
2374         "\r\n", total, id_text);
2375
2376         return 0;
2377 }
2378
2379 static int action_confbridgelistrooms(struct mansession *s, const struct message *m)
2380 {
2381         const char *actionid = astman_get_header(m, "ActionID");
2382         struct conference_bridge *bridge = NULL;
2383         struct ao2_iterator i;
2384         char id_text[512] = "";
2385         int totalitems = 0;
2386
2387         if (!ast_strlen_zero(actionid)) {
2388                 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", actionid);
2389         }
2390
2391         if (!ao2_container_count(conference_bridges)) {
2392                 astman_send_error(s, m, "No active conferences.");
2393                 return 0;
2394         }
2395
2396         astman_send_listack(s, m, "Confbridge conferences will follow", "start");
2397
2398         /* Traverse the conference list */
2399         i = ao2_iterator_init(conference_bridges, 0);
2400         while ((bridge = ao2_iterator_next(&i))) {
2401                 totalitems++;
2402
2403                 ao2_lock(bridge);
2404                 astman_append(s,
2405                 "Event: ConfbridgeListRooms\r\n"
2406                 "%s"
2407                 "Conference: %s\r\n"
2408                 "Parties: %d\r\n"
2409                 "Marked: %d\r\n"
2410                 "Locked: %s\r\n"
2411                 "\r\n",
2412                 id_text,
2413                 bridge->name,
2414                 bridge->users,
2415                 bridge->markedusers,
2416                 bridge->locked ? "Yes" : "No"); 
2417                 ao2_unlock(bridge);
2418
2419                 ao2_ref(bridge, -1);
2420         }
2421         ao2_iterator_destroy(&i);
2422
2423         /* Send final confirmation */
2424         astman_append(s,
2425         "Event: ConfbridgeListRoomsComplete\r\n"
2426         "EventList: Complete\r\n"
2427         "ListItems: %d\r\n"
2428         "%s"
2429         "\r\n", totalitems, id_text);
2430         return 0;
2431 }
2432
2433 static int action_mute_unmute_helper(struct mansession *s, const struct message *m, int mute)
2434 {
2435         const char *conference = astman_get_header(m, "Conference");
2436         const char *channel = astman_get_header(m, "Channel");
2437         int res = 0;
2438
2439         if (ast_strlen_zero(conference)) {
2440                 astman_send_error(s, m, "No Conference name provided.");
2441                 return 0;
2442         }
2443         if (ast_strlen_zero(channel)) {
2444                 astman_send_error(s, m, "No channel name provided.");
2445                 return 0;
2446         }
2447         if (!ao2_container_count(conference_bridges)) {
2448                 astman_send_error(s, m, "No active conferences.");
2449                 return 0;
2450         }
2451
2452         res = generic_mute_unmute_helper(mute, conference, channel);
2453
2454         if (res == -1) {
2455                 astman_send_error(s, m, "No Conference by that name found.");
2456                 return 0;
2457         } else if (res == -2) {
2458                 astman_send_error(s, m, "No Channel by that name found in Conference.");
2459                 return 0;
2460         }
2461
2462         astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
2463         return 0;
2464 }
2465
2466 static int action_confbridgeunmute(struct mansession *s, const struct message *m)
2467 {
2468         return action_mute_unmute_helper(s, m, 0);
2469 }
2470 static int action_confbridgemute(struct mansession *s, const struct message *m)
2471 {
2472         return action_mute_unmute_helper(s, m, 1);
2473 }
2474
2475 static int action_lock_unlock_helper(struct mansession *s, const struct message *m, int lock)
2476 {
2477         const char *conference = astman_get_header(m, "Conference");
2478         int res = 0;
2479
2480         if (ast_strlen_zero(conference)) {
2481                 astman_send_error(s, m, "No Conference name provided.");
2482                 return 0;
2483         }
2484         if (!ao2_container_count(conference_bridges)) {
2485                 astman_send_error(s, m, "No active conferences.");
2486                 return 0;
2487         }
2488         if ((res = generic_lock_unlock_helper(lock, conference))) {
2489                 astman_send_error(s, m, "No Conference by that name found.");
2490                 return 0;
2491         }
2492         astman_send_ack(s, m, lock ? "Conference locked" : "Conference unlocked");
2493         return 0;
2494 }
2495 static int action_confbridgeunlock(struct mansession *s, const struct message *m)
2496 {
2497         return action_lock_unlock_helper(s, m, 0);
2498 }
2499 static int action_confbridgelock(struct mansession *s, const struct message *m)
2500 {
2501         return action_lock_unlock_helper(s, m, 1);
2502 }
2503
2504 static int action_confbridgekick(struct mansession *s, const struct message *m)
2505 {
2506         const char *conference = astman_get_header(m, "Conference");
2507         const char *channel = astman_get_header(m, "Channel");
2508         struct conference_bridge_user *participant = NULL;
2509         struct conference_bridge *bridge = NULL;
2510         struct conference_bridge tmp;
2511         int found = 0;
2512
2513         if (ast_strlen_zero(conference)) {
2514                 astman_send_error(s, m, "No Conference name provided.");
2515                 return 0;
2516         }
2517         if (!ao2_container_count(conference_bridges)) {
2518                 astman_send_error(s, m, "No active conferences.");
2519                 return 0;
2520         }
2521         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2522         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2523         if (!bridge) {
2524                 astman_send_error(s, m, "No Conference by that name found.");
2525                 return 0;
2526         }
2527
2528         ao2_lock(bridge);
2529         AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2530                 if (!strcasecmp(ast_channel_name(participant->chan), channel)) {
2531                         participant->kicked = 1;
2532                         ast_bridge_remove(bridge->bridge, participant->chan);
2533                         found = 1;
2534                         break;
2535                 }
2536         }
2537         ao2_unlock(bridge);
2538         ao2_ref(bridge, -1);
2539
2540         if (found) {
2541                 astman_send_ack(s, m, "User kicked");
2542         } else {
2543                 astman_send_error(s, m, "No Channel by that name found in Conference.");
2544         }
2545         return 0;
2546 }
2547
2548 static int action_confbridgestartrecord(struct mansession *s, const struct message *m)
2549 {
2550         const char *conference = astman_get_header(m, "Conference");
2551         const char *recordfile = astman_get_header(m, "RecordFile");
2552         struct conference_bridge *bridge = NULL;
2553         struct conference_bridge tmp;
2554
2555         if (ast_strlen_zero(conference)) {
2556                 astman_send_error(s, m, "No Conference name provided.");
2557                 return 0;
2558         }
2559         if (!ao2_container_count(conference_bridges)) {
2560                 astman_send_error(s, m, "No active conferences.");
2561                 return 0;
2562         }
2563
2564         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2565         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2566         if (!bridge) {
2567                 astman_send_error(s, m, "No Conference by that name found.");
2568                 return 0;
2569         }
2570
2571         if (conf_is_recording(bridge)) {
2572                 astman_send_error(s, m, "Conference is already being recorded.");
2573                 ao2_ref(bridge, -1);
2574                 return 0;
2575         }
2576
2577         if (!ast_strlen_zero(recordfile)) {
2578                 ao2_lock(bridge);
2579                 ast_copy_string(bridge->b_profile.rec_file, recordfile, sizeof(bridge->b_profile.rec_file));
2580                 ao2_unlock(bridge);
2581         }
2582
2583         if (conf_start_record(bridge)) {
2584                 astman_send_error(s, m, "Internal error starting conference recording.");
2585                 ao2_ref(bridge, -1);
2586                 return 0;
2587         }
2588
2589         ao2_ref(bridge, -1);
2590         astman_send_ack(s, m, "Conference Recording Started.");
2591         return 0;
2592 }
2593 static int action_confbridgestoprecord(struct mansession *s, const struct message *m)
2594 {
2595         const char *conference = astman_get_header(m, "Conference");
2596         struct conference_bridge *bridge = NULL;
2597         struct conference_bridge tmp;
2598
2599         if (ast_strlen_zero(conference)) {
2600                 astman_send_error(s, m, "No Conference name provided.");
2601                 return 0;
2602         }
2603         if (!ao2_container_count(conference_bridges)) {
2604                 astman_send_error(s, m, "No active conferences.");
2605                 return 0;
2606         }
2607
2608         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2609         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2610         if (!bridge) {
2611                 astman_send_error(s, m, "No Conference by that name found.");
2612                 return 0;
2613         }
2614
2615         if (conf_stop_record(bridge)) {
2616                 astman_send_error(s, m, "Internal error while stopping recording.");
2617                 ao2_ref(bridge, -1);
2618                 return 0;
2619         }
2620
2621         ao2_ref(bridge, -1);
2622         astman_send_ack(s, m, "Conference Recording Stopped.");
2623         return 0;
2624 }
2625
2626 static int action_confbridgesetsinglevideosrc(struct mansession *s, const struct message *m)
2627 {
2628         const char *conference = astman_get_header(m, "Conference");
2629         const char *channel = astman_get_header(m, "Channel");
2630         struct conference_bridge_user *participant = NULL;
2631         struct conference_bridge *bridge = NULL;
2632         struct conference_bridge tmp;
2633
2634         if (ast_strlen_zero(conference)) {
2635                 astman_send_error(s, m, "No Conference name provided.");
2636                 return 0;
2637         }
2638         if (ast_strlen_zero(channel)) {
2639                 astman_send_error(s, m, "No channel name provided.");
2640                 return 0;
2641         }
2642         if (!ao2_container_count(conference_bridges)) {
2643                 astman_send_error(s, m, "No active conferences.");
2644                 return 0;
2645         }
2646
2647         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2648         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2649         if (!bridge) {
2650                 astman_send_error(s, m, "No Conference by that name found.");
2651                 return 0;
2652         }
2653
2654         /* find channel and set as video src. */
2655         ao2_lock(bridge);
2656         AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2657                 if (!strncmp(channel, ast_channel_name(participant->chan), strlen(channel))) {
2658                         ast_bridge_set_single_src_video_mode(bridge->bridge, participant->chan);
2659                         break;
2660                 }
2661         }
2662         ao2_unlock(bridge);
2663         ao2_ref(bridge, -1);
2664
2665         /* do not access participant after bridge unlock.  We are just
2666          * using this check to see if it was found or not */
2667         if (!participant) {
2668                 astman_send_error(s, m, "No channel by that name found in conference.");
2669                 return 0;
2670         }
2671         astman_send_ack(s, m, "Conference single video source set.");
2672         return 0;
2673 }
2674
2675 static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
2676 {
2677         char *parse = NULL;
2678         struct conference_bridge *bridge = NULL;
2679         struct conference_bridge_user *participant = NULL;
2680         struct conference_bridge tmp;
2681         int count = 0;
2682         AST_DECLARE_APP_ARGS(args,
2683                 AST_APP_ARG(type);
2684                 AST_APP_ARG(confno);
2685         );
2686
2687         /* parse all the required arguments and make sure they exist. */
2688         if (ast_strlen_zero(data)) {
2689                 return -1;
2690         }
2691         parse = ast_strdupa(data);
2692         AST_STANDARD_APP_ARGS(args, parse);
2693         if (ast_strlen_zero(args.confno) || ast_strlen_zero(args.type)) {
2694                 return -1;
2695         }
2696         if (!ao2_container_count(conference_bridges)) {
2697                 snprintf(buf, len, "0");
2698                 return 0;
2699         }
2700         ast_copy_string(tmp.name, args.confno, sizeof(tmp.name));
2701         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2702         if (!bridge) {
2703                 snprintf(buf, len, "0");
2704                 return 0;
2705         }
2706
2707         /* get the correct count for the type requested */
2708         ao2_lock(bridge);
2709         if (!strncasecmp(args.type, "parties", 7)) {
2710                 AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2711                         count++;
2712                 }
2713         } else if (!strncasecmp(args.type, "admins", 6)) {
2714                 AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2715                         if (ast_test_flag(&participant->u_profile, USER_OPT_ADMIN)) {
2716                                 count++;
2717                         }
2718                 }
2719         } else if (!strncasecmp(args.type, "marked", 6)) {
2720                 AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2721                         if (ast_test_flag(&participant->u_profile, USER_OPT_MARKEDUSER)) {
2722                                 count++;
2723                         }
2724                 }
2725         } else if (!strncasecmp(args.type, "locked", 6)) {
2726                 count = bridge->locked;
2727         } else {
2728                 ast_log(LOG_ERROR, "Invalid keyword '%s' passed to CONFBRIDGE_INFO.  Should be one of: "
2729                         "parties, admins, marked, or locked.\n", args.type);
2730         }
2731         snprintf(buf, len, "%d", count);
2732         ao2_unlock(bridge);
2733         ao2_ref(bridge, -1);
2734         return 0;
2735 }
2736
2737 /*! \brief Called when module is being unloaded */
2738 static int unload_module(void)
2739 {
2740         int res = ast_unregister_application(app);
2741
2742         ast_custom_function_unregister(&confbridge_function);
2743         ast_custom_function_unregister(&confbridge_info_function);
2744
2745         ast_cli_unregister_multiple(cli_confbridge, sizeof(cli_confbridge) / sizeof(struct ast_cli_entry));
2746
2747         /* Get rid of the conference bridges container. Since we only allow dynamic ones none will be active. */
2748         ao2_ref(conference_bridges, -1);
2749
2750         conf_destroy_config();
2751
2752         ast_channel_unregister(&record_tech);
2753         record_tech.capabilities = ast_format_cap_destroy(record_tech.capabilities);
2754
2755         res |= ast_manager_unregister("ConfbridgeList");
2756         res |= ast_manager_unregister("ConfbridgeListRooms");
2757         res |= ast_manager_unregister("ConfbridgeMute");
2758         res |= ast_manager_unregister("ConfbridgeUnmute");
2759         res |= ast_manager_unregister("ConfbridgeKick");
2760         res |= ast_manager_unregister("ConfbridgeUnlock");
2761         res |= ast_manager_unregister("ConfbridgeLock");
2762         res |= ast_manager_unregister("ConfbridgeStartRecord");
2763         res |= ast_manager_unregister("ConfbridgeStopRecord");
2764
2765         return res;
2766 }
2767
2768 /*! \brief Called when module is being loaded */
2769 static int load_module(void)
2770 {
2771         int res = 0;
2772         if ((ast_custom_function_register(&confbridge_function))) {
2773                 return AST_MODULE_LOAD_FAILURE;
2774         }
2775         if ((ast_custom_function_register(&confbridge_info_function))) {
2776                 return AST_MODULE_LOAD_FAILURE;
2777         }
2778         if (!(record_tech.capabilities = ast_format_cap_alloc())) {
2779                 return AST_MODULE_LOAD_FAILURE;
2780         }
2781         ast_format_cap_add_all(record_tech.capabilities);
2782         if (ast_channel_register(&record_tech)) {
2783                 ast_log(LOG_ERROR, "Unable to register ConfBridge recorder.\n");
2784                 return AST_MODULE_LOAD_FAILURE;
2785         }
2786         /* Create a container to hold the conference bridges */
2787         if (!(conference_bridges = ao2_container_alloc(CONFERENCE_BRIDGE_BUCKETS, conference_bridge_hash_cb, conference_bridge_cmp_cb))) {
2788                 return AST_MODULE_LOAD_FAILURE;
2789         }
2790         if (ast_register_application_xml(app, confbridge_exec)) {
2791                 ao2_ref(conference_bridges, -1);
2792                 return AST_MODULE_LOAD_FAILURE;
2793         }
2794
2795         res |= ast_cli_register_multiple(cli_confbridge, sizeof(cli_confbridge) / sizeof(struct ast_cli_entry));
2796         res |= ast_manager_register_xml("ConfbridgeList", EVENT_FLAG_REPORTING, action_confbridgelist);
2797         res |= ast_manager_register_xml("ConfbridgeListRooms", EVENT_FLAG_REPORTING, action_confbridgelistrooms);
2798         res |= ast_manager_register_xml("ConfbridgeMute", EVENT_FLAG_CALL, action_confbridgemute);
2799         res |= ast_manager_register_xml("ConfbridgeUnmute", EVENT_FLAG_CALL, action_confbridgeunmute);
2800         res |= ast_manager_register_xml("ConfbridgeKick", EVENT_FLAG_CALL, action_confbridgekick);
2801         res |= ast_manager_register_xml("ConfbridgeUnlock", EVENT_FLAG_CALL, action_confbridgeunlock);
2802         res |= ast_manager_register_xml("ConfbridgeLock", EVENT_FLAG_CALL, action_confbridgelock);
2803         res |= ast_manager_register_xml("ConfbridgeStartRecord", EVENT_FLAG_CALL, action_confbridgestartrecord);
2804         res |= ast_manager_register_xml("ConfbridgeStopRecord", EVENT_FLAG_CALL, action_confbridgestoprecord);
2805         res |= ast_manager_register_xml("ConfbridgeSetSingleVideoSrc", EVENT_FLAG_CALL, action_confbridgesetsinglevideosrc);
2806
2807         conf_load_config(0);
2808         return res;
2809 }
2810
2811 static int reload(void)
2812 {
2813         return conf_load_config(1);
2814 }
2815
2816 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Conference Bridge Application",
2817         .load = load_module,
2818         .unload = unload_module,
2819         .reload = reload,
2820         .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
2821 );