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