ast_channel opaquification of pointers and integral types
[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 /*** MODULEINFO
32         <support_level>core</support_level>
33  ***/
34
35 #include "asterisk.h"
36
37 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <signal.h>
44
45 #include "asterisk/cli.h"
46 #include "asterisk/file.h"
47 #include "asterisk/channel.h"
48 #include "asterisk/pbx.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/module.h"
51 #include "asterisk/lock.h"
52 #include "asterisk/bridging.h"
53 #include "asterisk/musiconhold.h"
54 #include "asterisk/say.h"
55 #include "asterisk/audiohook.h"
56 #include "asterisk/astobj2.h"
57 #include "confbridge/include/confbridge.h"
58 #include "asterisk/paths.h"
59 #include "asterisk/manager.h"
60 #include "asterisk/test.h"
61
62 /*** DOCUMENTATION
63     <application name="ConfBridge" language="en_US">
64             <synopsis>
65                     Conference bridge application.
66             </synopsis>
67             <syntax>
68                     <parameter name="confno">
69                             <para>The conference number</para>
70                     </parameter>
71                     <parameter name="bridge_profile">
72                             <para>The bridge profile name from confbridge.conf.  When left blank, a dynamically built bridge profile created by the CONFBRIDGE dialplan function is searched for on the channel and used.  If no dynamic profile is present, the 'default_bridge' profile found in confbridge.conf is used. </para>
73                             <para>It is important to note that while user profiles may be unique for each participant, mixing bridge profiles on a single conference is _NOT_ recommended and will produce undefined results.</para>
74                     </parameter>
75                     <parameter name="user_profile">
76                             <para>The user profile name from confbridge.conf.  When left blank, a dynamically built user profile created by the CONFBRIDGE dialplan function is searched for on the channel and used.  If no dynamic profile is present, the 'default_user' profile found in confbridge.conf is used.</para>
77                     </parameter>
78                     <parameter name="menu">
79                             <para>The name of the DTMF menu in confbridge.conf to be applied to this channel.  No menu is applied by default if this option is left blank.</para>
80                     </parameter>
81             </syntax>
82             <description>
83                     <para>Enters the user into a specified conference bridge. The user can exit the conference by hangup or DTMF menu option.</para>
84             </description>
85                         <see-also>
86                                 <ref type="application">ConfBridge</ref>
87                                 <ref type="function">CONFBRIDGE</ref>
88                                 <ref type="function">CONFBRIDGE_INFO</ref>
89                         </see-also>
90     </application>
91         <function name="CONFBRIDGE" language="en_US">
92                 <synopsis>
93                         Set a custom dynamic bridge and user profile on a channel for the ConfBridge application using the same options defined in confbridge.conf.
94                 </synopsis>
95                 <syntax>
96                         <parameter name="type" required="true">
97                                 <para>Type refers to which type of profile the option belongs too.  Type can be <literal>bridge</literal> or <literal>user</literal>.</para>
98                         </parameter>
99             <parameter name="option" required="true">
100                                 <para>Option refers to <filename>confbridge.conf</filename> option that is being set dynamically on this channel.</para>
101                         </parameter>
102                 </syntax>
103                 <description>
104                         <para>---- Example 1 ----</para>
105                         <para>In this example the custom set user profile on this channel will automatically be used by the ConfBridge app.</para> 
106                         <para>exten => 1,1,Answer() </para>
107                         <para>exten => 1,n,Set(CONFBRIDGE(user,announce_join_leave)=yes)</para>
108                         <para>exten => 1,n,Set(CONFBRIDGE(user,startmuted)=yes)</para>
109                         <para>exten => 1,n,ConfBridge(1) </para>
110                         <para>---- Example 2 ----</para>
111                         <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> 
112                         <para>exten => 1,1,Answer() </para>
113                         <para>exten => 1,n,Set(CONFBRIDGE(user,template)=default_user)</para>
114                         <para>exten => 1,n,Set(CONFBRIDGE(user,admin)=yes)</para>
115                         <para>exten => 1,n,Set(CONFBRIDGE(user,marked)=yes)</para>
116                         <para>exten => 1,n,ConfBridge(1)</para>
117                 </description>
118         </function>
119         <function name="CONFBRIDGE_INFO" language="en_US">
120                 <synopsis>
121                         Get information about a ConfBridge conference.
122                 </synopsis>
123                 <syntax>
124                         <parameter name="type" required="true">
125                                 <para>Type can be <literal>parties</literal>, <literal>admins</literal>, <literal>marked</literal>, or <literal>locked</literal>.</para>
126                         </parameter>
127                         <parameter name="conf" required="true">
128                                 <para>Conf refers to the name of the conference being referenced.</para>
129                         </parameter>
130                 </syntax>
131                 <description>
132                         <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> 
133                 </description>
134         </function>
135         <manager name="ConfbridgeList" language="en_US">
136                 <synopsis>
137                         List participants in a conference.
138                 </synopsis>
139                 <syntax>
140                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
141                         <parameter name="Conference" required="false">
142                                 <para>Conference number.</para>
143                         </parameter>
144                 </syntax>
145                 <description>
146                         <para>Lists all users in a particular ConfBridge conference.
147                         ConfbridgeList will follow as separate events, followed by a final event called
148                         ConfbridgeListComplete.</para>
149                 </description>
150         </manager>
151         <manager name="ConfbridgeListRooms" language="en_US">
152                 <synopsis>
153                         List active conferences.
154                 </synopsis>
155                 <syntax>
156                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
157                 </syntax>
158                 <description>
159                         <para>Lists data about all active conferences.
160                                 ConfbridgeListRooms will follow as separate events, followed by a final event called
161                                 ConfbridgeListRoomsComplete.</para>
162                 </description>
163         </manager>
164         <manager name="ConfbridgeMute" language="en_US">
165                 <synopsis>
166                         Mute a Confbridge user.
167                 </synopsis>
168                 <syntax>
169                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
170                         <parameter name="Conference" required="true" />
171                         <parameter name="Channel" required="true" />
172                 </syntax>
173                 <description>
174                 </description>
175         </manager>
176         <manager name="ConfbridgeUnmute" language="en_US">
177                 <synopsis>
178                         Unmute a Confbridge user.
179                 </synopsis>
180                 <syntax>
181                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
182                         <parameter name="Conference" required="true" />
183                         <parameter name="Channel" required="true" />
184                 </syntax>
185                 <description>
186                 </description>
187         </manager>
188         <manager name="ConfbridgeKick" language="en_US">
189                 <synopsis>
190                         Kick a Confbridge user.
191                 </synopsis>
192                 <syntax>
193                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
194                         <parameter name="Conference" required="true" />
195                         <parameter name="Channel" required="true" />
196                 </syntax>
197                 <description>
198                 </description>
199         </manager>
200         <manager name="ConfbridgeLock" language="en_US">
201                 <synopsis>
202                         Lock a Confbridge conference.
203                 </synopsis>
204                 <syntax>
205                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
206                         <parameter name="Conference" required="true" />
207                 </syntax>
208                 <description>
209                 </description>
210         </manager>
211         <manager name="ConfbridgeUnlock" language="en_US">
212                 <synopsis>
213                         Unlock a Confbridge conference.
214                 </synopsis>
215                 <syntax>
216                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
217                         <parameter name="Conference" required="true" />
218                 </syntax>
219                 <description>
220                 </description>
221         </manager>
222         <manager name="ConfbridgeStartRecord" language="en_US">
223                 <synopsis>
224                         Start recording a Confbridge conference.
225                 </synopsis>
226                 <syntax>
227                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
228                         <parameter name="Conference" required="true" />
229                         <parameter name="RecordFile" required="false" />
230                 </syntax>
231                 <description>
232                         <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>
233                 </description>
234         </manager>
235         <manager name="ConfbridgeStopRecord" language="en_US">
236                 <synopsis>
237                         Stop recording a Confbridge conference.
238                 </synopsis>
239                 <syntax>
240                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
241                         <parameter name="Conference" required="true" />
242                 </syntax>
243                 <description>
244                 </description>
245         </manager>
246         <manager name="ConfbridgeSetSingleVideoSrc" language="en_US">
247                 <synopsis>
248                         Set a conference user as the single video source distributed to all other participants.
249                 </synopsis>
250                 <syntax>
251                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
252                         <parameter name="Conference" required="true" />
253                         <parameter name="Channel" required="true" />
254                 </syntax>
255                 <description>
256                 </description>
257         </manager>
258
259 ***/
260
261 /*!
262  * \par Playing back a file to a channel in a conference
263  * You might notice in this application that while playing a sound file
264  * to a channel the actual conference bridge lock is not held. This is done so
265  * that other channels are not blocked from interacting with the conference bridge.
266  * Unfortunately because of this it is possible for things to change after the sound file
267  * is done being played. Data must therefore be checked after reacquiring the conference
268  * bridge lock if it is important.
269  */
270
271 static const char app[] = "ConfBridge";
272
273 /* Number of buckets our conference bridges container can have */
274 #define CONFERENCE_BRIDGE_BUCKETS 53
275
276 /*! \brief Container to hold all conference bridges in progress */
277 static struct ao2_container *conference_bridges;
278
279 static int play_sound_file(struct conference_bridge *conference_bridge, const char *filename);
280 static int play_sound_number(struct conference_bridge *conference_bridge, int say_number);
281 static int execute_menu_entry(struct conference_bridge *conference_bridge,
282         struct conference_bridge_user *conference_bridge_user,
283         struct ast_bridge_channel *bridge_channel,
284         struct conf_menu_entry *menu_entry,
285         struct conf_menu *menu);
286
287 /*! \brief Hashing function used for conference bridges container */
288 static int conference_bridge_hash_cb(const void *obj, const int flags)
289 {
290         const struct conference_bridge *conference_bridge = obj;
291         return ast_str_case_hash(conference_bridge->name);
292 }
293
294 /*! \brief Comparison function used for conference bridges container */
295 static int conference_bridge_cmp_cb(void *obj, void *arg, int flags)
296 {
297         const struct conference_bridge *conference_bridge0 = obj, *conference_bridge1 = arg;
298         return (!strcasecmp(conference_bridge0->name, conference_bridge1->name) ? CMP_MATCH | CMP_STOP : 0);
299 }
300
301 const char *conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds *custom_sounds)
302 {
303         switch (sound) {
304         case CONF_SOUND_HAS_JOINED:
305                 return S_OR(custom_sounds->hasjoin, "conf-hasjoin");
306         case CONF_SOUND_HAS_LEFT:
307                 return S_OR(custom_sounds->hasleft, "conf-hasleft");
308         case CONF_SOUND_KICKED:
309                 return S_OR(custom_sounds->kicked, "conf-kicked");
310         case CONF_SOUND_MUTED:
311                 return S_OR(custom_sounds->muted, "conf-muted");
312         case CONF_SOUND_UNMUTED:
313                 return S_OR(custom_sounds->unmuted, "conf-unmuted");
314         case CONF_SOUND_ONLY_ONE:
315                 return S_OR(custom_sounds->onlyone, "conf-onlyone");
316         case CONF_SOUND_THERE_ARE:
317                 return S_OR(custom_sounds->thereare, "conf-thereare");
318         case CONF_SOUND_OTHER_IN_PARTY:
319                 return S_OR(custom_sounds->otherinparty, "conf-otherinparty");
320         case CONF_SOUND_PLACE_IN_CONF:
321                 return S_OR(custom_sounds->placeintoconf, "conf-placeintoconf");
322         case CONF_SOUND_WAIT_FOR_LEADER:
323                 return S_OR(custom_sounds->waitforleader, "conf-waitforleader");
324         case CONF_SOUND_LEADER_HAS_LEFT:
325                 return S_OR(custom_sounds->leaderhasleft, "conf-leaderhasleft");
326         case CONF_SOUND_GET_PIN:
327                 return S_OR(custom_sounds->getpin, "conf-getpin");
328         case CONF_SOUND_INVALID_PIN:
329                 return S_OR(custom_sounds->invalidpin, "conf-invalidpin");
330         case CONF_SOUND_ONLY_PERSON:
331                 return S_OR(custom_sounds->onlyperson, "conf-onlyperson");
332         case CONF_SOUND_LOCKED:
333                 return S_OR(custom_sounds->locked, "conf-locked");
334         case CONF_SOUND_LOCKED_NOW:
335                 return S_OR(custom_sounds->lockednow, "conf-lockednow");
336         case CONF_SOUND_UNLOCKED_NOW:
337                 return S_OR(custom_sounds->unlockednow, "conf-unlockednow");
338         case CONF_SOUND_ERROR_MENU:
339                 return S_OR(custom_sounds->errormenu, "conf-errormenu");
340         case CONF_SOUND_JOIN:
341                 return S_OR(custom_sounds->join, "confbridge-join");
342         case CONF_SOUND_LEAVE:
343                 return S_OR(custom_sounds->leave, "confbridge-leave");
344         case CONF_SOUND_PARTICIPANTS_MUTED:
345                 return S_OR(custom_sounds->participantsmuted, "conf-now-muted");
346         case CONF_SOUND_PARTICIPANTS_UNMUTED:
347                 return S_OR(custom_sounds->participantsunmuted, "conf-now-unmuted");
348         }
349
350         return "";
351 }
352
353 static struct ast_frame *rec_read(struct ast_channel *ast)
354 {
355         return &ast_null_frame;
356 }
357 static int rec_write(struct ast_channel *ast, struct ast_frame *f)
358 {
359         return 0;
360 }
361 static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
362 static struct ast_channel_tech record_tech = {
363         .type = "ConfBridgeRec",
364         .description = "Conference Bridge Recording Channel",
365         .requester = rec_request,
366         .read = rec_read,
367         .write = rec_write,
368 };
369 static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
370 {
371         struct ast_channel *tmp;
372         struct ast_format fmt;
373         const char *conf_name = data;
374         if (!(tmp = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", NULL, 0,
375                 "ConfBridgeRecorder/conf-%s-uid-%d",
376                 conf_name,
377                 (int) ast_random()))) {
378                 return NULL;
379         }
380         ast_format_set(&fmt, AST_FORMAT_SLINEAR, 0);
381         ast_channel_tech_set(tmp, &record_tech);
382         ast_format_cap_add_all(ast_channel_nativeformats(tmp));
383         ast_format_copy(&tmp->writeformat, &fmt);
384         ast_format_copy(&tmp->rawwriteformat, &fmt);
385         ast_format_copy(&tmp->readformat, &fmt);
386         ast_format_copy(&tmp->rawreadformat, &fmt);
387         return tmp;
388 }
389
390 static void *record_thread(void *obj)
391 {
392         struct conference_bridge *conference_bridge = obj;
393         struct ast_app *mixmonapp = pbx_findapp("MixMonitor");
394         struct ast_channel *chan;
395         struct ast_str *filename = ast_str_alloca(PATH_MAX);
396
397         if (!mixmonapp) {
398                 ao2_ref(conference_bridge, -1);
399                 return NULL;
400         }
401
402         ao2_lock(conference_bridge);
403         if (!(conference_bridge->record_chan)) {
404                 conference_bridge->record_thread = AST_PTHREADT_NULL;
405                 ao2_unlock(conference_bridge);
406                 ao2_ref(conference_bridge, -1);
407                 return NULL;
408         }
409         chan = ast_channel_ref(conference_bridge->record_chan);
410
411         if (!(ast_strlen_zero(conference_bridge->b_profile.rec_file))) {
412                 ast_str_append(&filename, 0, "%s", conference_bridge->b_profile.rec_file);
413         } else {
414                 time_t now;
415                 time(&now);
416                 ast_str_append(&filename, 0, "confbridge-%s-%u.wav",
417                         conference_bridge->name,
418                         (unsigned int) now);
419         }
420         ao2_unlock(conference_bridge);
421
422         ast_answer(chan);
423         pbx_exec(chan, mixmonapp, ast_str_buffer(filename));
424         ast_bridge_join(conference_bridge->bridge, chan, NULL, NULL, NULL);
425
426         ao2_lock(conference_bridge);
427         conference_bridge->record_thread = AST_PTHREADT_NULL;
428         ao2_unlock(conference_bridge);
429
430         ast_hangup(chan); /* This will eat this threads reference to the channel as well */
431         ao2_ref(conference_bridge, -1);
432         return NULL;
433 }
434
435 /*!
436  * \internal
437  * \brief Returns whether or not conference is being recorded.
438  * \retval 1, conference is recording.
439  * \retval 0, conference is NOT recording.
440  */
441 static int conf_is_recording(struct conference_bridge *conference_bridge)
442 {
443         int res = 0;
444         ao2_lock(conference_bridge);
445         if (conference_bridge->record_chan || conference_bridge->record_thread != AST_PTHREADT_NULL) {
446                 res = 1;
447         }
448         ao2_unlock(conference_bridge);
449         return res;
450 }
451
452 /*!
453  * \internal
454  * \brief Stops the confbridge recording thread.
455  *
456  * \note do not call this function with any locks
457  */
458 static int conf_stop_record(struct conference_bridge *conference_bridge)
459 {
460         ao2_lock(conference_bridge);
461
462         if (conference_bridge->record_thread != AST_PTHREADT_NULL) {
463                 struct ast_channel *chan = ast_channel_ref(conference_bridge->record_chan);
464                 pthread_t thread = conference_bridge->record_thread;
465                 ao2_unlock(conference_bridge);
466
467                 ast_bridge_remove(conference_bridge->bridge, chan);
468                 ast_queue_frame(chan, &ast_null_frame);
469
470                 chan = ast_channel_unref(chan);
471                 pthread_join(thread, NULL);
472                 ast_test_suite_event_notify("CONF_STOP_RECORD", "Message: stopped conference recording channel\r\nConference: %s", conference_bridge->b_profile.name);
473
474                 ao2_lock(conference_bridge);
475         }
476
477         /* this is the reference given to the channel during the channel alloc */
478         if (conference_bridge->record_chan) {
479                 conference_bridge->record_chan = ast_channel_unref(conference_bridge->record_chan);
480         }
481
482         ao2_unlock(conference_bridge);
483         return 0;
484 }
485
486 static int conf_start_record(struct conference_bridge *conference_bridge)
487 {
488         struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
489         struct ast_format tmpfmt;
490         int cause;
491
492         ao2_lock(conference_bridge);
493         if (conference_bridge->record_chan || conference_bridge->record_thread != AST_PTHREADT_NULL) {
494                 ao2_unlock(conference_bridge);
495                 return -1; /* already recording */
496         }
497         if (!cap) {
498                 ao2_unlock(conference_bridge);
499                 return -1;
500         }
501         if (!pbx_findapp("MixMonitor")) {
502                 ast_log(LOG_WARNING, "Can not record ConfBridge, MixMonitor app is not installed\n");
503                 cap = ast_format_cap_destroy(cap);
504                 ao2_unlock(conference_bridge);
505                 return -1;
506         }
507         ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
508         if (!(conference_bridge->record_chan = ast_request("ConfBridgeRec", cap, NULL, conference_bridge->name, &cause))) {
509                 cap = ast_format_cap_destroy(cap);
510                 ao2_unlock(conference_bridge);
511                 return -1;
512         }
513
514         cap = ast_format_cap_destroy(cap);
515         ao2_ref(conference_bridge, +1); /* give the record thread a ref */
516
517         if (ast_pthread_create_background(&conference_bridge->record_thread, NULL, record_thread, conference_bridge)) {
518                 ast_log(LOG_WARNING, "Failed to create recording channel for conference %s\n", conference_bridge->name);
519
520                 ao2_unlock(conference_bridge);
521                 ao2_ref(conference_bridge, -1); /* error so remove ref */
522                 return -1;
523         }
524
525         ast_test_suite_event_notify("CONF_START_RECORD", "Message: started conference recording channel\r\nConference: %s", conference_bridge->b_profile.name);
526         ao2_unlock(conference_bridge);
527         return 0;
528 }
529
530 static void send_conf_start_event(const char *conf_name)
531 {
532         manager_event(EVENT_FLAG_CALL, "ConfbridgeStart", "Conference: %s\r\n", conf_name);
533 }
534
535 static void send_conf_end_event(const char *conf_name)
536 {
537         manager_event(EVENT_FLAG_CALL, "ConfbridgeEnd", "Conference: %s\r\n", conf_name);
538 }
539
540 static void send_join_event(struct ast_channel *chan, const char *conf_name)
541 {
542         ast_manager_event(chan, EVENT_FLAG_CALL, "ConfbridgeJoin",
543                 "Channel: %s\r\n"
544                 "Uniqueid: %s\r\n"
545                 "Conference: %s\r\n"
546                 "CallerIDnum: %s\r\n"
547                 "CallerIDname: %s\r\n",
548                 ast_channel_name(chan),
549                 ast_channel_uniqueid(chan),
550                 conf_name,
551                 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "<unknown>"),
552                 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "<unknown>")
553         );
554 }
555
556 static void send_leave_event(struct ast_channel *chan, const char *conf_name)
557 {
558         ast_manager_event(chan, EVENT_FLAG_CALL, "ConfbridgeLeave",
559                 "Channel: %s\r\n"
560                 "Uniqueid: %s\r\n"
561                 "Conference: %s\r\n"
562                 "CallerIDnum: %s\r\n"
563                 "CallerIDname: %s\r\n",
564                 ast_channel_name(chan),
565                 ast_channel_uniqueid(chan),
566                 conf_name,
567                 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "<unknown>"),
568                 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "<unknown>")
569         );
570 }
571
572 /*!
573  * \brief Announce number of users in the conference bridge to the caller
574  *
575  * \param conference_bridge Conference bridge to peek at
576  * \param (OPTIONAL) conference_bridge_user Caller
577  *
578  * \note if caller is NULL, the announcment will be sent to all participants in the conference.
579  * \return Returns 0 on success, -1 if the user hung up
580  */
581 static int announce_user_count(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
582 {
583         const char *other_in_party = conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, conference_bridge->b_profile.sounds);
584         const char *only_one = conf_get_sound(CONF_SOUND_ONLY_ONE, conference_bridge->b_profile.sounds);
585         const char *there_are = conf_get_sound(CONF_SOUND_THERE_ARE, conference_bridge->b_profile.sounds);
586
587         if (conference_bridge->users == 1) {
588                 /* Awww we are the only person in the conference bridge */
589                 return 0;
590         } else if (conference_bridge->users == 2) {
591                 if (conference_bridge_user) {
592                         /* Eep, there is one other person */
593                         if (ast_stream_and_wait(conference_bridge_user->chan,
594                                 only_one,
595                                 "")) {
596                                 return -1;
597                         }
598                 } else {
599                         play_sound_file(conference_bridge, only_one);
600                 }
601         } else {
602                 /* Alas multiple others in here */
603                 if (conference_bridge_user) {
604                         if (ast_stream_and_wait(conference_bridge_user->chan,
605                                 there_are,
606                                 "")) {
607                                 return -1;
608                         }
609                         if (ast_say_number(conference_bridge_user->chan, conference_bridge->users - 1, "", ast_channel_language(conference_bridge_user->chan), NULL)) {
610                                 return -1;
611                         }
612                         if (ast_stream_and_wait(conference_bridge_user->chan,
613                                 other_in_party,
614                                 "")) {
615                                 return -1;
616                         }
617                 } else if (ast_fileexists(there_are, NULL, NULL) && ast_fileexists(other_in_party, NULL, NULL)) {
618                         play_sound_file(conference_bridge, there_are);
619                         play_sound_number(conference_bridge, conference_bridge->users - 1);
620                         play_sound_file(conference_bridge, other_in_party);
621                 }
622         }
623         return 0;
624 }
625
626 /*!
627  * \brief Play back an audio file to a channel
628  *
629  * \param conference_bridge Conference bridge they are in
630  * \param chan Channel to play audio prompt to
631  * \param file Prompt to play
632  *
633  * \return Returns 0 on success, -1 if the user hung up
634  *
635  * \note This function assumes that conference_bridge is locked
636  */
637 static int play_prompt_to_channel(struct conference_bridge *conference_bridge, struct ast_channel *chan, const char *file)
638 {
639         int res;
640         ao2_unlock(conference_bridge);
641         res = ast_stream_and_wait(chan, file, "");
642         ao2_lock(conference_bridge);
643         return res;
644 }
645
646 static void handle_video_on_join(struct conference_bridge *conference_bridge, struct ast_channel *chan, int marked)
647 {
648         /* Right now, only marked users are automatically set as the single src of video.*/
649         if (!marked) {
650                 return;
651         }
652
653         if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED)) {
654                 int set = 1;
655                 struct conference_bridge_user *tmp_user = NULL;
656                 ao2_lock(conference_bridge);
657                 /* see if anyone is already the video src */
658                 AST_LIST_TRAVERSE(&conference_bridge->users_list, tmp_user, list) {
659                         if (tmp_user->chan == chan) {
660                                 continue;
661                         }
662                         if (ast_bridge_is_video_src(conference_bridge->bridge, tmp_user->chan)) {
663                                 set = 0;
664                                 break;
665                         }
666                 }
667                 ao2_unlock(conference_bridge);
668                 if (set) {
669                         ast_bridge_set_single_src_video_mode(conference_bridge->bridge, chan);
670                 }
671         } else if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
672                 /* we joined and are video capable, we override anyone else that may have already been the video feed */
673                 ast_bridge_set_single_src_video_mode(conference_bridge->bridge, chan);
674         }
675 }
676
677 static void handle_video_on_exit(struct conference_bridge *conference_bridge, struct ast_channel *chan)
678 {
679         struct conference_bridge_user *tmp_user = NULL;
680
681         /* if this isn't a video source, nothing to update */
682         if (!ast_bridge_is_video_src(conference_bridge->bridge, chan)) {
683                 return;
684         }
685
686         ast_bridge_remove_video_src(conference_bridge->bridge, chan);
687
688         /* If in follow talker mode, make sure to restore this mode on the
689          * bridge when a source is removed.  It is possible this channel was
690          * only set temporarily as a video source by an AMI or DTMF action. */
691         if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
692                 ast_bridge_set_talker_src_video_mode(conference_bridge->bridge);
693         }
694
695         /* if the video_mode isn't set to automatically pick the video source, do nothing on exit. */
696         if (!ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED) &&
697                 !ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
698                 return;
699         }
700
701         /* Make the next available marked user the video src.  */
702         ao2_lock(conference_bridge);
703         AST_LIST_TRAVERSE(&conference_bridge->users_list, tmp_user, list) {
704                 if (tmp_user->chan == chan) {
705                         continue;
706                 }
707                 if (ast_test_flag(&tmp_user->u_profile, USER_OPT_MARKEDUSER)) {
708                         ast_bridge_set_single_src_video_mode(conference_bridge->bridge, tmp_user->chan);
709                         break;
710                 }
711         }
712         ao2_unlock(conference_bridge);
713 }
714
715 /*!
716  * \brief Perform post-joining marked specific actions
717  *
718  * \param conference_bridge Conference bridge being joined
719  * \param conference_bridge_user Conference bridge user joining
720  *
721  * \return Returns 0 on success, -1 if the user hung up
722  */
723 static int post_join_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
724 {
725         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER)) {
726                 struct conference_bridge_user *other_conference_bridge_user = NULL;
727
728                 /* If we are not the first user to join, then the users are already
729                  * in the conference so we do not need to update them. */
730                 if (conference_bridge->markedusers >= 2) {
731                         return 0;
732                 }
733
734                 /* Iterate through every participant stopping MOH on them if need be */
735                 AST_LIST_TRAVERSE(&conference_bridge->users_list, other_conference_bridge_user, list) {
736                         if (other_conference_bridge_user == conference_bridge_user) {
737                                 continue;
738                         }
739                         if (other_conference_bridge_user->playing_moh && !ast_bridge_suspend(conference_bridge->bridge, other_conference_bridge_user->chan)) {
740                                 other_conference_bridge_user->playing_moh = 0;
741                                 ast_moh_stop(other_conference_bridge_user->chan);
742                                 ast_bridge_unsuspend(conference_bridge->bridge, other_conference_bridge_user->chan);
743                         }
744                 }
745
746                 /* Next play the audio file stating they are going to be placed into the conference */
747                 if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET)) {
748                         ao2_unlock(conference_bridge);
749                         ast_autoservice_start(conference_bridge_user->chan);
750                         play_sound_file(conference_bridge,
751                                 conf_get_sound(CONF_SOUND_PLACE_IN_CONF, conference_bridge_user->b_profile.sounds));
752                         ast_autoservice_stop(conference_bridge_user->chan);
753                         ao2_lock(conference_bridge);
754                 }
755
756                 /* Finally iterate through and unmute them all */
757                 AST_LIST_TRAVERSE(&conference_bridge->users_list, other_conference_bridge_user, list) {
758                         if (other_conference_bridge_user == conference_bridge_user) {
759                                 continue;
760                         }
761                         /* only unmute them if they are not supposed to start muted */
762                         if (!ast_test_flag(&other_conference_bridge_user->u_profile, USER_OPT_STARTMUTED)) {
763                                 other_conference_bridge_user->features.mute = 0;
764                         }
765                 }
766         } else {
767                 /* If a marked user already exists in the conference bridge we can just bail out now */
768                 if (conference_bridge->markedusers) {
769                         return 0;
770                 }
771                 /* Be sure we are muted so we can't talk to anybody else waiting */
772                 conference_bridge_user->features.mute = 1;
773                 /* If we have not been quieted play back that they are waiting for the leader */
774                 if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET)) {
775                         if (play_prompt_to_channel(conference_bridge,
776                                 conference_bridge_user->chan,
777                                 conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, conference_bridge_user->b_profile.sounds))) {
778                                 /* user hungup while the sound was playing */
779                                 return -1;
780                         }
781                 }
782                 /* Start music on hold if needed */
783                 /* We need to recheck the markedusers value here. play_prompt_to_channel unlocks the conference bridge, potentially
784                  * allowing a marked user to enter while the prompt was playing
785                  */
786                 if (!conference_bridge->markedusers && ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MUSICONHOLD)) {
787                         ast_moh_start(conference_bridge_user->chan, conference_bridge_user->u_profile.moh_class, NULL);
788                         conference_bridge_user->playing_moh = 1;
789                 }
790         }
791         return 0;
792 }
793
794 /*!
795  * \brief Perform post-joining non-marked specific actions
796  *
797  * \param conference_bridge Conference bridge being joined
798  * \param conference_bridge_user Conference bridge user joining
799  *
800  * \return Returns 0 on success, -1 if the user hung up
801  */
802 static int post_join_unmarked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
803 {
804         /* Play back audio prompt and start MOH if need be if we are the first participant */
805         if (conference_bridge->users == 1) {
806                 /* If audio prompts have not been quieted or this prompt quieted play it on out */
807                 if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET | USER_OPT_NOONLYPERSON)) {
808                         if (play_prompt_to_channel(conference_bridge,
809                                 conference_bridge_user->chan,
810                                 conf_get_sound(CONF_SOUND_ONLY_PERSON, conference_bridge_user->b_profile.sounds))) {
811                                 /* user hungup while the sound was playing */
812                                 return -1;
813                         }
814                 }
815                 /* If we need to start music on hold on the channel do so now */
816                 /* We need to re-check the number of users in the conference bridge here because another conference bridge
817                  * participant could have joined while the above prompt was playing for the first user.
818                  */
819                 if (conference_bridge->users == 1 && ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MUSICONHOLD)) {
820                         ast_moh_start(conference_bridge_user->chan, conference_bridge_user->u_profile.moh_class, NULL);
821                         conference_bridge_user->playing_moh = 1;
822                 }
823                 return 0;
824         }
825
826         /* Announce number of users if need be */
827         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ANNOUNCEUSERCOUNT)) {
828                 ao2_unlock(conference_bridge);
829                 if (announce_user_count(conference_bridge, conference_bridge_user)) {
830                         ao2_lock(conference_bridge);
831                         return -1;
832                 }
833                 ao2_lock(conference_bridge);
834         }
835
836         /* If we are the second participant we may need to stop music on hold on the first */
837         if (conference_bridge->users == 2) {
838                 struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->users_list);
839
840                 /* Temporarily suspend the above participant from the bridge so we have control to stop MOH if needed */
841                 if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) {
842                         first_participant->playing_moh = 0;
843                         ast_moh_stop(first_participant->chan);
844                         ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan);
845                 }
846         }
847
848         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ANNOUNCEUSERCOUNTALL) &&
849                 (conference_bridge->users > conference_bridge_user->u_profile.announce_user_count_all_after)) {
850                 ao2_unlock(conference_bridge);
851                 if (announce_user_count(conference_bridge, NULL)) {
852                         ao2_lock(conference_bridge);
853                         return -1;
854                 }
855                 ao2_lock(conference_bridge);
856         }
857         return 0;
858 }
859
860 /*!
861  * \brief Destroy a conference bridge
862  *
863  * \param obj The conference bridge object
864  *
865  * \return Returns nothing
866  */
867 static void destroy_conference_bridge(void *obj)
868 {
869         struct conference_bridge *conference_bridge = obj;
870
871         ast_debug(1, "Destroying conference bridge '%s'\n", conference_bridge->name);
872
873         ast_mutex_destroy(&conference_bridge->playback_lock);
874
875         if (conference_bridge->playback_chan) {
876                 struct ast_channel *underlying_channel = ast_channel_tech(conference_bridge->playback_chan)->bridged_channel(conference_bridge->playback_chan, NULL);
877                 if (underlying_channel) {
878                         ast_hangup(underlying_channel);
879                 }
880                 ast_hangup(conference_bridge->playback_chan);
881                 conference_bridge->playback_chan = NULL;
882         }
883
884         /* Destroying a conference bridge is simple, all we have to do is destroy the bridging object */
885         if (conference_bridge->bridge) {
886                 ast_bridge_destroy(conference_bridge->bridge);
887                 conference_bridge->bridge = NULL;
888         }
889         conf_bridge_profile_destroy(&conference_bridge->b_profile);
890 }
891
892 static void leave_conference_bridge(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user);
893
894 /*!
895  * \brief Join a conference bridge
896  *
897  * \param name The conference name
898  * \param conference_bridge_user Conference bridge user structure
899  *
900  * \return A pointer to the conference bridge struct, or NULL if the conference room wasn't found.
901  */
902 static struct conference_bridge *join_conference_bridge(const char *name, struct conference_bridge_user *conference_bridge_user)
903 {
904         struct conference_bridge *conference_bridge = NULL;
905         struct conference_bridge tmp;
906         int start_record = 0;
907         int max_members_reached = 0;
908
909         ast_copy_string(tmp.name, name, sizeof(tmp.name));
910
911         /* We explictly lock the conference bridges container ourselves so that other callers can not create duplicate conferences at the same */
912         ao2_lock(conference_bridges);
913
914         ast_debug(1, "Trying to find conference bridge '%s'\n", name);
915
916         /* Attempt to find an existing conference bridge */
917         conference_bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
918
919         if (conference_bridge && conference_bridge->b_profile.max_members) {
920                 max_members_reached = conference_bridge->b_profile.max_members > conference_bridge->users ? 0 : 1;
921         }
922
923         /* When finding a conference bridge that already exists make sure that it is not locked, and if so that we are not an admin */
924         if (conference_bridge && (max_members_reached || conference_bridge->locked) && !ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN)) {
925                 ao2_unlock(conference_bridges);
926                 ao2_ref(conference_bridge, -1);
927                 ast_debug(1, "Conference bridge '%s' is locked and caller is not an admin\n", name);
928                 ast_stream_and_wait(conference_bridge_user->chan,
929                                 conf_get_sound(CONF_SOUND_LOCKED, conference_bridge_user->b_profile.sounds),
930                                 "");
931                 return NULL;
932         }
933
934         /* If no conference bridge was found see if we can create one */
935         if (!conference_bridge) {
936                 /* Try to allocate memory for a new conference bridge, if we fail... this won't end well. */
937                 if (!(conference_bridge = ao2_alloc(sizeof(*conference_bridge), destroy_conference_bridge))) {
938                         ao2_unlock(conference_bridges);
939                         ast_log(LOG_ERROR, "Conference bridge '%s' does not exist.\n", name);
940                         return NULL;
941                 }
942
943                 /* Setup conference bridge parameters */
944                 conference_bridge->record_thread = AST_PTHREADT_NULL;
945                 ast_copy_string(conference_bridge->name, name, sizeof(conference_bridge->name));
946                 conf_bridge_profile_copy(&conference_bridge->b_profile, &conference_bridge_user->b_profile);
947
948                 /* Create an actual bridge that will do the audio mixing */
949                 if (!(conference_bridge->bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_MULTIMIX, 0))) {
950                         ao2_ref(conference_bridge, -1);
951                         conference_bridge = NULL;
952                         ao2_unlock(conference_bridges);
953                         ast_log(LOG_ERROR, "Conference bridge '%s' could not be created.\n", name);
954                         return NULL;
955                 }
956
957                 /* Set the internal sample rate on the bridge from the bridge profile */
958                 ast_bridge_set_internal_sample_rate(conference_bridge->bridge, conference_bridge->b_profile.internal_sample_rate);
959                 /* Set the internal mixing interval on the bridge from the bridge profile */
960                 ast_bridge_set_mixing_interval(conference_bridge->bridge, conference_bridge->b_profile.mix_interval);
961
962                 if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
963                         ast_bridge_set_talker_src_video_mode(conference_bridge->bridge);
964                 }
965
966                 /* Setup lock for playback channel */
967                 ast_mutex_init(&conference_bridge->playback_lock);
968
969                 /* Link it into the conference bridges container */
970                 ao2_link(conference_bridges, conference_bridge);
971
972
973                 send_conf_start_event(conference_bridge->name);
974                 ast_debug(1, "Created conference bridge '%s' and linked to container '%p'\n", name, conference_bridges);
975         }
976
977         ao2_unlock(conference_bridges);
978
979         /* Setup conference bridge user parameters */
980         conference_bridge_user->conference_bridge = conference_bridge;
981
982         ao2_lock(conference_bridge);
983
984         /* All good to go, add them in */
985         AST_LIST_INSERT_TAIL(&conference_bridge->users_list, conference_bridge_user, list);
986
987         /* Increment the users count on the bridge, but record it as it is going to need to be known right after this */
988         conference_bridge->users++;
989
990         /* If the caller is a marked user bump up the count */
991         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER)) {
992                 conference_bridge->markedusers++;
993         }
994
995         /* Set the device state for this conference */
996         if (conference_bridge->users == 1) {
997                 ast_devstate_changed(AST_DEVICE_INUSE, "confbridge:%s", conference_bridge->name);
998         }
999
1000         /* If the caller is a marked user or is waiting for a marked user to enter pass 'em off, otherwise pass them off to do regular joining stuff */
1001         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER | USER_OPT_WAITMARKED)) {
1002                 if (post_join_marked(conference_bridge, conference_bridge_user)) {
1003                         ao2_unlock(conference_bridge);
1004                         leave_conference_bridge(conference_bridge, conference_bridge_user);
1005                         return NULL;
1006                 }
1007         } else {
1008                 if (post_join_unmarked(conference_bridge, conference_bridge_user)) {
1009                         ao2_unlock(conference_bridge);
1010                         leave_conference_bridge(conference_bridge, conference_bridge_user);
1011                         return NULL;
1012                 }
1013         }
1014
1015         /* check to see if recording needs to be started or not */
1016         if (ast_test_flag(&conference_bridge->b_profile, BRIDGE_OPT_RECORD_CONFERENCE) && !conf_is_recording(conference_bridge)) {
1017                 start_record = 1;
1018         }
1019
1020         ao2_unlock(conference_bridge);
1021
1022         if (start_record) {
1023                 conf_start_record(conference_bridge);
1024         }
1025
1026         return conference_bridge;
1027 }
1028
1029 /*!
1030  * \brief Leave a conference bridge
1031  *
1032  * \param conference_bridge The conference bridge to leave
1033  * \param conference_bridge_user The conference bridge user structure
1034  *
1035  */
1036 static void leave_conference_bridge(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
1037 {
1038         ao2_lock(conference_bridge);
1039
1040         /* If this caller is a marked user bump down the count */
1041         if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER)) {
1042                 conference_bridge->markedusers--;
1043         }
1044
1045         /* Decrement the users count while keeping the previous participant count */
1046         conference_bridge->users--;
1047
1048         /* Drop conference bridge user from the list, they be going bye bye */
1049         AST_LIST_REMOVE(&conference_bridge->users_list, conference_bridge_user, list);
1050
1051         /* If there are still users in the conference bridge we may need to do things (such as start MOH on them) */
1052         if (conference_bridge->users) {
1053                 if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER) && !conference_bridge->markedusers) {
1054                         struct conference_bridge_user *other_participant = NULL;
1055
1056                         /* Start out with muting everyone */
1057                         AST_LIST_TRAVERSE(&conference_bridge->users_list, other_participant, list) {
1058                                 other_participant->features.mute = 1;
1059                         }
1060
1061                         /* Play back the audio prompt saying the leader has left the conference */
1062                         if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET)) {
1063                                 ao2_unlock(conference_bridge);
1064                                 ast_autoservice_start(conference_bridge_user->chan);
1065                                 play_sound_file(conference_bridge,
1066                                         conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, conference_bridge_user->b_profile.sounds));
1067                                 ast_autoservice_stop(conference_bridge_user->chan);
1068                                 ao2_lock(conference_bridge);
1069                         }
1070
1071                         /* Now on to starting MOH or kick if needed */
1072                         AST_LIST_TRAVERSE(&conference_bridge->users_list, other_participant, list) {
1073                                 if (ast_test_flag(&other_participant->u_profile, USER_OPT_ENDMARKED)) {
1074                                         other_participant->kicked = 1;
1075                                         ast_bridge_remove(conference_bridge->bridge, other_participant->chan);
1076                                 } else if (ast_test_flag(&other_participant->u_profile, USER_OPT_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, other_participant->chan)) {
1077                                         ast_moh_start(other_participant->chan, other_participant->u_profile.moh_class, NULL);
1078                                         other_participant->playing_moh = 1;
1079                                         ast_bridge_unsuspend(conference_bridge->bridge, other_participant->chan);
1080                                 }
1081                         }
1082                 } else if (conference_bridge->users == 1) {
1083                         /* Of course if there is one other person in here we may need to start up MOH on them */
1084                         struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->users_list);
1085
1086                         if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) {
1087                                 ast_moh_start(first_participant->chan, first_participant->u_profile.moh_class, NULL);
1088                                 first_participant->playing_moh = 1;
1089                                 ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan);
1090                         }
1091                 }
1092         } else {
1093                 /* Set device state to "not in use" */
1094                 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "confbridge:%s", conference_bridge->name);
1095
1096                 ao2_unlink(conference_bridges, conference_bridge);
1097                 send_conf_end_event(conference_bridge->name);
1098         }
1099
1100         /* Done mucking with the conference bridge, huzzah */
1101         ao2_unlock(conference_bridge);
1102
1103         if (!conference_bridge->users) {
1104                 conf_stop_record(conference_bridge);
1105         }
1106
1107         ao2_ref(conference_bridge, -1);
1108 }
1109
1110 /*!
1111  * \internal
1112  * \brief allocates playback chan on a channel
1113  * \pre expects conference to be locked before calling this function
1114  */
1115 static int alloc_playback_chan(struct conference_bridge *conference_bridge)
1116 {
1117         int cause;
1118         struct ast_format_cap *cap;
1119         struct ast_format tmpfmt;
1120
1121         if (conference_bridge->playback_chan) {
1122                 return 0;
1123         }
1124         if (!(cap = ast_format_cap_alloc_nolock())) {
1125                 return -1;
1126         }
1127         ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
1128         if (!(conference_bridge->playback_chan = ast_request("Bridge", cap, NULL, "", &cause))) {
1129                 cap = ast_format_cap_destroy(cap);
1130                 return -1;
1131         }
1132         cap = ast_format_cap_destroy(cap);
1133
1134         conference_bridge->playback_chan->bridge = conference_bridge->bridge;
1135
1136         if (ast_call(conference_bridge->playback_chan, "", 0)) {
1137                 ast_hangup(conference_bridge->playback_chan);
1138                 conference_bridge->playback_chan = NULL;
1139                 return -1;
1140         }
1141
1142         ast_debug(1, "Created a playback channel to conference bridge '%s'\n", conference_bridge->name);
1143         return 0;
1144 }
1145
1146 static int play_sound_helper(struct conference_bridge *conference_bridge, const char *filename, int say_number)
1147 {
1148         struct ast_channel *underlying_channel;
1149
1150         /* Do not waste resources trying to play files that do not exist */
1151         if (!ast_fileexists(filename, NULL, NULL)) {
1152                 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
1153                 return 0;
1154         }
1155
1156         ast_mutex_lock(&conference_bridge->playback_lock);
1157         if (!(conference_bridge->playback_chan)) {
1158                 if (alloc_playback_chan(conference_bridge)) {
1159                         ast_mutex_unlock(&conference_bridge->playback_lock);
1160                         return -1;
1161                 }
1162                 underlying_channel = ast_channel_tech(conference_bridge->playback_chan)->bridged_channel(conference_bridge->playback_chan, NULL);
1163         } else {
1164                 /* Channel was already available so we just need to add it back into the bridge */
1165                 underlying_channel = ast_channel_tech(conference_bridge->playback_chan)->bridged_channel(conference_bridge->playback_chan, NULL);
1166                 ast_bridge_impart(conference_bridge->bridge, underlying_channel, NULL, NULL, 0);
1167         }
1168
1169         /* The channel is all under our control, in goes the prompt */
1170         if (!ast_strlen_zero(filename)) {
1171                 ast_stream_and_wait(conference_bridge->playback_chan, filename, "");
1172         } else {
1173                 ast_say_number(conference_bridge->playback_chan, say_number, "", ast_channel_language(conference_bridge->playback_chan), NULL);
1174         }
1175
1176         ast_debug(1, "Departing underlying channel '%s' from bridge '%p'\n", ast_channel_name(underlying_channel), conference_bridge->bridge);
1177         ast_bridge_depart(conference_bridge->bridge, underlying_channel);
1178
1179         ast_mutex_unlock(&conference_bridge->playback_lock);
1180
1181         return 0;
1182 }
1183
1184 /*!
1185  * \brief Play sound file into conference bridge
1186  *
1187  * \param conference_bridge The conference bridge to play sound file into
1188  * \param filename Sound file to play
1189  *
1190  * \retval 0 success
1191  * \retval -1 failure
1192  */
1193 static int play_sound_file(struct conference_bridge *conference_bridge, const char *filename)
1194 {
1195         return play_sound_helper(conference_bridge, filename, 0);
1196 }
1197
1198 /*!
1199  * \brief Play number into the conference bridge
1200  *
1201  * \param conference_bridge The conference bridge to say the number into
1202  * \param number to say
1203  *
1204  * \retval 0 success
1205  * \retval -1 failure
1206  */
1207 static int play_sound_number(struct conference_bridge *conference_bridge, int say_number)
1208 {
1209         return play_sound_helper(conference_bridge, NULL, say_number);
1210 }
1211
1212 static void conf_handle_talker_destructor(void *pvt_data)
1213 {
1214         ast_free(pvt_data);
1215 }
1216
1217 static void conf_handle_talker_cb(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *pvt_data)
1218 {
1219         char *conf_name = pvt_data;
1220         int talking;
1221
1222         switch (bridge_channel->state) {
1223         case AST_BRIDGE_CHANNEL_STATE_START_TALKING:
1224                 talking = 1;
1225                 break;
1226         case AST_BRIDGE_CHANNEL_STATE_STOP_TALKING:
1227                 talking = 0;
1228                 break;
1229         default:
1230                 return; /* uhh this shouldn't happen, but bail if it does. */
1231         }
1232
1233         /* notify AMI someone is has either started or stopped talking */
1234         ast_manager_event(bridge_channel->chan, EVENT_FLAG_CALL, "ConfbridgeTalking",
1235               "Channel: %s\r\n"
1236               "Uniqueid: %s\r\n"
1237               "Conference: %s\r\n"
1238               "TalkingStatus: %s\r\n",
1239               ast_channel_name(bridge_channel->chan), ast_channel_uniqueid(bridge_channel->chan), conf_name, talking ? "on" : "off");
1240 }
1241
1242 static int conf_get_pin(struct ast_channel *chan, struct conference_bridge_user *conference_bridge_user)
1243 {
1244         char pin_guess[MAX_PIN+1] = { 0, };
1245         const char *pin = conference_bridge_user->u_profile.pin;
1246         char *tmp = pin_guess;
1247         int i, res;
1248         unsigned int len = MAX_PIN ;
1249
1250         /* give them three tries to get the pin right */
1251         for (i = 0; i < 3; i++) {
1252                 if (ast_app_getdata(chan,
1253                         conf_get_sound(CONF_SOUND_GET_PIN, conference_bridge_user->b_profile.sounds),
1254                         tmp, len, 0) >= 0) {
1255                         if (!strcasecmp(pin, pin_guess)) {
1256                                 return 0;
1257                         }
1258                 }
1259                 ast_streamfile(chan,
1260                         conf_get_sound(CONF_SOUND_INVALID_PIN, conference_bridge_user->b_profile.sounds),
1261                         ast_channel_language(chan));
1262                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1263                 if (res > 0) {
1264                         /* Account for digit already read during ivalid pin playback
1265                          * resetting pin buf. */
1266                         pin_guess[0] = res;
1267                         pin_guess[1] = '\0';
1268                         tmp = pin_guess + 1;
1269                         len = MAX_PIN - 1;
1270                 } else {
1271                         /* reset pin buf as empty buffer. */
1272                         tmp = pin_guess;
1273                         len = MAX_PIN;
1274                 }
1275         }
1276         return -1;
1277 }
1278
1279 static int conf_rec_name(struct conference_bridge_user *user, const char *conf_name)
1280 {
1281         char destdir[PATH_MAX];
1282         int res;
1283         int duration = 20;
1284
1285         snprintf(destdir, sizeof(destdir), "%s/confbridge", ast_config_AST_SPOOL_DIR);
1286
1287         if (ast_mkdir(destdir, 0777) != 0) {
1288                 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
1289                 return -1;
1290         }
1291         snprintf(user->name_rec_location, sizeof(user->name_rec_location),
1292                  "%s/confbridge-name-%s-%s", destdir,
1293                  conf_name, ast_channel_uniqueid(user->chan));
1294
1295         res = ast_play_and_record(user->chan,
1296                 "vm-rec-name",
1297                 user->name_rec_location,
1298                 10,
1299                 "sln",
1300                 &duration,
1301                 NULL,
1302                 ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE),
1303                 0,
1304                 NULL);
1305
1306         if (res == -1) {
1307                 user->name_rec_location[0] = '\0';
1308                 return -1;
1309         }
1310         return 0;
1311 }
1312
1313 /*! \brief The ConfBridge application */
1314 static int confbridge_exec(struct ast_channel *chan, const char *data)
1315 {
1316         int res = 0, volume_adjustments[2];
1317         int quiet = 0;
1318         char *parse;
1319         const char *b_profile_name = DEFAULT_BRIDGE_PROFILE;
1320         const char *u_profile_name = DEFAULT_USER_PROFILE;
1321         struct conference_bridge *conference_bridge = NULL;
1322         struct conference_bridge_user conference_bridge_user = {
1323                 .chan = chan,
1324                 .tech_args.talking_threshold = DEFAULT_TALKING_THRESHOLD,
1325                 .tech_args.silence_threshold = DEFAULT_SILENCE_THRESHOLD,
1326                 .tech_args.drop_silence = 0,
1327         };
1328         AST_DECLARE_APP_ARGS(args,
1329                 AST_APP_ARG(conf_name);
1330                 AST_APP_ARG(b_profile_name);
1331                 AST_APP_ARG(u_profile_name);
1332                 AST_APP_ARG(menu_name);
1333         );
1334         ast_bridge_features_init(&conference_bridge_user.features);
1335
1336         if (ast_channel_state(chan) != AST_STATE_UP) {
1337                 ast_answer(chan);
1338         }
1339
1340         if (ast_strlen_zero(data)) {
1341                 ast_log(LOG_WARNING, "%s requires an argument (conference name[,options])\n", app);
1342                 res = -1; /* invalid PIN */
1343                 goto confbridge_cleanup;
1344         }
1345
1346         /* We need to make a copy of the input string if we are going to modify it! */
1347         parse = ast_strdupa(data);
1348
1349         AST_STANDARD_APP_ARGS(args, parse);
1350
1351         /* bridge profile name */
1352         if (args.argc > 1 && !ast_strlen_zero(args.b_profile_name)) {
1353                 b_profile_name = args.b_profile_name;
1354         }
1355         if (!conf_find_bridge_profile(chan, b_profile_name, &conference_bridge_user.b_profile)) {
1356                 ast_log(LOG_WARNING, "Conference bridge profile %s does not exist\n", b_profile_name);
1357                 res = -1;
1358                 goto confbridge_cleanup;
1359         }
1360
1361         /* user profile name */
1362         if (args.argc > 2 && !ast_strlen_zero(args.u_profile_name)) {
1363                 u_profile_name = args.u_profile_name;
1364         }
1365
1366         if (!conf_find_user_profile(chan, u_profile_name, &conference_bridge_user.u_profile)) {
1367                 ast_log(LOG_WARNING, "Conference user profile %s does not exist\n", u_profile_name);
1368                 res = -1;
1369                 goto confbridge_cleanup;
1370         }
1371         quiet = ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_QUIET);
1372
1373         /* ask for a PIN immediately after finding user profile.  This has to be
1374          * prompted for requardless of quiet setting. */
1375         if (!ast_strlen_zero(conference_bridge_user.u_profile.pin)) {
1376                 if (conf_get_pin(chan, &conference_bridge_user)) {
1377                         res = -1; /* invalid PIN */
1378                         goto confbridge_cleanup;
1379                 }
1380         }
1381
1382         /* See if we need them to record a intro name */
1383         if (!quiet && ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE)) {
1384                 conf_rec_name(&conference_bridge_user, args.conf_name);
1385         }
1386
1387         /* menu name */
1388         if (args.argc > 3 && !ast_strlen_zero(args.menu_name)) {
1389                 ast_copy_string(conference_bridge_user.menu_name, args.menu_name, sizeof(conference_bridge_user.menu_name));
1390                 if (conf_set_menu_to_user(conference_bridge_user.menu_name, &conference_bridge_user)) {
1391                         ast_log(LOG_WARNING, "Conference menu %s does not exist and can not be applied to confbridge user.\n",
1392                                 args.menu_name);
1393                         res = -1; /* invalid PIN */
1394                         goto confbridge_cleanup;
1395                 }
1396         }
1397
1398         /* Set if DTMF should pass through for this user or not */
1399         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DTMF_PASS)) {
1400                 conference_bridge_user.features.dtmf_passthrough = 1;
1401         }
1402
1403         /* Set dsp threshold values if present */
1404         if (conference_bridge_user.u_profile.talking_threshold) {
1405                 conference_bridge_user.tech_args.talking_threshold = conference_bridge_user.u_profile.talking_threshold;
1406         }
1407         if (conference_bridge_user.u_profile.silence_threshold) {
1408                 conference_bridge_user.tech_args.silence_threshold = conference_bridge_user.u_profile.silence_threshold;
1409         }
1410
1411         /* Set a talker indicate call back if talking detection is requested */
1412         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_TALKER_DETECT)) {
1413                 char *conf_name = ast_strdup(args.conf_name); /* this is freed during feature cleanup */
1414                 if (!(conf_name)) {
1415                         res = -1; /* invalid PIN */
1416                         goto confbridge_cleanup;
1417                 }
1418                 ast_bridge_features_set_talk_detector(&conference_bridge_user.features,
1419                         conf_handle_talker_cb,
1420                         conf_handle_talker_destructor,
1421                         conf_name);
1422         }
1423
1424         /* Look for a conference bridge matching the provided name */
1425         if (!(conference_bridge = join_conference_bridge(args.conf_name, &conference_bridge_user))) {
1426                 res = -1; /* invalid PIN */
1427                 goto confbridge_cleanup;
1428         }
1429
1430         /* Keep a copy of volume adjustments so we can restore them later if need be */
1431         volume_adjustments[0] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_READ);
1432         volume_adjustments[1] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_WRITE);
1433
1434         /* If the caller should be joined already muted, make it so */
1435         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_STARTMUTED)) {
1436                 conference_bridge_user.features.mute = 1;
1437         }
1438
1439         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DROP_SILENCE)) {
1440                 conference_bridge_user.tech_args.drop_silence = 1;
1441         }
1442
1443         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_JITTERBUFFER)) {
1444                 char *func_jb;
1445                 if ((func_jb = ast_module_helper("", "func_jitterbuffer", 0, 0, 0, 0))) {
1446                         ast_free(func_jb);
1447                         ast_func_write(chan, "JITTERBUFFER(adaptive)", "default");
1448                 }
1449         }
1450
1451         if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DENOISE)) {
1452                 char *mod_speex;
1453                 /* Reduce background noise from each participant */
1454                 if ((mod_speex = ast_module_helper("", "codec_speex", 0, 0, 0, 0))) {
1455                         ast_free(mod_speex);
1456                         ast_func_write(chan, "DENOISE(rx)", "on");
1457                 }
1458         }
1459
1460         /* if this user has a intro, play it before entering */
1461         if (!ast_strlen_zero(conference_bridge_user.name_rec_location)) {
1462                 ast_autoservice_start(chan);
1463                 play_sound_file(conference_bridge, conference_bridge_user.name_rec_location);
1464                 play_sound_file(conference_bridge,
1465                         conf_get_sound(CONF_SOUND_HAS_JOINED, conference_bridge_user.b_profile.sounds));
1466                 ast_autoservice_stop(chan);
1467         }
1468
1469         /* Play the Join sound to both the conference and the user entering. */
1470         if (!quiet) {
1471                 const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, conference_bridge_user.b_profile.sounds);
1472                 if (conference_bridge_user.playing_moh) {
1473                         ast_moh_stop(chan);
1474                 }
1475                 ast_stream_and_wait(chan, join_sound, "");
1476                 ast_autoservice_start(chan);
1477                 play_sound_file(conference_bridge, join_sound);
1478                 ast_autoservice_stop(chan);
1479                 if (conference_bridge_user.playing_moh) {
1480                         ast_moh_start(chan, conference_bridge_user.u_profile.moh_class, NULL);
1481                 }
1482         }
1483
1484         /* See if we need to automatically set this user as a video source or not */
1485         handle_video_on_join(conference_bridge, conference_bridge_user.chan, ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_MARKEDUSER));
1486
1487         /* Join our conference bridge for real */
1488         send_join_event(conference_bridge_user.chan, conference_bridge->name);
1489         ast_bridge_join(conference_bridge->bridge,
1490                 chan,
1491                 NULL,
1492                 &conference_bridge_user.features,
1493                 &conference_bridge_user.tech_args);
1494         send_leave_event(conference_bridge_user.chan, conference_bridge->name);
1495
1496         /* if we're shutting down, don't attempt to do further processing */
1497         if (ast_shutting_down()) {
1498                 leave_conference_bridge(conference_bridge, &conference_bridge_user);
1499                 conference_bridge = NULL;
1500                 goto confbridge_cleanup;
1501         }
1502
1503         /* If this user was a video source, we need to clean up and possibly pick a new source. */
1504         handle_video_on_exit(conference_bridge, conference_bridge_user.chan);
1505
1506         /* if this user has a intro, play it when leaving */
1507         if (!quiet && !ast_strlen_zero(conference_bridge_user.name_rec_location)) {
1508                 ast_autoservice_start(chan);
1509                 play_sound_file(conference_bridge, conference_bridge_user.name_rec_location);
1510                 play_sound_file(conference_bridge,
1511                         conf_get_sound(CONF_SOUND_HAS_LEFT, conference_bridge_user.b_profile.sounds));
1512                 ast_autoservice_stop(chan);
1513         }
1514
1515         /* play the leave sound */
1516         if (!quiet) {
1517                 const char *leave_sound = conf_get_sound(CONF_SOUND_LEAVE, conference_bridge_user.b_profile.sounds);
1518                 ast_autoservice_start(chan);
1519                 play_sound_file(conference_bridge, leave_sound);
1520                 ast_autoservice_stop(chan);
1521         }
1522
1523         /* Easy as pie, depart this channel from the conference bridge */
1524         leave_conference_bridge(conference_bridge, &conference_bridge_user);
1525         conference_bridge = NULL;
1526
1527         /* If the user was kicked from the conference play back the audio prompt for it */
1528         if (!quiet && conference_bridge_user.kicked) {
1529                 res = ast_stream_and_wait(chan,
1530                         conf_get_sound(CONF_SOUND_KICKED, conference_bridge_user.b_profile.sounds),
1531                         "");
1532         }
1533
1534         /* Restore volume adjustments to previous values in case they were changed */
1535         if (volume_adjustments[0]) {
1536                 ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_READ, volume_adjustments[0]);
1537         }
1538         if (volume_adjustments[1]) {
1539                 ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_WRITE, volume_adjustments[1]);
1540         }
1541
1542         if (!ast_strlen_zero(conference_bridge_user.name_rec_location)) {
1543                 ast_filedelete(conference_bridge_user.name_rec_location, NULL);
1544         }
1545
1546 confbridge_cleanup:
1547         ast_bridge_features_cleanup(&conference_bridge_user.features);
1548         conf_bridge_profile_destroy(&conference_bridge_user.b_profile);
1549         return res;
1550 }
1551
1552 static int action_toggle_mute(struct conference_bridge *conference_bridge,
1553         struct conference_bridge_user *conference_bridge_user,
1554         struct ast_channel *chan)
1555 {
1556         /* Mute or unmute yourself, note we only allow manipulation if they aren't waiting for a marked user or if marked users exist */
1557         if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_WAITMARKED) || conference_bridge->markedusers) {
1558                 conference_bridge_user->features.mute = (!conference_bridge_user->features.mute ? 1 : 0);
1559                 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));
1560         }
1561         return ast_stream_and_wait(chan, (conference_bridge_user->features.mute ?
1562                 conf_get_sound(CONF_SOUND_MUTED, conference_bridge_user->b_profile.sounds) :
1563                 conf_get_sound(CONF_SOUND_UNMUTED, conference_bridge_user->b_profile.sounds)),
1564                 "");
1565 }
1566
1567 static int action_toggle_mute_participants(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
1568 {
1569         struct conference_bridge_user *participant = NULL;
1570         const char *sound_to_play;
1571
1572         ao2_lock(conference_bridge);
1573
1574         /* If already muted, then unmute */
1575         conference_bridge->muted = conference_bridge->muted ? 0 : 1;
1576         sound_to_play = conf_get_sound((conference_bridge->muted ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED),
1577                 conference_bridge_user->b_profile.sounds);
1578
1579         AST_LIST_TRAVERSE(&conference_bridge->users_list, participant, list) {
1580                 if (!ast_test_flag(&participant->u_profile, USER_OPT_ADMIN)) {
1581                         participant->features.mute = conference_bridge->muted;
1582                 }
1583         }
1584
1585         ao2_unlock(conference_bridge);
1586
1587         /* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */
1588         ast_stream_and_wait(conference_bridge_user->chan, sound_to_play, "");
1589
1590         /* Announce to the group that all participants are muted */
1591         ast_autoservice_start(conference_bridge_user->chan);
1592         play_sound_helper(conference_bridge, sound_to_play, 0);
1593         ast_autoservice_stop(conference_bridge_user->chan);
1594
1595         return 0;
1596 }
1597
1598 static int action_playback(struct ast_bridge_channel *bridge_channel, const char *playback_file)
1599 {
1600         char *file_copy = ast_strdupa(playback_file);
1601         char *file = NULL;
1602
1603         while ((file = strsep(&file_copy, "&"))) {
1604                 if (ast_stream_and_wait(bridge_channel->chan, file, "")) {
1605                         ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
1606                         return -1;
1607                 }
1608         }
1609         return 0;
1610 }
1611
1612 static int action_playback_and_continue(struct conference_bridge *conference_bridge,
1613         struct conference_bridge_user *conference_bridge_user,
1614         struct ast_bridge_channel *bridge_channel,
1615         struct conf_menu *menu,
1616         const char *playback_file,
1617         const char *cur_dtmf,
1618         int *stop_prompts)
1619 {
1620         int i;
1621         int digit = 0;
1622         char dtmf[MAXIMUM_DTMF_FEATURE_STRING];
1623         struct conf_menu_entry new_menu_entry = { { 0, }, };
1624         char *file_copy = ast_strdupa(playback_file);
1625         char *file = NULL;
1626
1627         while ((file = strsep(&file_copy, "&"))) {
1628                 if (ast_streamfile(bridge_channel->chan, file, ast_channel_language(bridge_channel->chan))) {
1629                         ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
1630                         return -1;
1631                 }
1632
1633                 /* now wait for more digits. */
1634                 if (!(digit = ast_waitstream(bridge_channel->chan, AST_DIGIT_ANY))) {
1635                         /* streaming finished and no DTMF was entered */
1636                         continue;
1637                 } else if (digit == -1) {
1638                         /* error */
1639                         return -1;
1640                 } else {
1641                         break; /* dtmf was entered */
1642                 }
1643         }
1644         if (!digit) {
1645                 /* streaming finished on all files and no DTMF was entered */
1646                 return -1;
1647         }
1648         ast_stopstream(bridge_channel->chan);
1649
1650         /* If we get here, then DTMF has been entered, This means no
1651          * additional prompts should be played for this menu entry */
1652         *stop_prompts = 1;
1653
1654         /* If a digit was pressed during the payback, update
1655          * the dtmf string and look for a new menu entry in the
1656          * menu structure */
1657         ast_copy_string(dtmf, cur_dtmf, sizeof(dtmf));
1658         for (i = 0; i < (MAXIMUM_DTMF_FEATURE_STRING - 1); i++) {
1659                 dtmf[i] = cur_dtmf[i];
1660                 if (!dtmf[i]) {
1661                         dtmf[i] = (char) digit;
1662                         dtmf[i + 1] = '\0';
1663                         i = -1;
1664                         break;
1665                 }
1666         }
1667         /* If i is not -1 then the new dtmf digit was _NOT_ added to the string.
1668          * If this is the case, no new DTMF sequence should be looked for. */
1669         if (i != -1) {
1670                 return 0;
1671         }
1672
1673         if (conf_find_menu_entry_by_sequence(dtmf, menu, &new_menu_entry)) {
1674                 execute_menu_entry(conference_bridge,
1675                         conference_bridge_user,
1676                         bridge_channel,
1677                         &new_menu_entry, menu);
1678                 conf_menu_entry_destroy(&new_menu_entry);
1679         }
1680         return 0;
1681 }
1682
1683 static int action_kick_last(struct conference_bridge *conference_bridge,
1684         struct ast_bridge_channel *bridge_channel,
1685         struct conference_bridge_user *conference_bridge_user)
1686 {
1687         struct conference_bridge_user *last_participant = NULL;
1688         int isadmin = ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN);
1689
1690         if (!isadmin) {
1691                 ast_stream_and_wait(bridge_channel->chan,
1692                         conf_get_sound(CONF_SOUND_ERROR_MENU, conference_bridge_user->b_profile.sounds),
1693                         "");
1694                 ast_log(LOG_WARNING, "Only admin users can use the kick_last menu action. Channel %s of conf %s is not an admin.\n",
1695                         ast_channel_name(bridge_channel->chan),
1696                         conference_bridge->name);
1697                 return -1;
1698         }
1699
1700         ao2_lock(conference_bridge);
1701         if (((last_participant = AST_LIST_LAST(&conference_bridge->users_list)) == conference_bridge_user)
1702                 || (ast_test_flag(&last_participant->u_profile, USER_OPT_ADMIN))) {
1703                 ao2_unlock(conference_bridge);
1704                 ast_stream_and_wait(bridge_channel->chan,
1705                         conf_get_sound(CONF_SOUND_ERROR_MENU, conference_bridge_user->b_profile.sounds),
1706                         "");
1707         } else if (last_participant) {
1708                 last_participant->kicked = 1;
1709                 ast_bridge_remove(conference_bridge->bridge, last_participant->chan);
1710                 ao2_unlock(conference_bridge);
1711         }
1712         return 0;
1713 }
1714
1715 static int action_dialplan_exec(struct ast_bridge_channel *bridge_channel, struct conf_menu_action *menu_action)
1716 {
1717         struct ast_pbx_args args;
1718         struct ast_pbx *pbx;
1719         char *exten;
1720         char *context;
1721         int priority;
1722         int res;
1723
1724         memset(&args, 0, sizeof(args));
1725         args.no_hangup_chan = 1;
1726
1727         ast_channel_lock(bridge_channel->chan);
1728
1729         /*save off*/
1730         exten = ast_strdupa(ast_channel_exten(bridge_channel->chan));
1731         context = ast_strdupa(ast_channel_context(bridge_channel->chan));
1732         priority = ast_channel_priority(bridge_channel->chan);
1733         pbx = ast_channel_pbx(bridge_channel->chan);
1734         ast_channel_pbx_set(bridge_channel->chan, NULL);
1735
1736         /*set new*/
1737         ast_channel_exten_set(bridge_channel->chan, menu_action->data.dialplan_args.exten);
1738         ast_channel_context_set(bridge_channel->chan, menu_action->data.dialplan_args.context);
1739         ast_channel_priority_set(bridge_channel->chan, menu_action->data.dialplan_args.priority);
1740
1741         ast_channel_unlock(bridge_channel->chan);
1742
1743         /*execute*/
1744         res = ast_pbx_run_args(bridge_channel->chan, &args);
1745
1746         /*restore*/
1747         ast_channel_lock(bridge_channel->chan);
1748
1749         ast_channel_exten_set(bridge_channel->chan, exten);
1750         ast_channel_context_set(bridge_channel->chan, context);
1751         ast_channel_priority_set(bridge_channel->chan, priority);
1752         ast_channel_pbx_set(bridge_channel->chan, pbx);
1753
1754         ast_channel_unlock(bridge_channel->chan);
1755
1756         return res;
1757 }
1758
1759 static int execute_menu_entry(struct conference_bridge *conference_bridge,
1760         struct conference_bridge_user *conference_bridge_user,
1761         struct ast_bridge_channel *bridge_channel,
1762         struct conf_menu_entry *menu_entry,
1763         struct conf_menu *menu)
1764 {
1765         struct conf_menu_action *menu_action;
1766         int isadmin = ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ADMIN);
1767         int stop_prompts = 0;
1768         int res = 0;
1769
1770         AST_LIST_TRAVERSE(&menu_entry->actions, menu_action, action) {
1771                 switch (menu_action->id) {
1772                 case MENU_ACTION_TOGGLE_MUTE:
1773                         res |= action_toggle_mute(conference_bridge,
1774                                 conference_bridge_user,
1775                                 bridge_channel->chan);
1776                         break;
1777                 case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS:
1778                         if (!isadmin) {
1779                                 break;
1780                         }
1781                         action_toggle_mute_participants(conference_bridge, conference_bridge_user);
1782                         break;
1783                 case MENU_ACTION_PARTICIPANT_COUNT:
1784                         announce_user_count(conference_bridge, conference_bridge_user);
1785                         break;
1786                 case MENU_ACTION_PLAYBACK:
1787                         if (!stop_prompts) {
1788                                 res |= action_playback(bridge_channel, menu_action->data.playback_file);
1789                         }
1790                         break;
1791                 case MENU_ACTION_RESET_LISTENING:
1792                         ast_audiohook_volume_set(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_WRITE, 0);
1793                         break;
1794                 case MENU_ACTION_RESET_TALKING:
1795                         ast_audiohook_volume_set(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_READ, 0);
1796                         break;
1797                 case MENU_ACTION_INCREASE_LISTENING:
1798                         ast_audiohook_volume_adjust(conference_bridge_user->chan,
1799                                 AST_AUDIOHOOK_DIRECTION_WRITE, 1);
1800                         break;
1801                 case MENU_ACTION_DECREASE_LISTENING:
1802                         ast_audiohook_volume_adjust(conference_bridge_user->chan,
1803                                 AST_AUDIOHOOK_DIRECTION_WRITE, -1);
1804                         break;
1805                 case MENU_ACTION_INCREASE_TALKING:
1806                         ast_audiohook_volume_adjust(conference_bridge_user->chan,
1807                                 AST_AUDIOHOOK_DIRECTION_READ, 1);
1808                         break;
1809                 case MENU_ACTION_DECREASE_TALKING:
1810                         ast_audiohook_volume_adjust(conference_bridge_user->chan,
1811                                 AST_AUDIOHOOK_DIRECTION_READ, -1);
1812                         break;
1813                 case MENU_ACTION_PLAYBACK_AND_CONTINUE:
1814                         if (!(stop_prompts)) {
1815                                 res |= action_playback_and_continue(conference_bridge,
1816                                         conference_bridge_user,
1817                                         bridge_channel,
1818                                         menu,
1819                                         menu_action->data.playback_file,
1820                                         menu_entry->dtmf,
1821                                         &stop_prompts);
1822                         }
1823                         break;
1824                 case MENU_ACTION_DIALPLAN_EXEC:
1825                         res |= action_dialplan_exec(bridge_channel, menu_action);
1826                         break;
1827                 case MENU_ACTION_ADMIN_TOGGLE_LOCK:
1828                         if (!isadmin) {
1829                                 break;
1830                         }
1831                         conference_bridge->locked = (!conference_bridge->locked ? 1 : 0);
1832                         res |= ast_stream_and_wait(bridge_channel->chan,
1833                                 (conference_bridge->locked ?
1834                                 conf_get_sound(CONF_SOUND_LOCKED_NOW, conference_bridge_user->b_profile.sounds) :
1835                                 conf_get_sound(CONF_SOUND_UNLOCKED_NOW, conference_bridge_user->b_profile.sounds)),
1836                                 "");
1837
1838                         break;
1839                 case MENU_ACTION_ADMIN_KICK_LAST:
1840                         res |= action_kick_last(conference_bridge, bridge_channel, conference_bridge_user);
1841                         break;
1842                 case MENU_ACTION_LEAVE:
1843                         ao2_lock(conference_bridge);
1844                         ast_bridge_remove(conference_bridge->bridge, bridge_channel->chan);
1845                         ao2_unlock(conference_bridge);
1846                         break;
1847                 case MENU_ACTION_NOOP:
1848                         break;
1849                 case MENU_ACTION_SET_SINGLE_VIDEO_SRC:
1850                         ao2_lock(conference_bridge);
1851                         ast_bridge_set_single_src_video_mode(conference_bridge->bridge, bridge_channel->chan);
1852                         ao2_unlock(conference_bridge);
1853                         break;
1854                 case MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC:
1855                         handle_video_on_exit(conference_bridge, bridge_channel->chan);
1856                         break;
1857                 }
1858         }
1859         return res;
1860 }
1861
1862 int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel,
1863         struct conference_bridge_user *conference_bridge_user,
1864         struct conf_menu_entry *menu_entry,
1865         struct conf_menu *menu)
1866 {
1867         struct conference_bridge *conference_bridge = conference_bridge_user->conference_bridge;
1868
1869         /* See if music on hold is playing */
1870         ao2_lock(conference_bridge);
1871         if (conference_bridge_user->playing_moh) {
1872                 /* MOH is going, let's stop it */
1873                 ast_moh_stop(bridge_channel->chan);
1874         }
1875         ao2_unlock(conference_bridge);
1876
1877         /* execute the list of actions associated with this menu entry */
1878         execute_menu_entry(conference_bridge, conference_bridge_user, bridge_channel, menu_entry, menu);
1879
1880         /* See if music on hold needs to be started back up again */
1881         ao2_lock(conference_bridge);
1882         if (conference_bridge_user->playing_moh) {
1883                 ast_moh_start(bridge_channel->chan, conference_bridge_user->u_profile.moh_class, NULL);
1884         }
1885         ao2_unlock(conference_bridge);
1886
1887         return 0;
1888 }
1889
1890 static char *complete_confbridge_name(const char *line, const char *word, int pos, int state)
1891 {
1892         int which = 0;
1893         struct conference_bridge *bridge = NULL;
1894         char *res = NULL;
1895         int wordlen = strlen(word);
1896         struct ao2_iterator i;
1897
1898         i = ao2_iterator_init(conference_bridges, 0);
1899         while ((bridge = ao2_iterator_next(&i))) {
1900                 if (!strncasecmp(bridge->name, word, wordlen) && ++which > state) {
1901                         res = ast_strdup(bridge->name);
1902                         ao2_ref(bridge, -1);
1903                         break;
1904                 }
1905                 ao2_ref(bridge, -1);
1906         }
1907         ao2_iterator_destroy(&i);
1908
1909         return res;
1910 }
1911
1912 static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1913 {
1914         struct conference_bridge *bridge = NULL;
1915         struct conference_bridge tmp;
1916         struct conference_bridge_user *participant = NULL;
1917
1918         switch (cmd) {
1919         case CLI_INIT:
1920                 e->command = "confbridge kick";
1921                 e->usage =
1922                         "Usage: confbridge kick <conference> <channel>\n"
1923                         "       Kicks a channel out of the conference bridge.\n";
1924                 return NULL;
1925         case CLI_GENERATE:
1926                 if (a->pos == 2) {
1927                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
1928                 }
1929                 /*
1930                 if (a->pos == 3) {
1931                         return complete_confbridge_channel(a->line, a->word, a->pos, a->n);
1932                 }
1933                 */
1934                 return NULL;
1935         }
1936
1937         if (a->argc != 4) {
1938                 return CLI_SHOWUSAGE;
1939         }
1940
1941         ast_copy_string(tmp.name, a->argv[2], sizeof(tmp.name));
1942         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
1943         if (!bridge) {
1944                 ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
1945                 return CLI_SUCCESS;
1946         }
1947         ao2_lock(bridge);
1948         AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
1949                 if (!strncmp(a->argv[3], ast_channel_name(participant->chan), strlen(ast_channel_name(participant->chan)))) {
1950                         break;
1951                 }
1952         }
1953         if (participant) {
1954                 ast_cli(a->fd, "Kicking %s from confbridge %s\n", ast_channel_name(participant->chan), bridge->name);
1955                 participant->kicked = 1;
1956                 ast_bridge_remove(bridge->bridge, participant->chan);
1957         }
1958         ao2_unlock(bridge);
1959         ao2_ref(bridge, -1);
1960         return CLI_SUCCESS;
1961 }
1962
1963 static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1964 {
1965         struct ao2_iterator i;
1966         struct conference_bridge *bridge = NULL;
1967         struct conference_bridge tmp;
1968         struct conference_bridge_user *participant = NULL;
1969
1970         switch (cmd) {
1971         case CLI_INIT:
1972                 e->command = "confbridge list";
1973                 e->usage =
1974                         "Usage: confbridge list [<name>]\n"
1975                         "       Lists all currently active conference bridges.\n";
1976                 return NULL;
1977         case CLI_GENERATE:
1978                 if (a->pos == 2) {
1979                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
1980                 }
1981                 return NULL;
1982         }
1983
1984         if (a->argc == 2) {
1985                 ast_cli(a->fd, "Conference Bridge Name           Users  Marked Locked?\n");
1986                 ast_cli(a->fd, "================================ ====== ====== ========\n");
1987                 i = ao2_iterator_init(conference_bridges, 0);
1988                 while ((bridge = ao2_iterator_next(&i))) {
1989                         ast_cli(a->fd, "%-32s %6i %6i %s\n", bridge->name, bridge->users, bridge->markedusers, (bridge->locked ? "locked" : "unlocked"));
1990                         ao2_ref(bridge, -1);
1991                 }
1992                 ao2_iterator_destroy(&i);
1993                 return CLI_SUCCESS;
1994         }
1995
1996         if (a->argc == 3) {
1997                 ast_copy_string(tmp.name, a->argv[2], sizeof(tmp.name));
1998                 bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
1999                 if (!bridge) {
2000                         ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
2001                         return CLI_SUCCESS;
2002                 }
2003                 ast_cli(a->fd, "Channel                       User Profile     Bridge Profile   Menu             CallerID\n");
2004                 ast_cli(a->fd, "============================= ================ ================ ================ ================\n");
2005                 ao2_lock(bridge);
2006                 AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2007                         ast_cli(a->fd, "%-29s ", ast_channel_name(participant->chan));
2008                         ast_cli(a->fd, "%-17s", participant->u_profile.name);
2009                         ast_cli(a->fd, "%-17s", participant->b_profile.name);
2010                         ast_cli(a->fd, "%-17s", participant->menu_name);
2011                         ast_cli(a->fd, "%-17s", S_COR(participant->chan->caller.id.number.valid, participant->chan->caller.id.number.str, "<unknown>"));
2012                         ast_cli(a->fd, "\n");
2013                 }
2014                 ao2_unlock(bridge);
2015                 ao2_ref(bridge, -1);
2016                 return CLI_SUCCESS;
2017         }
2018
2019         return CLI_SHOWUSAGE;
2020 }
2021
2022 /* \internal
2023  * \brief finds a conference by name and locks/unlocks.
2024  *
2025  * \retval 0 success
2026  * \retval -1 conference not found
2027  */
2028 static int generic_lock_unlock_helper(int lock, const char *conference)
2029 {
2030         struct conference_bridge *bridge = NULL;
2031         struct conference_bridge tmp;
2032         int res = 0;
2033
2034         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2035         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2036         if (!bridge) {
2037                 return -1;
2038         }
2039         ao2_lock(bridge);
2040         bridge->locked = lock;
2041         ast_test_suite_event_notify("CONF_LOCK", "Message: conference %s\r\nConference: %s", bridge->locked ? "locked" : "unlocked", bridge->b_profile.name);
2042         ao2_unlock(bridge);
2043         ao2_ref(bridge, -1);
2044
2045         return res;
2046 }
2047
2048 /* \internal
2049  * \brief finds a conference user by channel name and mutes/unmutes them.
2050  *
2051  * \retval 0 success
2052  * \retval -1 conference not found
2053  * \retval -2 user not found
2054  */
2055 static int generic_mute_unmute_helper(int mute, const char *conference, const char *user)
2056 {
2057         struct conference_bridge *bridge = NULL;
2058         struct conference_bridge tmp;
2059         struct conference_bridge_user *participant = NULL;
2060         int res = 0;
2061         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2062         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2063         if (!bridge) {
2064                 return -1;
2065         }
2066         ao2_lock(bridge);
2067         AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2068                 if (!strncmp(user, ast_channel_name(participant->chan), strlen(user))) {
2069                         break;
2070                 }
2071         }
2072         if (participant) {
2073                 participant->features.mute = mute;
2074                 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));
2075         } else {
2076                 res = -2;;
2077         }
2078         ao2_unlock(bridge);
2079         ao2_ref(bridge, -1);
2080
2081         return res;
2082 }
2083
2084 static int cli_mute_unmute_helper(int mute, struct ast_cli_args *a)
2085 {
2086         int res = generic_mute_unmute_helper(mute, a->argv[2], a->argv[3]);
2087
2088         if (res == -1) {
2089                 ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
2090                 return -1;
2091         } else if (res == -2) {
2092                 ast_cli(a->fd, "No channel named '%s' found in conference %s\n", a->argv[3], a->argv[2]);
2093                 return -1;
2094         }
2095         ast_cli(a->fd, "%s %s from confbridge %s\n", mute ? "Muting" : "Unmuting", a->argv[3], a->argv[2]);
2096         return 0;
2097 }
2098
2099 static char *handle_cli_confbridge_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2100 {
2101         switch (cmd) {
2102         case CLI_INIT:
2103                 e->command = "confbridge mute";
2104                 e->usage =
2105                         "Usage: confbridge mute <conference> <channel>\n";
2106                 return NULL;
2107         case CLI_GENERATE:
2108                 if (a->pos == 2) {
2109                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2110                 }
2111                 return NULL;
2112         }
2113         if (a->argc != 4) {
2114                 return CLI_SHOWUSAGE;
2115         }
2116
2117         cli_mute_unmute_helper(1, a);
2118
2119         return CLI_SUCCESS;
2120 }
2121
2122 static char *handle_cli_confbridge_unmute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2123 {
2124         switch (cmd) {
2125         case CLI_INIT:
2126                 e->command = "confbridge unmute";
2127                 e->usage =
2128                         "Usage: confbridge unmute <conference> <channel>\n";
2129                 return NULL;
2130         case CLI_GENERATE:
2131                 if (a->pos == 2) {
2132                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2133                 }
2134                 return NULL;
2135         }
2136         if (a->argc != 4) {
2137                 return CLI_SHOWUSAGE;
2138         }
2139
2140         cli_mute_unmute_helper(0, a);
2141
2142         return CLI_SUCCESS;
2143 }
2144
2145 static char *handle_cli_confbridge_lock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2146 {
2147         switch (cmd) {
2148         case CLI_INIT:
2149                 e->command = "confbridge lock";
2150                 e->usage =
2151                         "Usage: confbridge lock <conference>\n";
2152                 return NULL;
2153         case CLI_GENERATE:
2154                 if (a->pos == 2) {
2155                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2156                 }
2157                 return NULL;
2158         }
2159         if (a->argc != 3) {
2160                 return CLI_SHOWUSAGE;
2161         }
2162         if (generic_lock_unlock_helper(1, a->argv[2])) {
2163                 ast_cli(a->fd, "Conference %s is not found\n", a->argv[2]);
2164         } else {
2165                 ast_cli(a->fd, "Conference %s is locked.\n", a->argv[2]);
2166         }
2167         return CLI_SUCCESS;
2168 }
2169
2170 static char *handle_cli_confbridge_unlock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2171 {
2172         switch (cmd) {
2173         case CLI_INIT:
2174                 e->command = "confbridge unlock";
2175                 e->usage =
2176                         "Usage: confbridge unlock <conference>\n";
2177                 return NULL;
2178         case CLI_GENERATE:
2179                 if (a->pos == 2) {
2180                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2181                 }
2182                 return NULL;
2183         }
2184         if (a->argc != 3) {
2185                 return CLI_SHOWUSAGE;
2186         }
2187         if (generic_lock_unlock_helper(0, a->argv[2])) {
2188                 ast_cli(a->fd, "Conference %s is not found\n", a->argv[2]);
2189         } else {
2190                 ast_cli(a->fd, "Conference %s is unlocked.\n", a->argv[2]);
2191         }
2192         return CLI_SUCCESS;
2193 }
2194
2195 static char *handle_cli_confbridge_start_record(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2196 {
2197         const char *rec_file = NULL;
2198         struct conference_bridge *bridge = NULL;
2199         struct conference_bridge tmp;
2200
2201         switch (cmd) {
2202         case CLI_INIT:
2203                 e->command = "confbridge record start";
2204                 e->usage =
2205                         "Usage: confbridge record start <conference> <file>\n"
2206                         "       <file> is optional, Otherwise the bridge profile\n"
2207                         "       record file will be used.  If the bridge profile\n"
2208                         "       has no record file specified, a file will automatically\n"
2209                         "       be generated in the monitor directory\n";
2210                 return NULL;
2211         case CLI_GENERATE:
2212                 if (a->pos == 3) {
2213                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2214                 }
2215                 return NULL;
2216         }
2217         if (a->argc < 4) {
2218                 return CLI_SHOWUSAGE;
2219         }
2220         if (a->argc == 5) {
2221                 rec_file = a->argv[4];
2222         }
2223
2224         ast_copy_string(tmp.name, a->argv[3], sizeof(tmp.name));
2225         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2226         if (!bridge) {
2227                 ast_cli(a->fd, "Conference not found.\n");
2228                 return CLI_FAILURE;
2229         }
2230         if (conf_is_recording(bridge)) {
2231                 ast_cli(a->fd, "Conference is already being recorded.\n");
2232                 ao2_ref(bridge, -1);
2233                 return CLI_SUCCESS;
2234         }
2235         if (!ast_strlen_zero(rec_file)) {
2236                 ao2_lock(bridge);
2237                 ast_copy_string(bridge->b_profile.rec_file, rec_file, sizeof(bridge->b_profile.rec_file));
2238                 ao2_unlock(bridge);
2239         }
2240         if (conf_start_record(bridge)) {
2241                 ast_cli(a->fd, "Could not start recording due to internal error.\n");
2242                 ao2_ref(bridge, -1);
2243                 return CLI_FAILURE;
2244         }
2245         ast_cli(a->fd, "Recording started\n");
2246         ao2_ref(bridge, -1);
2247         return CLI_SUCCESS;
2248 }
2249
2250 static char *handle_cli_confbridge_stop_record(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2251 {
2252         struct conference_bridge *bridge = NULL;
2253         struct conference_bridge tmp;
2254
2255         switch (cmd) {
2256         case CLI_INIT:
2257                 e->command = "confbridge record stop";
2258                 e->usage =
2259                         "Usage: confbridge record stop <conference>\n";
2260                 return NULL;
2261         case CLI_GENERATE:
2262                 if (a->pos == 3) {
2263                         return complete_confbridge_name(a->line, a->word, a->pos, a->n);
2264                 }
2265                 return NULL;
2266         }
2267         if (a->argc != 4) {
2268                 return CLI_SHOWUSAGE;
2269         }
2270
2271         ast_copy_string(tmp.name, a->argv[3], sizeof(tmp.name));
2272         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2273         if (!bridge) {
2274                 ast_cli(a->fd, "Conference not found.\n");
2275                 return CLI_SUCCESS;
2276         }
2277         conf_stop_record(bridge);
2278         ast_cli(a->fd, "Recording stopped.\n");
2279         ao2_ref(bridge, -1);
2280         return CLI_SUCCESS;
2281 }
2282
2283 static struct ast_cli_entry cli_confbridge[] = {
2284         AST_CLI_DEFINE(handle_cli_confbridge_list, "List conference bridges and participants."),
2285         AST_CLI_DEFINE(handle_cli_confbridge_kick, "Kick participants out of conference bridges."),
2286         AST_CLI_DEFINE(handle_cli_confbridge_mute, "Mute a participant."),
2287         AST_CLI_DEFINE(handle_cli_confbridge_unmute, "Unmute a participant."),
2288         AST_CLI_DEFINE(handle_cli_confbridge_lock, "Lock a conference."),
2289         AST_CLI_DEFINE(handle_cli_confbridge_unlock, "Unlock a conference."),
2290         AST_CLI_DEFINE(handle_cli_confbridge_start_record, "Start recording a conference"),
2291         AST_CLI_DEFINE(handle_cli_confbridge_stop_record, "Stop recording a conference."),
2292 };
2293 static struct ast_custom_function confbridge_function = {
2294         .name = "CONFBRIDGE",
2295         .write = func_confbridge_helper,
2296 };
2297
2298 static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
2299 static struct ast_custom_function confbridge_info_function = {
2300         .name = "CONFBRIDGE_INFO",
2301         .read = func_confbridge_info,
2302 };
2303
2304 static int action_confbridgelist(struct mansession *s, const struct message *m)
2305 {
2306         const char *actionid = astman_get_header(m, "ActionID");
2307         const char *conference = astman_get_header(m, "Conference");
2308         struct conference_bridge_user *participant = NULL;
2309         struct conference_bridge *bridge = NULL;
2310         struct conference_bridge tmp;
2311         char id_text[80] = "";
2312         int total = 0;
2313
2314         if (!ast_strlen_zero(actionid)) {
2315                 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", actionid);
2316         }
2317         if (ast_strlen_zero(conference)) {
2318                 astman_send_error(s, m, "No Conference name provided.");
2319                 return 0;
2320         }
2321         if (!ao2_container_count(conference_bridges)) {
2322                 astman_send_error(s, m, "No active conferences.");
2323                 return 0;
2324         }
2325         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2326         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2327         if (!bridge) {
2328                 astman_send_error(s, m, "No Conference by that name found.");
2329                 return 0;
2330         }
2331
2332         astman_send_listack(s, m, "Confbridge user list will follow", "start");
2333
2334         ao2_lock(bridge);
2335         AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2336                 total++;
2337                 astman_append(s,
2338                         "Event: ConfbridgeList\r\n"
2339                         "%s"
2340                         "Conference: %s\r\n"
2341                         "CallerIDNum: %s\r\n"
2342                         "CallerIDName: %s\r\n"
2343                         "Channel: %s\r\n"
2344                         "Admin: %s\r\n"
2345                         "MarkedUser: %s\r\n"
2346                         "\r\n",
2347                         id_text,
2348                         bridge->name,
2349                         S_COR(participant->chan->caller.id.number.valid, participant->chan->caller.id.number.str, "<unknown>"),
2350                         S_COR(participant->chan->caller.id.name.valid, participant->chan->caller.id.name.str, "<no name>"),
2351                         ast_channel_name(participant->chan),
2352                         ast_test_flag(&participant->u_profile, USER_OPT_ADMIN) ? "Yes" : "No",
2353                         ast_test_flag(&participant->u_profile, USER_OPT_MARKEDUSER) ? "Yes" : "No");
2354         }
2355         ao2_unlock(bridge);
2356         ao2_ref(bridge, -1);
2357
2358         astman_append(s,
2359         "Event: ConfbridgeListComplete\r\n"
2360         "EventList: Complete\r\n"
2361         "ListItems: %d\r\n"
2362         "%s"
2363         "\r\n", total, id_text);
2364
2365         return 0;
2366 }
2367
2368 static int action_confbridgelistrooms(struct mansession *s, const struct message *m)
2369 {
2370         const char *actionid = astman_get_header(m, "ActionID");
2371         struct conference_bridge *bridge = NULL;
2372         struct ao2_iterator i;
2373         char id_text[512] = "";
2374         int totalitems = 0;
2375
2376         if (!ast_strlen_zero(actionid)) {
2377                 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", actionid);
2378         }
2379
2380         if (!ao2_container_count(conference_bridges)) {
2381                 astman_send_error(s, m, "No active conferences.");
2382                 return 0;
2383         }
2384
2385         astman_send_listack(s, m, "Confbridge conferences will follow", "start");
2386
2387         /* Traverse the conference list */
2388         i = ao2_iterator_init(conference_bridges, 0);
2389         while ((bridge = ao2_iterator_next(&i))) {
2390                 totalitems++;
2391
2392                 ao2_lock(bridge);
2393                 astman_append(s,
2394                 "Event: ConfbridgeListRooms\r\n"
2395                 "%s"
2396                 "Conference: %s\r\n"
2397                 "Parties: %d\r\n"
2398                 "Marked: %d\r\n"
2399                 "Locked: %s\r\n"
2400                 "\r\n",
2401                 id_text,
2402                 bridge->name,
2403                 bridge->users,
2404                 bridge->markedusers,
2405                 bridge->locked ? "Yes" : "No"); 
2406                 ao2_unlock(bridge);
2407
2408                 ao2_ref(bridge, -1);
2409         }
2410         ao2_iterator_destroy(&i);
2411
2412         /* Send final confirmation */
2413         astman_append(s,
2414         "Event: ConfbridgeListRoomsComplete\r\n"
2415         "EventList: Complete\r\n"
2416         "ListItems: %d\r\n"
2417         "%s"
2418         "\r\n", totalitems, id_text);
2419         return 0;
2420 }
2421
2422 static int action_mute_unmute_helper(struct mansession *s, const struct message *m, int mute)
2423 {
2424         const char *conference = astman_get_header(m, "Conference");
2425         const char *channel = astman_get_header(m, "Channel");
2426         int res = 0;
2427
2428         if (ast_strlen_zero(conference)) {
2429                 astman_send_error(s, m, "No Conference name provided.");
2430                 return 0;
2431         }
2432         if (ast_strlen_zero(channel)) {
2433                 astman_send_error(s, m, "No channel name provided.");
2434                 return 0;
2435         }
2436         if (!ao2_container_count(conference_bridges)) {
2437                 astman_send_error(s, m, "No active conferences.");
2438                 return 0;
2439         }
2440
2441         res = generic_mute_unmute_helper(mute, conference, channel);
2442
2443         if (res == -1) {
2444                 astman_send_error(s, m, "No Conference by that name found.");
2445                 return 0;
2446         } else if (res == -2) {
2447                 astman_send_error(s, m, "No Channel by that name found in Conference.");
2448                 return 0;
2449         }
2450
2451         astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
2452         return 0;
2453 }
2454
2455 static int action_confbridgeunmute(struct mansession *s, const struct message *m)
2456 {
2457         return action_mute_unmute_helper(s, m, 0);
2458 }
2459 static int action_confbridgemute(struct mansession *s, const struct message *m)
2460 {
2461         return action_mute_unmute_helper(s, m, 1);
2462 }
2463
2464 static int action_lock_unlock_helper(struct mansession *s, const struct message *m, int lock)
2465 {
2466         const char *conference = astman_get_header(m, "Conference");
2467         int res = 0;
2468
2469         if (ast_strlen_zero(conference)) {
2470                 astman_send_error(s, m, "No Conference name provided.");
2471                 return 0;
2472         }
2473         if (!ao2_container_count(conference_bridges)) {
2474                 astman_send_error(s, m, "No active conferences.");
2475                 return 0;
2476         }
2477         if ((res = generic_lock_unlock_helper(lock, conference))) {
2478                 astman_send_error(s, m, "No Conference by that name found.");
2479                 return 0;
2480         }
2481         astman_send_ack(s, m, lock ? "Conference locked" : "Conference unlocked");
2482         return 0;
2483 }
2484 static int action_confbridgeunlock(struct mansession *s, const struct message *m)
2485 {
2486         return action_lock_unlock_helper(s, m, 0);
2487 }
2488 static int action_confbridgelock(struct mansession *s, const struct message *m)
2489 {
2490         return action_lock_unlock_helper(s, m, 1);
2491 }
2492
2493 static int action_confbridgekick(struct mansession *s, const struct message *m)
2494 {
2495         const char *conference = astman_get_header(m, "Conference");
2496         const char *channel = astman_get_header(m, "Channel");
2497         struct conference_bridge_user *participant = NULL;
2498         struct conference_bridge *bridge = NULL;
2499         struct conference_bridge tmp;
2500         int found = 0;
2501
2502         if (ast_strlen_zero(conference)) {
2503                 astman_send_error(s, m, "No Conference name provided.");
2504                 return 0;
2505         }
2506         if (!ao2_container_count(conference_bridges)) {
2507                 astman_send_error(s, m, "No active conferences.");
2508                 return 0;
2509         }
2510         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2511         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2512         if (!bridge) {
2513                 astman_send_error(s, m, "No Conference by that name found.");
2514                 return 0;
2515         }
2516
2517         ao2_lock(bridge);
2518         AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2519                 if (!strcasecmp(ast_channel_name(participant->chan), channel)) {
2520                         participant->kicked = 1;
2521                         ast_bridge_remove(bridge->bridge, participant->chan);
2522                         found = 1;
2523                         break;
2524                 }
2525         }
2526         ao2_unlock(bridge);
2527         ao2_ref(bridge, -1);
2528
2529         if (found) {
2530                 astman_send_ack(s, m, "User kicked");
2531         } else {
2532                 astman_send_error(s, m, "No Channel by that name found in Conference.");
2533         }
2534         return 0;
2535 }
2536
2537 static int action_confbridgestartrecord(struct mansession *s, const struct message *m)
2538 {
2539         const char *conference = astman_get_header(m, "Conference");
2540         const char *recordfile = astman_get_header(m, "RecordFile");
2541         struct conference_bridge *bridge = NULL;
2542         struct conference_bridge tmp;
2543
2544         if (ast_strlen_zero(conference)) {
2545                 astman_send_error(s, m, "No Conference name provided.");
2546                 return 0;
2547         }
2548         if (!ao2_container_count(conference_bridges)) {
2549                 astman_send_error(s, m, "No active conferences.");
2550                 return 0;
2551         }
2552
2553         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2554         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2555         if (!bridge) {
2556                 astman_send_error(s, m, "No Conference by that name found.");
2557                 return 0;
2558         }
2559
2560         if (conf_is_recording(bridge)) {
2561                 astman_send_error(s, m, "Conference is already being recorded.");
2562                 ao2_ref(bridge, -1);
2563                 return 0;
2564         }
2565
2566         if (!ast_strlen_zero(recordfile)) {
2567                 ao2_lock(bridge);
2568                 ast_copy_string(bridge->b_profile.rec_file, recordfile, sizeof(bridge->b_profile.rec_file));
2569                 ao2_unlock(bridge);
2570         }
2571
2572         if (conf_start_record(bridge)) {
2573                 astman_send_error(s, m, "Internal error starting conference recording.");
2574                 ao2_ref(bridge, -1);
2575                 return 0;
2576         }
2577
2578         ao2_ref(bridge, -1);
2579         astman_send_ack(s, m, "Conference Recording Started.");
2580         return 0;
2581 }
2582 static int action_confbridgestoprecord(struct mansession *s, const struct message *m)
2583 {
2584         const char *conference = astman_get_header(m, "Conference");
2585         struct conference_bridge *bridge = NULL;
2586         struct conference_bridge tmp;
2587
2588         if (ast_strlen_zero(conference)) {
2589                 astman_send_error(s, m, "No Conference name provided.");
2590                 return 0;
2591         }
2592         if (!ao2_container_count(conference_bridges)) {
2593                 astman_send_error(s, m, "No active conferences.");
2594                 return 0;
2595         }
2596
2597         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2598         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2599         if (!bridge) {
2600                 astman_send_error(s, m, "No Conference by that name found.");
2601                 return 0;
2602         }
2603
2604         if (conf_stop_record(bridge)) {
2605                 astman_send_error(s, m, "Internal error while stopping recording.");
2606                 ao2_ref(bridge, -1);
2607                 return 0;
2608         }
2609
2610         ao2_ref(bridge, -1);
2611         astman_send_ack(s, m, "Conference Recording Stopped.");
2612         return 0;
2613 }
2614
2615 static int action_confbridgesetsinglevideosrc(struct mansession *s, const struct message *m)
2616 {
2617         const char *conference = astman_get_header(m, "Conference");
2618         const char *channel = astman_get_header(m, "Channel");
2619         struct conference_bridge_user *participant = NULL;
2620         struct conference_bridge *bridge = NULL;
2621         struct conference_bridge tmp;
2622
2623         if (ast_strlen_zero(conference)) {
2624                 astman_send_error(s, m, "No Conference name provided.");
2625                 return 0;
2626         }
2627         if (ast_strlen_zero(channel)) {
2628                 astman_send_error(s, m, "No channel name provided.");
2629                 return 0;
2630         }
2631         if (!ao2_container_count(conference_bridges)) {
2632                 astman_send_error(s, m, "No active conferences.");
2633                 return 0;
2634         }
2635
2636         ast_copy_string(tmp.name, conference, sizeof(tmp.name));
2637         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2638         if (!bridge) {
2639                 astman_send_error(s, m, "No Conference by that name found.");
2640                 return 0;
2641         }
2642
2643         /* find channel and set as video src. */
2644         ao2_lock(bridge);
2645         AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2646                 if (!strncmp(channel, ast_channel_name(participant->chan), strlen(channel))) {
2647                         ast_bridge_set_single_src_video_mode(bridge->bridge, participant->chan);
2648                         break;
2649                 }
2650         }
2651         ao2_unlock(bridge);
2652         ao2_ref(bridge, -1);
2653
2654         /* do not access participant after bridge unlock.  We are just
2655          * using this check to see if it was found or not */
2656         if (!participant) {
2657                 astman_send_error(s, m, "No channel by that name found in conference.");
2658                 return 0;
2659         }
2660         astman_send_ack(s, m, "Conference single video source set.");
2661         return 0;
2662 }
2663
2664 static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
2665 {
2666         char *parse = NULL;
2667         struct conference_bridge *bridge = NULL;
2668         struct conference_bridge_user *participant = NULL;
2669         struct conference_bridge tmp;
2670         int count = 0;
2671         AST_DECLARE_APP_ARGS(args,
2672                 AST_APP_ARG(type);
2673                 AST_APP_ARG(confno);
2674         );
2675
2676         /* parse all the required arguments and make sure they exist. */
2677         if (ast_strlen_zero(data)) {
2678                 return -1;
2679         }
2680         parse = ast_strdupa(data);
2681         AST_STANDARD_APP_ARGS(args, parse);
2682         if (ast_strlen_zero(args.confno) || ast_strlen_zero(args.type)) {
2683                 return -1;
2684         }
2685         if (!ao2_container_count(conference_bridges)) {
2686                 snprintf(buf, len, "0");
2687                 return 0;
2688         }
2689         ast_copy_string(tmp.name, args.confno, sizeof(tmp.name));
2690         bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
2691         if (!bridge) {
2692                 snprintf(buf, len, "0");
2693                 return 0;
2694         }
2695
2696         /* get the correct count for the type requested */
2697         ao2_lock(bridge);
2698         if (!strncasecmp(args.type, "parties", 7)) {
2699                 AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2700                         count++;
2701                 }
2702         } else if (!strncasecmp(args.type, "admins", 6)) {
2703                 AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2704                         if (ast_test_flag(&participant->u_profile, USER_OPT_ADMIN)) {
2705                                 count++;
2706                         }
2707                 }
2708         } else if (!strncasecmp(args.type, "marked", 6)) {
2709                 AST_LIST_TRAVERSE(&bridge->users_list, participant, list) {
2710                         if (ast_test_flag(&participant->u_profile, USER_OPT_MARKEDUSER)) {
2711                                 count++;
2712                         }
2713                 }
2714         } else if (!strncasecmp(args.type, "locked", 6)) {
2715                 count = bridge->locked;
2716         } else {
2717                 ast_log(LOG_ERROR, "Invalid keyword '%s' passed to CONFBRIDGE_INFO.  Should be one of: "
2718                         "parties, admins, marked, or locked.\n", args.type);
2719         }
2720         snprintf(buf, len, "%d", count);
2721         ao2_unlock(bridge);
2722         ao2_ref(bridge, -1);
2723         return 0;
2724 }
2725
2726 /*! \brief Called when module is being unloaded */
2727 static int unload_module(void)
2728 {
2729         int res = ast_unregister_application(app);
2730
2731         ast_custom_function_unregister(&confbridge_function);
2732         ast_custom_function_unregister(&confbridge_info_function);
2733
2734         ast_cli_unregister_multiple(cli_confbridge, sizeof(cli_confbridge) / sizeof(struct ast_cli_entry));
2735
2736         /* Get rid of the conference bridges container. Since we only allow dynamic ones none will be active. */
2737         ao2_ref(conference_bridges, -1);
2738
2739         conf_destroy_config();
2740
2741         ast_channel_unregister(&record_tech);
2742         record_tech.capabilities = ast_format_cap_destroy(record_tech.capabilities);
2743
2744         res |= ast_manager_unregister("ConfbridgeList");
2745         res |= ast_manager_unregister("ConfbridgeListRooms");
2746         res |= ast_manager_unregister("ConfbridgeMute");
2747         res |= ast_manager_unregister("ConfbridgeUnmute");
2748         res |= ast_manager_unregister("ConfbridgeKick");
2749         res |= ast_manager_unregister("ConfbridgeUnlock");
2750         res |= ast_manager_unregister("ConfbridgeLock");
2751         res |= ast_manager_unregister("ConfbridgeStartRecord");
2752         res |= ast_manager_unregister("ConfbridgeStopRecord");
2753
2754         return res;
2755 }
2756
2757 /*! \brief Called when module is being loaded */
2758 static int load_module(void)
2759 {
2760         int res = 0;
2761         if ((ast_custom_function_register(&confbridge_function))) {
2762                 return AST_MODULE_LOAD_FAILURE;
2763         }
2764         if ((ast_custom_function_register(&confbridge_info_function))) {
2765                 return AST_MODULE_LOAD_FAILURE;
2766         }
2767         if (!(record_tech.capabilities = ast_format_cap_alloc())) {
2768                 return AST_MODULE_LOAD_FAILURE;
2769         }
2770         ast_format_cap_add_all(record_tech.capabilities);
2771         if (ast_channel_register(&record_tech)) {
2772                 ast_log(LOG_ERROR, "Unable to register ConfBridge recorder.\n");
2773                 return AST_MODULE_LOAD_FAILURE;
2774         }
2775         /* Create a container to hold the conference bridges */
2776         if (!(conference_bridges = ao2_container_alloc(CONFERENCE_BRIDGE_BUCKETS, conference_bridge_hash_cb, conference_bridge_cmp_cb))) {
2777                 return AST_MODULE_LOAD_FAILURE;
2778         }
2779         if (ast_register_application_xml(app, confbridge_exec)) {
2780                 ao2_ref(conference_bridges, -1);
2781                 return AST_MODULE_LOAD_FAILURE;
2782         }
2783
2784         res |= ast_cli_register_multiple(cli_confbridge, sizeof(cli_confbridge) / sizeof(struct ast_cli_entry));
2785         res |= ast_manager_register_xml("ConfbridgeList", EVENT_FLAG_REPORTING, action_confbridgelist);
2786         res |= ast_manager_register_xml("ConfbridgeListRooms", EVENT_FLAG_REPORTING, action_confbridgelistrooms);
2787         res |= ast_manager_register_xml("ConfbridgeMute", EVENT_FLAG_CALL, action_confbridgemute);
2788         res |= ast_manager_register_xml("ConfbridgeUnmute", EVENT_FLAG_CALL, action_confbridgeunmute);
2789         res |= ast_manager_register_xml("ConfbridgeKick", EVENT_FLAG_CALL, action_confbridgekick);
2790         res |= ast_manager_register_xml("ConfbridgeUnlock", EVENT_FLAG_CALL, action_confbridgeunlock);
2791         res |= ast_manager_register_xml("ConfbridgeLock", EVENT_FLAG_CALL, action_confbridgelock);
2792         res |= ast_manager_register_xml("ConfbridgeStartRecord", EVENT_FLAG_CALL, action_confbridgestartrecord);
2793         res |= ast_manager_register_xml("ConfbridgeStopRecord", EVENT_FLAG_CALL, action_confbridgestoprecord);
2794         res |= ast_manager_register_xml("ConfbridgeSetSingleVideoSrc", EVENT_FLAG_CALL, action_confbridgesetsinglevideosrc);
2795
2796         conf_load_config(0);
2797         return res;
2798 }
2799
2800 static int reload(void)
2801 {
2802         return conf_load_config(1);
2803 }
2804
2805 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Conference Bridge Application",
2806         .load = load_module,
2807         .unload = unload_module,
2808         .reload = reload,
2809         .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
2810 );