Confbridge CLI new record file name check.
[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 conference_bridge_user *user);
309 static int play_sound_number(struct conference_bridge *conference_bridge, int say_number);
310 static int execute_menu_entry(struct conference_bridge *conference_bridge,
311         struct conference_bridge_user *conference_bridge_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 conference_bridge *conference_bridge = obj;
320         return ast_str_case_hash(conference_bridge->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 conference_bridge *conference_bridge0 = obj, *conference_bridge1 = arg;
327         return (!strcasecmp(conference_bridge0->name, conference_bridge1->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 conference_bridge *bridge, struct ast_str **filename, int is_new)
600 {
601         char *rec_file = bridge->b_profile.rec_file;
602         time_t now;
603         char *ext;
604
605         if (ast_str_strlen(*filename) && ast_test_flag(&bridge->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", bridge->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(&bridge->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 conference_bridge *conference_bridge = 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_bridge->record_lock);
654         if (!mixmonapp) {
655                 ast_log(LOG_WARNING, "Can not record ConfBridge, MixMonitor app is not installed\n");
656                 conference_bridge->record_thread = AST_PTHREADT_NULL;
657                 ast_mutex_unlock(&conference_bridge->record_lock);
658                 ao2_ref(conference_bridge, -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_bridge->record_state != CONF_RECORD_EXIT) {
664                 set_rec_filename(conference_bridge, &filename,
665                                  is_new_rec_file(conference_bridge->b_profile.rec_file, &orig_rec_file));
666                 chan = ast_channel_ref(conference_bridge->record_chan);
667                 ast_answer(chan);
668                 pbx_exec(chan, mixmonapp, ast_str_buffer(filename));
669                 ast_bridge_join(conference_bridge->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_bridge->record_cond, &conference_bridge->record_lock);
674         }
675         ast_free(orig_rec_file);
676         ast_mutex_unlock(&conference_bridge->record_lock);
677         ao2_ref(conference_bridge, -1);
678         return NULL;
679 }
680
681 /*! \brief Returns whether or not conference is being recorded.
682  * \param conference_bridge 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 conference_bridge *conference_bridge)
687 {
688         return conference_bridge->record_state == CONF_RECORD_START;
689 }
690
691 /*! \brief Stop recording a conference bridge
692  * \internal
693  * \param conference_bridge 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 conference_bridge *conference_bridge)
698 {
699         struct ast_channel *chan;
700         if (conference_bridge->record_thread == AST_PTHREADT_NULL || !conf_is_recording(conference_bridge)) {
701                 return -1;
702         }
703         conference_bridge->record_state = CONF_RECORD_STOP;
704         chan = ast_channel_ref(conference_bridge->record_chan);
705         ast_bridge_remove(conference_bridge->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_bridge->b_profile.name);
709         send_stop_record_event(conference_bridge->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_bridge locked
719  */
720 static int conf_stop_record_thread(struct conference_bridge *conference_bridge)
721 {
722         if (conference_bridge->record_thread == AST_PTHREADT_NULL) {
723                 return -1;
724         }
725         conf_stop_record(conference_bridge);
726
727         ast_mutex_lock(&conference_bridge->record_lock);
728         conference_bridge->record_state = CONF_RECORD_EXIT;
729         ast_cond_signal(&conference_bridge->record_cond);
730         ast_mutex_unlock(&conference_bridge->record_lock);
731
732         pthread_join(conference_bridge->record_thread, NULL);
733         conference_bridge->record_thread = AST_PTHREADT_NULL;
734
735         /* this is the reference given to the channel during the channel alloc */
736         if (conference_bridge->record_chan) {
737                 conference_bridge->record_chan = ast_channel_unref(conference_bridge->record_chan);
738         }
739
740         return 0;
741 }
742
743 /*! \brief Start recording the conference
744  * \internal
745  * \note conference_bridge must be locked when calling this function
746  * \param conference_bridge The conference bridge to start recording
747  * \retval 0 success
748  * \rteval non-zero failure
749  */
750 static int conf_start_record(struct conference_bridge *conference_bridge)
751 {
752         struct ast_format_cap *cap;
753         struct ast_format tmpfmt;
754         int cause;
755
756         if (conference_bridge->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_bridge->record_chan = ast_request("ConfBridgeRec", cap, NULL, conference_bridge->name, &cause))) {
772                 cap = ast_format_cap_destroy(cap);
773                 return -1;
774         }
775
776         cap = ast_format_cap_destroy(cap);
777
778         conference_bridge->record_state = CONF_RECORD_START;
779         ast_mutex_lock(&conference_bridge->record_lock);
780         ast_cond_signal(&conference_bridge->record_cond);
781         ast_mutex_unlock(&conference_bridge->record_lock);
782         ast_test_suite_event_notify("CONF_START_RECORD", "Message: started conference recording channel\r\nConference: %s", conference_bridge->b_profile.name);
783         send_start_record_event(conference_bridge->name);
784
785         return 0;
786 }
787
788 /*! \brief Start the recording thread on a conference bridge
789  * \internal
790  * \param conference_bridge 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 conference_bridge *conference_bridge)
795 {
796         conf_start_record(conference_bridge);
797
798         /*
799          * if the thread has already been started, don't start another
800          */
801         if (conference_bridge->record_thread != AST_PTHREADT_NULL) {
802                 return 0;
803         }
804
805         ao2_ref(conference_bridge, +1); /* give the record thread a ref */
806
807         if (ast_pthread_create_background(&conference_bridge->record_thread, NULL, record_thread, conference_bridge)) {
808                 ast_log(LOG_WARNING, "Failed to create recording channel for conference %s\n", conference_bridge->name);
809                 ao2_ref(conference_bridge, -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_bridge Conference bridge to peek at
837  * \param conference_bridge_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 conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
843 {
844         const char *other_in_party = conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, conference_bridge->b_profile.sounds);
845         const char *only_one = conf_get_sound(CONF_SOUND_ONLY_ONE, conference_bridge->b_profile.sounds);
846         const char *there_are = conf_get_sound(CONF_SOUND_THERE_ARE, conference_bridge->b_profile.sounds);
847
848         if (conference_bridge->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_bridge->activeusers == 2) {
852                 if (conference_bridge_user) {
853                         /* Eep, there is one other person */
854                         if (ast_stream_and_wait(conference_bridge_user->chan,
855                                 only_one,
856                                 "")) {
857                                 return -1;
858                         }
859                 } else {
860                         play_sound_file(conference_bridge, only_one);
861                 }
862         } else {
863                 /* Alas multiple others in here */
864                 if (conference_bridge_user) {
865                         if (ast_stream_and_wait(conference_bridge_user->chan,
866                                 there_are,
867                                 "")) {
868                                 return -1;
869                         }
870                         if (ast_say_number(conference_bridge_user->chan, conference_bridge->activeusers - 1, "", ast_channel_language(conference_bridge_user->chan), NULL)) {
871                                 return -1;
872                         }
873                         if (ast_stream_and_wait(conference_bridge_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_bridge, there_are);
880                         play_sound_number(conference_bridge, conference_bridge->activeusers - 1);
881                         play_sound_file(conference_bridge, other_in_party);
882                 }
883         }
884         return 0;
885 }
886
887 /*!
888  * \brief Play back an audio file to a channel
889  *
890  * \param cbu 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 conference_bridge_user *cbu, const char *filename)
899 {
900         return ast_stream_and_wait(cbu->chan, filename, "");
901 }
902
903 static void handle_video_on_join(struct conference_bridge *conference_bridge, 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_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED)) {
911                 int set = 1;
912                 struct conference_bridge_user *tmp_user = NULL;
913                 ao2_lock(conference_bridge);
914                 /* see if anyone is already the video src */
915                 AST_LIST_TRAVERSE(&conference_bridge->active_list, tmp_user, list) {
916                         if (tmp_user->chan == chan) {
917                                 continue;
918                         }
919                         if (ast_bridge_is_video_src(conference_bridge->bridge, tmp_user->chan)) {
920                                 set = 0;
921                                 break;
922                         }
923                 }
924                 ao2_unlock(conference_bridge);
925                 if (set) {
926                         ast_bridge_set_single_src_video_mode(conference_bridge->bridge, chan);
927                 }
928         } else if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
929                 /* we joined and are video capable, we override anyone else that may have already been the video feed */
930                 ast_bridge_set_single_src_video_mode(conference_bridge->bridge, chan);
931         }
932 }
933
934 static void handle_video_on_exit(struct conference_bridge *conference_bridge, struct ast_channel *chan)
935 {
936         struct conference_bridge_user *tmp_user = NULL;
937
938         /* if this isn't a video source, nothing to update */
939         if (!ast_bridge_is_video_src(conference_bridge->bridge, chan)) {
940                 return;
941         }
942
943         ast_bridge_remove_video_src(conference_bridge->bridge, chan);
944
945         /* If in follow talker mode, make sure to restore this mode on the
946          * bridge when a source is removed.  It is possible this channel was
947          * only set temporarily as a video source by an AMI or DTMF action. */
948         if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
949                 ast_bridge_set_talker_src_video_mode(conference_bridge->bridge);
950         }
951
952         /* if the video_mode isn't set to automatically pick the video source, do nothing on exit. */
953         if (!ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED) &&
954                 !ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
955                 return;
956         }
957
958         /* Make the next available marked user the video src.  */
959         ao2_lock(conference_bridge);
960         AST_LIST_TRAVERSE(&conference_bridge->active_list, tmp_user, list) {
961                 if (tmp_user->chan == chan) {
962                         continue;
963                 }
964                 if (ast_test_flag(&tmp_user->u_profile, USER_OPT_MARKEDUSER)) {
965                         ast_bridge_set_single_src_video_mode(conference_bridge->bridge, tmp_user->chan);
966                         break;
967                 }
968         }
969         ao2_unlock(conference_bridge);
970 }
971
972 /*!
973  * \brief Destroy a conference bridge
974  *
975  * \param obj The conference bridge object
976  *
977  * \return Returns nothing
978  */
979 static void destroy_conference_bridge(void *obj)
980 {
981         struct conference_bridge *conference_bridge = obj;
982
983         ast_debug(1, "Destroying conference bridge '%s'\n", conference_bridge->name);
984
985         if (conference_bridge->playback_chan) {
986                 struct ast_channel *underlying_channel = ast_channel_tech(conference_bridge->playback_chan)->bridged_channel(conference_bridge->playback_chan, NULL);
987                 if (underlying_channel) {
988                         ast_hangup(underlying_channel);
989                 }
990                 ast_hangup(conference_bridge->playback_chan);
991                 conference_bridge->playback_chan = NULL;
992         }
993
994         /* Destroying a conference bridge is simple, all we have to do is destroy the bridging object */
995         if (conference_bridge->bridge) {
996                 ast_bridge_destroy(conference_bridge->bridge);
997                 conference_bridge->bridge = NULL;
998         }
999
1000         conf_bridge_profile_destroy(&conference_bridge->b_profile);
1001         ast_cond_destroy(&conference_bridge->record_cond);
1002         ast_mutex_destroy(&conference_bridge->record_lock);
1003         ast_mutex_destroy(&conference_bridge->playback_lock);
1004 }
1005
1006 /*! \brief Call the proper join event handler for the user for the conference bridge's current state
1007  * \internal
1008  * \param cbu The conference bridge user that is joining
1009  * \retval 0 success
1010  * \retval -1 failure
1011  */
1012 static int handle_conf_user_join(struct conference_bridge_user *cbu)
1013 {
1014         conference_event_fn handler;
1015         if (ast_test_flag(&cbu->u_profile, USER_OPT_MARKEDUSER)) {
1016                 handler = cbu->conference_bridge->state->join_marked;
1017         } else if (ast_test_flag(&cbu->u_profile, USER_OPT_WAITMARKED)) {
1018                 handler = cbu->conference_bridge->state->join_waitmarked;
1019         } else {
1020                 handler = cbu->conference_bridge->state->join_unmarked;
1021         }
1022
1023         ast_assert(handler != NULL);
1024
1025         if (!handler) {
1026                 conf_invalid_event_fn(cbu);
1027                 return -1;
1028         }
1029
1030         handler(cbu);
1031
1032         return 0;
1033 }
1034
1035 /*! \brief Call the proper leave event handler for the user for the conference bridge's current state
1036  * \internal
1037  * \param cbu The conference bridge user that is leaving
1038  * \retval 0 success
1039  * \retval -1 failure
1040  */
1041 static int handle_conf_user_leave(struct conference_bridge_user *cbu)
1042 {
1043         conference_event_fn handler;
1044         if (ast_test_flag(&cbu->u_profile, USER_OPT_MARKEDUSER)) {
1045                 handler = cbu->conference_bridge->state->leave_marked;
1046         } else if (ast_test_flag(&cbu->u_profile, USER_OPT_WAITMARKED)) {
1047                 handler = cbu->conference_bridge->state->leave_waitmarked;
1048         } else {
1049                 handler = cbu->conference_bridge->state->leave_unmarked;
1050         }
1051
1052         ast_assert(handler != NULL);
1053
1054         if (!handler) {
1055                 /* This should never happen. If it does, though, it is bad. The user will not have been removed
1056                  * from the appropriate list, so counts will be off and stuff. The conference won't be torn down, etc.
1057                  * Shouldn't happen, though. */
1058                 conf_invalid_event_fn(cbu);
1059                 return -1;
1060         }
1061
1062         handler(cbu);
1063
1064         return 0;
1065 }
1066
1067 void conf_moh_stop(struct conference_bridge_user *user)
1068 {
1069         user->playing_moh = 0;
1070         if (!user->suspended_moh) {
1071                 int in_bridge;
1072
1073                 /*
1074                  * Locking the ast_bridge here is the only way to hold off the
1075                  * call to ast_bridge_join() in confbridge_exec() from
1076                  * interfering with the bridge and MOH operations here.
1077                  */
1078                 ast_bridge_lock(user->conference_bridge->bridge);
1079
1080                 /*
1081                  * Temporarily suspend the user from the bridge so we have
1082                  * control to stop MOH if needed.
1083                  */
1084                 in_bridge = !ast_bridge_suspend(user->conference_bridge->bridge, user->chan);
1085                 ast_moh_stop(user->chan);
1086                 if (in_bridge) {
1087                         ast_bridge_unsuspend(user->conference_bridge->bridge, user->chan);
1088                 }
1089
1090                 ast_bridge_unlock(user->conference_bridge->bridge);
1091         }
1092 }
1093
1094 void conf_moh_start(struct conference_bridge_user *user)
1095 {
1096         user->playing_moh = 1;
1097         if (!user->suspended_moh) {
1098                 int in_bridge;
1099
1100                 /*
1101                  * Locking the ast_bridge here is the only way to hold off the
1102                  * call to ast_bridge_join() in confbridge_exec() from
1103                  * interfering with the bridge and MOH operations here.
1104                  */
1105                 ast_bridge_lock(user->conference_bridge->bridge);
1106
1107                 /*
1108                  * Temporarily suspend the user from the bridge so we have
1109                  * control to start MOH if needed.
1110                  */
1111                 in_bridge = !ast_bridge_suspend(user->conference_bridge->bridge, user->chan);
1112                 ast_moh_start(user->chan, user->u_profile.moh_class, NULL);
1113                 if (in_bridge) {
1114                         ast_bridge_unsuspend(user->conference_bridge->bridge, user->chan);
1115                 }
1116
1117                 ast_bridge_unlock(user->conference_bridge->bridge);
1118         }
1119 }
1120
1121 /*!
1122  * \internal
1123  * \brief Unsuspend MOH for the conference user.
1124  *
1125  * \param user Conference user to unsuspend MOH on.
1126  *
1127  * \return Nothing
1128  */
1129 static void conf_moh_unsuspend(struct conference_bridge_user *user)
1130 {
1131         ao2_lock(user->conference_bridge);
1132         if (--user->suspended_moh == 0 && user->playing_moh) {
1133                 ast_moh_start(user->chan, user->u_profile.moh_class, NULL);
1134         }
1135         ao2_unlock(user->conference_bridge);
1136 }
1137
1138 /*!
1139  * \internal
1140  * \brief Suspend MOH for the conference user.
1141  *
1142  * \param user Conference user to suspend MOH on.
1143  *
1144  * \return Nothing
1145  */
1146 static void conf_moh_suspend(struct conference_bridge_user *user)
1147 {
1148         ao2_lock(user->conference_bridge);
1149         if (user->suspended_moh++ == 0 && user->playing_moh) {
1150                 ast_moh_stop(user->chan);
1151         }
1152         ao2_unlock(user->conference_bridge);
1153 }
1154
1155 int conf_handle_first_marked_common(struct conference_bridge_user *cbu)
1156 {
1157         if (!ast_test_flag(&cbu->u_profile, USER_OPT_QUIET) && play_prompt_to_user(cbu, conf_get_sound(CONF_SOUND_PLACE_IN_CONF, cbu->b_profile.sounds))) {
1158                 return -1;
1159         }
1160         return 0;
1161 }
1162
1163 int conf_handle_inactive_waitmarked(struct conference_bridge_user *cbu)
1164 {
1165         /* If we have not been quieted play back that they are waiting for the leader */
1166         if (!ast_test_flag(&cbu->u_profile, USER_OPT_QUIET) && play_prompt_to_user(cbu,
1167                         conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, cbu->b_profile.sounds))) {
1168                 /* user hungup while the sound was playing */
1169                 return -1;
1170         }
1171         return 0;
1172 }
1173
1174 int conf_handle_only_unmarked(struct conference_bridge_user *cbu)
1175 {
1176         /* If audio prompts have not been quieted or this prompt quieted play it on out */
1177         if (!ast_test_flag(&cbu->u_profile, USER_OPT_QUIET | USER_OPT_NOONLYPERSON)) {
1178                 if (play_prompt_to_user(cbu,
1179                         conf_get_sound(CONF_SOUND_ONLY_PERSON, cbu->b_profile.sounds))) {
1180                         /* user hungup while the sound was playing */
1181                         return -1;
1182                 }
1183         }
1184         return 0;
1185 }
1186
1187 int conf_add_post_join_action(struct conference_bridge_user *cbu, int (*func)(struct conference_bridge_user *cbu))
1188 {
1189         struct post_join_action *action;
1190         if (!(action = ast_calloc(1, sizeof(*action)))) {
1191                 return -1;
1192         }
1193         action->func = func;
1194         AST_LIST_INSERT_TAIL(&cbu->post_join_list, action, list);
1195         return 0;
1196 }
1197
1198
1199 void conf_handle_first_join(struct conference_bridge *conference_bridge)
1200 {
1201         ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", conference_bridge->name);
1202 }
1203
1204 void conf_handle_second_active(struct conference_bridge *conference_bridge)
1205 {
1206         /* If we are the second participant we may need to stop music on hold on the first */
1207         struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->active_list);
1208
1209         if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD)) {
1210                 conf_moh_stop(first_participant);
1211         }
1212         if (!ast_test_flag(&first_participant->u_profile, USER_OPT_STARTMUTED)) {
1213                 first_participant->features.mute = 0;
1214         }
1215 }
1216
1217 void conf_ended(struct conference_bridge *conference_bridge)
1218 {
1219         /* Called with a reference to conference_bridge */
1220         ao2_unlink(conference_bridges, conference_bridge);
1221         send_conf_end_event(conference_bridge->name);
1222         conf_stop_record_thread(conference_bridge);
1223 }
1224
1225 /*!
1226  * \brief Join a conference bridge
1227  *
1228  * \param name The conference name
1229  * \param conference_bridge_user Conference bridge user structure
1230  *
1231  * \return A pointer to the conference bridge struct, or NULL if the conference room wasn't found.
1232  */
1233 static struct conference_bridge *join_conference_bridge(const char *name, struct conference_bridge_user *conference_bridge_user)
1234 {
1235         struct conference_bridge *conference_bridge = NULL;
1236         struct post_join_action *action;
1237         struct conference_bridge tmp;
1238         int max_members_reached = 0;
1239
1240         ast_copy_string(tmp.name, name, sizeof(tmp.name));
1241
1242         /* We explictly lock the conference bridges container ourselves so that other callers can not create duplicate conferences at the same */
1243         ao2_lock(conference_bridges);
1244
1245         ast_debug(1, "Trying to find conference bridge '%s'\n", name);
1246
1247         /* Attempt to find an existing conference bridge */
1248         conference_bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
1249
1250         if (conference_bridge && conference_bridge->b_profile.max_members) {
1251                 max_members_reached = conference_bridge->b_profile.max_members > conference_bridge->activeusers ? 0 : 1;
1252         }
1253
1254         /* When finding a conference bridge that already exists make sure that it is not locked, and if so that we are not an admin */
1255         if (conference_bridge && (max_members_reached || conference_bridge->locked) && !ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN)) {
1256                 ao2_unlock(conference_bridges);
1257                 ao2_ref(conference_bridge, -1);
1258                 ast_debug(1, "Conference '%s' is locked and caller is not an admin\n", name);
1259                 ast_stream_and_wait(conference_bridge_user->chan,
1260                                 conf_get_sound(CONF_SOUND_LOCKED, conference_bridge_user->b_profile.sounds),
1261                                 "");
1262                 return NULL;
1263         }
1264
1265         /* If no conference bridge was found see if we can create one */
1266         if (!conference_bridge) {
1267                 /* Try to allocate memory for a new conference bridge, if we fail... this won't end well. */
1268                 if (!(conference_bridge = ao2_alloc(sizeof(*conference_bridge), destroy_conference_bridge))) {
1269                         ao2_unlock(conference_bridges);
1270                         ast_log(LOG_ERROR, "Conference '%s' could not be created.\n", name);
1271                         return NULL;
1272                 }
1273
1274                 /* Setup lock for playback channel */
1275                 ast_mutex_init(&conference_bridge->playback_lock);
1276
1277                 /* Setup lock for the record channel */
1278                 ast_mutex_init(&conference_bridge->record_lock);
1279                 ast_cond_init(&conference_bridge->record_cond, NULL);
1280
1281                 /* Setup conference bridge parameters */
1282                 conference_bridge->record_thread = AST_PTHREADT_NULL;
1283                 ast_copy_string(conference_bridge->name, name, sizeof(conference_bridge->name));
1284                 conf_bridge_profile_copy(&conference_bridge->b_profile, &conference_bridge_user->b_profile);
1285
1286                 /* Create an actual bridge that will do the audio mixing */
1287                 if (!(conference_bridge->bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_MULTIMIX, 0))) {
1288                         ao2_ref(conference_bridge, -1);
1289                         conference_bridge = NULL;
1290                         ao2_unlock(conference_bridges);
1291                         ast_log(LOG_ERROR, "Conference '%s' mixing bridge could not be created.\n", name);
1292                         return NULL;
1293                 }
1294
1295                 /* Set the internal sample rate on the bridge from the bridge profile */
1296                 ast_bridge_set_internal_sample_rate(conference_bridge->bridge, conference_bridge->b_profile.internal_sample_rate);
1297                 /* Set the internal mixing interval on the bridge from the bridge profile */
1298                 ast_bridge_set_mixing_interval(conference_bridge->bridge, conference_bridge->b_profile.mix_interval);
1299
1300                 if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
1301                         ast_bridge_set_talker_src_video_mode(conference_bridge->bridge);
1302                 }
1303
1304                 /* Link it into the conference bridges container */
1305                 if (!ao2_link(conference_bridges, conference_bridge)) {
1306                         ao2_ref(conference_bridge, -1);
1307                         conference_bridge = NULL;
1308                         ao2_unlock(conference_bridges);
1309                         ast_log(LOG_ERROR,
1310                                 "Conference '%s' could not be added to the conferences list.\n", name);
1311                         return NULL;
1312                 }
1313
1314                 /* Set the initial state to EMPTY */
1315                 conference_bridge->state = CONF_STATE_EMPTY;
1316
1317                 conference_bridge->record_state = CONF_RECORD_STOP;
1318                 if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_RECORD_CONFERENCE)) {
1319                         ao2_lock(conference_bridge);
1320                         start_conf_record_thread(conference_bridge);
1321                         ao2_unlock(conference_bridge);
1322                 }
1323
1324                 send_conf_start_event(conference_bridge->name);
1325                 ast_debug(1, "Created conference '%s' and linked to container.\n", name);
1326         }
1327
1328         ao2_unlock(conference_bridges);
1329
1330         /* Setup conference bridge user parameters */
1331         conference_bridge_user->conference_bridge = conference_bridge;
1332
1333         ao2_lock(conference_bridge);
1334
1335         /*
1336          * Suspend any MOH until the user actually joins the bridge of
1337          * the conference.  This way any pre-join file playback does not
1338          * need to worry about MOH.
1339          */
1340         conference_bridge_user->suspended_moh = 1;
1341
1342         if (handle_conf_user_join(conference_bridge_user)) {
1343                 /* Invalid event, nothing was done, so we don't want to process a leave. */
1344                 ao2_unlock(conference_bridge);
1345                 ao2_ref(conference_bridge, -1);
1346                 return NULL;
1347         }
1348
1349         if (ast_check_hangup(conference_bridge_user->chan)) {
1350                 ao2_unlock(conference_bridge);
1351                 leave_conference(conference_bridge_user);
1352                 return NULL;
1353         }
1354
1355         ao2_unlock(conference_bridge);
1356
1357         /* If an announcement is to be played play it */
1358         if (!ast_strlen_zero(conference_bridge_user->u_profile.announcement)) {
1359                 if (play_prompt_to_user(conference_bridge_user,
1360                         conference_bridge_user->u_profile.announcement)) {
1361                         leave_conference(conference_bridge_user);
1362                         return NULL;
1363                 }
1364         }
1365
1366         /* Announce number of users if need be */
1367         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ANNOUNCEUSERCOUNT)) {
1368                 if (announce_user_count(conference_bridge, conference_bridge_user)) {
1369                         leave_conference(conference_bridge_user);
1370                         return NULL;
1371                 }
1372         }
1373
1374         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ANNOUNCEUSERCOUNTALL) &&
1375                 (conference_bridge->activeusers > conference_bridge_user->u_profile.announce_user_count_all_after)) {
1376                 int user_count_res;
1377
1378                 /*
1379                  * We have to autoservice the new user because he has not quite
1380                  * joined the conference yet.
1381                  */
1382                 ast_autoservice_start(conference_bridge_user->chan);
1383                 user_count_res = announce_user_count(conference_bridge, NULL);
1384                 ast_autoservice_stop(conference_bridge_user->chan);
1385                 if (user_count_res) {
1386                         leave_conference(conference_bridge_user);
1387                         return NULL;
1388                 }
1389         }
1390
1391         /* Handle post-join actions */
1392         while ((action = AST_LIST_REMOVE_HEAD(&conference_bridge_user->post_join_list, list))) {
1393                 action->func(conference_bridge_user);
1394                 ast_free(action);
1395         }
1396
1397         return conference_bridge;
1398 }
1399
1400 /*!
1401  * \brief Leave a conference
1402  *
1403  * \param user The conference user
1404  */
1405 static void leave_conference(struct conference_bridge_user *user)
1406 {
1407         struct post_join_action *action;
1408
1409         ao2_lock(user->conference_bridge);
1410         handle_conf_user_leave(user);
1411         ao2_unlock(user->conference_bridge);
1412
1413         /* Discard any post-join actions */
1414         while ((action = AST_LIST_REMOVE_HEAD(&user->post_join_list, list))) {
1415                 ast_free(action);
1416         }
1417
1418         /* Done mucking with the conference, huzzah */
1419         ao2_ref(user->conference_bridge, -1);
1420         user->conference_bridge = NULL;
1421 }
1422
1423 /*!
1424  * \internal
1425  * \brief allocates playback chan on a channel
1426  * \pre expects conference to be locked before calling this function
1427  */
1428 static int alloc_playback_chan(struct conference_bridge *conference_bridge)
1429 {
1430         int cause;
1431         struct ast_format_cap *cap;
1432         struct ast_format tmpfmt;
1433
1434         if (conference_bridge->playback_chan) {
1435                 return 0;
1436         }
1437         if (!(cap = ast_format_cap_alloc_nolock())) {
1438                 return -1;
1439         }
1440         ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
1441         if (!(conference_bridge->playback_chan = ast_request("Bridge", cap, NULL, "", &cause))) {
1442                 cap = ast_format_cap_destroy(cap);
1443                 return -1;
1444         }
1445         cap = ast_format_cap_destroy(cap);
1446
1447         ast_channel_internal_bridge_set(conference_bridge->playback_chan, conference_bridge->bridge);
1448
1449         if (ast_call(conference_bridge->playback_chan, "", 0)) {
1450                 ast_hangup(conference_bridge->playback_chan);
1451                 conference_bridge->playback_chan = NULL;
1452                 return -1;
1453         }
1454
1455         ast_debug(1, "Created a playback channel to conference bridge '%s'\n", conference_bridge->name);
1456         return 0;
1457 }
1458
1459 static int play_sound_helper(struct conference_bridge *conference_bridge, const char *filename, int say_number)
1460 {
1461         struct ast_channel *underlying_channel;
1462
1463         /* Do not waste resources trying to play files that do not exist */
1464         if (!ast_strlen_zero(filename) && !sound_file_exists(filename)) {
1465                 return 0;
1466         }
1467
1468         ast_mutex_lock(&conference_bridge->playback_lock);
1469         if (!(conference_bridge->playback_chan)) {
1470                 if (alloc_playback_chan(conference_bridge)) {
1471                         ast_mutex_unlock(&conference_bridge->playback_lock);
1472                         return -1;
1473                 }
1474                 underlying_channel = ast_channel_tech(conference_bridge->playback_chan)->bridged_channel(conference_bridge->playback_chan, NULL);
1475         } else {
1476                 /* Channel was already available so we just need to add it back into the bridge */
1477                 underlying_channel = ast_channel_tech(conference_bridge->playback_chan)->bridged_channel(conference_bridge->playback_chan, NULL);
1478                 if (ast_bridge_impart(conference_bridge->bridge, underlying_channel, NULL, NULL, 0)) {
1479                         ast_mutex_unlock(&conference_bridge->playback_lock);
1480                         return -1;
1481                 }
1482         }
1483
1484         /* The channel is all under our control, in goes the prompt */
1485         if (!ast_strlen_zero(filename)) {
1486                 ast_stream_and_wait(conference_bridge->playback_chan, filename, "");
1487         } else if (say_number >= 0) {
1488                 ast_say_number(conference_bridge->playback_chan, say_number, "", ast_channel_language(conference_bridge->playback_chan), NULL);
1489         }
1490
1491         ast_debug(1, "Departing underlying channel '%s' from bridge '%p'\n", ast_channel_name(underlying_channel), conference_bridge->bridge);
1492         ast_bridge_depart(conference_bridge->bridge, underlying_channel);
1493
1494         ast_mutex_unlock(&conference_bridge->playback_lock);
1495
1496         return 0;
1497 }
1498
1499 int play_sound_file(struct conference_bridge *conference_bridge, const char *filename)
1500 {
1501         return play_sound_helper(conference_bridge, filename, -1);
1502 }
1503
1504 /*!
1505  * \brief Play number into the conference bridge
1506  *
1507  * \param conference_bridge The conference bridge to say the number into
1508  * \param say_number number to say
1509  *
1510  * \retval 0 success
1511  * \retval -1 failure
1512  */
1513 static int play_sound_number(struct conference_bridge *conference_bridge, int say_number)
1514 {
1515         return play_sound_helper(conference_bridge, NULL, say_number);
1516 }
1517
1518 static void conf_handle_talker_destructor(void *pvt_data)
1519 {
1520         ast_free(pvt_data);
1521 }
1522
1523 static void conf_handle_talker_cb(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *pvt_data)
1524 {
1525         char *conf_name = pvt_data;
1526         int talking;
1527
1528         switch (bridge_channel->state) {
1529         case AST_BRIDGE_CHANNEL_STATE_START_TALKING:
1530                 talking = 1;
1531                 break;
1532         case AST_BRIDGE_CHANNEL_STATE_STOP_TALKING:
1533                 talking = 0;
1534                 break;
1535         default:
1536                 return; /* uhh this shouldn't happen, but bail if it does. */
1537         }
1538
1539         /* notify AMI someone is has either started or stopped talking */
1540         /*** DOCUMENTATION
1541                 <managerEventInstance>
1542                         <synopsis>Raised when a conference participant has started or stopped talking.</synopsis>
1543                         <syntax>
1544                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='ConfbridgeStart']/managerEventInstance/syntax/parameter[@name='Conference'])" />
1545                                 <parameter name="TalkingStatus">
1546                                         <enumlist>
1547                                                 <enum name="on"/>
1548                                                 <enum name="off"/>
1549                                         </enumlist>
1550                                 </parameter>
1551                         </syntax>
1552                 </managerEventInstance>
1553         ***/
1554         ast_manager_event(bridge_channel->chan, EVENT_FLAG_CALL, "ConfbridgeTalking",
1555               "Channel: %s\r\n"
1556               "Uniqueid: %s\r\n"
1557               "Conference: %s\r\n"
1558               "TalkingStatus: %s\r\n",
1559               ast_channel_name(bridge_channel->chan), ast_channel_uniqueid(bridge_channel->chan), conf_name, talking ? "on" : "off");
1560 }
1561
1562 static int conf_get_pin(struct ast_channel *chan, struct conference_bridge_user *conference_bridge_user)
1563 {
1564         char pin_guess[MAX_PIN+1] = { 0, };
1565         const char *pin = conference_bridge_user->u_profile.pin;
1566         char *tmp = pin_guess;
1567         int i, res;
1568         unsigned int len = MAX_PIN ;
1569
1570         /* give them three tries to get the pin right */
1571         for (i = 0; i < 3; i++) {
1572                 if (ast_app_getdata(chan,
1573                         conf_get_sound(CONF_SOUND_GET_PIN, conference_bridge_user->b_profile.sounds),
1574                         tmp, len, 0) >= 0) {
1575                         if (!strcasecmp(pin, pin_guess)) {
1576                                 return 0;
1577                         }
1578                 }
1579                 ast_streamfile(chan,
1580                         conf_get_sound(CONF_SOUND_INVALID_PIN, conference_bridge_user->b_profile.sounds),
1581                         ast_channel_language(chan));
1582                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1583                 if (res > 0) {
1584                         /* Account for digit already read during ivalid pin playback
1585                          * resetting pin buf. */
1586                         pin_guess[0] = res;
1587                         pin_guess[1] = '\0';
1588                         tmp = pin_guess + 1;
1589                         len = MAX_PIN - 1;
1590                 } else {
1591                         /* reset pin buf as empty buffer. */
1592                         tmp = pin_guess;
1593                         len = MAX_PIN;
1594                 }
1595         }
1596         return -1;
1597 }
1598
1599 static int conf_rec_name(struct conference_bridge_user *user, const char *conf_name)
1600 {
1601         char destdir[PATH_MAX];
1602         int res;
1603         int duration = 20;
1604
1605         snprintf(destdir, sizeof(destdir), "%s/confbridge", ast_config_AST_SPOOL_DIR);
1606
1607         if (ast_mkdir(destdir, 0777) != 0) {
1608                 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
1609                 return -1;
1610         }
1611         snprintf(user->name_rec_location, sizeof(user->name_rec_location),
1612                  "%s/confbridge-name-%s-%s", destdir,
1613                  conf_name, ast_channel_uniqueid(user->chan));
1614
1615         res = ast_play_and_record(user->chan,
1616                 "vm-rec-name",
1617                 user->name_rec_location,
1618                 10,
1619                 "sln",
1620                 &duration,
1621                 NULL,
1622                 ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE),
1623                 0,
1624                 NULL);
1625
1626         if (res == -1) {
1627                 user->name_rec_location[0] = '\0';
1628                 return -1;
1629         }
1630         return 0;
1631 }
1632
1633 /*! \brief The ConfBridge application */
1634 static int confbridge_exec(struct ast_channel *chan, const char *data)
1635 {
1636         int res = 0, volume_adjustments[2];
1637         int quiet = 0;
1638         char *parse;
1639         const char *b_profile_name = DEFAULT_BRIDGE_PROFILE;
1640         const char *u_profile_name = DEFAULT_USER_PROFILE;
1641         struct conference_bridge *conference_bridge = NULL;
1642         struct conference_bridge_user conference_bridge_user = {
1643                 .chan = chan,
1644                 .tech_args.talking_threshold = DEFAULT_TALKING_THRESHOLD,
1645                 .tech_args.silence_threshold = DEFAULT_SILENCE_THRESHOLD,
1646                 .tech_args.drop_silence = 0,
1647         };
1648         AST_DECLARE_APP_ARGS(args,
1649                 AST_APP_ARG(conf_name);
1650                 AST_APP_ARG(b_profile_name);
1651                 AST_APP_ARG(u_profile_name);
1652                 AST_APP_ARG(menu_name);
1653         );
1654         ast_bridge_features_init(&conference_bridge_user.features);
1655
1656         if (ast_channel_state(chan) != AST_STATE_UP) {
1657                 ast_answer(chan);
1658         }
1659
1660         if (ast_strlen_zero(data)) {
1661                 ast_log(LOG_WARNING, "%s requires an argument (conference name[,options])\n", app);
1662                 res = -1; /* invalid PIN */
1663                 goto confbridge_cleanup;
1664         }
1665
1666         /* We need to make a copy of the input string if we are going to modify it! */
1667         parse = ast_strdupa(data);
1668
1669         AST_STANDARD_APP_ARGS(args, parse);
1670
1671         /* bridge profile name */
1672         if (args.argc > 1 && !ast_strlen_zero(args.b_profile_name)) {
1673                 b_profile_name = args.b_profile_name;
1674         }
1675         if (!conf_find_bridge_profile(chan, b_profile_name, &conference_bridge_user.b_profile)) {
1676                 ast_log(LOG_WARNING, "Conference bridge profile %s does not exist\n", b_profile_name);
1677                 res = -1;
1678                 goto confbridge_cleanup;
1679         }
1680
1681         /* user profile name */
1682         if (args.argc > 2 && !ast_strlen_zero(args.u_profile_name)) {
1683                 u_profile_name = args.u_profile_name;
1684         }
1685         if (!conf_find_user_profile(chan, u_profile_name, &conference_bridge_user.u_profile)) {
1686                 ast_log(LOG_WARNING, "Conference user profile %s does not exist\n", u_profile_name);
1687                 res = -1;
1688                 goto confbridge_cleanup;
1689         }
1690
1691         quiet = ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_QUIET);
1692
1693         /* ask for a PIN immediately after finding user profile.  This has to be
1694          * prompted for requardless of quiet setting. */
1695         if (!ast_strlen_zero(conference_bridge_user.u_profile.pin)) {
1696                 if (conf_get_pin(chan, &conference_bridge_user)) {
1697                         res = -1; /* invalid PIN */
1698                         goto confbridge_cleanup;
1699                 }
1700         }
1701
1702         /* See if we need them to record a intro name */
1703         if (!quiet && ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE)) {
1704                 conf_rec_name(&conference_bridge_user, args.conf_name);
1705         }
1706
1707         /* menu name */
1708         if (args.argc > 3 && !ast_strlen_zero(args.menu_name)) {
1709                 ast_copy_string(conference_bridge_user.menu_name, args.menu_name, sizeof(conference_bridge_user.menu_name));
1710                 if (conf_set_menu_to_user(conference_bridge_user.menu_name, &conference_bridge_user)) {
1711                         ast_log(LOG_WARNING, "Conference menu %s does not exist and can not be applied to confbridge user.\n",
1712                                 args.menu_name);
1713                         res = -1; /* invalid PIN */
1714                         goto confbridge_cleanup;
1715                 }
1716         }
1717
1718         /* Set if DTMF should pass through for this user or not */
1719         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DTMF_PASS)) {
1720                 conference_bridge_user.features.dtmf_passthrough = 1;
1721         }
1722
1723         /* Set dsp threshold values if present */
1724         if (conference_bridge_user.u_profile.talking_threshold) {
1725                 conference_bridge_user.tech_args.talking_threshold = conference_bridge_user.u_profile.talking_threshold;
1726         }
1727         if (conference_bridge_user.u_profile.silence_threshold) {
1728                 conference_bridge_user.tech_args.silence_threshold = conference_bridge_user.u_profile.silence_threshold;
1729         }
1730
1731         /* Set a talker indicate call back if talking detection is requested */
1732         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_TALKER_DETECT)) {
1733                 char *conf_name = ast_strdup(args.conf_name); /* this is freed during feature cleanup */
1734                 if (!(conf_name)) {
1735                         res = -1; /* invalid PIN */
1736                         goto confbridge_cleanup;
1737                 }
1738                 ast_bridge_features_set_talk_detector(&conference_bridge_user.features,
1739                         conf_handle_talker_cb,
1740                         conf_handle_talker_destructor,
1741                         conf_name);
1742         }
1743
1744         /* Look for a conference bridge matching the provided name */
1745         if (!(conference_bridge = join_conference_bridge(args.conf_name, &conference_bridge_user))) {
1746                 res = -1; /* invalid PIN */
1747                 goto confbridge_cleanup;
1748         }
1749
1750         /* Keep a copy of volume adjustments so we can restore them later if need be */
1751         volume_adjustments[0] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_READ);
1752         volume_adjustments[1] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_WRITE);
1753
1754         /* If the caller should be joined already muted, make it so */
1755         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_STARTMUTED)) {
1756                 conference_bridge_user.features.mute = 1;
1757         }
1758
1759         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DROP_SILENCE)) {
1760                 conference_bridge_user.tech_args.drop_silence = 1;
1761         }
1762
1763         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_JITTERBUFFER)) {
1764                 char *func_jb;
1765                 if ((func_jb = ast_module_helper("", "func_jitterbuffer", 0, 0, 0, 0))) {
1766                         ast_free(func_jb);
1767                         ast_func_write(chan, "JITTERBUFFER(adaptive)", "default");
1768                 }
1769         }
1770
1771         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DENOISE)) {
1772                 char *mod_speex;
1773                 /* Reduce background noise from each participant */
1774                 if ((mod_speex = ast_module_helper("", "codec_speex", 0, 0, 0, 0))) {
1775                         ast_free(mod_speex);
1776                         ast_func_write(chan, "DENOISE(rx)", "on");
1777                 }
1778         }
1779
1780         /* if this user has a intro, play it before entering */
1781         if (!ast_strlen_zero(conference_bridge_user.name_rec_location)) {
1782                 ast_autoservice_start(chan);
1783                 play_sound_file(conference_bridge, conference_bridge_user.name_rec_location);
1784                 play_sound_file(conference_bridge,
1785                         conf_get_sound(CONF_SOUND_HAS_JOINED, conference_bridge_user.b_profile.sounds));
1786                 ast_autoservice_stop(chan);
1787         }
1788
1789         /* Play the Join sound to both the conference and the user entering. */
1790         if (!quiet) {
1791                 const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, conference_bridge_user.b_profile.sounds);
1792
1793                 ast_stream_and_wait(chan, join_sound, "");
1794                 ast_autoservice_start(chan);
1795                 play_sound_file(conference_bridge, join_sound);
1796                 ast_autoservice_stop(chan);
1797         }
1798
1799         /* See if we need to automatically set this user as a video source or not */
1800         handle_video_on_join(conference_bridge, conference_bridge_user.chan, ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_MARKEDUSER));
1801
1802         conf_moh_unsuspend(&conference_bridge_user);
1803
1804         /* Join our conference bridge for real */
1805         send_join_event(conference_bridge_user.chan, conference_bridge->name);
1806         ast_bridge_join(conference_bridge->bridge,
1807                 chan,
1808                 NULL,
1809                 &conference_bridge_user.features,
1810                 &conference_bridge_user.tech_args);
1811         send_leave_event(conference_bridge_user.chan, conference_bridge->name);
1812
1813         /* if we're shutting down, don't attempt to do further processing */
1814         if (ast_shutting_down()) {
1815                 leave_conference(&conference_bridge_user);
1816                 conference_bridge = NULL;
1817                 goto confbridge_cleanup;
1818         }
1819
1820         /* If this user was a video source, we need to clean up and possibly pick a new source. */
1821         handle_video_on_exit(conference_bridge, conference_bridge_user.chan);
1822
1823         /* if this user has a intro, play it when leaving */
1824         if (!quiet && !ast_strlen_zero(conference_bridge_user.name_rec_location)) {
1825                 ast_autoservice_start(chan);
1826                 play_sound_file(conference_bridge, conference_bridge_user.name_rec_location);
1827                 play_sound_file(conference_bridge,
1828                         conf_get_sound(CONF_SOUND_HAS_LEFT, conference_bridge_user.b_profile.sounds));
1829                 ast_autoservice_stop(chan);
1830         }
1831
1832         /* play the leave sound */
1833         if (!quiet) {
1834                 const char *leave_sound = conf_get_sound(CONF_SOUND_LEAVE, conference_bridge_user.b_profile.sounds);
1835                 ast_autoservice_start(chan);
1836                 play_sound_file(conference_bridge, leave_sound);
1837                 ast_autoservice_stop(chan);
1838         }
1839
1840         /* Easy as pie, depart this channel from the conference bridge */
1841         leave_conference(&conference_bridge_user);
1842         conference_bridge = NULL;
1843
1844         /* If the user was kicked from the conference play back the audio prompt for it */
1845         if (!quiet && conference_bridge_user.kicked) {
1846                 res = ast_stream_and_wait(chan,
1847                         conf_get_sound(CONF_SOUND_KICKED, conference_bridge_user.b_profile.sounds),
1848                         "");
1849         }
1850
1851         /* Restore volume adjustments to previous values in case they were changed */
1852         if (volume_adjustments[0]) {
1853                 ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_READ, volume_adjustments[0]);
1854         }
1855         if (volume_adjustments[1]) {
1856                 ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_WRITE, volume_adjustments[1]);
1857         }
1858
1859         if (!ast_strlen_zero(conference_bridge_user.name_rec_location)) {
1860                 ast_filedelete(conference_bridge_user.name_rec_location, NULL);
1861         }
1862
1863 confbridge_cleanup:
1864         ast_bridge_features_cleanup(&conference_bridge_user.features);
1865         conf_bridge_profile_destroy(&conference_bridge_user.b_profile);
1866         return res;
1867 }
1868
1869 static int action_toggle_mute(struct conference_bridge *conference_bridge,
1870         struct conference_bridge_user *conference_bridge_user,
1871         struct ast_channel *chan)
1872 {
1873         /* Mute or unmute yourself, note we only allow manipulation if they aren't waiting for a marked user or if marked users exist */
1874         if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_WAITMARKED) || conference_bridge->markedusers) {
1875                 conference_bridge_user->features.mute = (!conference_bridge_user->features.mute ? 1 : 0);
1876                 ast_test_suite_event_notify("CONF_MUTE", "Message: participant %s %s\r\nConference: %s\r\nChannel: %s", ast_channel_name(chan), conference_bridge_user->features.mute ? "muted" : "unmuted", conference_bridge_user->b_profile.name, ast_channel_name(chan));
1877                 if (conference_bridge_user->features.mute) {
1878                         send_mute_event(chan, conference_bridge->name);
1879                 } else { 
1880                         send_unmute_event(chan, conference_bridge->name);
1881                 }
1882         }
1883         return ast_stream_and_wait(chan, (conference_bridge_user->features.mute ?
1884                 conf_get_sound(CONF_SOUND_MUTED, conference_bridge_user->b_profile.sounds) :
1885                 conf_get_sound(CONF_SOUND_UNMUTED, conference_bridge_user->b_profile.sounds)),
1886                 "");
1887 }
1888
1889 static int action_toggle_mute_participants(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
1890 {
1891         struct conference_bridge_user *participant = NULL;
1892         const char *sound_to_play;
1893
1894         ao2_lock(conference_bridge);
1895
1896         /* If already muted, then unmute */
1897         conference_bridge->muted = conference_bridge->muted ? 0 : 1;
1898         sound_to_play = conf_get_sound((conference_bridge->muted ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED),
1899                 conference_bridge_user->b_profile.sounds);
1900
1901         AST_LIST_TRAVERSE(&conference_bridge->active_list, participant, list) {
1902                 if (!ast_test_flag(&participant->u_profile, USER_OPT_ADMIN)) {
1903                         participant->features.mute = conference_bridge->muted;
1904                 }
1905         }
1906
1907         ao2_unlock(conference_bridge);
1908
1909         /* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */
1910         ast_stream_and_wait(conference_bridge_user->chan, sound_to_play, "");
1911
1912         /* Announce to the group that all participants are muted */
1913         ast_autoservice_start(conference_bridge_user->chan);
1914         play_sound_helper(conference_bridge, sound_to_play, 0);
1915         ast_autoservice_stop(conference_bridge_user->chan);
1916
1917         return 0;
1918 }
1919
1920 static int action_playback(struct ast_bridge_channel *bridge_channel, const char *playback_file)
1921 {
1922         char *file_copy = ast_strdupa(playback_file);
1923         char *file = NULL;
1924
1925         while ((file = strsep(&file_copy, "&"))) {
1926                 if (ast_stream_and_wait(bridge_channel->chan, file, "")) {
1927                         ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
1928                         return -1;
1929                 }
1930         }
1931         return 0;
1932 }
1933
1934 static int action_playback_and_continue(struct conference_bridge *conference_bridge,
1935         struct conference_bridge_user *conference_bridge_user,
1936         struct ast_bridge_channel *bridge_channel,
1937         struct conf_menu *menu,
1938         const char *playback_file,
1939         const char *cur_dtmf,
1940         int *stop_prompts)
1941 {
1942         int i;
1943         int digit = 0;
1944         char dtmf[MAXIMUM_DTMF_FEATURE_STRING];
1945         struct conf_menu_entry new_menu_entry = { { 0, }, };
1946         char *file_copy = ast_strdupa(playback_file);
1947         char *file = NULL;
1948
1949         while ((file = strsep(&file_copy, "&"))) {
1950                 if (ast_streamfile(bridge_channel->chan, file, ast_channel_language(bridge_channel->chan))) {
1951                         ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
1952                         return -1;
1953                 }
1954
1955                 /* now wait for more digits. */
1956                 if (!(digit = ast_waitstream(bridge_channel->chan, AST_DIGIT_ANY))) {
1957                         /* streaming finished and no DTMF was entered */
1958                         continue;
1959                 } else if (digit == -1) {
1960                         /* error */
1961                         return -1;
1962                 } else {
1963                         break; /* dtmf was entered */
1964                 }
1965         }
1966         if (!digit) {
1967                 /* streaming finished on all files and no DTMF was entered */
1968                 return -1;
1969         }
1970         ast_stopstream(bridge_channel->chan);
1971
1972         /* If we get here, then DTMF has been entered, This means no
1973          * additional prompts should be played for this menu entry */
1974         *stop_prompts = 1;
1975
1976         /* If a digit was pressed during the payback, update
1977          * the dtmf string and look for a new menu entry in the
1978          * menu structure */
1979         ast_copy_string(dtmf, cur_dtmf, sizeof(dtmf));
1980         for (i = 0; i < (MAXIMUM_DTMF_FEATURE_STRING - 1); i++) {
1981                 dtmf[i] = cur_dtmf[i];
1982                 if (!dtmf[i]) {
1983                         dtmf[i] = (char) digit;
1984                         dtmf[i + 1] = '\0';
1985                         i = -1;
1986                         break;
1987                 }
1988         }
1989         /* If i is not -1 then the new dtmf digit was _NOT_ added to the string.
1990          * If this is the case, no new DTMF sequence should be looked for. */
1991         if (i != -1) {
1992                 return 0;
1993         }
1994
1995         if (conf_find_menu_entry_by_sequence(dtmf, menu, &new_menu_entry)) {
1996                 execute_menu_entry(conference_bridge,
1997                         conference_bridge_user,
1998                         bridge_channel,
1999                         &new_menu_entry, menu);
2000                 conf_menu_entry_destroy(&new_menu_entry);
2001         }
2002         return 0;
2003 }
2004
2005 static int action_kick_last(struct conference_bridge *conference_bridge,
2006         struct ast_bridge_channel *bridge_channel,
2007         struct conference_bridge_user *conference_bridge_user)
2008 {
2009         struct conference_bridge_user *last_participant = NULL;
2010         int isadmin = ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN);
2011
2012         if (!isadmin) {
2013                 ast_stream_and_wait(bridge_channel->chan,
2014                         conf_get_sound(CONF_SOUND_ERROR_MENU, conference_bridge_user->b_profile.sounds),
2015                         "");
2016                 ast_log(LOG_WARNING, "Only admin users can use the kick_last menu action. Channel %s of conf %s is not an admin.\n",
2017                         ast_channel_name(bridge_channel->chan),
2018                         conference_bridge->name);
2019                 return -1;
2020         }
2021
2022         ao2_lock(conference_bridge);
2023         if (((last_participant = AST_LIST_LAST(&conference_bridge->active_list)) == conference_bridge_user)
2024                 || (ast_test_flag(&last_participant->u_profile, USER_OPT_ADMIN))) {
2025                 ao2_unlock(conference_bridge);
2026                 ast_stream_and_wait(bridge_channel->chan,
2027                         conf_get_sound(CONF_SOUND_ERROR_MENU, conference_bridge_user->b_profile.sounds),
2028                         "");
2029         } else if (last_participant) {
2030                 last_participant->kicked = 1;
2031                 ast_bridge_remove(conference_bridge->bridge, last_participant->chan);
2032                 ao2_unlock(conference_bridge);
2033         }
2034         return 0;
2035 }
2036
2037 static int action_dialplan_exec(struct ast_bridge_channel *bridge_channel, struct conf_menu_action *menu_action)
2038 {
2039         struct ast_pbx_args args;
2040         struct ast_pbx *pbx;
2041         char *exten;
2042         char *context;
2043         int priority;
2044         int res;
2045
2046         memset(&args, 0, sizeof(args));
2047         args.no_hangup_chan = 1;
2048
2049         ast_channel_lock(bridge_channel->chan);
2050
2051         /*save off*/
2052         exten = ast_strdupa(ast_channel_exten(bridge_channel->chan));
2053         context = ast_strdupa(ast_channel_context(bridge_channel->chan));
2054         priority = ast_channel_priority(bridge_channel->chan);
2055         pbx = ast_channel_pbx(bridge_channel->chan);
2056         ast_channel_pbx_set(bridge_channel->chan, NULL);
2057
2058         /*set new*/
2059         ast_channel_exten_set(bridge_channel->chan, menu_action->data.dialplan_args.exten);
2060         ast_channel_context_set(bridge_channel->chan, menu_action->data.dialplan_args.context);
2061         ast_channel_priority_set(bridge_channel->chan, menu_action->data.dialplan_args.priority);
2062
2063         ast_channel_unlock(bridge_channel->chan);
2064
2065         /*execute*/
2066         res = ast_pbx_run_args(bridge_channel->chan, &args);
2067
2068         /*restore*/
2069         ast_channel_lock(bridge_channel->chan);
2070
2071         ast_channel_exten_set(bridge_channel->chan, exten);
2072         ast_channel_context_set(bridge_channel->chan, context);
2073         ast_channel_priority_set(bridge_channel->chan, priority);
2074         ast_channel_pbx_set(bridge_channel->chan, pbx);
2075
2076         ast_channel_unlock(bridge_channel->chan);
2077
2078         return res;
2079 }
2080
2081 static int execute_menu_entry(struct conference_bridge *conference_bridge,
2082         struct conference_bridge_user *conference_bridge_user,
2083         struct ast_bridge_channel *bridge_channel,
2084         struct conf_menu_entry *menu_entry,
2085         struct conf_menu *menu)
2086 {
2087         struct conf_menu_action *menu_action;
2088         int isadmin = ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN);
2089         int stop_prompts = 0;
2090         int res = 0;
2091
2092         AST_LIST_TRAVERSE(&menu_entry->actions, menu_action, action) {
2093                 switch (menu_action->id) {
2094                 case MENU_ACTION_TOGGLE_MUTE:
2095                         res |= action_toggle_mute(conference_bridge,
2096                                 conference_bridge_user,
2097                                 bridge_channel->chan);
2098                         break;
2099                 case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS:
2100                         if (!isadmin) {
2101                                 break;
2102                         }
2103                         action_toggle_mute_participants(conference_bridge, conference_bridge_user);
2104                         break;
2105                 case MENU_ACTION_PARTICIPANT_COUNT:
2106                         announce_user_count(conference_bridge, conference_bridge_user);
2107                         break;
2108                 case MENU_ACTION_PLAYBACK:
2109                         if (!stop_prompts) {
2110                                 res |= action_playback(bridge_channel, menu_action->data.playback_file);
2111                         }
2112                         break;
2113                 case MENU_ACTION_RESET_LISTENING:
2114                         ast_audiohook_volume_set(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_WRITE, 0);
2115                         break;
2116                 case MENU_ACTION_RESET_TALKING:
2117                         ast_audiohook_volume_set(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_READ, 0);
2118                         break;
2119                 case MENU_ACTION_INCREASE_LISTENING:
2120                         ast_audiohook_volume_adjust(conference_bridge_user->chan,
2121                                 AST_AUDIOHOOK_DIRECTION_WRITE, 1);
2122                         break;
2123                 case MENU_ACTION_DECREASE_LISTENING:
2124                         ast_audiohook_volume_adjust(conference_bridge_user->chan,
2125                                 AST_AUDIOHOOK_DIRECTION_WRITE, -1);
2126                         break;
2127                 case MENU_ACTION_INCREASE_TALKING:
2128                         ast_audiohook_volume_adjust(conference_bridge_user->chan,
2129                                 AST_AUDIOHOOK_DIRECTION_READ, 1);
2130                         break;
2131                 case MENU_ACTION_DECREASE_TALKING:
2132                         ast_audiohook_volume_adjust(conference_bridge_user->chan,
2133                                 AST_AUDIOHOOK_DIRECTION_READ, -1);
2134                         break;
2135                 case MENU_ACTION_PLAYBACK_AND_CONTINUE:
2136                         if (!(stop_prompts)) {
2137                                 res |= action_playback_and_continue(conference_bridge,
2138                                         conference_bridge_user,
2139                                         bridge_channel,
2140                                         menu,
2141                                         menu_action->data.playback_file,
2142                                         menu_entry->dtmf,
2143                                         &stop_prompts);
2144                         }
2145                         break;
2146                 case MENU_ACTION_DIALPLAN_EXEC:
2147                         res |= action_dialplan_exec(bridge_channel, menu_action);
2148                         break;
2149                 case MENU_ACTION_ADMIN_TOGGLE_LOCK:
2150                         if (!isadmin) {
2151                                 break;
2152                         }
2153                         conference_bridge->locked = (!conference_bridge->locked ? 1 : 0);
2154                         res |= ast_stream_and_wait(bridge_channel->chan,
2155                                 (conference_bridge->locked ?
2156                                 conf_get_sound(CONF_SOUND_LOCKED_NOW, conference_bridge_user->b_profile.sounds) :
2157                                 conf_get_sound(CONF_SOUND_UNLOCKED_NOW, conference_bridge_user->b_profile.sounds)),
2158                                 "");
2159
2160                         break;
2161                 case MENU_ACTION_ADMIN_KICK_LAST:
2162                         res |= action_kick_last(conference_bridge, bridge_channel, conference_bridge_user);
2163                         break;
2164                 case MENU_ACTION_LEAVE:
2165                         ao2_lock(conference_bridge);
2166                         ast_bridge_remove(conference_bridge->bridge, bridge_channel->chan);
2167                         ao2_unlock(conference_bridge);
2168                         break;
2169                 case MENU_ACTION_NOOP:
2170                         break;
2171                 case MENU_ACTION_SET_SINGLE_VIDEO_SRC:
2172                         ao2_lock(conference_bridge);
2173                         ast_bridge_set_single_src_video_mode(conference_bridge->bridge, bridge_channel->chan);
2174                         ao2_unlock(conference_bridge);
2175                         break;
2176                 case MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC:
2177                         handle_video_on_exit(conference_bridge, bridge_channel->chan);
2178                         break;
2179                 }
2180         }
2181         return res;
2182 }
2183
2184 int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel,
2185         struct conference_bridge_user *conference_bridge_user,
2186         struct conf_menu_entry *menu_entry,
2187         struct conf_menu *menu)
2188 {
2189         /* See if music on hold is playing */
2190         conf_moh_suspend(conference_bridge_user);
2191
2192         /* execute the list of actions associated with this menu entry */
2193         execute_menu_entry(conference_bridge_user->conference_bridge, conference_bridge_user, bridge_channel, menu_entry, menu);
2194
2195         /* See if music on hold needs to be started back up again */
2196         conf_moh_unsuspend(conference_bridge_user);
2197
2198         return 0;
2199 }
2200
2201 static int kick_conference_participant(struct conference_bridge *bridge, const char *channel)
2202 {
2203         struct conference_bridge_user *participant = NULL;
2204
2205         SCOPED_AO2LOCK(bridge_lock, bridge);
2206         AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
2207                 if (!strcasecmp(ast_channel_name(participant->chan), channel)) {
2208                         participant->kicked = 1;
2209                         ast_bridge_remove(bridge->bridge, participant->chan);
2210                         return 0;
2211                 }
2212         }
2213         AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) {
2214                 if (!strcasecmp(ast_channel_name(participant->chan), channel)) {
2215                         participant->kicked = 1;
2216                         ast_bridge_remove(bridge->bridge, participant->chan);
2217                         return 0;
2218                 }
2219         }
2220
2221         return -1;
2222 }
2223
2224 static char *complete_confbridge_name(const char *line, const char *word, int pos, int state)
2225 {
2226         int which = 0;
2227         struct conference_bridge *bridge = NULL;
2228         char *res = NULL;
2229         int wordlen = strlen(word);
2230         struct ao2_iterator iter;
2231
2232         iter = ao2_iterator_init(conference_bridges, 0);
2233         while ((bridge = ao2_iterator_next(&iter))) {
2234                 if (!strncasecmp(bridge->name, word, wordlen) && ++which > state) {
2235                         res = ast_strdup(bridge->name);
2236                         ao2_ref(bridge, -1);
2237                         break;
2238                 }
2239                 ao2_ref(bridge, -1);
2240         }
2241         ao2_iterator_destroy(&iter);
2242
2243         return res;
2244 }
2245
2246 static char *complete_confbridge_participant(const char *bridge_name, const char *line, const char *word, int pos, int state)
2247 {
2248         int which = 0;
2249         RAII_VAR(struct conference_bridge *, bridge, NULL, ao2_cleanup);
2250         struct conference_bridge tmp;
2251         struct conference_bridge_user *participant;
2252         char *res = NULL;
2253         int wordlen = strlen(word);
2254
2255         ast_copy_string(tmp.name, bridge_name, sizeof(tmp.name));
2256         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2257         if (!bridge) {
2258                 return NULL;
2259         }
2260
2261         {
2262                 SCOPED_AO2LOCK(bridge_lock, bridge);
2263                 AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
2264                         if (!strncasecmp(ast_channel_name(participant->chan), word, wordlen) && ++which > state) {
2265                                 res = ast_strdup(ast_channel_name(participant->chan));
2266                                 return res;
2267                         }
2268                 }
2269                 AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) {
2270                         if (!strncasecmp(ast_channel_name(participant->chan), word, wordlen) && ++which > state) {
2271                                 res = ast_strdup(ast_channel_name(participant->chan));
2272                                 return res;
2273                         }
2274                 }
2275         }
2276
2277         return NULL;
2278 }
2279
2280 static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2281 {
2282         struct conference_bridge *bridge = NULL;
2283         struct conference_bridge tmp;
2284
2285         switch (cmd) {
2286         case CLI_INIT:
2287                 e->command = "confbridge kick";
2288                 e->usage =
2289                         "Usage: confbridge kick <conference> <channel>\n"
2290                         "       Kicks a channel out of the conference bridge.\n";
2291                 return NULL;
2292         case CLI_GENERATE:
2293                 if (a->pos == 2) {
2294                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2295                 }
2296                 if (a->pos == 3) {
2297                         return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
2298                 }
2299                 return NULL;
2300         }
2301
2302         if (a->argc != 4) {
2303                 return CLI_SHOWUSAGE;
2304         }
2305
2306         ast_copy_string(tmp.name, a->argv[2], sizeof(tmp.name));
2307         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2308         if (!bridge) {
2309                 ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
2310                 return CLI_SUCCESS;
2311         }
2312         if (kick_conference_participant(bridge, a->argv[3])) {
2313                 ast_cli(a->fd, "No participant named '%s' found!\n", a->argv[3]);
2314                 return CLI_SUCCESS;
2315         }
2316         ao2_ref(bridge, -1);
2317         ast_cli(a->fd, "Participant '%s' kicked out of conference '%s'\n", a->argv[3], a->argv[2]);
2318         return CLI_SUCCESS;
2319 }
2320
2321 static void handle_cli_confbridge_list_item(struct ast_cli_args *a, struct conference_bridge_user *participant, int waiting)
2322 {
2323         char flag_str[5 + 1];/* Max flags + terminator */
2324         int pos = 0;
2325
2326         /* Build flags column string. */
2327         if (ast_test_flag(&participant->u_profile, USER_OPT_ADMIN)) {
2328                 flag_str[pos++] = 'A';
2329         }
2330         if (ast_test_flag(&participant->u_profile, USER_OPT_MARKEDUSER)) {
2331                 flag_str[pos++] = 'M';
2332         }
2333         if (ast_test_flag(&participant->u_profile, USER_OPT_WAITMARKED)) {
2334                 flag_str[pos++] = 'W';
2335         }
2336         if (ast_test_flag(&participant->u_profile, USER_OPT_ENDMARKED)) {
2337                 flag_str[pos++] = 'E';
2338         }
2339         if (waiting) {
2340                 flag_str[pos++] = 'w';
2341         }
2342         flag_str[pos] = '\0';
2343
2344         ast_cli(a->fd, "%-29s ", ast_channel_name(participant->chan));
2345         ast_cli(a->fd, "%-5s ", flag_str);
2346         ast_cli(a->fd, "%-17s", participant->u_profile.name);
2347         ast_cli(a->fd, "%-17s", participant->b_profile.name);
2348         ast_cli(a->fd, "%-17s", participant->menu_name);
2349         ast_cli(a->fd, "%-17s", S_COR(ast_channel_caller(participant->chan)->id.number.valid, ast_channel_caller(participant->chan)->id.number.str, "<unknown>"));
2350         ast_cli(a->fd, "\n");
2351 }
2352
2353 static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2354 {
2355         struct conference_bridge *bridge;
2356
2357         switch (cmd) {
2358         case CLI_INIT:
2359                 e->command = "confbridge list";
2360                 e->usage =
2361                         "Usage: confbridge list [<name>]\n"
2362                         "       Lists all currently active conference bridges or a specific conference bridge.\n"
2363                         "\n"
2364                         "       When a conference bridge name is provided, flags may be shown for users. Below\n"
2365                         "       are the flags and what they represent.\n" 
2366                         "\n"
2367                         "       Flags:\n"
2368                         "         A - The user is an admin\n"
2369                         "         M - The user is a marked user\n"
2370                         "         W - The user must wait for a marked user to join\n"
2371                         "         E - The user will be kicked after the last marked user leaves the conference\n"
2372                         "         w - The user is waiting for a marked user to join\n";
2373                 return NULL;
2374         case CLI_GENERATE:
2375                 if (a->pos == 2) {
2376                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2377                 }
2378                 return NULL;
2379         }
2380
2381         if (a->argc == 2) {
2382                 struct ao2_iterator iter;
2383
2384                 ast_cli(a->fd, "Conference Bridge Name           Users  Marked Locked?\n");
2385                 ast_cli(a->fd, "================================ ====== ====== ========\n");
2386                 iter = ao2_iterator_init(conference_bridges, 0);
2387                 while ((bridge = ao2_iterator_next(&iter))) {
2388                         ast_cli(a->fd, "%-32s %6i %6i %s\n", bridge->name, bridge->activeusers + bridge->waitingusers, bridge->markedusers, (bridge->locked ? "locked" : "unlocked"));
2389                         ao2_ref(bridge, -1);
2390                 }
2391                 ao2_iterator_destroy(&iter);
2392                 return CLI_SUCCESS;
2393         }
2394
2395         if (a->argc == 3) {
2396                 struct conference_bridge_user *participant;
2397                 struct conference_bridge tmp;
2398
2399                 ast_copy_string(tmp.name, a->argv[2], sizeof(tmp.name));
2400                 bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2401                 if (!bridge) {
2402                         ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
2403                         return CLI_SUCCESS;
2404                 }
2405                 ast_cli(a->fd, "Channel                       Flags User Profile     Bridge Profile   Menu             CallerID\n");
2406                 ast_cli(a->fd, "============================= ===== ================ ================ ================ ================\n");
2407                 ao2_lock(bridge);
2408                 AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
2409                         handle_cli_confbridge_list_item(a, participant, 0);
2410                 }
2411                 AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) {
2412                         handle_cli_confbridge_list_item(a, participant, 1);
2413                 }
2414                 ao2_unlock(bridge);
2415                 ao2_ref(bridge, -1);
2416                 return CLI_SUCCESS;
2417         }
2418
2419         return CLI_SHOWUSAGE;
2420 }
2421
2422 /* \internal
2423  * \brief finds a conference by name and locks/unlocks.
2424  *
2425  * \retval 0 success
2426  * \retval -1 conference not found
2427  */
2428 static int generic_lock_unlock_helper(int lock, const char *conference)
2429 {
2430         struct conference_bridge *bridge = NULL;
2431         struct conference_bridge tmp;
2432         int res = 0;
2433
2434         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2435         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2436         if (!bridge) {
2437                 return -1;
2438         }
2439         ao2_lock(bridge);
2440         bridge->locked = lock;
2441         ast_test_suite_event_notify("CONF_LOCK", "Message: conference %s\r\nConference: %s", bridge->locked ? "locked" : "unlocked", bridge->b_profile.name);
2442         ao2_unlock(bridge);
2443         ao2_ref(bridge, -1);
2444
2445         return res;
2446 }
2447
2448 /* \internal
2449  * \brief finds a conference user by channel name and mutes/unmutes them.
2450  *
2451  * \retval 0 success
2452  * \retval -1 conference not found
2453  * \retval -2 user not found
2454  */
2455 static int generic_mute_unmute_helper(int mute, const char *conference, const char *user)
2456 {
2457         struct conference_bridge *bridge = NULL;
2458         struct conference_bridge tmp;
2459         struct conference_bridge_user *participant = NULL;
2460         int res = 0;
2461         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2462         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2463         if (!bridge) {
2464                 return -1;
2465         }
2466         ao2_lock(bridge);
2467         AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
2468                 if (!strncmp(user, ast_channel_name(participant->chan), strlen(user))) {
2469                         break;
2470                 }
2471         }
2472         if (participant) {
2473                 participant->features.mute = mute;
2474                 ast_test_suite_event_notify("CONF_MUTE", "Message: participant %s %s\r\nConference: %s\r\nChannel: %s", ast_channel_name(participant->chan), participant->features.mute ? "muted" : "unmuted", bridge->b_profile.name, ast_channel_name(participant->chan));
2475         } else {
2476                 res = -2;;
2477         }
2478         ao2_unlock(bridge);
2479         ao2_ref(bridge, -1);
2480
2481         return res;
2482 }
2483
2484 static int cli_mute_unmute_helper(int mute, struct ast_cli_args *a)
2485 {
2486         int res = generic_mute_unmute_helper(mute, a->argv[2], a->argv[3]);
2487
2488         if (res == -1) {
2489                 ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
2490                 return -1;
2491         } else if (res == -2) {
2492                 ast_cli(a->fd, "No channel named '%s' found in conference %s\n", a->argv[3], a->argv[2]);
2493                 return -1;
2494         }
2495         ast_cli(a->fd, "%s %s from confbridge %s\n", mute ? "Muting" : "Unmuting", a->argv[3], a->argv[2]);
2496         return 0;
2497 }
2498
2499 static char *handle_cli_confbridge_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2500 {
2501         switch (cmd) {
2502         case CLI_INIT:
2503                 e->command = "confbridge mute";
2504                 e->usage =
2505                         "Usage: confbridge mute <conference> <channel>\n"
2506                         "       Mute a channel in a conference.\n";
2507                 return NULL;
2508         case CLI_GENERATE:
2509                 if (a->pos == 2) {
2510                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2511                 }
2512                 if (a->pos == 3) {
2513                         return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
2514                 }
2515                 return NULL;
2516         }
2517         if (a->argc != 4) {
2518                 return CLI_SHOWUSAGE;
2519         }
2520
2521         cli_mute_unmute_helper(1, a);
2522
2523         return CLI_SUCCESS;
2524 }
2525
2526 static char *handle_cli_confbridge_unmute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2527 {
2528         switch (cmd) {
2529         case CLI_INIT:
2530                 e->command = "confbridge unmute";
2531                 e->usage =
2532                         "Usage: confbridge unmute <conference> <channel>\n"
2533                         "       Unmute a channel in a conference.\n";
2534                 return NULL;
2535         case CLI_GENERATE:
2536                 if (a->pos == 2) {
2537                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2538                 }
2539                 if (a->pos == 3) {
2540                         return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
2541                 }
2542                 return NULL;
2543         }
2544         if (a->argc != 4) {
2545                 return CLI_SHOWUSAGE;
2546         }
2547
2548         cli_mute_unmute_helper(0, a);
2549
2550         return CLI_SUCCESS;
2551 }
2552
2553 static char *handle_cli_confbridge_lock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2554 {
2555         switch (cmd) {
2556         case CLI_INIT:
2557                 e->command = "confbridge lock";
2558                 e->usage =
2559                         "Usage: confbridge lock <conference>\n"
2560                         "       Lock a conference. While locked, no new non-admins\n"
2561                         "       may join the conference.\n";
2562                 return NULL;
2563         case CLI_GENERATE:
2564                 if (a->pos == 2) {
2565                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2566                 }
2567                 return NULL;
2568         }
2569         if (a->argc != 3) {
2570                 return CLI_SHOWUSAGE;
2571         }
2572         if (generic_lock_unlock_helper(1, a->argv[2])) {
2573                 ast_cli(a->fd, "Conference %s is not found\n", a->argv[2]);
2574         } else {
2575                 ast_cli(a->fd, "Conference %s is locked.\n", a->argv[2]);
2576         }
2577         return CLI_SUCCESS;
2578 }
2579
2580 static char *handle_cli_confbridge_unlock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2581 {
2582         switch (cmd) {
2583         case CLI_INIT:
2584                 e->command = "confbridge unlock";
2585                 e->usage =
2586                         "Usage: confbridge unlock <conference>\n"
2587                         "       Unlock a previously locked conference.\n";
2588                 return NULL;
2589         case CLI_GENERATE:
2590                 if (a->pos == 2) {
2591                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2592                 }
2593                 return NULL;
2594         }
2595         if (a->argc != 3) {
2596                 return CLI_SHOWUSAGE;
2597         }
2598         if (generic_lock_unlock_helper(0, a->argv[2])) {
2599                 ast_cli(a->fd, "Conference %s is not found\n", a->argv[2]);
2600         } else {
2601                 ast_cli(a->fd, "Conference %s is unlocked.\n", a->argv[2]);
2602         }
2603         return CLI_SUCCESS;
2604 }
2605
2606 static char *handle_cli_confbridge_start_record(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2607 {
2608         const char *rec_file = NULL;
2609         struct conference_bridge *bridge = NULL;
2610         struct conference_bridge tmp;
2611
2612         switch (cmd) {
2613         case CLI_INIT:
2614                 e->command = "confbridge record start";
2615                 e->usage =
2616                         "Usage: confbridge record start <conference> <file>\n"
2617                         "       <file> is optional, Otherwise the bridge profile\n"
2618                         "       record file will be used.  If the bridge profile\n"
2619                         "       has no record file specified, a file will automatically\n"
2620                         "       be generated in the monitor directory\n";
2621                 return NULL;
2622         case CLI_GENERATE:
2623                 if (a->pos == 3) {
2624                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2625                 }
2626                 return NULL;
2627         }
2628         if (a->argc < 4) {
2629                 return CLI_SHOWUSAGE;
2630         }
2631         if (a->argc == 5) {
2632                 rec_file = a->argv[4];
2633         }
2634
2635         ast_copy_string(tmp.name, a->argv[3], sizeof(tmp.name));
2636         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2637         if (!bridge) {
2638                 ast_cli(a->fd, "Conference not found.\n");
2639                 return CLI_FAILURE;
2640         }
2641         ao2_lock(bridge);
2642         if (conf_is_recording(bridge)) {
2643                 ast_cli(a->fd, "Conference is already being recorded.\n");
2644                 ao2_unlock(bridge);
2645                 ao2_ref(bridge, -1);
2646                 return CLI_SUCCESS;
2647         }
2648         if (!ast_strlen_zero(rec_file)) {
2649                 ast_copy_string(bridge->b_profile.rec_file, rec_file, sizeof(bridge->b_profile.rec_file));
2650         }
2651
2652         if (start_conf_record_thread(bridge)) {
2653                 ast_cli(a->fd, "Could not start recording due to internal error.\n");
2654                 ao2_unlock(bridge);
2655                 ao2_ref(bridge, -1);
2656                 return CLI_FAILURE;
2657         }
2658         ao2_unlock(bridge);
2659
2660         ast_cli(a->fd, "Recording started\n");
2661         ao2_ref(bridge, -1);
2662         return CLI_SUCCESS;
2663 }
2664
2665 static char *handle_cli_confbridge_stop_record(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2666 {
2667         struct conference_bridge *bridge = NULL;
2668         struct conference_bridge tmp;
2669         int ret;
2670
2671         switch (cmd) {
2672         case CLI_INIT:
2673                 e->command = "confbridge record stop";
2674                 e->usage =
2675                         "Usage: confbridge record stop <conference>\n"
2676                         "       Stop a previously started recording.\n";
2677                 return NULL;
2678         case CLI_GENERATE:
2679                 if (a->pos == 3) {
2680                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2681                 }
2682                 return NULL;
2683         }
2684         if (a->argc != 4) {
2685                 return CLI_SHOWUSAGE;
2686         }
2687
2688         ast_copy_string(tmp.name, a->argv[3], sizeof(tmp.name));
2689         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2690         if (!bridge) {
2691                 ast_cli(a->fd, "Conference not found.\n");
2692                 return CLI_SUCCESS;
2693         }
2694         ao2_lock(bridge);
2695         ret = conf_stop_record(bridge);
2696         ao2_unlock(bridge);
2697         ast_cli(a->fd, "Recording %sstopped.\n", ret ? "could not be " : "");
2698         ao2_ref(bridge, -1);
2699         return CLI_SUCCESS;
2700 }
2701
2702 static struct ast_cli_entry cli_confbridge[] = {
2703         AST_CLI_DEFINE(handle_cli_confbridge_list, "List conference bridges and participants."),
2704         AST_CLI_DEFINE(handle_cli_confbridge_kick, "Kick participants out of conference bridges."),
2705         AST_CLI_DEFINE(handle_cli_confbridge_mute, "Mute a participant."),
2706         AST_CLI_DEFINE(handle_cli_confbridge_unmute, "Unmute a participant."),
2707         AST_CLI_DEFINE(handle_cli_confbridge_lock, "Lock a conference."),
2708         AST_CLI_DEFINE(handle_cli_confbridge_unlock, "Unlock a conference."),
2709         AST_CLI_DEFINE(handle_cli_confbridge_start_record, "Start recording a conference"),
2710         AST_CLI_DEFINE(handle_cli_confbridge_stop_record, "Stop recording a conference."),
2711 };
2712 static struct ast_custom_function confbridge_function = {
2713         .name = "CONFBRIDGE",
2714         .write = func_confbridge_helper,
2715 };
2716
2717 static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
2718 static struct ast_custom_function confbridge_info_function = {
2719         .name = "CONFBRIDGE_INFO",
2720         .read = func_confbridge_info,
2721 };
2722
2723 static void action_confbridgelist_item(struct mansession *s, const char *id_text, struct conference_bridge *bridge, struct conference_bridge_user *participant, int waiting)
2724 {
2725         astman_append(s,
2726                 "Event: ConfbridgeList\r\n"
2727                 "%s"
2728                 "Conference: %s\r\n"
2729                 "CallerIDNum: %s\r\n"
2730                 "CallerIDName: %s\r\n"
2731                 "Channel: %s\r\n"
2732                 "Admin: %s\r\n"
2733                 "MarkedUser: %s\r\n"
2734                 "WaitMarked: %s\r\n"
2735                 "EndMarked: %s\r\n"
2736                 "Waiting: %s\r\n"
2737                 "\r\n",
2738                 id_text,
2739                 bridge->name,
2740                 S_COR(ast_channel_caller(participant->chan)->id.number.valid, ast_channel_caller(participant->chan)->id.number.str, "<unknown>"),
2741                 S_COR(ast_channel_caller(participant->chan)->id.name.valid, ast_channel_caller(participant->chan)->id.name.str, "<no name>"),
2742                 ast_channel_name(participant->chan),
2743                 ast_test_flag(&participant->u_profile, USER_OPT_ADMIN) ? "Yes" : "No",
2744                 ast_test_flag(&participant->u_profile, USER_OPT_MARKEDUSER) ? "Yes" : "No",
2745                 ast_test_flag(&participant->u_profile, USER_OPT_WAITMARKED) ? "Yes" : "No",
2746                 ast_test_flag(&participant->u_profile, USER_OPT_ENDMARKED) ? "Yes" : "No",
2747                 waiting ? "Yes" : "No");
2748 }
2749
2750 static int action_confbridgelist(struct mansession *s, const struct message *m)
2751 {
2752         const char *actionid = astman_get_header(m, "ActionID");
2753         const char *conference = astman_get_header(m, "Conference");
2754         struct conference_bridge_user *participant;
2755         struct conference_bridge *bridge;
2756         struct conference_bridge tmp;
2757         char id_text[80];
2758         int total = 0;
2759
2760         id_text[0] = '\0';
2761         if (!ast_strlen_zero(actionid)) {
2762                 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", actionid);
2763         }
2764         if (ast_strlen_zero(conference)) {
2765                 astman_send_error(s, m, "No Conference name provided.");
2766                 return 0;
2767         }
2768         if (!ao2_container_count(conference_bridges)) {
2769                 astman_send_error(s, m, "No active conferences.");
2770                 return 0;
2771         }
2772         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2773         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2774         if (!bridge) {
2775                 astman_send_error(s, m, "No Conference by that name found.");
2776                 return 0;
2777         }
2778
2779         astman_send_listack(s, m, "Confbridge user list will follow", "start");
2780
2781         ao2_lock(bridge);
2782         AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
2783                 total++;
2784                 action_confbridgelist_item(s, id_text, bridge, participant, 0);
2785         }
2786         AST_LIST_TRAVERSE(&bridge->waiting_list, participant, list) {
2787                 total++;
2788                 action_confbridgelist_item(s, id_text, bridge, participant, 1);
2789         }
2790         ao2_unlock(bridge);
2791         ao2_ref(bridge, -1);
2792
2793         astman_append(s,
2794         "Event: ConfbridgeListComplete\r\n"
2795         "EventList: Complete\r\n"
2796         "ListItems: %d\r\n"
2797         "%s"
2798         "\r\n", total, id_text);
2799
2800         return 0;
2801 }
2802
2803 static int action_confbridgelistrooms(struct mansession *s, const struct message *m)
2804 {
2805         const char *actionid = astman_get_header(m, "ActionID");
2806         struct conference_bridge *bridge = NULL;
2807         struct ao2_iterator iter;
2808         char id_text[512] = "";
2809         int totalitems = 0;
2810
2811         if (!ast_strlen_zero(actionid)) {
2812                 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", actionid);
2813         }
2814
2815         if (!ao2_container_count(conference_bridges)) {
2816                 astman_send_error(s, m, "No active conferences.");
2817                 return 0;
2818         }
2819
2820         astman_send_listack(s, m, "Confbridge conferences will follow", "start");
2821
2822         /* Traverse the conference list */
2823         iter = ao2_iterator_init(conference_bridges, 0);
2824         while ((bridge = ao2_iterator_next(&iter))) {
2825                 totalitems++;
2826
2827                 ao2_lock(bridge);
2828                 astman_append(s,
2829                 "Event: ConfbridgeListRooms\r\n"
2830                 "%s"
2831                 "Conference: %s\r\n"
2832                 "Parties: %d\r\n"
2833                 "Marked: %d\r\n"
2834                 "Locked: %s\r\n"
2835                 "\r\n",
2836                 id_text,
2837                 bridge->name,
2838                 bridge->activeusers + bridge->waitingusers,
2839                 bridge->markedusers,
2840                 bridge->locked ? "Yes" : "No"); 
2841                 ao2_unlock(bridge);
2842
2843                 ao2_ref(bridge, -1);
2844         }
2845         ao2_iterator_destroy(&iter);
2846
2847         /* Send final confirmation */
2848         astman_append(s,
2849         "Event: ConfbridgeListRoomsComplete\r\n"
2850         "EventList: Complete\r\n"
2851         "ListItems: %d\r\n"
2852         "%s"
2853         "\r\n", totalitems, id_text);
2854         return 0;
2855 }
2856
2857 static int action_mute_unmute_helper(struct mansession *s, const struct message *m, int mute)
2858 {
2859         const char *conference = astman_get_header(m, "Conference");
2860         const char *channel = astman_get_header(m, "Channel");
2861         int res = 0;
2862
2863         if (ast_strlen_zero(conference)) {
2864                 astman_send_error(s, m, "No Conference name provided.");
2865                 return 0;
2866         }
2867         if (ast_strlen_zero(channel)) {
2868                 astman_send_error(s, m, "No channel name provided.");
2869                 return 0;
2870         }
2871         if (!ao2_container_count(conference_bridges)) {
2872                 astman_send_error(s, m, "No active conferences.");
2873                 return 0;
2874         }
2875
2876         res = generic_mute_unmute_helper(mute, conference, channel);
2877
2878         if (res == -1) {
2879                 astman_send_error(s, m, "No Conference by that name found.");
2880                 return 0;
2881         } else if (res == -2) {
2882                 astman_send_error(s, m, "No Channel by that name found in Conference.");
2883                 return 0;
2884         }
2885
2886         astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
2887         return 0;
2888 }
2889
2890 static int action_confbridgeunmute(struct mansession *s, const struct message *m)
2891 {
2892         return action_mute_unmute_helper(s, m, 0);
2893 }
2894 static int action_confbridgemute(struct mansession *s, const struct message *m)
2895 {
2896         return action_mute_unmute_helper(s, m, 1);
2897 }
2898
2899 static int action_lock_unlock_helper(struct mansession *s, const struct message *m, int lock)
2900 {
2901         const char *conference = astman_get_header(m, "Conference");
2902         int res = 0;
2903
2904         if (ast_strlen_zero(conference)) {
2905                 astman_send_error(s, m, "No Conference name provided.");
2906                 return 0;
2907         }
2908         if (!ao2_container_count(conference_bridges)) {
2909                 astman_send_error(s, m, "No active conferences.");
2910                 return 0;
2911         }
2912         if ((res = generic_lock_unlock_helper(lock, conference))) {
2913                 astman_send_error(s, m, "No Conference by that name found.");
2914                 return 0;
2915         }
2916         astman_send_ack(s, m, lock ? "Conference locked" : "Conference unlocked");
2917         return 0;
2918 }
2919 static int action_confbridgeunlock(struct mansession *s, const struct message *m)
2920 {
2921         return action_lock_unlock_helper(s, m, 0);
2922 }
2923 static int action_confbridgelock(struct mansession *s, const struct message *m)
2924 {
2925         return action_lock_unlock_helper(s, m, 1);
2926 }
2927
2928 static int action_confbridgekick(struct mansession *s, const struct message *m)
2929 {
2930         const char *conference = astman_get_header(m, "Conference");
2931         const char *channel = astman_get_header(m, "Channel");
2932         struct conference_bridge *bridge = NULL;
2933         struct conference_bridge tmp;
2934         int found = 0;
2935
2936         if (ast_strlen_zero(conference)) {
2937                 astman_send_error(s, m, "No Conference name provided.");
2938                 return 0;
2939         }
2940         if (!ao2_container_count(conference_bridges)) {
2941                 astman_send_error(s, m, "No active conferences.");
2942                 return 0;
2943         }
2944
2945         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2946         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2947         if (!bridge) {
2948                 astman_send_error(s, m, "No Conference by that name found.");
2949                 return 0;
2950         }
2951
2952         found = !kick_conference_participant(bridge, channel);
2953         ao2_ref(bridge, -1);
2954
2955         if (found) {
2956                 astman_send_ack(s, m, "User kicked");
2957         } else {
2958                 astman_send_error(s, m, "No Channel by that name found in Conference.");
2959         }
2960         return 0;
2961 }
2962
2963 static int action_confbridgestartrecord(struct mansession *s, const struct message *m)
2964 {
2965         const char *conference = astman_get_header(m, "Conference");
2966         const char *recordfile = astman_get_header(m, "RecordFile");
2967         struct conference_bridge *bridge = NULL;
2968         struct conference_bridge tmp;
2969
2970         if (ast_strlen_zero(conference)) {
2971                 astman_send_error(s, m, "No Conference name provided.");
2972                 return 0;
2973         }
2974         if (!ao2_container_count(conference_bridges)) {
2975                 astman_send_error(s, m, "No active conferences.");
2976                 return 0;
2977         }
2978
2979         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2980         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2981         if (!bridge) {
2982                 astman_send_error(s, m, "No Conference by that name found.");
2983                 return 0;
2984         }
2985
2986         ao2_lock(bridge);
2987         if (conf_is_recording(bridge)) {
2988                 astman_send_error(s, m, "Conference is already being recorded.");
2989                 ao2_unlock(bridge);
2990                 ao2_ref(bridge, -1);
2991                 return 0;
2992         }
2993
2994         if (!ast_strlen_zero(recordfile)) {
2995                 ast_copy_string(bridge->b_profile.rec_file, recordfile, sizeof(bridge->b_profile.rec_file));
2996         }
2997
2998         if (start_conf_record_thread(bridge)) {
2999                 astman_send_error(s, m, "Internal error starting conference recording.");
3000                 ao2_unlock(bridge);
3001                 ao2_ref(bridge, -1);
3002                 return 0;
3003         }
3004         ao2_unlock(bridge);
3005
3006         ao2_ref(bridge, -1);
3007         astman_send_ack(s, m, "Conference Recording Started.");
3008         return 0;
3009 }
3010 static int action_confbridgestoprecord(struct mansession *s, const struct message *m)
3011 {
3012         const char *conference = astman_get_header(m, "Conference");
3013         struct conference_bridge *bridge = NULL;
3014         struct conference_bridge tmp;
3015
3016         if (ast_strlen_zero(conference)) {
3017                 astman_send_error(s, m, "No Conference name provided.");
3018                 return 0;
3019         }
3020         if (!ao2_container_count(conference_bridges)) {
3021                 astman_send_error(s, m, "No active conferences.");
3022                 return 0;
3023         }
3024
3025         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
3026         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
3027         if (!bridge) {
3028                 astman_send_error(s, m, "No Conference by that name found.");
3029                 return 0;
3030         }
3031
3032         ao2_lock(bridge);
3033         if (conf_stop_record(bridge)) {
3034                 ao2_unlock(bridge);
3035                 astman_send_error(s, m, "Internal error while stopping recording.");
3036                 ao2_ref(bridge, -1);
3037                 return 0;
3038         }
3039         ao2_unlock(bridge);
3040
3041         ao2_ref(bridge, -1);
3042         astman_send_ack(s, m, "Conference Recording Stopped.");
3043         return 0;
3044 }
3045
3046 static int action_confbridgesetsinglevideosrc(struct mansession *s, const struct message *m)
3047 {
3048         const char *conference = astman_get_header(m, "Conference");
3049         const char *channel = astman_get_header(m, "Channel");
3050         struct conference_bridge_user *participant = NULL;
3051         struct conference_bridge *bridge = NULL;
3052         struct conference_bridge tmp;
3053
3054         if (ast_strlen_zero(conference)) {
3055                 astman_send_error(s, m, "No Conference name provided.");
3056                 return 0;
3057         }
3058         if (ast_strlen_zero(channel)) {
3059                 astman_send_error(s, m, "No channel name provided.");
3060                 return 0;
3061         }
3062         if (!ao2_container_count(conference_bridges)) {
3063                 astman_send_error(s, m, "No active conferences.");
3064                 return 0;
3065         }
3066
3067         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
3068         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
3069         if (!bridge) {
3070                 astman_send_error(s, m, "No Conference by that name found.");
3071                 return 0;
3072         }
3073
3074         /* find channel and set as video src. */
3075         ao2_lock(bridge);
3076         AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
3077                 if (!strncmp(channel, ast_channel_name(participant->chan), strlen(channel))) {
3078                         ast_bridge_set_single_src_video_mode(bridge->bridge, participant->chan);
3079                         break;
3080                 }
3081         }
3082         ao2_unlock(bridge);
3083         ao2_ref(bridge, -1);
3084
3085         /* do not access participant after bridge unlock.  We are just
3086          * using this check to see if it was found or not */
3087         if (!participant) {
3088                 astman_send_error(s, m, "No channel by that name found in conference.");
3089                 return 0;
3090         }
3091         astman_send_ack(s, m, "Conference single video source set.");
3092         return 0;
3093 }
3094
3095 static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
3096 {
3097         char *parse = NULL;
3098         struct conference_bridge *bridge = NULL;
3099         struct conference_bridge_user *participant = NULL;
3100         struct conference_bridge tmp;
3101         int count = 0;
3102         AST_DECLARE_APP_ARGS(args,
3103                 AST_APP_ARG(type);
3104                 AST_APP_ARG(confno);
3105         );
3106
3107         /* parse all the required arguments and make sure they exist. */
3108         if (ast_strlen_zero(data)) {
3109                 return -1;
3110         }
3111         parse = ast_strdupa(data);
3112         AST_STANDARD_APP_ARGS(args, parse);
3113         if (ast_strlen_zero(args.confno) || ast_strlen_zero(args.type)) {
3114                 return -1;
3115         }
3116         if (!ao2_container_count(conference_bridges)) {
3117                 snprintf(buf, len, "0");
3118                 return 0;
3119         }
3120         ast_copy_string(tmp.name, args.confno, sizeof(tmp.name));
3121         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
3122         if (!bridge) {
3123                 snprintf(buf, len, "0");
3124                 return 0;
3125         }
3126
3127         /* get the correct count for the type requested */
3128         ao2_lock(bridge);
3129         if (!strncasecmp(args.type, "parties", 7)) {
3130                 AST_LIST_TRAVERSE(&bridge->active_list, participant, list) {
3131                         count++;
3132                 }