Confbridge: add test events for dynamic menus test
[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_language_set(conference->playback_chan, conference->b_profile.language);
1372
1373         ast_debug(1, "Created announcer channel '%s' to conference bridge '%s'\n",
1374                 ast_channel_name(conference->playback_chan), conference->name);
1375         return 0;
1376 }
1377
1378 static int play_sound_helper(struct confbridge_conference *conference, const char *filename, int say_number)
1379 {
1380         /* Do not waste resources trying to play files that do not exist */
1381         if (!ast_strlen_zero(filename) && !sound_file_exists(filename)) {
1382                 return 0;
1383         }
1384
1385         ast_mutex_lock(&conference->playback_lock);
1386         if (!conference->playback_chan && alloc_playback_chan(conference)) {
1387                 ast_mutex_unlock(&conference->playback_lock);
1388                 return -1;
1389         }
1390         if (conf_announce_channel_push(conference->playback_chan)) {
1391                 ast_mutex_unlock(&conference->playback_lock);
1392                 return -1;
1393         }
1394
1395         /* The channel is all under our control, in goes the prompt */
1396         if (!ast_strlen_zero(filename)) {
1397                 ast_stream_and_wait(conference->playback_chan, filename, "");
1398         } else if (say_number >= 0) {
1399                 ast_say_number(conference->playback_chan, say_number, "",
1400                         ast_channel_language(conference->playback_chan), NULL);
1401         }
1402
1403         ast_debug(1, "Departing announcer channel '%s' from conference bridge '%s'\n",
1404                 ast_channel_name(conference->playback_chan), conference->name);
1405         conf_announce_channel_depart(conference->playback_chan);
1406
1407         ast_mutex_unlock(&conference->playback_lock);
1408
1409         return 0;
1410 }
1411
1412 int play_sound_file(struct confbridge_conference *conference, const char *filename)
1413 {
1414         return play_sound_helper(conference, filename, -1);
1415 }
1416
1417 /*!
1418  * \brief Play number into the conference bridge
1419  *
1420  * \param conference The conference bridge to say the number into
1421  * \param say_number number to say
1422  *
1423  * \retval 0 success
1424  * \retval -1 failure
1425  */
1426 static int play_sound_number(struct confbridge_conference *conference, int say_number)
1427 {
1428         return play_sound_helper(conference, NULL, say_number);
1429 }
1430
1431 static void conf_handle_talker_destructor(void *pvt_data)
1432 {
1433         ast_free(pvt_data);
1434 }
1435
1436 static int conf_handle_talker_cb(struct ast_bridge_channel *bridge_channel, void *hook_pvt, int talking)
1437 {
1438         const char *conf_name = hook_pvt;
1439         struct confbridge_conference *conference = ao2_find(conference_bridges, conf_name, OBJ_KEY);
1440         struct ast_json *talking_extras;
1441
1442         if (!conference) {
1443                 /* Remove the hook since the conference does not exist. */
1444                 return -1;
1445         }
1446
1447         talking_extras = ast_json_pack("{s: s}",
1448                 "talking_status", talking ? "on" : "off");
1449         if (!talking_extras) {
1450                 return 0;
1451         }
1452
1453         send_conf_stasis(conference, bridge_channel->chan, confbridge_talking_type(), talking_extras, 0);
1454         ast_json_unref(talking_extras);
1455         return 0;
1456 }
1457
1458 static int conf_get_pin(struct ast_channel *chan, struct confbridge_user *user)
1459 {
1460         char pin_guess[MAX_PIN+1] = { 0, };
1461         const char *pin = user->u_profile.pin;
1462         char *tmp = pin_guess;
1463         int i, res;
1464         unsigned int len = MAX_PIN ;
1465
1466         /* give them three tries to get the pin right */
1467         for (i = 0; i < 3; i++) {
1468                 if (ast_app_getdata(chan,
1469                         conf_get_sound(CONF_SOUND_GET_PIN, user->b_profile.sounds),
1470                         tmp, len, 0) >= 0) {
1471                         if (!strcasecmp(pin, pin_guess)) {
1472                                 return 0;
1473                         }
1474                 }
1475                 ast_streamfile(chan,
1476                         conf_get_sound(CONF_SOUND_INVALID_PIN, user->b_profile.sounds),
1477                         ast_channel_language(chan));
1478                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1479                 if (res > 0) {
1480                         /* Account for digit already read during ivalid pin playback
1481                          * resetting pin buf. */
1482                         pin_guess[0] = res;
1483                         pin_guess[1] = '\0';
1484                         tmp = pin_guess + 1;
1485                         len = MAX_PIN - 1;
1486                 } else {
1487                         /* reset pin buf as empty buffer. */
1488                         tmp = pin_guess;
1489                         len = MAX_PIN;
1490                 }
1491         }
1492         return -1;
1493 }
1494
1495 static int conf_rec_name(struct confbridge_user *user, const char *conf_name)
1496 {
1497         char destdir[PATH_MAX];
1498         int res;
1499         int duration = 20;
1500
1501         snprintf(destdir, sizeof(destdir), "%s/confbridge", ast_config_AST_SPOOL_DIR);
1502
1503         if (ast_mkdir(destdir, 0777) != 0) {
1504                 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
1505                 return -1;
1506         }
1507         snprintf(user->name_rec_location, sizeof(user->name_rec_location),
1508                  "%s/confbridge-name-%s-%s", destdir,
1509                  conf_name, ast_channel_uniqueid(user->chan));
1510
1511         res = ast_play_and_record(user->chan,
1512                 "vm-rec-name",
1513                 user->name_rec_location,
1514                 10,
1515                 "sln",
1516                 &duration,
1517                 NULL,
1518                 ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE),
1519                 0,
1520                 NULL);
1521
1522         if (res == -1) {
1523                 user->name_rec_location[0] = '\0';
1524                 return -1;
1525         }
1526         return 0;
1527 }
1528
1529 /*! \brief The ConfBridge application */
1530 static int confbridge_exec(struct ast_channel *chan, const char *data)
1531 {
1532         int res = 0, volume_adjustments[2];
1533         int quiet = 0;
1534         char *parse;
1535         const char *b_profile_name = NULL;
1536         const char *u_profile_name = NULL;
1537         const char *menu_profile_name = NULL;
1538         struct confbridge_conference *conference = NULL;
1539         struct confbridge_user user = {
1540                 .chan = chan,
1541                 .tech_args.talking_threshold = DEFAULT_TALKING_THRESHOLD,
1542                 .tech_args.silence_threshold = DEFAULT_SILENCE_THRESHOLD,
1543                 .tech_args.drop_silence = 0,
1544         };
1545         AST_DECLARE_APP_ARGS(args,
1546                 AST_APP_ARG(conf_name);
1547                 AST_APP_ARG(b_profile_name);
1548                 AST_APP_ARG(u_profile_name);
1549                 AST_APP_ARG(menu_profile_name);
1550         );
1551
1552         if (ast_channel_state(chan) != AST_STATE_UP) {
1553                 ast_answer(chan);
1554         }
1555
1556         if (ast_bridge_features_init(&user.features)) {
1557                 res = -1;
1558                 goto confbridge_cleanup;
1559         }
1560
1561         if (ast_strlen_zero(data)) {
1562                 ast_log(LOG_WARNING, "%s requires an argument (conference name[,options])\n", app);
1563                 res = -1;
1564                 goto confbridge_cleanup;
1565         }
1566
1567         /* We need to make a copy of the input string if we are going to modify it! */
1568         parse = ast_strdupa(data);
1569
1570         AST_STANDARD_APP_ARGS(args, parse);
1571
1572         /* bridge profile name */
1573         if (args.argc > 1 && !ast_strlen_zero(args.b_profile_name)) {
1574                 b_profile_name = args.b_profile_name;
1575         }
1576         if (!conf_find_bridge_profile(chan, b_profile_name, &user.b_profile)) {
1577                 ast_log(LOG_WARNING, "Conference bridge profile %s does not exist\n", b_profile_name ?
1578                         b_profile_name : DEFAULT_BRIDGE_PROFILE);
1579                 res = -1;
1580                 goto confbridge_cleanup;
1581         }
1582
1583         /* user profile name */
1584         if (args.argc > 2 && !ast_strlen_zero(args.u_profile_name)) {
1585                 u_profile_name = args.u_profile_name;
1586         }
1587         if (!conf_find_user_profile(chan, u_profile_name, &user.u_profile)) {
1588                 ast_log(LOG_WARNING, "Conference user profile %s does not exist\n", u_profile_name ?
1589                         u_profile_name : DEFAULT_USER_PROFILE);
1590                 res = -1;
1591                 goto confbridge_cleanup;
1592         }
1593
1594         quiet = ast_test_flag(&user.u_profile, USER_OPT_QUIET);
1595
1596         /* ask for a PIN immediately after finding user profile.  This has to be
1597          * prompted for requardless of quiet setting. */
1598         if (!ast_strlen_zero(user.u_profile.pin)) {
1599                 if (conf_get_pin(chan, &user)) {
1600                         res = -1; /* invalid PIN */
1601                         goto confbridge_cleanup;
1602                 }
1603         }
1604
1605         /* See if we need them to record a intro name */
1606         if (!quiet && ast_test_flag(&user.u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE)) {
1607                 conf_rec_name(&user, args.conf_name);
1608         }
1609
1610         /* menu name */
1611         if (args.argc > 3 && !ast_strlen_zero(args.menu_profile_name)) {
1612                 menu_profile_name = args.menu_profile_name;
1613         }
1614
1615         if (conf_set_menu_to_user(chan, &user, menu_profile_name)) {
1616                 ast_log(LOG_WARNING, "Conference menu profile %s does not exist\n", menu_profile_name ?
1617                         menu_profile_name : DEFAULT_MENU_PROFILE);
1618                 res = -1;
1619                 goto confbridge_cleanup;
1620         }
1621
1622         /* Set if DTMF should pass through for this user or not */
1623         if (ast_test_flag(&user.u_profile, USER_OPT_DTMF_PASS)) {
1624                 user.features.dtmf_passthrough = 1;
1625         } else {
1626                 user.features.dtmf_passthrough = 0;
1627         }
1628
1629         /* Set dsp threshold values if present */
1630         if (user.u_profile.talking_threshold) {
1631                 user.tech_args.talking_threshold = user.u_profile.talking_threshold;
1632         }
1633         if (user.u_profile.silence_threshold) {
1634                 user.tech_args.silence_threshold = user.u_profile.silence_threshold;
1635         }
1636
1637         /* Set a talker indicate call back if talking detection is requested */
1638         if (ast_test_flag(&user.u_profile, USER_OPT_TALKER_DETECT)) {
1639                 char *conf_name = ast_strdup(args.conf_name); /* this is freed during feature cleanup */
1640
1641                 if (!conf_name) {
1642                         res = -1;
1643                         goto confbridge_cleanup;
1644                 }
1645                 if (ast_bridge_talk_detector_hook(&user.features, conf_handle_talker_cb,
1646                         conf_name, conf_handle_talker_destructor, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
1647                         ast_free(conf_name);
1648                         res = -1;
1649                         goto confbridge_cleanup;
1650                 }
1651         }
1652
1653         /* Look for a conference bridge matching the provided name */
1654         if (!(conference = join_conference_bridge(args.conf_name, &user))) {
1655                 res = -1;
1656                 goto confbridge_cleanup;
1657         }
1658
1659         /* Keep a copy of volume adjustments so we can restore them later if need be */
1660         volume_adjustments[0] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_READ);
1661         volume_adjustments[1] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_WRITE);
1662
1663         /* If the caller should be joined already muted, make it so */
1664         if (ast_test_flag(&user.u_profile, USER_OPT_STARTMUTED)) {
1665                 /* Set user level mute request. */
1666                 user.muted = 1;
1667         }
1668
1669         if (ast_test_flag(&user.u_profile, USER_OPT_DROP_SILENCE)) {
1670                 user.tech_args.drop_silence = 1;
1671         }
1672
1673         if (ast_test_flag(&user.u_profile, USER_OPT_JITTERBUFFER)) {
1674                 char *func_jb;
1675                 if ((func_jb = ast_module_helper("", "func_jitterbuffer", 0, 0, 0, 0))) {
1676                         ast_free(func_jb);
1677                         ast_func_write(chan, "JITTERBUFFER(adaptive)", "default");
1678                 }
1679         }
1680
1681         if (ast_test_flag(&user.u_profile, USER_OPT_DENOISE)) {
1682                 char *mod_speex;
1683                 /* Reduce background noise from each participant */
1684                 if ((mod_speex = ast_module_helper("", "codec_speex", 0, 0, 0, 0))) {
1685                         ast_free(mod_speex);
1686                         ast_func_write(chan, "DENOISE(rx)", "on");
1687                 }
1688         }
1689
1690         /* if this user has a intro, play it before entering */
1691         if (!ast_strlen_zero(user.name_rec_location)) {
1692                 ast_autoservice_start(chan);
1693                 play_sound_file(conference, user.name_rec_location);
1694                 play_sound_file(conference,
1695                         conf_get_sound(CONF_SOUND_HAS_JOINED, user.b_profile.sounds));
1696                 ast_autoservice_stop(chan);
1697         }
1698
1699         /* Play the Join sound to both the conference and the user entering. */
1700         if (!quiet) {
1701                 const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, user.b_profile.sounds);
1702
1703                 ast_stream_and_wait(chan, join_sound, "");
1704                 ast_autoservice_start(chan);
1705                 play_sound_file(conference, join_sound);
1706                 ast_autoservice_stop(chan);
1707         }
1708
1709         /* See if we need to automatically set this user as a video source or not */
1710         handle_video_on_join(conference, user.chan, ast_test_flag(&user.u_profile, USER_OPT_MARKEDUSER));
1711
1712         conf_moh_unsuspend(&user);
1713
1714         /* Join our conference bridge for real */
1715         send_join_event(user.chan, conference);
1716         ast_bridge_join(conference->bridge,
1717                 chan,
1718                 NULL,
1719                 &user.features,
1720                 &user.tech_args,
1721                 0);
1722         send_leave_event(user.chan, conference);
1723
1724         /* if we're shutting down, don't attempt to do further processing */
1725         if (ast_shutting_down()) {
1726                 leave_conference(&user);
1727                 conference = NULL;
1728                 goto confbridge_cleanup;
1729         }
1730
1731         /* If this user was a video source, we need to clean up and possibly pick a new source. */
1732         handle_video_on_exit(conference, user.chan);
1733
1734         /* if this user has a intro, play it when leaving */
1735         if (!quiet && !ast_strlen_zero(user.name_rec_location)) {
1736                 ast_autoservice_start(chan);
1737                 play_sound_file(conference, user.name_rec_location);
1738                 play_sound_file(conference,
1739                         conf_get_sound(CONF_SOUND_HAS_LEFT, user.b_profile.sounds));
1740                 ast_autoservice_stop(chan);
1741         }
1742
1743         /* play the leave sound */
1744         if (!quiet) {
1745                 const char *leave_sound = conf_get_sound(CONF_SOUND_LEAVE, user.b_profile.sounds);
1746                 ast_autoservice_start(chan);
1747                 play_sound_file(conference, leave_sound);
1748                 ast_autoservice_stop(chan);
1749         }
1750
1751         /* Easy as pie, depart this channel from the conference bridge */
1752         leave_conference(&user);
1753         conference = NULL;
1754
1755         /* If the user was kicked from the conference play back the audio prompt for it */
1756         if (!quiet && user.kicked) {
1757                 res = ast_stream_and_wait(chan,
1758                         conf_get_sound(CONF_SOUND_KICKED, user.b_profile.sounds),
1759                         "");
1760         }
1761
1762         /* Restore volume adjustments to previous values in case they were changed */
1763         if (volume_adjustments[0]) {
1764                 ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_READ, volume_adjustments[0]);
1765         }
1766         if (volume_adjustments[1]) {
1767                 ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_WRITE, volume_adjustments[1]);
1768         }
1769
1770         if (!ast_strlen_zero(user.name_rec_location)) {
1771                 ast_filedelete(user.name_rec_location, NULL);
1772         }
1773
1774 confbridge_cleanup:
1775         ast_bridge_features_cleanup(&user.features);
1776         conf_bridge_profile_destroy(&user.b_profile);
1777         return res;
1778 }
1779
1780 static int action_toggle_mute(struct confbridge_conference *conference,
1781         struct confbridge_user *user,
1782         struct ast_channel *chan)
1783 {
1784         int mute;
1785
1786         /* Toggle user level mute request. */
1787         mute = !user->muted;
1788         user->muted = mute;
1789
1790         conf_update_user_mute(user);
1791         ast_test_suite_event_notify("CONF_MUTE",
1792                 "Message: participant %s %s\r\n"
1793                 "Conference: %s\r\n"
1794                 "Channel: %s",
1795                 ast_channel_name(chan),
1796                 mute ? "muted" : "unmuted",
1797                 user->b_profile.name,
1798                 ast_channel_name(chan));
1799         if (mute) {
1800                 send_mute_event(chan, conference);
1801         } else {
1802                 send_unmute_event(chan, conference);
1803         }
1804
1805         return ast_stream_and_wait(chan, (mute ?
1806                 conf_get_sound(CONF_SOUND_MUTED, user->b_profile.sounds) :
1807                 conf_get_sound(CONF_SOUND_UNMUTED, user->b_profile.sounds)),
1808                 "");
1809 }
1810
1811 static int action_toggle_mute_participants(struct confbridge_conference *conference, struct confbridge_user *user)
1812 {
1813         struct confbridge_user *cur_user = NULL;
1814         const char *sound_to_play;
1815         int mute;
1816
1817         ao2_lock(conference);
1818
1819         /* Toggle bridge level mute request. */
1820         mute = !conference->muted;
1821         conference->muted = mute;
1822
1823         AST_LIST_TRAVERSE(&conference->active_list, cur_user, list) {
1824                 if (!ast_test_flag(&cur_user->u_profile, USER_OPT_ADMIN)) {
1825                         /* Set user level to bridge level mute request. */
1826                         cur_user->muted = mute;
1827                         conf_update_user_mute(cur_user);
1828                 }
1829         }
1830
1831         ao2_unlock(conference);
1832
1833         sound_to_play = conf_get_sound((mute ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED),
1834                 user->b_profile.sounds);
1835
1836         /* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */
1837         ast_stream_and_wait(user->chan, sound_to_play, "");
1838
1839         /* Announce to the group that all participants are muted */
1840         ast_autoservice_start(user->chan);
1841         play_sound_helper(conference, sound_to_play, 0);
1842         ast_autoservice_stop(user->chan);
1843
1844         return 0;
1845 }
1846
1847 static int action_playback(struct ast_bridge_channel *bridge_channel, const char *playback_file)
1848 {
1849         char *file_copy = ast_strdupa(playback_file);
1850         char *file = NULL;
1851
1852         while ((file = strsep(&file_copy, "&"))) {
1853                 if (ast_stream_and_wait(bridge_channel->chan, file, "")) {
1854                         ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
1855                         return -1;
1856                 }
1857         }
1858         return 0;
1859 }
1860
1861 static int action_playback_and_continue(struct confbridge_conference *conference,
1862         struct confbridge_user *user,
1863         struct ast_bridge_channel *bridge_channel,
1864         struct conf_menu *menu,
1865         const char *playback_file,
1866         const char *cur_dtmf,
1867         int *stop_prompts)
1868 {
1869         int i;
1870         int digit = 0;
1871         char dtmf[MAXIMUM_DTMF_FEATURE_STRING];
1872         struct conf_menu_entry new_menu_entry = { { 0, }, };
1873         char *file_copy = ast_strdupa(playback_file);
1874         char *file = NULL;
1875
1876         while ((file = strsep(&file_copy, "&"))) {
1877                 if (ast_streamfile(bridge_channel->chan, file, ast_channel_language(bridge_channel->chan))) {
1878                         ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
1879                         return -1;
1880                 }
1881
1882                 /* now wait for more digits. */
1883                 if (!(digit = ast_waitstream(bridge_channel->chan, AST_DIGIT_ANY))) {
1884                         /* streaming finished and no DTMF was entered */
1885                         continue;
1886                 } else if (digit == -1) {
1887                         /* error */
1888                         return -1;
1889                 } else {
1890                         break; /* dtmf was entered */
1891                 }
1892         }
1893         if (!digit) {
1894                 /* streaming finished on all files and no DTMF was entered */
1895                 return -1;
1896         }
1897         ast_stopstream(bridge_channel->chan);
1898
1899         /* If we get here, then DTMF has been entered, This means no
1900          * additional prompts should be played for this menu entry */
1901         *stop_prompts = 1;
1902
1903         /* If a digit was pressed during the payback, update
1904          * the dtmf string and look for a new menu entry in the
1905          * menu structure */
1906         ast_copy_string(dtmf, cur_dtmf, sizeof(dtmf));
1907         for (i = 0; i < (MAXIMUM_DTMF_FEATURE_STRING - 1); i++) {
1908                 dtmf[i] = cur_dtmf[i];
1909                 if (!dtmf[i]) {
1910                         dtmf[i] = (char) digit;
1911                         dtmf[i + 1] = '\0';
1912                         i = -1;
1913                         break;
1914                 }
1915         }
1916         /* If i is not -1 then the new dtmf digit was _NOT_ added to the string.
1917          * If this is the case, no new DTMF sequence should be looked for. */
1918         if (i != -1) {
1919                 return 0;
1920         }
1921
1922         if (conf_find_menu_entry_by_sequence(dtmf, menu, &new_menu_entry)) {
1923                 execute_menu_entry(conference,
1924                         user,
1925                         bridge_channel,
1926                         &new_menu_entry, menu);
1927                 conf_menu_entry_destroy(&new_menu_entry);
1928         }
1929         return 0;
1930 }
1931
1932 static int action_kick_last(struct confbridge_conference *conference,
1933         struct ast_bridge_channel *bridge_channel,
1934         struct confbridge_user *user)
1935 {
1936         struct confbridge_user *last_user = NULL;
1937         int isadmin = ast_test_flag(&user->u_profile, USER_OPT_ADMIN);
1938
1939         if (!isadmin) {
1940                 ast_stream_and_wait(bridge_channel->chan,
1941                         conf_get_sound(CONF_SOUND_ERROR_MENU, user->b_profile.sounds),
1942                         "");
1943                 ast_log(LOG_WARNING, "Only admin users can use the kick_last menu action. Channel %s of conf %s is not an admin.\n",
1944                         ast_channel_name(bridge_channel->chan),
1945                         conference->name);
1946                 return -1;
1947         }
1948
1949         ao2_lock(conference);
1950         if (((last_user = AST_LIST_LAST(&conference->active_list)) == user)
1951                 || (ast_test_flag(&last_user->u_profile, USER_OPT_ADMIN))) {
1952                 ao2_unlock(conference);
1953                 ast_stream_and_wait(bridge_channel->chan,
1954                         conf_get_sound(CONF_SOUND_ERROR_MENU, user->b_profile.sounds),
1955                         "");
1956         } else if (last_user) {
1957                 last_user->kicked = 1;
1958                 ast_bridge_remove(conference->bridge, last_user->chan);
1959                 ao2_unlock(conference);
1960         }
1961         return 0;
1962 }
1963
1964 static int action_dialplan_exec(struct ast_bridge_channel *bridge_channel, struct conf_menu_action *menu_action)
1965 {
1966         struct ast_pbx_args args;
1967         struct ast_pbx *pbx;
1968         char *exten;
1969         char *context;
1970         int priority;
1971         int res;
1972
1973         memset(&args, 0, sizeof(args));
1974         args.no_hangup_chan = 1;
1975
1976         ast_channel_lock(bridge_channel->chan);
1977
1978         /*save off*/
1979         exten = ast_strdupa(ast_channel_exten(bridge_channel->chan));
1980         context = ast_strdupa(ast_channel_context(bridge_channel->chan));
1981         priority = ast_channel_priority(bridge_channel->chan);
1982         pbx = ast_channel_pbx(bridge_channel->chan);
1983         ast_channel_pbx_set(bridge_channel->chan, NULL);
1984
1985         /*set new*/
1986         ast_channel_exten_set(bridge_channel->chan, menu_action->data.dialplan_args.exten);
1987         ast_channel_context_set(bridge_channel->chan, menu_action->data.dialplan_args.context);
1988         ast_channel_priority_set(bridge_channel->chan, menu_action->data.dialplan_args.priority);
1989
1990         ast_channel_unlock(bridge_channel->chan);
1991
1992         /*execute*/
1993         res = ast_pbx_run_args(bridge_channel->chan, &args);
1994
1995         /*restore*/
1996         ast_channel_lock(bridge_channel->chan);
1997
1998         ast_channel_exten_set(bridge_channel->chan, exten);
1999         ast_channel_context_set(bridge_channel->chan, context);
2000         ast_channel_priority_set(bridge_channel->chan, priority);
2001         ast_channel_pbx_set(bridge_channel->chan, pbx);
2002
2003         ast_channel_unlock(bridge_channel->chan);
2004
2005         return res;
2006 }
2007
2008 static int execute_menu_entry(struct confbridge_conference *conference,
2009         struct confbridge_user *user,
2010         struct ast_bridge_channel *bridge_channel,
2011         struct conf_menu_entry *menu_entry,
2012         struct conf_menu *menu)
2013 {
2014         struct conf_menu_action *menu_action;
2015         int isadmin = ast_test_flag(&user->u_profile, USER_OPT_ADMIN);
2016         int stop_prompts = 0;
2017         int res = 0;
2018
2019         AST_LIST_TRAVERSE(&menu_entry->actions, menu_action, action) {
2020                 switch (menu_action->id) {
2021                 case MENU_ACTION_TOGGLE_MUTE:
2022                         res |= action_toggle_mute(conference,
2023                                 user,
2024                                 bridge_channel->chan);
2025                         break;
2026                 case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS:
2027                         if (!isadmin) {
2028                                 break;
2029                         }
2030                         action_toggle_mute_participants(conference, user);
2031                         break;
2032                 case MENU_ACTION_PARTICIPANT_COUNT:
2033                         announce_user_count(conference, user);
2034                         break;
2035                 case MENU_ACTION_PLAYBACK:
2036                         if (!stop_prompts) {
2037                                 res |= action_playback(bridge_channel, menu_action->data.playback_file);
2038                                 ast_test_suite_event_notify("CONF_MENU_PLAYBACK",
2039                                         "Message: %s\r\nChannel: %s",
2040                                         menu_action->data.playback_file, ast_channel_name(bridge_channel->chan));
2041                         }
2042                         break;
2043                 case MENU_ACTION_RESET_LISTENING:
2044                         ast_audiohook_volume_set(user->chan, AST_AUDIOHOOK_DIRECTION_WRITE, 0);
2045                         break;
2046                 case MENU_ACTION_RESET_TALKING:
2047                         ast_audiohook_volume_set(user->chan, AST_AUDIOHOOK_DIRECTION_READ, 0);
2048                         break;
2049                 case MENU_ACTION_INCREASE_LISTENING:
2050                         ast_audiohook_volume_adjust(user->chan,
2051                                 AST_AUDIOHOOK_DIRECTION_WRITE, 1);
2052                         break;
2053                 case MENU_ACTION_DECREASE_LISTENING:
2054                         ast_audiohook_volume_adjust(user->chan,
2055                                 AST_AUDIOHOOK_DIRECTION_WRITE, -1);
2056                         break;
2057                 case MENU_ACTION_INCREASE_TALKING:
2058                         ast_audiohook_volume_adjust(user->chan,
2059                                 AST_AUDIOHOOK_DIRECTION_READ, 1);
2060                         break;
2061                 case MENU_ACTION_DECREASE_TALKING:
2062                         ast_audiohook_volume_adjust(user->chan,
2063                                 AST_AUDIOHOOK_DIRECTION_READ, -1);
2064                         break;
2065                 case MENU_ACTION_PLAYBACK_AND_CONTINUE:
2066                         if (!(stop_prompts)) {
2067                                 res |= action_playback_and_continue(conference,
2068                                         user,
2069                                         bridge_channel,
2070                                         menu,
2071                                         menu_action->data.playback_file,
2072                                         menu_entry->dtmf,
2073                                         &stop_prompts);
2074                         }
2075                         break;
2076                 case MENU_ACTION_DIALPLAN_EXEC:
2077                         res |= action_dialplan_exec(bridge_channel, menu_action);
2078                         break;
2079                 case MENU_ACTION_ADMIN_TOGGLE_LOCK:
2080                         if (!isadmin) {
2081                                 break;
2082                         }
2083                         conference->locked = (!conference->locked ? 1 : 0);
2084                         res |= ast_stream_and_wait(bridge_channel->chan,
2085                                 (conference->locked ?
2086                                 conf_get_sound(CONF_SOUND_LOCKED_NOW, user->b_profile.sounds) :
2087                                 conf_get_sound(CONF_SOUND_UNLOCKED_NOW, user->b_profile.sounds)),
2088                                 "");
2089
2090                         break;
2091                 case MENU_ACTION_ADMIN_KICK_LAST:
2092                         res |= action_kick_last(conference, bridge_channel, user);
2093                         break;
2094                 case MENU_ACTION_LEAVE:
2095                         ao2_lock(conference);
2096                         ast_bridge_remove(conference->bridge, bridge_channel->chan);
2097                         ast_test_suite_event_notify("CONF_MENU_LEAVE",
2098                                 "Channel: %s",
2099                                 ast_channel_name(bridge_channel->chan));
2100                         ao2_unlock(conference);
2101                         break;
2102                 case MENU_ACTION_NOOP:
2103                         break;
2104                 case MENU_ACTION_SET_SINGLE_VIDEO_SRC:
2105                         ao2_lock(conference);
2106                         ast_bridge_set_single_src_video_mode(conference->bridge, bridge_channel->chan);
2107                         ao2_unlock(conference);
2108                         break;
2109                 case MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC:
2110                         handle_video_on_exit(conference, bridge_channel->chan);
2111                         break;
2112                 }
2113         }
2114         return res;
2115 }
2116
2117 int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel,
2118         struct confbridge_user *user,
2119         struct conf_menu_entry *menu_entry,
2120         struct conf_menu *menu)
2121 {
2122         /* See if music on hold is playing */
2123         conf_moh_suspend(user);
2124
2125         /* execute the list of actions associated with this menu entry */
2126         execute_menu_entry(user->conference, user, bridge_channel, menu_entry, menu);
2127
2128         /* See if music on hold needs to be started back up again */
2129         conf_moh_unsuspend(user);
2130
2131         return 0;
2132 }
2133
2134 static int kick_conference_participant(struct confbridge_conference *conference, const char *channel)
2135 {
2136         int res = -1;
2137         struct confbridge_user *user = NULL;
2138
2139         SCOPED_AO2LOCK(bridge_lock, conference);
2140         AST_LIST_TRAVERSE(&conference->active_list, user, list) {
2141                 if (!strcasecmp(ast_channel_name(user->chan), channel)) {
2142                         user->kicked = 1;
2143                         ast_bridge_remove(conference->bridge, user->chan);
2144                         return 0;
2145                 } else if (!strcasecmp("all", channel)) {
2146                         user->kicked = 1;
2147                         ast_bridge_remove(conference->bridge, user->chan);
2148                         res = 0;
2149                 }
2150         }
2151         AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
2152                 if (!strcasecmp(ast_channel_name(user->chan), channel)) {
2153                         user->kicked = 1;
2154                         ast_bridge_remove(conference->bridge, user->chan);
2155                         return 0;
2156                 } else if (!strcasecmp("all", channel)) {
2157                         user->kicked = 1;
2158                         ast_bridge_remove(conference->bridge, user->chan);
2159                         res = 0;
2160                 }
2161         }
2162
2163         return res;
2164 }
2165
2166 static char *complete_confbridge_name(const char *line, const char *word, int pos, int state)
2167 {
2168         int which = 0;
2169         struct confbridge_conference *conference;
2170         char *res = NULL;
2171         int wordlen = strlen(word);
2172         struct ao2_iterator iter;
2173
2174         iter = ao2_iterator_init(conference_bridges, 0);
2175         while ((conference = ao2_iterator_next(&iter))) {
2176                 if (!strncasecmp(conference->name, word, wordlen) && ++which > state) {
2177                         res = ast_strdup(conference->name);
2178                         ao2_ref(conference, -1);
2179                         break;
2180                 }
2181                 ao2_ref(conference, -1);
2182         }
2183         ao2_iterator_destroy(&iter);
2184
2185         return res;
2186 }
2187
2188 static char *complete_confbridge_participant(const char *conference_name, const char *line, const char *word, int pos, int state)
2189 {
2190         int which = 0;
2191         RAII_VAR(struct confbridge_conference *, conference, NULL, ao2_cleanup);
2192         struct confbridge_user *user;
2193         char *res = NULL;
2194         int wordlen = strlen(word);
2195
2196         conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
2197         if (!conference) {
2198                 return NULL;
2199         }
2200
2201         {
2202                 SCOPED_AO2LOCK(bridge_lock, conference);
2203                 AST_LIST_TRAVERSE(&conference->active_list, user, list) {
2204                         if (!strncasecmp(ast_channel_name(user->chan), word, wordlen) && ++which > state) {
2205                                 res = ast_strdup(ast_channel_name(user->chan));
2206                                 return res;
2207                         }
2208                 }
2209                 AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
2210                         if (!strncasecmp(ast_channel_name(user->chan), word, wordlen) && ++which > state) {
2211                                 res = ast_strdup(ast_channel_name(user->chan));
2212                                 return res;
2213                         }
2214                 }
2215         }
2216
2217         return NULL;
2218 }
2219
2220 static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2221 {
2222         struct confbridge_conference *conference;
2223
2224         switch (cmd) {
2225         case CLI_INIT:
2226                 e->command = "confbridge kick";
2227                 e->usage =
2228                         "Usage: confbridge kick <conference> <channel>\n"
2229                         "       Kicks a channel out of the conference bridge.\n";
2230                 return NULL;
2231         case CLI_GENERATE:
2232                 if (a->pos == 2) {
2233                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2234                 }
2235                 if (a->pos == 3) {
2236                         return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
2237                 }
2238                 return NULL;
2239         }
2240
2241         if (a->argc != 4) {
2242                 return CLI_SHOWUSAGE;
2243         }
2244
2245         conference = ao2_find(conference_bridges, a->argv[2], OBJ_KEY);
2246         if (!conference) {
2247                 ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
2248                 return CLI_SUCCESS;
2249         }
2250         if (kick_conference_participant(conference, a->argv[3])) {
2251                 ast_cli(a->fd, "No participant named '%s' found!\n", a->argv[3]);
2252                 return CLI_SUCCESS;
2253         }
2254         ao2_ref(conference, -1);
2255         ast_cli(a->fd, "Participant '%s' kicked out of conference '%s'\n", a->argv[3], a->argv[2]);
2256         return CLI_SUCCESS;
2257 }
2258
2259 static void handle_cli_confbridge_list_item(struct ast_cli_args *a, struct confbridge_user *user, int waiting)
2260 {
2261         char flag_str[6 + 1];/* Max flags + terminator */
2262         int pos = 0;
2263
2264         /* Build flags column string. */
2265         if (ast_test_flag(&user->u_profile, USER_OPT_ADMIN)) {
2266                 flag_str[pos++] = 'A';
2267         }
2268         if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
2269                 flag_str[pos++] = 'M';
2270         }
2271         if (ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED)) {
2272                 flag_str[pos++] = 'W';
2273         }
2274         if (ast_test_flag(&user->u_profile, USER_OPT_ENDMARKED)) {
2275                 flag_str[pos++] = 'E';
2276         }
2277         if (user->muted) {
2278                 flag_str[pos++] = 'm';
2279         }
2280         if (waiting) {
2281                 flag_str[pos++] = 'w';
2282         }
2283         flag_str[pos] = '\0';
2284
2285         ast_cli(a->fd, "%-30s %-6s %-16s %-16s %-16s %s\n",
2286                 ast_channel_name(user->chan),
2287                 flag_str,
2288                 user->u_profile.name,
2289                 user->b_profile.name,
2290                 user->menu_name,
2291                 S_COR(ast_channel_caller(user->chan)->id.number.valid,
2292                         ast_channel_caller(user->chan)->id.number.str, "<unknown>"));
2293 }
2294
2295 static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2296 {
2297         struct confbridge_conference *conference;
2298
2299         switch (cmd) {
2300         case CLI_INIT:
2301                 e->command = "confbridge list";
2302                 e->usage =
2303                         "Usage: confbridge list [<name>]\n"
2304                         "       Lists all currently active conference bridges or a specific conference bridge.\n"
2305                         "\n"
2306                         "       When a conference bridge name is provided, flags may be shown for users. Below\n"
2307                         "       are the flags and what they represent.\n"
2308                         "\n"
2309                         "       Flags:\n"
2310                         "         A - The user is an admin\n"
2311                         "         M - The user is a marked user\n"
2312                         "         W - The user must wait for a marked user to join\n"
2313                         "         E - The user will be kicked after the last marked user leaves the conference\n"
2314                         "         m - The user is muted\n"
2315                         "         w - The user is waiting for a marked user to join\n";
2316                 return NULL;
2317         case CLI_GENERATE:
2318                 if (a->pos == 2) {
2319                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2320                 }
2321                 return NULL;
2322         }
2323
2324         if (a->argc == 2) {
2325                 struct ao2_iterator iter;
2326
2327                 ast_cli(a->fd, "Conference Bridge Name           Users  Marked Locked?\n");
2328                 ast_cli(a->fd, "================================ ====== ====== ========\n");
2329                 iter = ao2_iterator_init(conference_bridges, 0);
2330                 while ((conference = ao2_iterator_next(&iter))) {
2331                         ast_cli(a->fd, "%-32s %6i %6i %s\n", conference->name, conference->activeusers + conference->waitingusers, conference->markedusers, (conference->locked ? "locked" : "unlocked"));
2332                         ao2_ref(conference, -1);
2333                 }
2334                 ao2_iterator_destroy(&iter);
2335                 return CLI_SUCCESS;
2336         }
2337
2338         if (a->argc == 3) {
2339                 struct confbridge_user *user;
2340
2341                 conference = ao2_find(conference_bridges, a->argv[2], OBJ_KEY);
2342                 if (!conference) {
2343                         ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
2344                         return CLI_SUCCESS;
2345                 }
2346                 ast_cli(a->fd, "Channel                        Flags  User Profile     Bridge Profile   Menu             CallerID\n");
2347                 ast_cli(a->fd, "============================== ====== ================ ================ ================ ================\n");
2348                 ao2_lock(conference);
2349                 AST_LIST_TRAVERSE(&conference->active_list, user, list) {
2350                         handle_cli_confbridge_list_item(a, user, 0);
2351                 }
2352                 AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
2353                         handle_cli_confbridge_list_item(a, user, 1);
2354                 }
2355                 ao2_unlock(conference);
2356                 ao2_ref(conference, -1);
2357                 return CLI_SUCCESS;
2358         }
2359
2360         return CLI_SHOWUSAGE;
2361 }
2362
2363 /* \internal
2364  * \brief finds a conference by name and locks/unlocks.
2365  *
2366  * \retval 0 success
2367  * \retval -1 conference not found
2368  */
2369 static int generic_lock_unlock_helper(int lock, const char *conference_name)
2370 {
2371         struct confbridge_conference *conference;
2372         int res = 0;
2373
2374         conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
2375         if (!conference) {
2376                 return -1;
2377         }
2378         ao2_lock(conference);
2379         conference->locked = lock;
2380         ast_test_suite_event_notify("CONF_LOCK", "Message: conference %s\r\nConference: %s", conference->locked ? "locked" : "unlocked", conference->b_profile.name);
2381         ao2_unlock(conference);
2382         ao2_ref(conference, -1);
2383
2384         return res;
2385 }
2386
2387 /* \internal
2388  * \brief finds a conference user by channel name and mutes/unmutes them.
2389  *
2390  * \retval 0 success
2391  * \retval -1 conference not found
2392  * \retval -2 user not found
2393  */
2394 static int generic_mute_unmute_helper(int mute, const char *conference_name, const char *chan_name)
2395 {
2396         struct confbridge_conference *conference;
2397         struct confbridge_user *user;
2398         int res = 0;
2399
2400         conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
2401         if (!conference) {
2402                 return -1;
2403         }
2404         ao2_lock(conference);
2405         AST_LIST_TRAVERSE(&conference->active_list, user, list) {
2406                 if (!strncmp(chan_name, ast_channel_name(user->chan), strlen(chan_name))) {
2407                         break;
2408                 }
2409         }
2410         if (user) {
2411                 /* Set user level mute request. */
2412                 user->muted = mute ? 1 : 0;
2413
2414                 conf_update_user_mute(user);
2415                 ast_test_suite_event_notify("CONF_MUTE",
2416                         "Message: participant %s %s\r\n"
2417                         "Conference: %s\r\n"
2418                         "Channel: %s",
2419                         ast_channel_name(user->chan),
2420                         mute ? "muted" : "unmuted",
2421                         conference->b_profile.name,
2422                         ast_channel_name(user->chan));
2423                 if (mute) {
2424                         send_mute_event(user->chan, conference);
2425                 } else {
2426                         send_unmute_event(user->chan, conference);
2427                 }
2428         } else {
2429                 res = -2;;
2430         }
2431         ao2_unlock(conference);
2432         ao2_ref(conference, -1);
2433
2434         return res;
2435 }
2436
2437 static int cli_mute_unmute_helper(int mute, struct ast_cli_args *a)
2438 {
2439         int res = generic_mute_unmute_helper(mute, a->argv[2], a->argv[3]);
2440
2441         if (res == -1) {
2442                 ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
2443                 return -1;
2444         } else if (res == -2) {
2445                 ast_cli(a->fd, "No channel named '%s' found in conference %s\n", a->argv[3], a->argv[2]);
2446                 return -1;
2447         }
2448         ast_cli(a->fd, "%s %s from confbridge %s\n", mute ? "Muting" : "Unmuting", a->argv[3], a->argv[2]);
2449         return 0;
2450 }
2451
2452 static char *handle_cli_confbridge_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2453 {
2454         switch (cmd) {
2455         case CLI_INIT:
2456                 e->command = "confbridge mute";
2457                 e->usage =
2458                         "Usage: confbridge mute <conference> <channel>\n"
2459                         "       Mute a channel in a conference.\n";
2460                 return NULL;
2461         case CLI_GENERATE:
2462                 if (a->pos == 2) {
2463                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2464                 }
2465                 if (a->pos == 3) {
2466                         return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
2467                 }
2468                 return NULL;
2469         }
2470         if (a->argc != 4) {
2471                 return CLI_SHOWUSAGE;
2472         }
2473
2474         cli_mute_unmute_helper(1, a);
2475
2476         return CLI_SUCCESS;
2477 }
2478
2479 static char *handle_cli_confbridge_unmute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2480 {
2481         switch (cmd) {
2482         case CLI_INIT:
2483                 e->command = "confbridge unmute";
2484                 e->usage =
2485                         "Usage: confbridge unmute <conference> <channel>\n"
2486                         "       Unmute a channel in a conference.\n";
2487                 return NULL;
2488         case CLI_GENERATE:
2489                 if (a->pos == 2) {
2490                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2491                 }
2492                 if (a->pos == 3) {
2493                         return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
2494                 }
2495                 return NULL;
2496         }
2497         if (a->argc != 4) {
2498                 return CLI_SHOWUSAGE;
2499         }
2500
2501         cli_mute_unmute_helper(0, a);
2502
2503         return CLI_SUCCESS;
2504 }
2505
2506 static char *handle_cli_confbridge_lock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2507 {
2508         switch (cmd) {
2509         case CLI_INIT:
2510                 e->command = "confbridge lock";
2511                 e->usage =
2512                         "Usage: confbridge lock <conference>\n"
2513                         "       Lock a conference. While locked, no new non-admins\n"
2514                         "       may join the conference.\n";
2515                 return NULL;
2516         case CLI_GENERATE:
2517                 if (a->pos == 2) {
2518                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2519                 }
2520                 return NULL;
2521         }
2522         if (a->argc != 3) {
2523                 return CLI_SHOWUSAGE;
2524         }
2525         if (generic_lock_unlock_helper(1, a->argv[2])) {
2526                 ast_cli(a->fd, "Conference %s is not found\n", a->argv[2]);
2527         } else {
2528                 ast_cli(a->fd, "Conference %s is locked.\n", a->argv[2]);
2529         }
2530         return CLI_SUCCESS;
2531 }
2532
2533 static char *handle_cli_confbridge_unlock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2534 {
2535         switch (cmd) {
2536         case CLI_INIT:
2537                 e->command = "confbridge unlock";
2538                 e->usage =
2539                         "Usage: confbridge unlock <conference>\n"
2540                         "       Unlock a previously locked conference.\n";
2541                 return NULL;
2542         case CLI_GENERATE:
2543                 if (a->pos == 2) {
2544                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2545                 }
2546                 return NULL;
2547         }
2548         if (a->argc != 3) {
2549                 return CLI_SHOWUSAGE;
2550         }
2551         if (generic_lock_unlock_helper(0, a->argv[2])) {
2552                 ast_cli(a->fd, "Conference %s is not found\n", a->argv[2]);
2553         } else {
2554                 ast_cli(a->fd, "Conference %s is unlocked.\n", a->argv[2]);
2555         }
2556         return CLI_SUCCESS;
2557 }
2558
2559 static char *handle_cli_confbridge_start_record(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2560 {
2561         const char *rec_file = NULL;
2562         struct confbridge_conference *conference;
2563
2564         switch (cmd) {
2565         case CLI_INIT:
2566                 e->command = "confbridge record start";
2567                 e->usage =
2568                         "Usage: confbridge record start <conference> <file>\n"
2569                         "       <file> is optional, Otherwise the bridge profile\n"
2570                         "       record file will be used.  If the bridge profile\n"
2571                         "       has no record file specified, a file will automatically\n"
2572                         "       be generated in the monitor directory\n";
2573                 return NULL;
2574         case CLI_GENERATE:
2575                 if (a->pos == 3) {
2576                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2577                 }
2578                 return NULL;
2579         }
2580         if (a->argc < 4) {
2581                 return CLI_SHOWUSAGE;
2582         }
2583         if (a->argc == 5) {
2584                 rec_file = a->argv[4];
2585         }
2586
2587         conference = ao2_find(conference_bridges, a->argv[3], OBJ_KEY);
2588         if (!conference) {
2589                 ast_cli(a->fd, "Conference not found.\n");
2590                 return CLI_FAILURE;
2591         }
2592         ao2_lock(conference);
2593         if (conf_is_recording(conference)) {
2594                 ast_cli(a->fd, "Conference is already being recorded.\n");
2595                 ao2_unlock(conference);
2596                 ao2_ref(conference, -1);
2597                 return CLI_SUCCESS;
2598         }
2599         if (!ast_strlen_zero(rec_file)) {
2600                 ast_copy_string(conference->b_profile.rec_file, rec_file, sizeof(conference->b_profile.rec_file));
2601         }
2602
2603         if (start_conf_record_thread(conference)) {
2604                 ast_cli(a->fd, "Could not start recording due to internal error.\n");
2605                 ao2_unlock(conference);
2606                 ao2_ref(conference, -1);
2607                 return CLI_FAILURE;
2608         }
2609         ao2_unlock(conference);
2610
2611         ast_cli(a->fd, "Recording started\n");
2612         ao2_ref(conference, -1);
2613         return CLI_SUCCESS;
2614 }
2615
2616 static char *handle_cli_confbridge_stop_record(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2617 {
2618         struct confbridge_conference *conference;
2619         int ret;
2620
2621         switch (cmd) {
2622         case CLI_INIT:
2623                 e->command = "confbridge record stop";
2624                 e->usage =
2625                         "Usage: confbridge record stop <conference>\n"
2626                         "       Stop a previously started recording.\n";
2627                 return NULL;
2628         case CLI_GENERATE:
2629                 if (a->pos == 3) {
2630                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2631                 }
2632                 return NULL;
2633         }
2634         if (a->argc != 4) {
2635                 return CLI_SHOWUSAGE;
2636         }
2637
2638         conference = ao2_find(conference_bridges, a->argv[3], OBJ_KEY);
2639         if (!conference) {
2640                 ast_cli(a->fd, "Conference not found.\n");
2641                 return CLI_SUCCESS;
2642         }
2643         ao2_lock(conference);
2644         ret = conf_stop_record(conference);
2645         ao2_unlock(conference);
2646         ast_cli(a->fd, "Recording %sstopped.\n", ret ? "could not be " : "");
2647         ao2_ref(conference, -1);
2648         return CLI_SUCCESS;
2649 }
2650
2651 static struct ast_cli_entry cli_confbridge[] = {
2652         AST_CLI_DEFINE(handle_cli_confbridge_list, "List conference bridges and participants."),
2653         AST_CLI_DEFINE(handle_cli_confbridge_kick, "Kick participants out of conference bridges."),
2654         AST_CLI_DEFINE(handle_cli_confbridge_mute, "Mute a participant."),
2655         AST_CLI_DEFINE(handle_cli_confbridge_unmute, "Unmute a participant."),
2656         AST_CLI_DEFINE(handle_cli_confbridge_lock, "Lock a conference."),
2657         AST_CLI_DEFINE(handle_cli_confbridge_unlock, "Unlock a conference."),
2658         AST_CLI_DEFINE(handle_cli_confbridge_start_record, "Start recording a conference"),
2659         AST_CLI_DEFINE(handle_cli_confbridge_stop_record, "Stop recording a conference."),
2660 };
2661 static struct ast_custom_function confbridge_function = {
2662         .name = "CONFBRIDGE",
2663         .write = func_confbridge_helper,
2664 };
2665
2666 static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
2667 static struct ast_custom_function confbridge_info_function = {
2668         .name = "CONFBRIDGE_INFO",
2669         .read = func_confbridge_info,
2670 };
2671
2672 static void action_confbridgelist_item(struct mansession *s, const char *id_text, struct confbridge_conference *conference, struct confbridge_user *user, int waiting)
2673 {
2674         astman_append(s,
2675                 "Event: ConfbridgeList\r\n"
2676                 "%s"
2677                 "Conference: %s\r\n"
2678                 "CallerIDNum: %s\r\n"
2679                 "CallerIDName: %s\r\n"
2680                 "Channel: %s\r\n"
2681                 "Admin: %s\r\n"
2682                 "MarkedUser: %s\r\n"
2683                 "WaitMarked: %s\r\n"
2684                 "EndMarked: %s\r\n"
2685                 "Waiting: %s\r\n"
2686                 "Muted: %s\r\n"
2687                 "\r\n",
2688                 id_text,
2689                 conference->name,
2690                 S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
2691                 S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
2692                 ast_channel_name(user->chan),
2693                 ast_test_flag(&user->u_profile, USER_OPT_ADMIN) ? "Yes" : "No",
2694                 ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER) ? "Yes" : "No",
2695                 ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED) ? "Yes" : "No",
2696                 ast_test_flag(&user->u_profile, USER_OPT_ENDMARKED) ? "Yes" : "No",
2697                 waiting ? "Yes" : "No",
2698                 user->muted ? "Yes" : "No");
2699 }
2700
2701 static int action_confbridgelist(struct mansession *s, const struct message *m)
2702 {
2703         const char *actionid = astman_get_header(m, "ActionID");
2704         const char *conference_name = astman_get_header(m, "Conference");
2705         struct confbridge_user *user;
2706         struct confbridge_conference *conference;
2707         char id_text[80];
2708         int total = 0;
2709
2710         id_text[0] = '\0';
2711         if (!ast_strlen_zero(actionid)) {
2712                 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", actionid);
2713         }
2714         if (ast_strlen_zero(conference_name)) {
2715                 astman_send_error(s, m, "No Conference name provided.");
2716                 return 0;
2717         }
2718         if (!ao2_container_count(conference_bridges)) {
2719                 astman_send_error(s, m, "No active conferences.");
2720                 return 0;
2721         }
2722         conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
2723         if (!conference) {
2724                 astman_send_error(s, m, "No Conference by that name found.");
2725                 return 0;
2726         }
2727
2728         astman_send_listack(s, m, "Confbridge user list will follow", "start");
2729
2730         ao2_lock(conference);
2731         AST_LIST_TRAVERSE(&conference->active_list, user, list) {
2732                 total++;
2733                 action_confbridgelist_item(s, id_text, conference, user, 0);
2734         }
2735         AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
2736                 total++;
2737                 action_confbridgelist_item(s, id_text, conference, user, 1);
2738         }
2739         ao2_unlock(conference);
2740         ao2_ref(conference, -1);
2741
2742         astman_append(s,
2743         "Event: ConfbridgeListComplete\r\n"
2744         "EventList: Complete\r\n"
2745         "ListItems: %d\r\n"
2746         "%s"
2747         "\r\n", total, id_text);
2748
2749         return 0;
2750 }
2751
2752 static int action_confbridgelistrooms(struct mansession *s, const struct message *m)
2753 {
2754         const char *actionid = astman_get_header(m, "ActionID");
2755         struct confbridge_conference *conference;
2756         struct ao2_iterator iter;
2757         char id_text[512] = "";
2758         int totalitems = 0;
2759
2760         if (!ast_strlen_zero(actionid)) {
2761                 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", actionid);
2762         }
2763
2764         if (!ao2_container_count(conference_bridges)) {
2765                 astman_send_error(s, m, "No active conferences.");
2766                 return 0;
2767         }
2768
2769         astman_send_listack(s, m, "Confbridge conferences will follow", "start");
2770
2771         /* Traverse the conference list */
2772         iter = ao2_iterator_init(conference_bridges, 0);
2773         while ((conference = ao2_iterator_next(&iter))) {
2774                 totalitems++;
2775
2776                 ao2_lock(conference);
2777                 astman_append(s,
2778                 "Event: ConfbridgeListRooms\r\n"
2779                 "%s"
2780                 "Conference: %s\r\n"
2781                 "Parties: %d\r\n"
2782                 "Marked: %d\r\n"
2783                 "Locked: %s\r\n"
2784                 "\r\n",
2785                 id_text,
2786                 conference->name,
2787                 conference->activeusers + conference->waitingusers,
2788                 conference->markedusers,
2789                 conference->locked ? "Yes" : "No");
2790                 ao2_unlock(conference);
2791
2792                 ao2_ref(conference, -1);
2793         }
2794         ao2_iterator_destroy(&iter);
2795
2796         /* Send final confirmation */
2797         astman_append(s,
2798         "Event: ConfbridgeListRoomsComplete\r\n"
2799         "EventList: Complete\r\n"
2800         "ListItems: %d\r\n"
2801         "%s"
2802         "\r\n", totalitems, id_text);
2803         return 0;
2804 }
2805
2806 static int action_mute_unmute_helper(struct mansession *s, const struct message *m, int mute)
2807 {
2808         const char *conference_name = astman_get_header(m, "Conference");
2809         const char *channel_name = astman_get_header(m, "Channel");
2810         int res = 0;
2811
2812         if (ast_strlen_zero(conference_name)) {
2813                 astman_send_error(s, m, "No Conference name provided.");
2814                 return 0;
2815         }
2816         if (ast_strlen_zero(channel_name)) {
2817                 astman_send_error(s, m, "No channel name provided.");
2818                 return 0;
2819         }
2820         if (!ao2_container_count(conference_bridges)) {
2821                 astman_send_error(s, m, "No active conferences.");
2822                 return 0;
2823         }
2824
2825         res = generic_mute_unmute_helper(mute, conference_name, channel_name);
2826
2827         if (res == -1) {
2828                 astman_send_error(s, m, "No Conference by that name found.");
2829                 return 0;
2830         } else if (res == -2) {
2831                 astman_send_error(s, m, "No Channel by that name found in Conference.");
2832                 return 0;
2833         }
2834
2835         astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
2836         return 0;
2837 }
2838
2839 static int action_confbridgeunmute(struct mansession *s, const struct message *m)
2840 {
2841         return action_mute_unmute_helper(s, m, 0);
2842 }
2843 static int action_confbridgemute(struct mansession *s, const struct message *m)
2844 {
2845         return action_mute_unmute_helper(s, m, 1);
2846 }
2847
2848 static int action_lock_unlock_helper(struct mansession *s, const struct message *m, int lock)
2849 {
2850         const char *conference_name = astman_get_header(m, "Conference");
2851         int res = 0;
2852
2853         if (ast_strlen_zero(conference_name)) {
2854                 astman_send_error(s, m, "No Conference name provided.");
2855                 return 0;
2856         }
2857         if (!ao2_container_count(conference_bridges)) {
2858                 astman_send_error(s, m, "No active conferences.");
2859                 return 0;
2860         }
2861         if ((res = generic_lock_unlock_helper(lock, conference_name))) {
2862                 astman_send_error(s, m, "No Conference by that name found.");
2863                 return 0;
2864         }
2865         astman_send_ack(s, m, lock ? "Conference locked" : "Conference unlocked");
2866         return 0;
2867 }
2868 static int action_confbridgeunlock(struct mansession *s, const struct message *m)
2869 {
2870         return action_lock_unlock_helper(s, m, 0);
2871 }
2872 static int action_confbridgelock(struct mansession *s, const struct message *m)
2873 {
2874         return action_lock_unlock_helper(s, m, 1);
2875 }
2876
2877 static int action_confbridgekick(struct mansession *s, const struct message *m)
2878 {
2879         const char *conference_name = astman_get_header(m, "Conference");
2880         const char *channel = astman_get_header(m, "Channel");
2881         struct confbridge_conference *conference;
2882         int found = 0;
2883
2884         if (ast_strlen_zero(conference_name)) {
2885                 astman_send_error(s, m, "No Conference name provided.");
2886                 return 0;
2887         }
2888         if (!ao2_container_count(conference_bridges)) {
2889                 astman_send_error(s, m, "No active conferences.");
2890                 return 0;
2891         }
2892
2893         conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
2894         if (!conference) {
2895                 astman_send_error(s, m, "No Conference by that name found.");
2896                 return 0;
2897         }
2898
2899         found = !kick_conference_participant(conference, channel);
2900         ao2_ref(conference, -1);
2901
2902         if (found) {
2903                 astman_send_ack(s, m, "User kicked");
2904         } else {
2905                 astman_send_error(s, m, "No Channel by that name found in Conference.");
2906         }
2907         return 0;
2908 }
2909
2910 static int action_confbridgestartrecord(struct mansession *s, const struct message *m)
2911 {
2912         const char *conference_name = astman_get_header(m, "Conference");
2913         const char *recordfile = astman_get_header(m, "RecordFile");
2914         struct confbridge_conference *conference;
2915
2916         if (ast_strlen_zero(conference_name)) {
2917                 astman_send_error(s, m, "No Conference name provided.");
2918                 return 0;
2919         }
2920         if (!ao2_container_count(conference_bridges)) {
2921                 astman_send_error(s, m, "No active conferences.");
2922                 return 0;
2923         }
2924
2925         conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
2926         if (!conference) {
2927                 astman_send_error(s, m, "No Conference by that name found.");
2928                 return 0;
2929         }
2930
2931         ao2_lock(conference);
2932         if (conf_is_recording(conference)) {
2933                 astman_send_error(s, m, "Conference is already being recorded.");
2934                 ao2_unlock(conference);
2935                 ao2_ref(conference, -1);
2936                 return 0;
2937         }
2938
2939         if (!ast_strlen_zero(recordfile)) {
2940                 ast_copy_string(conference->b_profile.rec_file, recordfile, sizeof(conference->b_profile.rec_file));
2941         }
2942
2943         if (start_conf_record_thread(conference)) {
2944                 astman_send_error(s, m, "Internal error starting conference recording.");
2945                 ao2_unlock(conference);
2946                 ao2_ref(conference, -1);
2947                 return 0;
2948         }
2949         ao2_unlock(conference);
2950
2951         ao2_ref(conference, -1);
2952         astman_send_ack(s, m, "Conference Recording Started.");
2953         return 0;
2954 }
2955 static int action_confbridgestoprecord(struct mansession *s, const struct message *m)
2956 {
2957         const char *conference_name = astman_get_header(m, "Conference");
2958         struct confbridge_conference *conference;
2959
2960         if (ast_strlen_zero(conference_name)) {
2961                 astman_send_error(s, m, "No Conference name provided.");
2962                 return 0;
2963         }
2964         if (!ao2_container_count(conference_bridges)) {
2965                 astman_send_error(s, m, "No active conferences.");
2966                 return 0;
2967         }
2968
2969         conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
2970         if (!conference) {
2971                 astman_send_error(s, m, "No Conference by that name found.");
2972                 return 0;
2973         }
2974
2975         ao2_lock(conference);
2976         if (conf_stop_record(conference)) {
2977                 ao2_unlock(conference);
2978                 astman_send_error(s, m, "Internal error while stopping recording.");
2979                 ao2_ref(conference, -1);
2980                 return 0;
2981         }
2982         ao2_unlock(conference);
2983
2984         ao2_ref(conference, -1);
2985         astman_send_ack(s, m, "Conference Recording Stopped.");
2986         return 0;
2987 }
2988
2989 static int action_confbridgesetsinglevideosrc(struct mansession *s, const struct message *m)
2990 {
2991         const char *conference_name = astman_get_header(m, "Conference");
2992         const char *channel = astman_get_header(m, "Channel");
2993         struct confbridge_user *user;
2994         struct confbridge_conference *conference;
2995
2996         if (ast_strlen_zero(conference_name)) {
2997                 astman_send_error(s, m, "No Conference name provided.");
2998                 return 0;
2999         }
3000         if (ast_strlen_zero(channel)) {
3001                 astman_send_error(s, m, "No channel name provided.");
3002                 return 0;
3003         }
3004         if (!ao2_container_count(conference_bridges)) {
3005                 astman_send_error(s, m, "No active conferences.");
3006                 return 0;
3007         }
3008
3009         conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
3010         if (!conference) {
3011                 astman_send_error(s, m, "No Conference by that name found.");
3012                 return 0;
3013         }
3014
3015         /* find channel and set as video src. */
3016         ao2_lock(conference);
3017         AST_LIST_TRAVERSE(&conference->active_list, user, list) {
3018                 if (!strncmp(channel, ast_channel_name(user->chan), strlen(channel))) {
3019                         ast_bridge_set_single_src_video_mode(conference->bridge, user->chan);
3020                         break;
3021                 }
3022         }
3023         ao2_unlock(conference);
3024         ao2_ref(conference, -1);
3025
3026         /* do not access user after conference unlock.  We are just
3027          * using this check to see if it was found or not */
3028         if (!user) {
3029                 astman_send_error(s, m, "No channel by that name found in conference.");
3030                 return 0;
3031         }
3032         astman_send_ack(s, m, "Conference single video source set.");
3033         return 0;
3034 }
3035
3036 static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
3037 {
3038         char *parse;
3039         struct confbridge_conference *conference;
3040         struct confbridge_user *user;
3041         int count = 0;
3042         AST_DECLARE_APP_ARGS(args,
3043                 AST_APP_ARG(type);
3044                 AST_APP_ARG(confno);
3045         );
3046
3047         /* parse all the required arguments and make sure they exist. */
3048         if (ast_strlen_zero(data)) {
3049                 return -1;
3050         }
3051         parse = ast_strdupa(data);
3052         AST_STANDARD_APP_ARGS(args, parse);
3053         if (ast_strlen_zero(args.confno) || ast_strlen_zero(args.type)) {
3054                 return -1;
3055         }
3056         conference = ao2_find(conference_bridges, args.confno, OBJ_KEY);
3057         if (!conference) {
3058                 snprintf(buf, len, "0");
3059                 return 0;
3060         }
3061
3062         /* get the correct count for the type requested */
3063         ao2_lock(conference);
3064         if (!strncasecmp(args.type, "parties", 7)) {
3065                 AST_LIST_TRAVERSE(&conference->active_list, user, list) {
3066                         count++;
3067                 }
3068                 AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
3069                         count++;
3070                 }
3071         } else if (!strncasecmp(args.type, "admins", 6)) {
3072                 AST_LIST_TRAVERSE(&conference->active_list, user, list) {
3073                         if (ast_test_flag(&user->u_profile, USER_OPT_ADMIN)) {
3074                                 count++;
3075                         }
3076                 }
3077         } else if (!strncasecmp(args.type, "marked", 6)) {
3078                 AST_LIST_TRAVERSE(&conference->active_list, user, list) {
3079                         if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
3080                                 count++;
3081                         }
3082                 }
3083         } else if (!strncasecmp(args.type, "locked", 6)) {
3084                 count = conference->locked;
3085         } else {
3086                 ast_log(LOG_ERROR, "Invalid keyword '%s' passed to CONFBRIDGE_INFO.  Should be one of: "
3087                         "parties, admins, marked, or locked.\n", args.type);
3088         }
3089         snprintf(buf, len, "%d", count);
3090         ao2_unlock(conference);
3091         ao2_ref(conference, -1);
3092         return 0;
3093 }
3094
3095 void conf_add_user_active(struct confbridge_conference *conference, struct confbridge_user *user)
3096 {
3097         AST_LIST_INSERT_TAIL(&conference->active_list, user, list);
3098         conference->activeusers++;
3099 }
3100
3101 void conf_add_user_marked(struct confbridge_conference *conference, struct confbridge_user *user)
3102 {
3103         AST_LIST_INSERT_TAIL(&conference->active_list, user, list);
3104         conference->activeusers++;
3105         conference->markedusers++;
3106 }
3107
3108 void conf_add_user_waiting(struct confbridge_conference *conference, struct confbridge_user *user)
3109 {
3110         AST_LIST_INSERT_TAIL(&conference->waiting_list, user, list);
3111         conference->waitingusers++;
3112 }
3113
3114 void conf_remove_user_active(struct confbridge_conference *conference, struct confbridge_user *user)
3115 {
3116         AST_LIST_REMOVE(&conference->active_list, user, list);
3117         conference->activeusers--;
3118 }
3119
3120 void conf_remove_user_marked(struct confbridge_conference *conference, struct confbridge_user *user)
3121 {
3122         AST_LIST_REMOVE(&conference->active_list, user, list);
3123         conference->activeusers--;
3124         conference->markedusers--;
3125 }
3126
3127 void conf_mute_only_active(struct confbridge_conference *conference)
3128 {
3129         struct confbridge_user *only_user = AST_LIST_FIRST(&conference->active_list);
3130
3131         /* Turn on MOH if the single participant is set up for it */
3132         if (ast_test_flag(&only_user->u_profile, USER_OPT_MUSICONHOLD)) {
3133                 conf_moh_start(only_user);
3134         }
3135         conf_update_user_mute(only_user);
3136 }
3137
3138 void conf_remove_user_waiting(struct confbridge_conference *conference, struct confbridge_user *user)
3139 {
3140         AST_LIST_REMOVE(&conference->waiting_list, user, list);
3141         conference->waitingusers--;
3142 }
3143
3144 /*!
3145  * \internal
3146  * \brief Unregister a ConfBridge channel technology.
3147  * \since 12.0.0
3148  *
3149  * \param tech What to unregister.
3150  *
3151  * \return Nothing
3152  */
3153 static void unregister_channel_tech(struct ast_channel_tech *tech)
3154 {
3155         ast_channel_unregister(tech);
3156         tech->capabilities = ast_format_cap_destroy(tech->capabilities);
3157 }
3158
3159 /*!
3160  * \internal
3161  * \brief Register a ConfBridge channel technology.
3162  * \since 12.0.0
3163  *
3164  * \param tech What to register.
3165  *
3166  * \retval 0 on success.
3167  * \retval -1 on error.
3168  */
3169 static int register_channel_tech(struct ast_channel_tech *tech)
3170 {
3171         tech->capabilities = ast_format_cap_alloc(0);
3172         if (!tech->capabilities) {
3173                 return -1;
3174         }
3175         ast_format_cap_add_all(tech->capabilities);
3176         if (ast_channel_register(tech)) {
3177                 ast_log(LOG_ERROR, "Unable to register channel technology %s(%s).\n",
3178                         tech->type, tech->description);
3179                 return -1;
3180         }
3181         return 0;
3182 }
3183
3184 /*! \brief Called when module is being unloaded */
3185 static int unload_module(void)
3186 {
3187         ast_unregister_application(app);