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