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