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