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