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