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