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