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