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