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