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