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