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