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