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