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