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