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