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