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