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