ecb989f7bee5da3fcb8ddb12548a8e1dbf1ce77e
[asterisk/asterisk.git] / apps / confbridge / conf_config_parser.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2011, Digium, Inc.
5  *
6  * David Vossel <dvossel@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief ConfBridge config parser
22  *
23  * \author David Vossel <dvossel@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33 #include "asterisk/logger.h"
34 #include "asterisk/config.h"
35 #include "asterisk/config_options.h"
36 #include "include/confbridge.h"
37 #include "asterisk/astobj2.h"
38 #include "asterisk/cli.h"
39 #include "asterisk/bridging_features.h"
40 #include "asterisk/stringfields.h"
41 #include "asterisk/pbx.h"
42
43
44 /*** DOCUMENTATION
45         <configInfo name="app_confbridge" language="en_US">
46                 <synopsis>Conference Bridge Application</synopsis>
47                 <configFile name="confbridge.conf">
48                         <configObject name="global">
49                                 <synopsis>Unused, but reserved.</synopsis>
50                         </configObject>
51                         <configObject name="user_profile">
52                                 <synopsis>A named profile to apply to specific callers.</synopsis>
53                                 <description><para>Callers in a ConfBridge have a profile associated with them
54                                 that determine their options. A configuration section is determined to be a
55                                 user_profile when the <literal>type</literal> parameter has a value
56                                 of <literal>user</literal>.
57                                 </para></description>
58                                 <configOption name="type">
59                                         <synopsis>Define this configuration category as a user profile.</synopsis>
60                                         <description><para>The type parameter determines how a context in the
61                                         configuration file is interpreted.</para>
62                                         <enumlist>
63                                                 <enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
64                                                 <enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
65                                                 <enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
66                                         </enumlist>
67                                         </description>
68                                 </configOption>
69                                 <configOption name="admin">
70                                         <synopsis>Sets if the user is an admin or not</synopsis>
71                                 </configOption>
72                                 <configOption name="marked">
73                                         <synopsis>Sets if this is a marked user or not</synopsis>
74                                 </configOption>
75                                 <configOption name="startmuted">
76                                         <synopsis>Sets if all users should start out muted</synopsis>
77                                 </configOption>
78                                 <configOption name="music_on_hold_when_empty">
79                                         <synopsis>Play MOH when user is alone or waiting on a marked user</synopsis>
80                                 </configOption>
81                                 <configOption name="quiet">
82                                         <synopsis>Silence enter/leave prompts and user intros for this user</synopsis>
83                                 </configOption>
84                                 <configOption name="announce_user_count">
85                                         <synopsis>Sets if the number of users should be announced to the user</synopsis>
86                                 </configOption>
87                                 <configOption name="announce_user_count_all">
88                                         <synopsis>Announce user count to all the other users when this user joins</synopsis>
89                                         <description><para>Sets if the number of users should be announced to all the other users
90                                         in the conference when this user joins. This option can be either set to 'yes' or
91                                         a number. When set to a number, the announcement will only occur once the user
92                                         count is above the specified number.
93                                         </para></description>
94                                 </configOption>
95                                 <configOption name="announce_only_user">
96                                         <synopsis>Announce to a user when they join an empty conference</synopsis>
97                                 </configOption>
98                                 <configOption name="wait_marked">
99                                         <synopsis>Sets if the user must wait for a marked user to enter before joining a conference</synopsis>
100                                 </configOption>
101                                 <configOption name="end_marked">
102                                         <synopsis>Kick the user from the conference when the last marked user leaves</synopsis>
103                                 </configOption>
104                                 <configOption name="talk_detection_events">
105                                         <synopsis>Set whether or not notifications of when a user begins and ends talking should be sent out as events over AMI</synopsis>
106                                 </configOption>
107                                 <configOption name="dtmf_passthrough">
108                                         <synopsis>Sets whether or not DTMF should pass through the conference</synopsis>
109                                 </configOption>
110                                 <configOption name="announce_join_leave">
111                                         <synopsis>Prompt user for their name when joining a conference and play it to the conference when they enter</synopsis>
112                                 </configOption>
113                                 <configOption name="pin">
114                                         <synopsis>Sets a PIN the user must enter before joining the conference</synopsis>
115                                 </configOption>
116                                 <configOption name="music_on_hold_class">
117                                         <synopsis>The MOH class to use for this user</synopsis>
118                                 </configOption>
119                                 <configOption name="announcement">
120                                         <synopsis>Sound file to play to the user when they join a conference</synopsis>
121                                 </configOption>
122                                 <configOption name="denoise">
123                                         <synopsis>Apply a denoise filter to the audio before mixing</synopsis>
124                                         <description><para>Sets whether or not a denoise filter should be applied
125                                         to the audio before mixing or not.  Off by default. Requires
126                                         codec_speex to be built and installed.  Do not confuse this option
127                                         with drop_silence.  Denoise is useful if there is a lot of background
128                                         noise for a user as it attempts to remove the noise while preserving
129                                         the speech.  This option does NOT remove silence from being mixed into
130                                         the conference and does come at the cost of a slight performance hit.
131                                         </para></description>
132                                 </configOption>
133                                 <configOption name="dsp_drop_silence">
134                                         <synopsis>Drop what Asterisk detects as silence from audio sent to the bridge</synopsis>
135                                         <description><para>
136                                         This option drops what Asterisk detects as silence from
137                                         entering into the bridge.  Enabling this option will drastically
138                                         improve performance and help remove the buildup of background
139                                         noise from the conference. Highly recommended for large conferences
140                                         due to its performance enhancements.
141                                         </para></description>
142                                 </configOption>
143                                 <configOption name="dsp_silence_threshold">
144                                         <synopsis>The number of milliseconds of detected silence necessary to trigger silence detection</synopsis>
145                                         <description><para>
146                                         The time in milliseconds of sound falling within the what
147                                         the dsp has established as baseline silence before a user
148                                         is considered be silent.  This value affects several
149                                         operations and should not be changed unless the impact
150                                         on call quality is fully understood.</para>
151                                         <para>What this value affects internally:</para>
152                                         <para>
153                                                 1. When talk detection AMI events are enabled, this value
154                                                 determines when the user has stopped talking after a
155                                                 period of talking.  If this value is set too low
156                                                 AMI events indicating the user has stopped talking
157                                                 may get falsely sent out when the user briefly pauses
158                                                 during mid sentence.
159                                         </para>
160                                         <para>
161                                                 2. The drop_silence option depends on this value to
162                                                 determine when the user's audio should begin to be
163                                                 dropped from the conference bridge after the user
164                                                 stops talking.  If this value is set too low the user's
165                                                 audio stream may sound choppy to the other participants.
166                                                 This is caused by the user transitioning constantly from
167                                                 silence to talking during mid sentence.
168                                         </para>
169                                         <para>
170                                                 The best way to approach this option is to set it slightly above
171                                                 the maximum amount of ms of silence a user may generate during
172                                                 natural speech.
173                                         </para>
174                                         <para>By default this value is 2500ms. Valid values are 1 through 2^31.</para>
175                                         </description>
176                                 </configOption>
177                                 <configOption name="dsp_talking_threshold">
178                                         <synopsis>The number of milliseconds of detected non-silence necessary to triger talk detection</synopsis>
179                                         <description><para>
180                                                 The time in milliseconds of sound above what the dsp has
181                                                 established as base line silence for a user before a user
182                                                 is considered to be talking.  This value affects several
183                                                 operations and should not be changed unless the impact on
184                                                 call quality is fully understood.</para>
185                                                 <para>
186                                                 What this value affects internally:
187                                                 </para>
188                                                 <para>
189                                                 1. Audio is only mixed out of a user's incoming audio stream
190                                                 if talking is detected.  If this value is set too
191                                                 loose the user will hear themselves briefly each
192                                                 time they begin talking until the dsp has time to
193                                                 establish that they are in fact talking.
194                                                 </para>
195                                                 <para>
196                                                 2. When talk detection AMI events are enabled, this value
197                                                 determines when talking has begun which results in
198                                                 an AMI event to fire.  If this value is set too tight
199                                                 AMI events may be falsely triggered by variants in
200                                                 room noise.
201                                                 </para>
202                                                 <para>
203                                                 3. The drop_silence option depends on this value to determine
204                                                 when the user's audio should be mixed into the bridge
205                                                 after periods of silence.  If this value is too loose
206                                                 the beginning of a user's speech will get cut off as they
207                                                 transition from silence to talking.
208                                                 </para>
209                                                 <para>By default this value is 160 ms. Valid values are 1 through 2^31</para>
210                                         </description>
211                                 </configOption>
212                                 <configOption name="jitterbuffer">
213                                         <synopsis>Place a jitter buffer on the user's audio stream before audio mixing is performed</synopsis>
214                                         <description><para>
215                                                 Enabling this option places a jitterbuffer on the user's audio stream
216                                                 before audio mixing is performed.  This is highly recommended but will
217                                                 add a slight delay to the audio.  This option is using the <literal>JITTERBUFFER</literal>
218                                                 dialplan function's default adaptive jitterbuffer.  For a more fine tuned
219                                                 jitterbuffer, disable this option and use the <literal>JITTERBUFFER</literal> dialplan function
220                                                 on the user before entering the ConfBridge application.
221                                         </para></description>
222                                 </configOption>
223                                 <configOption name="template">
224                                         <synopsis>When using the CONFBRIDGE dialplan function, use a user profile as a template for creating a new temporary profile</synopsis>
225                                 </configOption>
226                         </configObject>
227                         <configObject name="bridge_profile">
228                                 <synopsis>A named profile to apply to specific bridges.</synopsis>
229                                 <description><para>ConfBridge bridges have a profile associated with them
230                                 that determine their options. A configuration section is determined to be a
231                                 <literal>bridge_profile</literal> when the <literal>type</literal> parameter has a value
232                                 of <literal>bridge</literal>.
233                                 </para></description>
234                                 <configOption name="type">
235                                         <synopsis>Define this configuration category as a bridge profile</synopsis>
236                                         <description><para>The type parameter determines how a context in the
237                                         configuration file is interpreted.</para>
238                                         <enumlist>
239                                                 <enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
240                                                 <enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
241                                                 <enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
242                                         </enumlist>
243                                         </description>
244                                 </configOption>
245                                 <configOption name="jitterbuffer">
246                                         <synopsis>Place a jitter buffer on the conference's audio stream</synopsis>
247                                 </configOption>
248                                 <configOption name="internal_sample_rate">
249                                         <synopsis>Set the internal native sample rate for mixing the conference</synopsis>
250                                         <description><para>
251                                                 Sets the internal native sample rate the
252                                                 conference is mixed at.  This is set to automatically
253                                                 adjust the sample rate to the best quality by default.
254                                                 Other values can be anything from 8000-192000.  If a
255                                                 sample rate is set that Asterisk does not support, the
256                                                 closest sample rate Asterisk does support to the one requested
257                                                 will be used.
258                                         </para></description>
259                                 </configOption>
260                                 <configOption name="mixing_interval">
261                                         <synopsis>Sets the internal mixing interval in milliseconds for the bridge</synopsis>
262                                         <description><para>
263                                                 Sets the internal mixing interval in milliseconds for the bridge.  This
264                                                 number reflects how tight or loose the mixing will be for the conference.
265                                                 In order to improve performance a larger mixing interval such as 40ms may
266                                                 be chosen.  Using a larger mixing interval comes at the cost of introducing
267                                                 larger amounts of delay into the bridge.  Valid values here are 10, 20, 40,
268                                                 or 80.
269                                         </para></description>
270                                 </configOption>
271                                 <configOption name="record_conference">
272                                         <synopsis>Record the conference starting with the first active user's entrance and ending with the last active user's exit</synopsis>
273                                         <description><para>
274                                                 Records the conference call starting when the first user
275                                                 enters the room, and ending when the last user exits the room.
276                                                 The default recorded filename is
277                                                 <filename>'confbridge-${name of conference bridge}-${start time}.wav</filename>
278                                                 and the default format is 8khz slinear.  This file will be
279                                                 located in the configured monitoring directory in asterisk.conf.
280                                         </para></description>
281                                 </configOption>
282                                 <configOption name="record_file" default="confbridge-${name of conference bridge}-${start time}.wav">
283                                         <synopsis>The filename of the conference recording</synopsis>
284                                         <description><para>
285                                                 When record_conference is set to yes, the specific name of the
286                                                 record file can be set using this option.  Note that since multiple
287                                                 conferences may use the same bridge profile, this may cause issues
288                                                 depending on the configuration.  It is recommended to only use this
289                                                 option dynamically with the <literal>CONFBRIDGE()</literal> dialplan function. This
290                                                 allows the record name to be specified and a unique name to be chosen.
291                                                 By default, the record_file is stored in Asterisk's spool/monitor directory
292                                                 with a unique filename starting with the 'confbridge' prefix.
293                                         </para></description>
294                                 </configOption>
295                                 <configOption name="video_mode">
296                                         <synopsis>Sets how confbridge handles video distribution to the conference participants</synopsis>
297                                         <description><para>
298                                                 Sets how confbridge handles video distribution to the conference participants.
299                                                 Note that participants wanting to view and be the source of a video feed
300                                                 _MUST_ be sharing the same video codec.  Also, using video in conjunction with
301                                                 with the jitterbuffer currently results in the audio being slightly out of sync
302                                                 with the video.  This is a result of the jitterbuffer only working on the audio
303                                                 stream.  It is recommended to disable the jitterbuffer when video is used.</para>
304                                                 <enumlist>
305                                                         <enum name="none">
306                                                                 <para>No video sources are set by default in the conference. It is still
307                                                                 possible for a user to be set as a video source via AMI or DTMF action
308                                                                 at any time.</para>
309                                                         </enum>
310                                                         <enum name="follow_talker">
311                                                                 <para>The video feed will follow whoever is talking and providing video.</para>
312                                                         </enum>
313                                                         <enum name="last_marked">
314                                                                 <para>The last marked user to join the conference with video capabilities
315                                                                 will be the single source of video distributed to all participants.
316                                                                 If multiple marked users are capable of video, the last one to join
317                                                                 is always the source, when that user leaves it goes to the one who
318                                                                 joined before them.</para>
319                                                         </enum>
320                                                         <enum name="first_marked">
321                                                                 <para>The first marked user to join the conference with video capabilities
322                                                                 is the single source of video distribution among all participants. If
323                                                                 that user leaves, the marked user to join after them becomes the source.</para>
324                                                         </enum>
325                                                 </enumlist>
326                                         </description>
327                                 </configOption>
328                                 <configOption name="max_members">
329                                         <synopsis>Limit the maximum number of participants for a single conference</synopsis>
330                                         <description><para>
331                                                 This option limits the number of participants for a single
332                                                 conference to a specific number.  By default conferences
333                                                 have no participant limit. After the limit is reached, the
334                                                 conference will be locked until someone leaves.  Note however
335                                                 that an Admin user will always be alowed to join the conference
336                                                 regardless if this limit is reached or not.
337                                         </para></description>
338                                 </configOption>
339                                 <configOption name="^sound_">
340                                         <synopsis>Override the various conference bridge sound files</synopsis>
341                                         <description><para>
342                                                 All sounds in the conference are customizable using the bridge profile options below.
343                                                 Simply state the option followed by the filename or full path of the filename after
344                                                 the option.  Example: <literal>sound_had_joined=conf-hasjoin</literal>  This will play the <literal>conf-hasjoin</literal>
345                                                 sound file found in the sounds directory when announcing someone's name is joining the
346                                                 conference.</para>
347                                                 <enumlist>
348                                                         <enum name="sound_join"><para>The sound played to everyone when someone enters the conference.</para></enum>
349                                                         <enum name="sound_leave"><para>The sound played to everyone when someone leaves the conference.</para></enum>
350                                                         <enum name="sound_has_joined"><para>The sound played before announcing someone's name has
351                                                                                 joined the conference. This is used for user intros.
352                                                                                 Example <literal>"_____ has joined the conference"</literal></para></enum>
353                                                         <enum name="sound_has_left"><para>The sound played when announcing someone's name has
354                                                                                 left the conference. This is used for user intros.
355                                                                                 Example <literal>"_____ has left the conference"</literal></para></enum>
356                                                         <enum name="sound_kicked"><para>The sound played to a user who has been kicked from the conference.</para></enum>
357                                                         <enum name="sound_muted"><para>The sound played when the mute option it toggled on.</para></enum>
358                                                         <enum name="sound_unmuted"><para>The sound played when the mute option it toggled off.</para></enum>
359                                                         <enum name="sound_only_person"><para>The sound played when the user is the only person in the conference.</para></enum>
360                                                         <enum name="sound_only_one"><para>The sound played to a user when there is only one other
361                                                                                 person is in the conference.</para></enum>
362                                                         <enum name="sound_there_are"><para>The sound played when announcing how many users there
363                                                                                 are in a conference.</para></enum>
364                                                         <enum name="sound_other_in_party"><para>This file is used in conjunction with <literal>sound_there_are</literal>
365                                                                                 when announcing how many users there are in the conference.
366                                                                                 The sounds are stringed together like this.
367                                                                                 <literal>"sound_there_are" ${number of participants} "sound_other_in_party"</literal></para></enum>
368                                                         <enum name="sound_place_into_conference"><para>The sound played when someone is placed into the conference
369                                                                                 after waiting for a marked user.</para></enum>
370                                                         <enum name="sound_wait_for_leader"><para>The sound played when a user is placed into a conference that
371                                                                                 can not start until a marked user enters.</para></enum>
372                                                         <enum name="sound_leader_has_left"><para>The sound played when the last marked user leaves the conference.</para></enum>
373                                                         <enum name="sound_get_pin"><para>The sound played when prompting for a conference pin number.</para></enum>
374                                                         <enum name="sound_invalid_pin"><para>The sound played when an invalid pin is entered too many times.</para></enum>
375                                                         <enum name="sound_locked"><para>The sound played to a user trying to join a locked conference.</para></enum>
376                                                         <enum name="sound_locked_now"><para>The sound played to an admin after toggling the conference to locked mode.</para></enum>
377                                                         <enum name="sound_unlocked_now"><para>The sound played to an admin after toggling the conference to unlocked mode.</para></enum>
378                                                         <enum name="sound_error_menu"><para>The sound played when an invalid menu option is entered.</para></enum>
379                                                 </enumlist>
380                                         </description>
381                                 </configOption>
382                                 <configOption name="template">
383                                         <synopsis>When using the CONFBRIDGE dialplan function, use a bridge profile as a template for creating a new temporary profile</synopsis>
384                                 </configOption>
385                         </configObject>
386                         <configObject name="menu">
387                                 <synopsis>A conference user menu</synopsis>
388                                 <description>
389                                         <para>Conference users, as defined by a <literal>conf_user</literal>,
390                                         can have a DTMF menu assigned to their profile when they enter the
391                                         <literal>ConfBridge</literal> application.</para>
392                                 </description>
393                                 <configOption name="type">
394                                         <synopsis>Define this configuration category as a menu</synopsis>
395                                         <description><para>The type parameter determines how a context in the
396                                         configuration file is interpreted.</para>
397                                         <enumlist>
398                                                 <enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
399                                                 <enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
400                                                 <enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
401                                         </enumlist>
402                                         </description>
403                                 </configOption>
404                                 <configOption name="^[0-9A-D*#]+$">
405                                         <synopsis>DTMF sequences to assign various confbridge actions to</synopsis>
406                                         <description><para>--- ConfBridge Menu Options ---</para>
407                                         <para>The ConfBridge application also has the ability to apply custom DTMF menus to
408                                         each channel using the application.  Like the User and Bridge profiles a menu
409                                         is passed in to ConfBridge as an argument in the dialplan.</para>
410                                         <para>Below is a list of menu actions that can be assigned to a DTMF sequence.</para>
411                                         <note><para>
412                                         A single DTMF sequence can have multiple actions associated with it. This is
413                                         accomplished by stringing the actions together and using a <literal>,</literal> as the
414                                         delimiter.  Example:  Both listening and talking volume is reset when <literal>5</literal> is
415                                         pressed.  <literal>5=reset_talking_volume, reset_listening_volume</literal></para></note>
416                                         <enumlist>
417                                                 <enum name="playback(filename&amp;filename2&amp;...)"><para>
418                                                         <literal>playback</literal> will play back an audio file to a channel
419                                                         and then immediately return to the conference.
420                                                         This file can not be interupted by DTMF.
421                                                         Multiple files can be chained together using the
422                                                         <literal>&amp;</literal> character.</para></enum>
423                                                 <enum name="playback_and_continue(filename&amp;filename2&amp;...)"><para>
424                                                         <literal>playback_and_continue</literal> will
425                                                         play back a prompt while continuing to
426                                                         collect the dtmf sequence.  This is useful
427                                                         when using a menu prompt that describes all
428                                                         the menu options.  Note however that any DTMF
429                                                         during this action will terminate the prompts
430                                                         playback.  Prompt files can be chained together
431                                                         using the <literal>&amp;</literal> character as a delimiter.</para></enum>
432                                                 <enum name="toggle_mute"><para>
433                                                         Toggle turning on and off mute.  Mute will make the user silent
434                                                         to everyone else, but the user will still be able to listen in.
435                                                         continue to collect the dtmf sequence.</para></enum>
436                                                 <enum name="no_op"><para>
437                                                         This action does nothing (No Operation). Its only real purpose exists for
438                                                         being able to reserve a sequence in the config as a menu exit sequence.</para></enum>
439                                                 <enum name="decrease_listening_volume"><para>
440                                                         Decreases the channel's listening volume.</para></enum>
441                                                 <enum name="increase_listening_volume"><para>
442                                                         Increases the channel's listening volume.</para></enum>
443                                                 <enum name="reset_listening_volume"><para>
444                                                         Reset channel's listening volume to default level.</para></enum>
445                                                 <enum name="decrease_talking_volume"><para>
446                                                         Decreases the channel's talking volume.</para></enum>
447                                                 <enum name="increase_talking_volume"><para>
448                                                         Increases the channel's talking volume.</para></enum>
449                                                 <enum name="reset_talking_volume"><para>
450                                                         Reset channel's talking volume to default level.</para></enum>
451                                                 <enum name="dialplan_exec(context,exten,priority)"><para>
452                                                         The <literal>dialplan_exec</literal> action allows a user
453                                                         to escape from the conference and execute
454                                                         commands in the dialplan.  Once the dialplan
455                                                         exits the user will be put back into the
456                                                         conference.  The possibilities are endless!</para></enum>
457                                                 <enum name="leave_conference"><para>
458                                                         This action allows a user to exit the conference and continue
459                                                         execution in the dialplan.</para></enum>
460                                                 <enum name="admin_kick_last"><para>
461                                                         This action allows an Admin to kick the last participant from the
462                                                         conference. This action will only work for admins which allows
463                                                         a single menu to be used for both users and admins.</para></enum>
464                                                 <enum name="admin_toggle_conference_lock"><para>
465                                                         This action allows an Admin to toggle locking and
466                                                         unlocking the conference.  Non admins can not use
467                                                         this action even if it is in their menu.</para></enum>
468                                                 <enum name="set_as_single_video_src"><para>
469                                                         This action allows any user to set themselves as the
470                                                         single video source distributed to all participants.
471                                                         This will make the video feed stick to them regardless
472                                                         of what the <literal>video_mode</literal> is set to.</para></enum>
473                                                 <enum name="release_as_single_video_src"><para>
474                                                         This action allows a user to release themselves as
475                                                         the video source.  If <literal>video_mode</literal> is not set to <literal>none</literal>
476                                                         this action will result in the conference returning to
477                                                         whatever video mode the bridge profile is using.</para>
478                                                         <para>Note that this action will have no effect if the user
479                                                         is not currently the video source.  Also, the user is
480                                                         not guaranteed by using this action that they will not
481                                                         become the video source again.  The bridge will return
482                                                         to whatever operation the <literal>video_mode</literal> option is set to
483                                                         upon release of the video src.</para></enum>
484                                                 <enum name="admin_toggle_mute_participants"><para>
485                                                         This action allows an administrator to toggle the mute
486                                                         state for all non-admins within a conference.  All
487                                                         admin users are unaffected by this option.  Note that all
488                                                         users, regardless of their admin status, are notified
489                                                         that the conference is muted.</para></enum>
490                                                 <enum name="participant_count"><para>
491                                                         This action plays back the number of participants currently
492                                                         in a conference</para></enum>
493                                                 </enumlist>
494                                         </description>
495                                 </configOption>
496                         </configObject>
497                 </configFile>
498         </configInfo>
499 ***/
500
501 struct confbridge_cfg {
502         struct ao2_container *bridge_profiles;
503         struct ao2_container *user_profiles;
504         struct ao2_container *menus;
505 };
506
507 static void *bridge_profile_alloc(const char *category);
508 static void *bridge_profile_find(struct ao2_container *container, const char *category);
509 static struct bridge_profile_sounds *bridge_profile_sounds_alloc(void);
510
511 static void bridge_profile_destructor(void *obj)
512 {
513         struct bridge_profile *b_profile = obj;
514         ao2_cleanup(b_profile->sounds);
515 }
516
517 static void *bridge_profile_alloc(const char *category)
518 {
519         struct bridge_profile *b_profile;
520
521         if (!(b_profile = ao2_alloc(sizeof(*b_profile), bridge_profile_destructor))) {
522                 return NULL;
523         }
524
525         if (!(b_profile->sounds = bridge_profile_sounds_alloc())) {
526                 ao2_ref(b_profile, -1);
527                 return NULL;
528         }
529
530         ast_copy_string(b_profile->name, category, sizeof(b_profile->name));
531
532         return b_profile;
533 }
534
535 static void *bridge_profile_find(struct ao2_container *container, const char *category)
536 {
537         return ao2_find(container, category, OBJ_KEY);
538 }
539
540 static struct aco_type bridge_type = {
541         .type = ACO_ITEM,
542         .name = "bridge_profile",
543         .category_match = ACO_BLACKLIST,
544         .category = "^general$",
545         .matchfield = "type",
546         .matchvalue = "bridge",
547         .item_alloc = bridge_profile_alloc,
548         .item_find = bridge_profile_find,
549         .item_offset = offsetof(struct confbridge_cfg, bridge_profiles),
550 };
551
552 static void *user_profile_alloc(const char *category);
553 static void *user_profile_find(struct ao2_container *container, const char *category);
554 static void user_profile_destructor(void *obj)
555 {
556         return;
557 }
558
559 static void *user_profile_alloc(const char *category)
560 {
561         struct user_profile *u_profile;
562
563         if (!(u_profile = ao2_alloc(sizeof(*u_profile), user_profile_destructor))) {
564                 return NULL;
565         }
566
567         ast_copy_string(u_profile->name, category, sizeof(u_profile->name));
568
569         return u_profile;
570 }
571
572 static void *user_profile_find(struct ao2_container *container, const char *category)
573 {
574         return ao2_find(container, category, OBJ_KEY);
575 }
576
577 static struct aco_type user_type = {
578         .type = ACO_ITEM,
579         .name  = "user_profile",
580         .category_match = ACO_BLACKLIST,
581         .category = "^general$",
582         .matchfield = "type",
583         .matchvalue = "user",
584         .item_alloc = user_profile_alloc,
585         .item_find = user_profile_find,
586         .item_offset = offsetof(struct confbridge_cfg, user_profiles),
587 };
588
589 static void *menu_alloc(const char *category);
590 static void *menu_find(struct ao2_container *container, const char *category);
591 static void menu_destructor(void *obj);
592
593 static void *menu_alloc(const char *category)
594 {
595         struct conf_menu *menu;
596         if (!(menu = ao2_alloc(sizeof(*menu), menu_destructor))) {
597                 return NULL;
598         }
599         ast_copy_string(menu->name, category, sizeof(menu->name));
600         return menu;
601 }
602
603 static void *menu_find(struct ao2_container *container, const char *category)
604 {
605         return ao2_find(container, category, OBJ_KEY);
606 }
607
608 static struct aco_type menu_type = {
609         .type = ACO_ITEM,
610         .name = "menu",
611         .category_match = ACO_BLACKLIST,
612         .category = "^general$",
613         .matchfield = "type",
614         .matchvalue = "menu",
615         .item_alloc = menu_alloc,
616         .item_find = menu_find,
617         .item_offset = offsetof(struct confbridge_cfg, menus),
618 };
619
620 /* Used to pass to aco_option_register */
621 static struct aco_type *bridge_types[] = ACO_TYPES(&bridge_type);
622 static struct aco_type *menu_types[] = ACO_TYPES(&menu_type);
623 static struct aco_type *user_types[] = ACO_TYPES(&user_type);
624
625 /* The general category is reserved, but unused */
626 static struct aco_type general_type = {
627         .type = ACO_GLOBAL,
628         .name = "global",
629         .category_match = ACO_WHITELIST,
630         .category = "^general$",
631 };
632
633 static struct aco_file confbridge_conf = {
634         .filename = "confbridge.conf",
635         .types = ACO_TYPES(&bridge_type, &user_type, &menu_type, &general_type),
636 };
637
638 static AO2_GLOBAL_OBJ_STATIC(cfg_handle);
639
640 static void *confbridge_cfg_alloc(void);
641
642 CONFIG_INFO_STANDARD(cfg_info, cfg_handle, confbridge_cfg_alloc,
643         .files = ACO_FILES(&confbridge_conf),
644 );
645
646 /*! bridge profile container functions */
647 static int bridge_cmp_cb(void *obj, void *arg, int flags)
648 {
649         const struct bridge_profile *entry1 = obj, *entry2 = arg;
650         const char *name = arg;
651         return (!strcasecmp(entry1->name, flags & OBJ_KEY ? name : entry2->name)) ?
652                 CMP_MATCH | CMP_STOP : 0;
653 }
654 static int bridge_hash_cb(const void *obj, const int flags)
655 {
656         const struct bridge_profile *b_profile = obj;
657         const char *name = obj;
658         return ast_str_case_hash(flags & OBJ_KEY ? name : b_profile->name);
659 }
660
661 /*! menu container functions */
662 static int menu_cmp_cb(void *obj, void *arg, int flags)
663 {
664         const struct conf_menu *entry1 = obj, *entry2 = arg;
665         const char *name = arg;
666         return (!strcasecmp(entry1->name, flags & OBJ_KEY ? name : entry2->name)) ?
667                 CMP_MATCH | CMP_STOP : 0;
668 }
669 static int menu_hash_cb(const void *obj, const int flags)
670 {
671         const struct conf_menu *menu = obj;
672         const char *name = obj;
673         return ast_str_case_hash(flags & OBJ_KEY ? name : menu->name);
674 }
675 static void menu_destructor(void *obj)
676 {
677         struct conf_menu *menu = obj;
678         struct conf_menu_entry *entry = NULL;
679
680         while ((entry = AST_LIST_REMOVE_HEAD(&menu->entries, entry))) {
681                 conf_menu_entry_destroy(entry);
682                 ast_free(entry);
683         }
684 }
685
686 /*! User profile container functions */
687 static int user_cmp_cb(void *obj, void *arg, int flags)
688 {
689         const struct user_profile *entry1 = obj, *entry2 = arg;
690         const char *name = arg;
691         return (!strcasecmp(entry1->name, flags & OBJ_KEY ? name : entry2->name)) ?
692                 CMP_MATCH | CMP_STOP : 0;
693 }
694 static int user_hash_cb(const void *obj, const int flags)
695 {
696         const struct user_profile *u_profile = obj;
697         const char *name = obj;
698         return ast_str_case_hash(flags & OBJ_KEY ? name : u_profile->name);
699 }
700
701 /*! Bridge Profile Sounds functions */
702 static void bridge_profile_sounds_destroy_cb(void *obj)
703 {
704         struct bridge_profile_sounds *sounds = obj;
705         ast_string_field_free_memory(sounds);
706 }
707
708 static struct bridge_profile_sounds *bridge_profile_sounds_alloc(void)
709 {
710         struct bridge_profile_sounds *sounds = ao2_alloc(sizeof(*sounds), bridge_profile_sounds_destroy_cb);
711
712         if (!sounds) {
713                 return NULL;
714         }
715         if (ast_string_field_init(sounds, 512)) {
716                 ao2_ref(sounds, -1);
717                 return NULL;
718         }
719
720         return sounds;
721 }
722
723 static int set_sound(const char *sound_name, const char *sound_file, struct bridge_profile *b_profile)
724 {
725         struct bridge_profile_sounds *sounds = b_profile->sounds;
726         if (ast_strlen_zero(sound_file)) {
727                 return -1;
728         }
729
730         if (!strcasecmp(sound_name, "sound_only_person")) {
731                 ast_string_field_set(sounds, onlyperson, sound_file);
732         } else if (!strcasecmp(sound_name, "sound_only_one")) {
733                 ast_string_field_set(sounds, onlyone, sound_file);
734         } else if (!strcasecmp(sound_name, "sound_has_joined")) {
735                 ast_string_field_set(sounds, hasjoin, sound_file);
736         } else if (!strcasecmp(sound_name, "sound_has_left")) {
737                 ast_string_field_set(sounds, hasleft, sound_file);
738         } else if (!strcasecmp(sound_name, "sound_kicked")) {
739                 ast_string_field_set(sounds, kicked, sound_file);
740         } else if (!strcasecmp(sound_name, "sound_muted")) {
741                 ast_string_field_set(sounds, muted, sound_file);
742         } else if (!strcasecmp(sound_name, "sound_unmuted")) {
743                 ast_string_field_set(sounds, unmuted, sound_file);
744         } else if (!strcasecmp(sound_name, "sound_there_are")) {
745                 ast_string_field_set(sounds, thereare, sound_file);
746         } else if (!strcasecmp(sound_name, "sound_other_in_party")) {
747                 ast_string_field_set(sounds, otherinparty, sound_file);
748         } else if (!strcasecmp(sound_name, "sound_place_into_conference")) {
749                 ast_string_field_set(sounds, placeintoconf, sound_file);
750         } else if (!strcasecmp(sound_name, "sound_wait_for_leader")) {
751                 ast_string_field_set(sounds, waitforleader, sound_file);
752         } else if (!strcasecmp(sound_name, "sound_leader_has_left")) {
753                 ast_string_field_set(sounds, leaderhasleft, sound_file);
754         } else if (!strcasecmp(sound_name, "sound_get_pin")) {
755                 ast_string_field_set(sounds, getpin, sound_file);
756         } else if (!strcasecmp(sound_name, "sound_invalid_pin")) {
757                 ast_string_field_set(sounds, invalidpin, sound_file);
758         } else if (!strcasecmp(sound_name, "sound_locked")) {
759                 ast_string_field_set(sounds, locked, sound_file);
760         } else if (!strcasecmp(sound_name, "sound_unlocked_now")) {
761                 ast_string_field_set(sounds, unlockednow, sound_file);
762         } else if (!strcasecmp(sound_name, "sound_locked_now")) {
763                 ast_string_field_set(sounds, lockednow, sound_file);
764         } else if (!strcasecmp(sound_name, "sound_error_menu")) {
765                 ast_string_field_set(sounds, errormenu, sound_file);
766         } else if (!strcasecmp(sound_name, "sound_join")) {
767                 ast_string_field_set(sounds, join, sound_file);
768         } else if (!strcasecmp(sound_name, "sound_leave")) {
769                 ast_string_field_set(sounds, leave, sound_file);
770         } else if (!strcasecmp(sound_name, "sound_participants_muted")) {
771                 ast_string_field_set(sounds, participantsmuted, sound_file);
772         } else if (!strcasecmp(sound_name, "sound_participants_unmuted")) {
773                 ast_string_field_set(sounds, participantsunmuted, sound_file);
774         } else {
775                 return -1;
776         }
777
778         return 0;
779 }
780
781 /*! CONFBRIDGE dialplan function functions and channel datastore. */
782 struct func_confbridge_data {
783         struct bridge_profile b_profile;
784         struct user_profile u_profile;
785         unsigned int b_usable:1; /*!< Tells if bridge profile is usable or not */
786         unsigned int u_usable:1; /*!< Tells if user profile is usable or not */
787 };
788 static void func_confbridge_destroy_cb(void *data)
789 {
790         struct func_confbridge_data *b_data = data;
791         conf_bridge_profile_destroy(&b_data->b_profile);
792         ast_free(b_data);
793 };
794 static const struct ast_datastore_info confbridge_datastore = {
795         .type = "confbridge",
796         .destroy = func_confbridge_destroy_cb
797 };
798 int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
799 {
800         struct ast_datastore *datastore;
801         struct func_confbridge_data *b_data;
802         char *parse;
803         struct ast_variable tmpvar = { 0, };
804         AST_DECLARE_APP_ARGS(args,
805                 AST_APP_ARG(type);
806                 AST_APP_ARG(option);
807         );
808
809         /* parse all the required arguments and make sure they exist. */
810         if (ast_strlen_zero(data)) {
811                 return -1;
812         }
813         parse = ast_strdupa(data);
814         AST_STANDARD_APP_ARGS(args, parse);
815         if (ast_strlen_zero(args.type) || ast_strlen_zero(args.option)) {
816                 return -1;
817         }
818
819         ast_channel_lock(chan);
820         datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
821         if (!datastore) {
822                 datastore = ast_datastore_alloc(&confbridge_datastore, NULL);
823                 if (!datastore) {
824                         ast_channel_unlock(chan);
825                         return 0;
826                 }
827                 b_data = ast_calloc(1, sizeof(*b_data));
828                 if (!b_data) {
829                         ast_channel_unlock(chan);
830                         ast_datastore_free(datastore);
831                         return 0;
832                 }
833                 b_data->b_profile.sounds = bridge_profile_sounds_alloc();
834                 if (!b_data->b_profile.sounds) {
835                         ast_channel_unlock(chan);
836                         ast_datastore_free(datastore);
837                         ast_free(b_data);
838                         return 0;
839                 }
840                 datastore->data = b_data;
841                 ast_channel_datastore_add(chan, datastore);
842         } else {
843                 b_data = datastore->data;
844         }
845         ast_channel_unlock(chan);
846
847         /* SET(CONFBRIDGE(type,option)=value) */
848         if (!value) {
849                 value = "";
850         }
851         tmpvar.name = args.option;
852         tmpvar.value = value;
853         tmpvar.file = "CONFBRIDGE";
854         if (!strcasecmp(args.type, "bridge")) {
855                 if (!aco_process_var(&bridge_type, "dialplan", &tmpvar, &b_data->b_profile)) {
856                         b_data->b_usable = 1;
857                         return 0;
858                 }
859         } else if (!strcasecmp(args.type, "user")) {
860                 if (!aco_process_var(&user_type, "dialplan", &tmpvar, &b_data->u_profile)) {
861                         b_data->u_usable = 1;
862                         return 0;
863                 }
864         }
865
866         ast_log(LOG_WARNING, "%s(%s,%s) cannot be set to '%s'. Invalid type, option, or value.\n",
867                 cmd, args.type, args.option, value);
868         return -1;
869 }
870
871 static int add_action_to_menu_entry(struct conf_menu_entry *menu_entry, enum conf_menu_action_id id, char *databuf)
872 {
873         struct conf_menu_action *menu_action = ast_calloc(1, sizeof(*menu_action));
874
875         if (!menu_action) {
876                 return -1;
877         }
878         menu_action->id = id;
879
880         switch (id) {
881         case MENU_ACTION_NOOP:
882         case MENU_ACTION_TOGGLE_MUTE:
883         case MENU_ACTION_INCREASE_LISTENING:
884         case MENU_ACTION_DECREASE_LISTENING:
885         case MENU_ACTION_INCREASE_TALKING:
886         case MENU_ACTION_DECREASE_TALKING:
887         case MENU_ACTION_RESET_LISTENING:
888         case MENU_ACTION_RESET_TALKING:
889         case MENU_ACTION_ADMIN_TOGGLE_LOCK:
890         case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS:
891         case MENU_ACTION_PARTICIPANT_COUNT:
892         case MENU_ACTION_ADMIN_KICK_LAST:
893         case MENU_ACTION_LEAVE:
894         case MENU_ACTION_SET_SINGLE_VIDEO_SRC:
895         case MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC:
896                 break;
897         case MENU_ACTION_PLAYBACK:
898         case MENU_ACTION_PLAYBACK_AND_CONTINUE:
899                 if (!(ast_strlen_zero(databuf))) {
900                         ast_copy_string(menu_action->data.playback_file, databuf, sizeof(menu_action->data.playback_file));
901                 } else {
902                         ast_free(menu_action);
903                         return -1;
904                 }
905                 break;
906         case MENU_ACTION_DIALPLAN_EXEC:
907                 if (!(ast_strlen_zero(databuf))) {
908                         AST_DECLARE_APP_ARGS(args,
909                                 AST_APP_ARG(context);
910                                 AST_APP_ARG(exten);
911                                 AST_APP_ARG(priority);
912                         );
913                         AST_STANDARD_APP_ARGS(args, databuf);
914                         if (!ast_strlen_zero(args.context)) {
915                                 ast_copy_string(menu_action->data.dialplan_args.context,
916                                         args.context,
917                                         sizeof(menu_action->data.dialplan_args.context));
918                         }
919                         if (!ast_strlen_zero(args.exten)) {
920                                 ast_copy_string(menu_action->data.dialplan_args.exten,
921                                         args.exten,
922                                         sizeof(menu_action->data.dialplan_args.exten));
923                         }
924                         menu_action->data.dialplan_args.priority = 1; /* 1 by default */
925                         if (!ast_strlen_zero(args.priority) &&
926                                 (sscanf(args.priority, "%30u", &menu_action->data.dialplan_args.priority) != 1)) {
927                                 /* invalid priority */
928                                 ast_free(menu_action);
929                                 return -1;
930                         }
931                 } else {
932                         ast_free(menu_action);
933                         return -1;
934                 }
935         };
936
937         AST_LIST_INSERT_TAIL(&menu_entry->actions, menu_action, action);
938
939         return 0;
940 }
941
942 static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char *action_names)
943 {
944         struct conf_menu_entry *menu_entry = NULL, *cur = NULL;
945         int res = 0;
946         char *tmp_action_names = ast_strdupa(action_names);
947         char *action = NULL;
948         char *action_args;
949         char *tmp;
950         char buf[PATH_MAX];
951         char *delimiter = ",";
952
953         if (!(menu_entry = ast_calloc(1, sizeof(*menu_entry)))) {
954                 return -1;
955         }
956
957         for (;;) {
958                 char *comma;
959                 char *startbrace;
960                 char *endbrace;
961                 unsigned int action_len;
962
963                 if (ast_strlen_zero(tmp_action_names)) {
964                         break;
965                 }
966                 startbrace = strchr(tmp_action_names, '(');
967                 endbrace = strchr(tmp_action_names, ')');
968                 comma = strchr(tmp_action_names, ',');
969
970                 /* If the next action has brackets with comma delimited arguments in it,
971                  * make the delimeter ')' instead of a comma to preserve the argments */
972                 if (startbrace && endbrace && comma && (comma > startbrace && comma < endbrace)) {
973                         delimiter = ")";
974                 } else {
975                         delimiter = ",";
976                 }
977
978                 if (!(action = strsep(&tmp_action_names, delimiter))) {
979                         break;
980                 }
981
982                 action = ast_strip(action);
983                 if (ast_strlen_zero(action)) {
984                         continue;
985                 }
986
987                 action_len = strlen(action);
988                 ast_copy_string(menu_entry->dtmf, dtmf, sizeof(menu_entry->dtmf));
989                 if (!strcasecmp(action, "toggle_mute")) {
990                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_TOGGLE_MUTE, NULL);
991                 } else if (!strcasecmp(action, "no_op")) {
992                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_NOOP, NULL);
993                 } else if (!strcasecmp(action, "increase_listening_volume")) {
994                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_INCREASE_LISTENING, NULL);
995                 } else if (!strcasecmp(action, "decrease_listening_volume")) {
996                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_DECREASE_LISTENING, NULL);
997                 } else if (!strcasecmp(action, "increase_talking_volume")) {
998                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_INCREASE_TALKING, NULL);
999                 } else if (!strcasecmp(action, "reset_listening_volume")) {
1000                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_RESET_LISTENING, NULL);
1001                 } else if (!strcasecmp(action, "reset_talking_volume")) {
1002                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_RESET_TALKING, NULL);
1003                 } else if (!strcasecmp(action, "decrease_talking_volume")) {
1004                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_DECREASE_TALKING, NULL);
1005                 } else if (!strcasecmp(action, "admin_toggle_conference_lock")) {
1006                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_ADMIN_TOGGLE_LOCK, NULL);
1007                 } else if (!strcasecmp(action, "admin_toggle_mute_participants")) {
1008                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS, NULL);
1009                 } else if (!strcasecmp(action, "participant_count")) {
1010                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PARTICIPANT_COUNT, NULL);
1011                 } else if (!strcasecmp(action, "admin_kick_last")) {
1012                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_ADMIN_KICK_LAST, NULL);
1013                 } else if (!strcasecmp(action, "leave_conference")) {
1014                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_LEAVE, NULL);
1015                 } else if (!strcasecmp(action, "set_as_single_video_src")) {
1016                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_SET_SINGLE_VIDEO_SRC, NULL);
1017                 } else if (!strcasecmp(action, "release_as_single_video_src")) {
1018                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC, NULL);
1019                 } else if (!strncasecmp(action, "dialplan_exec(", 14)) {
1020                         ast_copy_string(buf, action, sizeof(buf));
1021                         action_args = buf;
1022                         if ((action_args = strchr(action, '('))) {
1023                                 action_args++;
1024                         }
1025                         /* it is possible that this argument may or may not
1026                          * have a closing brace at this point, it all depends on if
1027                          * comma delimited arguments were provided */
1028                         if ((tmp = strchr(action, ')'))) {
1029                                 *tmp = '\0';
1030                         }
1031                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_DIALPLAN_EXEC, action_args);
1032                 } else if (action_len >= 21 && !strncasecmp(action, "playback_and_continue(", 22)) {
1033                         ast_copy_string(buf, action, sizeof(buf));
1034                         action_args = buf;
1035                         if ((action_args = strchr(action, '(')) && (tmp = strrchr(action_args, ')'))) {
1036                                 *tmp = '\0';
1037                                 action_args++;
1038                         }
1039                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PLAYBACK_AND_CONTINUE, action_args);
1040                 } else if (action_len >= 8 && !strncasecmp(action, "playback(", 9)) {
1041                         ast_copy_string(buf, action, sizeof(buf));
1042                         action_args = buf;
1043                         if ((action_args = strchr(action, '(')) && (tmp = strrchr(action_args, ')'))) {
1044                                 *tmp = '\0';
1045                                 action_args++;
1046                         }
1047                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PLAYBACK, action_args);
1048                 }
1049         }
1050
1051         /* if adding any of the actions failed, bail */
1052         if (res) {
1053                 struct conf_menu_action *menu_action;
1054                 while ((menu_action = AST_LIST_REMOVE_HEAD(&menu_entry->actions, action))) {
1055                         ast_free(menu_action);
1056                 }
1057                 ast_free(menu_entry);
1058                 return -1;
1059         }
1060
1061         /* remove any list entry with an identical DTMF sequence for overrides */
1062         AST_LIST_TRAVERSE_SAFE_BEGIN(&menu->entries, cur, entry) {
1063                 if (!strcasecmp(cur->dtmf, menu_entry->dtmf)) {
1064                         AST_LIST_REMOVE_CURRENT(entry);
1065                         ast_free(cur);
1066                         break;
1067                 }
1068         }
1069         AST_LIST_TRAVERSE_SAFE_END;
1070
1071         AST_LIST_INSERT_TAIL(&menu->entries, menu_entry, entry);
1072
1073         return 0;
1074 }
1075
1076 static char *complete_user_profile_name(const char *line, const char *word, int pos, int state)
1077 {
1078         int which = 0;
1079         char *res = NULL;
1080         int wordlen = strlen(word);
1081         struct ao2_iterator i;
1082         struct user_profile *u_profile = NULL;
1083         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
1084
1085         if (!cfg) {
1086                 return NULL;
1087         }
1088
1089         i = ao2_iterator_init(cfg->user_profiles, 0);
1090         while ((u_profile = ao2_iterator_next(&i))) {
1091                 if (!strncasecmp(u_profile->name, word, wordlen) && ++which > state) {
1092                         res = ast_strdup(u_profile->name);
1093                         ao2_ref(u_profile, -1);
1094                         break;
1095                 }
1096                 ao2_ref(u_profile, -1);
1097         }
1098         ao2_iterator_destroy(&i);
1099
1100         return res;
1101 }
1102
1103 static char *handle_cli_confbridge_show_user_profiles(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1104 {
1105         struct ao2_iterator it;
1106         struct user_profile *u_profile;
1107         RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1108
1109         switch (cmd) {
1110         case CLI_INIT:
1111                 e->command = "confbridge show profile users";
1112                 e->usage =
1113                         "Usage confbridge show profile users\n";
1114                 return NULL;
1115         case CLI_GENERATE:
1116                 return NULL;
1117         }
1118
1119         if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1120                 return NULL;
1121         }
1122
1123         ast_cli(a->fd,"--------- User Profiles -----------\n");
1124         ao2_lock(cfg->user_profiles);
1125         it = ao2_iterator_init(cfg->user_profiles, 0);
1126         while ((u_profile = ao2_iterator_next(&it))) {
1127                 ast_cli(a->fd,"%s\n", u_profile->name);
1128                 ao2_ref(u_profile, -1);
1129         }
1130         ao2_iterator_destroy(&it);
1131         ao2_unlock(cfg->user_profiles);
1132
1133         return CLI_SUCCESS;
1134 }
1135 static char *handle_cli_confbridge_show_user_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1136 {
1137         struct user_profile u_profile;
1138
1139         switch (cmd) {
1140         case CLI_INIT:
1141                 e->command = "confbridge show profile user";
1142                 e->usage =
1143                         "Usage confbridge show profile user [<profile name>]\n";
1144                 return NULL;
1145         case CLI_GENERATE:
1146                 if (a->pos == 4) {
1147                         return complete_user_profile_name(a->line, a->word, a->pos, a->n);
1148                 }
1149                 return NULL;
1150         }
1151
1152         if (a->argc != 5) {
1153                 return CLI_SHOWUSAGE;
1154         }
1155
1156         if (!(conf_find_user_profile(NULL, a->argv[4], &u_profile))) {
1157                 ast_cli(a->fd, "No conference user profile named '%s' found!\n", a->argv[4]);
1158                 return CLI_SUCCESS;
1159         }
1160
1161         ast_cli(a->fd,"--------------------------------------------\n");
1162         ast_cli(a->fd,"Name:                    %s\n",
1163                 u_profile.name);
1164         ast_cli(a->fd,"Admin:                   %s\n",
1165                 u_profile.flags & USER_OPT_ADMIN ?
1166                 "true" : "false");
1167         ast_cli(a->fd,"Marked User:             %s\n",
1168                 u_profile.flags & USER_OPT_MARKEDUSER ?
1169                 "true" : "false");
1170         ast_cli(a->fd,"Start Muted:             %s\n",
1171                 u_profile.flags & USER_OPT_STARTMUTED?
1172                 "true" : "false");
1173         ast_cli(a->fd,"MOH When Empty:          %s\n",
1174                 u_profile.flags & USER_OPT_MUSICONHOLD ?
1175                 "enabled" : "disabled");
1176         ast_cli(a->fd,"MOH Class:               %s\n",
1177                 ast_strlen_zero(u_profile.moh_class) ?
1178                 "default" : u_profile.moh_class);
1179         ast_cli(a->fd,"Announcement:            %s\n",
1180                 u_profile.announcement);
1181         ast_cli(a->fd,"Quiet:                   %s\n",
1182                 u_profile.flags & USER_OPT_QUIET ?
1183                 "enabled" : "disabled");
1184         ast_cli(a->fd,"Wait Marked:             %s\n",
1185                 u_profile.flags & USER_OPT_WAITMARKED ?
1186                 "enabled" : "disabled");
1187         ast_cli(a->fd,"END Marked:              %s\n",
1188                 u_profile.flags & USER_OPT_ENDMARKED ?
1189                 "enabled" : "disabled");
1190         ast_cli(a->fd,"Drop_silence:            %s\n",
1191                 u_profile.flags & USER_OPT_DROP_SILENCE ?
1192                 "enabled" : "disabled");
1193         ast_cli(a->fd,"Silence Threshold:       %dms\n",
1194                 u_profile.silence_threshold);
1195         ast_cli(a->fd,"Talking Threshold:       %dms\n",
1196                 u_profile.talking_threshold);
1197         ast_cli(a->fd,"Denoise:                 %s\n",
1198                 u_profile.flags & USER_OPT_DENOISE ?
1199                 "enabled" : "disabled");
1200         ast_cli(a->fd,"Jitterbuffer:            %s\n",
1201                 u_profile.flags & USER_OPT_JITTERBUFFER ?
1202                 "enabled" : "disabled");
1203         ast_cli(a->fd,"Talk Detect Events:      %s\n",
1204                 u_profile.flags & USER_OPT_TALKER_DETECT ?
1205                 "enabled" : "disabled");
1206         ast_cli(a->fd,"DTMF Pass Through:       %s\n",
1207                 u_profile.flags & USER_OPT_DTMF_PASS ?
1208                 "enabled" : "disabled");
1209         ast_cli(a->fd,"PIN:                     %s\n",
1210                 ast_strlen_zero(u_profile.pin) ?
1211                 "None" : u_profile.pin);
1212         ast_cli(a->fd,"Announce User Count:     %s\n",
1213                 u_profile.flags & USER_OPT_ANNOUNCEUSERCOUNT ?
1214                 "enabled" : "disabled");
1215         ast_cli(a->fd,"Announce join/leave:     %s\n",
1216                 u_profile.flags & USER_OPT_ANNOUNCE_JOIN_LEAVE ?
1217                 "enabled" : "disabled");
1218         ast_cli(a->fd,"Announce User Count all: %s\n",
1219                 u_profile.flags & USER_OPT_ANNOUNCEUSERCOUNTALL ?
1220                 "enabled" : "disabled");
1221                 ast_cli(a->fd,"\n");
1222
1223         return CLI_SUCCESS;
1224 }
1225
1226 static char *complete_bridge_profile_name(const char *line, const char *word, int pos, int state)
1227 {
1228         int which = 0;
1229         char *res = NULL;
1230         int wordlen = strlen(word);
1231         struct ao2_iterator i;
1232         struct bridge_profile *b_profile = NULL;
1233         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
1234
1235         if (!cfg) {
1236                 return NULL;
1237         }
1238
1239         i = ao2_iterator_init(cfg->bridge_profiles, 0);
1240         while ((b_profile = ao2_iterator_next(&i))) {
1241                 if (!strncasecmp(b_profile->name, word, wordlen) && ++which > state) {
1242                         res = ast_strdup(b_profile->name);
1243                         ao2_ref(b_profile, -1);
1244                         break;
1245                 }
1246                 ao2_ref(b_profile, -1);
1247         }
1248         ao2_iterator_destroy(&i);
1249
1250         return res;
1251 }
1252
1253 static char *handle_cli_confbridge_show_bridge_profiles(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1254 {
1255         struct ao2_iterator it;
1256         struct bridge_profile *b_profile;
1257         RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1258
1259         switch (cmd) {
1260         case CLI_INIT:
1261                 e->command = "confbridge show profile bridges";
1262                 e->usage =
1263                         "Usage confbridge show profile bridges\n";
1264                 return NULL;
1265         case CLI_GENERATE:
1266                 return NULL;
1267         }
1268
1269         if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1270                 return NULL;
1271         }
1272
1273         ast_cli(a->fd,"--------- Bridge Profiles -----------\n");
1274         ao2_lock(cfg->bridge_profiles);
1275         it = ao2_iterator_init(cfg->bridge_profiles, 0);
1276         while ((b_profile = ao2_iterator_next(&it))) {
1277                 ast_cli(a->fd,"%s\n", b_profile->name);
1278                 ao2_ref(b_profile, -1);
1279         }
1280         ao2_iterator_destroy(&it);
1281         ao2_unlock(cfg->bridge_profiles);
1282
1283         return CLI_SUCCESS;
1284 }
1285
1286 static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1287 {
1288         struct bridge_profile b_profile;
1289         char tmp[64];
1290
1291         switch (cmd) {
1292         case CLI_INIT:
1293                 e->command = "confbridge show profile bridge";
1294                 e->usage =
1295                         "Usage confbridge show profile bridge <profile name>\n";
1296                 return NULL;
1297         case CLI_GENERATE:
1298                 if (a->pos == 4) {
1299                         return complete_bridge_profile_name(a->line, a->word, a->pos, a->n);
1300                 }
1301                 return NULL;
1302         }
1303
1304         if (a->argc != 5) {
1305                 return CLI_SHOWUSAGE;
1306         }
1307
1308         if (!(conf_find_bridge_profile(NULL, a->argv[4], &b_profile))) {
1309                 ast_cli(a->fd, "No conference bridge profile named '%s' found!\n", a->argv[4]);
1310                 return CLI_SUCCESS;
1311         }
1312
1313         ast_cli(a->fd,"--------------------------------------------\n");
1314         ast_cli(a->fd,"Name:                 %s\n", b_profile.name);
1315
1316         if (b_profile.internal_sample_rate) {
1317                 snprintf(tmp, sizeof(tmp), "%d", b_profile.internal_sample_rate);
1318         } else {
1319                 ast_copy_string(tmp, "auto", sizeof(tmp));
1320         }
1321         ast_cli(a->fd,"Internal Sample Rate: %s\n", tmp);
1322
1323         if (b_profile.mix_interval) {
1324                 ast_cli(a->fd,"Mixing Interval:      %d\n", b_profile.mix_interval);
1325         } else {
1326                 ast_cli(a->fd,"Mixing Interval:      Default 20ms\n");
1327         }
1328
1329         ast_cli(a->fd,"Record Conference:    %s\n",
1330                 b_profile.flags & BRIDGE_OPT_RECORD_CONFERENCE ?
1331                 "yes" : "no");
1332
1333         ast_cli(a->fd,"Record File Append:    %s\n",
1334                 b_profile.flags & BRIDGE_OPT_RECORD_FILE_APPEND ?
1335                 "yes" : "no");
1336
1337         ast_cli(a->fd,"Record File:          %s\n",
1338                 ast_strlen_zero(b_profile.rec_file) ? "Auto Generated" :
1339                 b_profile.rec_file);
1340
1341         if (b_profile.max_members) {
1342                 ast_cli(a->fd,"Max Members:          %d\n", b_profile.max_members);
1343         } else {
1344                 ast_cli(a->fd,"Max Members:          No Limit\n");
1345         }
1346
1347         switch (b_profile.flags
1348                 & (BRIDGE_OPT_VIDEO_SRC_LAST_MARKED | BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED
1349                         | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
1350         case BRIDGE_OPT_VIDEO_SRC_LAST_MARKED:
1351                 ast_cli(a->fd, "Video Mode:           last_marked\n");
1352                 break;
1353         case BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED:
1354                 ast_cli(a->fd, "Video Mode:           first_marked\n");
1355                 break;
1356         case BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER:
1357                 ast_cli(a->fd, "Video Mode:           follow_talker\n");
1358                 break;
1359         case 0:
1360                 ast_cli(a->fd, "Video Mode:           no video\n");
1361                 break;
1362         default:
1363                 /* Opps.  We have more than one video mode flag set. */
1364                 ast_assert(0);
1365                 break;
1366         }
1367
1368         ast_cli(a->fd,"sound_only_person:    %s\n", conf_get_sound(CONF_SOUND_ONLY_PERSON, b_profile.sounds));
1369         ast_cli(a->fd,"sound_only_one:       %s\n", conf_get_sound(CONF_SOUND_ONLY_ONE, b_profile.sounds));
1370         ast_cli(a->fd,"sound_has_joined:     %s\n", conf_get_sound(CONF_SOUND_HAS_JOINED, b_profile.sounds));
1371         ast_cli(a->fd,"sound_has_left:       %s\n", conf_get_sound(CONF_SOUND_HAS_LEFT, b_profile.sounds));
1372         ast_cli(a->fd,"sound_kicked:         %s\n", conf_get_sound(CONF_SOUND_KICKED, b_profile.sounds));
1373         ast_cli(a->fd,"sound_muted:          %s\n", conf_get_sound(CONF_SOUND_MUTED, b_profile.sounds));
1374         ast_cli(a->fd,"sound_unmuted:        %s\n", conf_get_sound(CONF_SOUND_UNMUTED, b_profile.sounds));
1375         ast_cli(a->fd,"sound_there_are:      %s\n", conf_get_sound(CONF_SOUND_THERE_ARE, b_profile.sounds));
1376         ast_cli(a->fd,"sound_other_in_party: %s\n", conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, b_profile.sounds));
1377         ast_cli(a->fd,"sound_place_into_conference: %s\n", conf_get_sound(CONF_SOUND_PLACE_IN_CONF, b_profile.sounds));
1378         ast_cli(a->fd,"sound_wait_for_leader:       %s\n", conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, b_profile.sounds));
1379         ast_cli(a->fd,"sound_leader_has_left:       %s\n", conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, b_profile.sounds));
1380         ast_cli(a->fd,"sound_get_pin:        %s\n", conf_get_sound(CONF_SOUND_GET_PIN, b_profile.sounds));
1381         ast_cli(a->fd,"sound_invalid_pin:    %s\n", conf_get_sound(CONF_SOUND_INVALID_PIN, b_profile.sounds));
1382         ast_cli(a->fd,"sound_locked:         %s\n", conf_get_sound(CONF_SOUND_LOCKED, b_profile.sounds));
1383         ast_cli(a->fd,"sound_unlocked_now:   %s\n", conf_get_sound(CONF_SOUND_UNLOCKED_NOW, b_profile.sounds));
1384         ast_cli(a->fd,"sound_lockednow:      %s\n", conf_get_sound(CONF_SOUND_LOCKED_NOW, b_profile.sounds));
1385         ast_cli(a->fd,"sound_error_menu:     %s\n", conf_get_sound(CONF_SOUND_ERROR_MENU, b_profile.sounds));
1386         ast_cli(a->fd,"sound_join:           %s\n", conf_get_sound(CONF_SOUND_JOIN, b_profile.sounds));
1387         ast_cli(a->fd,"sound_leave:          %s\n", conf_get_sound(CONF_SOUND_LEAVE, b_profile.sounds));
1388         ast_cli(a->fd,"sound_participants_muted:     %s\n", conf_get_sound(CONF_SOUND_PARTICIPANTS_MUTED, b_profile.sounds));
1389         ast_cli(a->fd,"sound_participants_unmuted:     %s\n", conf_get_sound(CONF_SOUND_PARTICIPANTS_UNMUTED, b_profile.sounds));
1390         ast_cli(a->fd,"\n");
1391
1392         conf_bridge_profile_destroy(&b_profile);
1393         return CLI_SUCCESS;
1394 }
1395
1396 static char *complete_menu_name(const char *line, const char *word, int pos, int state)
1397 {
1398         int which = 0;
1399         char *res = NULL;
1400         int wordlen = strlen(word);
1401         struct ao2_iterator i;
1402         struct conf_menu *menu = NULL;
1403         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
1404
1405         if (!cfg) {
1406                 return NULL;
1407         }
1408
1409         i = ao2_iterator_init(cfg->menus, 0);
1410         while ((menu = ao2_iterator_next(&i))) {
1411                 if (!strncasecmp(menu->name, word, wordlen) && ++which > state) {
1412                         res = ast_strdup(menu->name);
1413                         ao2_ref(menu, -1);
1414                         break;
1415                 }
1416                 ao2_ref(menu, -1);
1417         }
1418         ao2_iterator_destroy(&i);
1419
1420         return res;
1421 }
1422
1423 static char *handle_cli_confbridge_show_menus(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1424 {
1425         struct ao2_iterator it;
1426         struct conf_menu *menu;
1427         RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1428
1429         switch (cmd) {
1430         case CLI_INIT:
1431                 e->command = "confbridge show menus";
1432                 e->usage =
1433                         "Usage confbridge show profile menus\n";
1434                 return NULL;
1435         case CLI_GENERATE:
1436                 return NULL;
1437         }
1438
1439         if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1440                 return NULL;
1441         }
1442
1443         ast_cli(a->fd,"--------- Menus -----------\n");
1444         ao2_lock(cfg->menus);
1445         it = ao2_iterator_init(cfg->menus, 0);
1446         while ((menu = ao2_iterator_next(&it))) {
1447                 ast_cli(a->fd,"%s\n", menu->name);
1448                 ao2_ref(menu, -1);
1449         }
1450         ao2_iterator_destroy(&it);
1451         ao2_unlock(cfg->menus);
1452
1453         return CLI_SUCCESS;
1454 }
1455
1456 static char *handle_cli_confbridge_show_menu(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1457 {
1458         RAII_VAR(struct conf_menu *, menu, NULL, ao2_cleanup);
1459         RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1460         struct conf_menu_entry *menu_entry = NULL;
1461         struct conf_menu_action *menu_action = NULL;
1462
1463         switch (cmd) {
1464         case CLI_INIT:
1465                 e->command = "confbridge show menu";
1466                 e->usage =
1467                         "Usage confbridge show menu [<menu name>]\n";
1468                 return NULL;
1469         case CLI_GENERATE:
1470                 if (a->pos == 3) {
1471                         return complete_menu_name(a->line, a->word, a->pos, a->n);
1472                 }
1473                 return NULL;
1474         }
1475
1476         if (a->argc != 4) {
1477                 return CLI_SHOWUSAGE;
1478         }
1479
1480         if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1481                 return NULL;
1482         }
1483
1484         if (!(menu = menu_find(cfg->menus, a->argv[3]))) {
1485                 ast_cli(a->fd, "No conference menu named '%s' found!\n", a->argv[3]);
1486                 return CLI_SUCCESS;
1487         }
1488         ao2_lock(menu);
1489
1490         ast_cli(a->fd,"Name: %s\n", menu->name);
1491         AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
1492                 int action_num = 0;
1493                 ast_cli(a->fd, "%s=", menu_entry->dtmf);
1494                 AST_LIST_TRAVERSE(&menu_entry->actions, menu_action, action) {
1495                         if (action_num) {
1496                                 ast_cli(a->fd, ", ");
1497                         }
1498                         switch (menu_action->id) {
1499                         case MENU_ACTION_TOGGLE_MUTE:
1500                                 ast_cli(a->fd, "toggle_mute");
1501                                 break;
1502                         case MENU_ACTION_NOOP:
1503                                 ast_cli(a->fd, "no_op");
1504                                 break;
1505                         case MENU_ACTION_INCREASE_LISTENING:
1506                                 ast_cli(a->fd, "increase_listening_volume");
1507                                 break;
1508                         case MENU_ACTION_DECREASE_LISTENING:
1509                                 ast_cli(a->fd, "decrease_listening_volume");
1510                                 break;
1511                         case MENU_ACTION_RESET_LISTENING:
1512                                 ast_cli(a->fd, "reset_listening_volume");
1513                                 break;
1514                         case MENU_ACTION_RESET_TALKING:
1515                                 ast_cli(a->fd, "reset_talking_volume");
1516                                 break;
1517                         case MENU_ACTION_INCREASE_TALKING:
1518                                 ast_cli(a->fd, "increase_talking_volume");
1519                                 break;
1520                         case MENU_ACTION_DECREASE_TALKING:
1521                                 ast_cli(a->fd, "decrease_talking_volume");
1522                                 break;
1523                         case MENU_ACTION_PLAYBACK:
1524                                 ast_cli(a->fd, "playback(%s)", menu_action->data.playback_file);
1525                                 break;
1526                         case MENU_ACTION_PLAYBACK_AND_CONTINUE:
1527                                 ast_cli(a->fd, "playback_and_continue(%s)", menu_action->data.playback_file);
1528                                 break;
1529                         case MENU_ACTION_DIALPLAN_EXEC:
1530                                 ast_cli(a->fd, "dialplan_exec(%s,%s,%d)",
1531                                         menu_action->data.dialplan_args.context,
1532                                         menu_action->data.dialplan_args.exten,
1533                                         menu_action->data.dialplan_args.priority);
1534                                 break;
1535                         case MENU_ACTION_ADMIN_TOGGLE_LOCK:
1536                                 ast_cli(a->fd, "admin_toggle_conference_lock");
1537                                 break;
1538                         case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS:
1539                                 ast_cli(a->fd, "admin_toggle_mute_participants");
1540                                 break;
1541                         case MENU_ACTION_PARTICIPANT_COUNT:
1542                                 ast_cli(a->fd, "participant_count");
1543                                 break;
1544                         case MENU_ACTION_ADMIN_KICK_LAST:
1545                                 ast_cli(a->fd, "admin_kick_last");
1546                                 break;
1547                         case MENU_ACTION_LEAVE:
1548                                 ast_cli(a->fd, "leave_conference");
1549                                 break;
1550                         case MENU_ACTION_SET_SINGLE_VIDEO_SRC:
1551                                 ast_cli(a->fd, "set_as_single_video_src");
1552                                 break;
1553                         case MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC:
1554                                 ast_cli(a->fd, "release_as_single_video_src");
1555                                 break;
1556                         }
1557                         action_num++;
1558                 }
1559                 ast_cli(a->fd,"\n");
1560         }
1561
1562
1563         ao2_unlock(menu);
1564         return CLI_SUCCESS;
1565 }
1566
1567 static struct ast_cli_entry cli_confbridge_parser[] = {
1568         AST_CLI_DEFINE(handle_cli_confbridge_show_user_profile, "Show a conference user profile."),
1569         AST_CLI_DEFINE(handle_cli_confbridge_show_bridge_profile, "Show a conference bridge profile."),
1570         AST_CLI_DEFINE(handle_cli_confbridge_show_menu, "Show a conference menu"),
1571         AST_CLI_DEFINE(handle_cli_confbridge_show_user_profiles, "Show a list of conference user profiles."),
1572         AST_CLI_DEFINE(handle_cli_confbridge_show_bridge_profiles, "Show a list of conference bridge profiles."),
1573         AST_CLI_DEFINE(handle_cli_confbridge_show_menus, "Show a list of conference menus"),
1574
1575 };
1576
1577 static void confbridge_cfg_destructor(void *obj)
1578 {
1579         struct confbridge_cfg *cfg = obj;
1580         ao2_cleanup(cfg->user_profiles);
1581         ao2_cleanup(cfg->bridge_profiles);
1582         ao2_cleanup(cfg->menus);
1583 }
1584
1585 void *confbridge_cfg_alloc(void)
1586 {
1587         struct confbridge_cfg *cfg;
1588
1589         if (!(cfg = ao2_alloc(sizeof(*cfg), confbridge_cfg_destructor))) {
1590                 return NULL;
1591         }
1592
1593         if (!(cfg->user_profiles = ao2_container_alloc(283, user_hash_cb, user_cmp_cb))) {
1594                 goto error;
1595         }
1596
1597         if (!(cfg->bridge_profiles = ao2_container_alloc(283, bridge_hash_cb, bridge_cmp_cb))) {
1598                 goto error;
1599         }
1600
1601         if (!(cfg->menus = ao2_container_alloc(283, menu_hash_cb, menu_cmp_cb))) {
1602                 goto error;
1603         }
1604
1605         return cfg;
1606 error:
1607         ao2_ref(cfg, -1);
1608         return NULL;
1609 }
1610
1611 static int announce_user_count_all_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1612 {
1613         struct user_profile *u_profile = obj;
1614
1615         if (strcasecmp(var->name, "announce_user_count_all")) {
1616                 return -1;
1617         }
1618         if (ast_true(var->value)) {
1619                 u_profile->flags = u_profile->flags | USER_OPT_ANNOUNCEUSERCOUNTALL;
1620         } else if (ast_false(var->value)) {
1621                 u_profile->flags = u_profile->flags & ~USER_OPT_ANNOUNCEUSERCOUNTALL;
1622         } else if (sscanf(var->value, "%30u", &u_profile->announce_user_count_all_after) == 1) {
1623                 u_profile->flags = u_profile->flags | USER_OPT_ANNOUNCEUSERCOUNTALL;
1624         } else {
1625                 return -1;
1626         }
1627         return 0;
1628 }
1629
1630 static int mix_interval_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1631 {
1632         struct bridge_profile *b_profile = obj;
1633
1634         if (strcasecmp(var->name, "mixing_interval")) {
1635                 return -1;
1636         }
1637         if (sscanf(var->value, "%30u", &b_profile->mix_interval) != 1) {
1638                 return -1;
1639         }
1640         switch (b_profile->mix_interval) {
1641         case 10:
1642         case 20:
1643         case 40:
1644         case 80:
1645                 return 0;
1646         default:
1647                 return -1;
1648         }
1649 }
1650
1651 static int video_mode_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1652 {
1653         struct bridge_profile *b_profile = obj;
1654
1655         if (strcasecmp(var->name, "video_mode")) {
1656                 return -1;
1657         }
1658         if (!strcasecmp(var->value, "first_marked")) {
1659                 ast_set_flags_to(b_profile,
1660                         BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED
1661                                 | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED
1662                                 | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER,
1663                         BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED);
1664         } else if (!strcasecmp(var->value, "last_marked")) {
1665                 ast_set_flags_to(b_profile,
1666                         BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED
1667                                 | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED
1668                                 | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER,
1669                         BRIDGE_OPT_VIDEO_SRC_LAST_MARKED);
1670         } else if (!strcasecmp(var->value, "follow_talker")) {
1671                 ast_set_flags_to(b_profile,
1672                         BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED
1673                                 | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED
1674                                 | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER,
1675                         BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER);
1676         } else if (!strcasecmp(var->value, "none")) {
1677                 ast_clear_flag(b_profile,
1678                         BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED
1679                                 | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED
1680                                 | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER);
1681         } else {
1682                 return -1;
1683         }
1684         return 0;
1685 }
1686
1687 static int user_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1688 {
1689         struct user_profile *u_profile = obj;
1690
1691         return conf_find_user_profile(NULL, var->value, u_profile) ? 0 : -1;
1692 }
1693
1694 static int bridge_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1695 {
1696         struct bridge_profile *b_profile = obj;
1697         struct bridge_profile_sounds *sounds = bridge_profile_sounds_alloc();
1698         struct bridge_profile_sounds *oldsounds = b_profile->sounds;
1699
1700         if (!sounds) {
1701                 return -1;
1702         }
1703         if (!(conf_find_bridge_profile(NULL, var->value, b_profile))) {
1704                 ao2_ref(sounds, -1);
1705                 return -1;
1706         }
1707         /* Using a bridge profile as a template is a little complicated due to the sounds. Since the sounds
1708          * structure of a dynamic profile will need to be altered, a completely new sounds structure must be
1709          * created instead of simply holding a reference to the one built by the config file. */
1710         ast_string_field_set(sounds, onlyperson, b_profile->sounds->onlyperson);
1711         ast_string_field_set(sounds, onlyone, b_profile->sounds->onlyone);
1712         ast_string_field_set(sounds, hasjoin, b_profile->sounds->hasjoin);
1713         ast_string_field_set(sounds, hasleft, b_profile->sounds->hasleft);
1714         ast_string_field_set(sounds, kicked, b_profile->sounds->kicked);
1715         ast_string_field_set(sounds, muted, b_profile->sounds->muted);
1716         ast_string_field_set(sounds, unmuted, b_profile->sounds->unmuted);
1717         ast_string_field_set(sounds, thereare, b_profile->sounds->thereare);
1718         ast_string_field_set(sounds, otherinparty, b_profile->sounds->otherinparty);
1719         ast_string_field_set(sounds, placeintoconf, b_profile->sounds->placeintoconf);
1720         ast_string_field_set(sounds, waitforleader, b_profile->sounds->waitforleader);
1721         ast_string_field_set(sounds, leaderhasleft, b_profile->sounds->leaderhasleft);
1722         ast_string_field_set(sounds, getpin, b_profile->sounds->getpin);
1723         ast_string_field_set(sounds, invalidpin, b_profile->sounds->invalidpin);
1724         ast_string_field_set(sounds, locked, b_profile->sounds->locked);
1725         ast_string_field_set(sounds, unlockednow, b_profile->sounds->unlockednow);
1726         ast_string_field_set(sounds, lockednow, b_profile->sounds->lockednow);
1727         ast_string_field_set(sounds, errormenu, b_profile->sounds->errormenu);
1728         ast_string_field_set(sounds, join, b_profile->sounds->join);
1729         ast_string_field_set(sounds, leave, b_profile->sounds->leave);
1730         ast_string_field_set(sounds, participantsmuted, b_profile->sounds->participantsmuted);
1731         ast_string_field_set(sounds, participantsunmuted, b_profile->sounds->participantsunmuted);
1732
1733         ao2_ref(b_profile->sounds, -1); /* sounds struct copied over to it from the template by reference only. */
1734         ao2_ref(oldsounds, -1);    /* original sounds struct we don't need anymore */
1735         b_profile->sounds = sounds;     /* the new sounds struct that is a deep copy of the one from the template. */
1736
1737         return 0;
1738 }
1739
1740 static int sound_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1741 {
1742         set_sound(var->name, var->value, obj);
1743         return 0;
1744 }
1745
1746 static int menu_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1747 {
1748         add_menu_entry(obj, var->name, var->value);
1749         return 0;
1750 }
1751
1752 int conf_load_config(int reload)
1753 {
1754         if (!reload) {
1755                 if (aco_info_init(&cfg_info)) {
1756                         return -1;
1757                 }
1758         }
1759
1760         /* User options */
1761         aco_option_register(&cfg_info, "type", ACO_EXACT, user_types, NULL, OPT_NOOP_T, 0, 0);
1762         aco_option_register(&cfg_info, "admin", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ADMIN);
1763         aco_option_register(&cfg_info, "marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_MARKEDUSER);
1764         aco_option_register(&cfg_info, "startmuted", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_STARTMUTED);
1765         aco_option_register(&cfg_info, "music_on_hold_when_empty", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_MUSICONHOLD);
1766         aco_option_register(&cfg_info, "quiet", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_QUIET);
1767         aco_option_register_custom(&cfg_info, "announce_user_count_all", ACO_EXACT, user_types, "no", announce_user_count_all_handler, 0);
1768         aco_option_register(&cfg_info, "announce_user_count", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ANNOUNCEUSERCOUNT);
1769         /* Negative logic. Defaults to "yes" and evaluates with ast_false(). If !ast_false(), USER_OPT_NOONLYPERSON is cleared */
1770         aco_option_register(&cfg_info, "announce_only_user", ACO_EXACT, user_types, "yes", OPT_BOOLFLAG_T, 0, FLDSET(struct user_profile, flags), USER_OPT_NOONLYPERSON);
1771         aco_option_register(&cfg_info, "wait_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_WAITMARKED);
1772         aco_option_register(&cfg_info, "end_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ENDMARKED);
1773         aco_option_register(&cfg_info, "talk_detection_events", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_TALKER_DETECT);
1774         aco_option_register(&cfg_info, "dtmf_passthrough", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_DTMF_PASS);
1775         aco_option_register(&cfg_info, "announce_join_leave", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ANNOUNCE_JOIN_LEAVE);
1776         aco_option_register(&cfg_info, "pin", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, pin));
1777         aco_option_register(&cfg_info, "music_on_hold_class", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, moh_class));
1778         aco_option_register(&cfg_info, "announcement", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, announcement));
1779         aco_option_register(&cfg_info, "denoise", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_DENOISE);
1780         aco_option_register(&cfg_info, "dsp_drop_silence", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_DROP_SILENCE);
1781         aco_option_register(&cfg_info, "dsp_silence_threshold", ACO_EXACT, user_types, __stringify(DEFAULT_SILENCE_THRESHOLD), OPT_UINT_T, 0, FLDSET(struct user_profile, silence_threshold));
1782         aco_option_register(&cfg_info, "dsp_talking_threshold", ACO_EXACT, user_types, __stringify(DEFAULT_TALKING_THRESHOLD), OPT_UINT_T, 0, FLDSET(struct user_profile, silence_threshold));
1783         aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_JITTERBUFFER);
1784         /* This option should only be used with the CONFBRIDGE dialplan function */
1785         aco_option_register_custom(&cfg_info, "template", ACO_EXACT, user_types, NULL, user_template_handler, 0);
1786
1787         /* Bridge options */
1788         aco_option_register(&cfg_info, "type", ACO_EXACT, bridge_types, NULL, OPT_NOOP_T, 0, 0);
1789         aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), USER_OPT_JITTERBUFFER);
1790         /* "auto" will fail to parse as a uint, but we use PARSE_DEFAULT to set the value to 0 in that case, which is the value that auto resolves to */
1791         aco_option_register(&cfg_info, "internal_sample_rate", ACO_EXACT, bridge_types, "0", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct bridge_profile, internal_sample_rate), 0);
1792         aco_option_register_custom(&cfg_info, "mixing_interval", ACO_EXACT, bridge_types, "20", mix_interval_handler, 0);
1793         aco_option_register(&cfg_info, "record_conference", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_RECORD_CONFERENCE);
1794         aco_option_register_custom(&cfg_info, "video_mode", ACO_EXACT, bridge_types, NULL, video_mode_handler, 0);
1795         aco_option_register(&cfg_info, "record_file_append", ACO_EXACT, bridge_types, "yes", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_RECORD_FILE_APPEND);
1796         aco_option_register(&cfg_info, "max_members", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, max_members));
1797         aco_option_register(&cfg_info, "record_file", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_file));
1798         aco_option_register_custom(&cfg_info, "^sound_", ACO_REGEX, bridge_types, NULL, sound_option_handler, 0);
1799         /* This option should only be used with the CONFBRIDGE dialplan function */
1800         aco_option_register_custom(&cfg_info, "template", ACO_EXACT, bridge_types, NULL, bridge_template_handler, 0);
1801
1802         /* Menu options */
1803         aco_option_register(&cfg_info, "type", ACO_EXACT, menu_types, NULL, OPT_NOOP_T, 0, 0);
1804         aco_option_register_custom(&cfg_info, "^[0-9A-D*#]+$", ACO_REGEX, menu_types, NULL, menu_option_handler, 0);
1805
1806         if (aco_process_config(&cfg_info, reload) == ACO_PROCESS_ERROR) {
1807                 goto error;
1808         }
1809
1810         if (!reload && ast_cli_register_multiple(cli_confbridge_parser, ARRAY_LEN(cli_confbridge_parser))) {
1811                 goto error;
1812         }
1813
1814         return 0;
1815 error:
1816         /* On a reload, just keep the config we already have in place. */
1817         if (!reload) {
1818                 conf_destroy_config();
1819         }
1820         return -1;
1821 }
1822
1823 static void conf_user_profile_copy(struct user_profile *dst, struct user_profile *src)
1824 {
1825         *dst = *src;
1826 }
1827
1828 const struct user_profile *conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result)
1829 {
1830         struct user_profile *tmp2;
1831         struct ast_datastore *datastore = NULL;
1832         struct func_confbridge_data *b_data = NULL;
1833         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
1834
1835         if (!cfg) {
1836                 return NULL;
1837         }
1838
1839         if (chan) {
1840                 ast_channel_lock(chan);
1841                 datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
1842                 ast_channel_unlock(chan);
1843                 if (datastore) {
1844                         b_data = datastore->data;
1845                         if (b_data->u_usable) {
1846                                 conf_user_profile_copy(result, &b_data->u_profile);
1847                                 return result;
1848                         }
1849                 }
1850         }
1851
1852         if (ast_strlen_zero(user_profile_name)) {
1853                 user_profile_name = DEFAULT_USER_PROFILE;
1854         }
1855         if (!(tmp2 = ao2_find(cfg->user_profiles, user_profile_name, OBJ_KEY))) {
1856                 return NULL;
1857         }
1858         ao2_lock(tmp2);
1859         conf_user_profile_copy(result, tmp2);
1860         ao2_unlock(tmp2);
1861         ao2_ref(tmp2, -1);
1862
1863         return result;
1864 }
1865
1866 void conf_bridge_profile_copy(struct bridge_profile *dst, struct bridge_profile *src)
1867 {
1868         *dst = *src;
1869         if (src->sounds) {
1870                 ao2_ref(src->sounds, +1);
1871         }
1872 }
1873
1874 void conf_bridge_profile_destroy(struct bridge_profile *b_profile)
1875 {
1876         if (b_profile->sounds) {
1877                 ao2_ref(b_profile->sounds, -1);
1878                 b_profile->sounds = NULL;
1879         }
1880 }
1881
1882 const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan, const char *bridge_profile_name, struct bridge_profile *result)
1883 {
1884         struct bridge_profile *tmp2;
1885         struct ast_datastore *datastore = NULL;
1886         struct func_confbridge_data *b_data = NULL;
1887         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
1888
1889         if (!cfg) {
1890                 return NULL;
1891         }
1892
1893         if (chan) {
1894                 ast_channel_lock(chan);
1895                 datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
1896                 ast_channel_unlock(chan);
1897                 if (datastore) {
1898                         b_data = datastore->data;
1899                         if (b_data->b_usable) {
1900                                 conf_bridge_profile_copy(result, &b_data->b_profile);
1901                                 return result;
1902                         }
1903                 }
1904         }
1905         if (ast_strlen_zero(bridge_profile_name)) {
1906                 bridge_profile_name = DEFAULT_BRIDGE_PROFILE;
1907         }
1908         if (!(tmp2 = ao2_find(cfg->bridge_profiles, bridge_profile_name, OBJ_KEY))) {
1909                 return NULL;
1910         }
1911         ao2_lock(tmp2);
1912         conf_bridge_profile_copy(result, tmp2);
1913         ao2_unlock(tmp2);
1914         ao2_ref(tmp2, -1);
1915
1916         return result;
1917 }
1918
1919 struct dtmf_menu_hook_pvt {
1920         struct conference_bridge_user *conference_bridge_user;
1921         struct conf_menu_entry menu_entry;
1922         struct conf_menu *menu;
1923 };
1924
1925 static void menu_hook_destroy(void *hook_pvt)
1926 {
1927         struct dtmf_menu_hook_pvt *pvt = hook_pvt;
1928         struct conf_menu_action *action = NULL;
1929
1930         ao2_ref(pvt->menu, -1);
1931
1932         while ((action = AST_LIST_REMOVE_HEAD(&pvt->menu_entry.actions, action))) {
1933                 ast_free(action);
1934         }
1935         ast_free(pvt);
1936 }
1937
1938 static int menu_hook_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
1939 {
1940         struct dtmf_menu_hook_pvt *pvt = hook_pvt;
1941         return conf_handle_dtmf(bridge_channel, pvt->conference_bridge_user, &pvt->menu_entry, pvt->menu);
1942 }
1943
1944 static int copy_menu_entry(struct conf_menu_entry *dst, struct conf_menu_entry *src)
1945 {
1946         struct conf_menu_action *menu_action = NULL;
1947         struct conf_menu_action *new_menu_action = NULL;
1948
1949         memcpy(dst, src, sizeof(*dst));
1950         AST_LIST_HEAD_INIT_NOLOCK(&dst->actions);
1951
1952         AST_LIST_TRAVERSE(&src->actions, menu_action, action) {
1953                 if (!(new_menu_action = ast_calloc(1, sizeof(*new_menu_action)))) {
1954                         return -1;
1955                 }
1956                 memcpy(new_menu_action, menu_action, sizeof(*new_menu_action));
1957                 AST_LIST_INSERT_HEAD(&dst->actions, new_menu_action, action);
1958         }
1959         return 0;
1960 }
1961
1962 void conf_menu_entry_destroy(struct conf_menu_entry *menu_entry)
1963 {
1964         struct conf_menu_action *menu_action = NULL;
1965         while ((menu_action = AST_LIST_REMOVE_HEAD(&menu_entry->actions, action))) {
1966                 ast_free(menu_action);
1967         }
1968 }
1969
1970 int conf_find_menu_entry_by_sequence(const char *dtmf_sequence, struct conf_menu *menu, struct conf_menu_entry *result)
1971 {
1972         struct conf_menu_entry *menu_entry = NULL;
1973
1974         ao2_lock(menu);
1975         AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
1976                 if (!strcasecmp(menu_entry->dtmf, dtmf_sequence)) {
1977                         copy_menu_entry(result, menu_entry);
1978                         ao2_unlock(menu);
1979                         return 1;
1980                 }
1981         }
1982         ao2_unlock(menu);
1983
1984         return 0;
1985 }
1986
1987 int conf_set_menu_to_user(const char *menu_name, struct conference_bridge_user *conference_bridge_user)
1988 {
1989         struct conf_menu *menu;
1990         struct conf_menu_entry *menu_entry = NULL;
1991         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
1992
1993         if (!cfg) {
1994                 return -1;
1995         }
1996
1997         if (!(menu = menu_find(cfg->menus, menu_name))) {
1998                 return -1;
1999         }
2000         ao2_lock(menu);
2001         AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
2002                 struct dtmf_menu_hook_pvt *pvt;
2003                 if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
2004                         ao2_unlock(menu);
2005                         ao2_ref(menu, -1);
2006                         return -1;
2007                 }
2008                 if (copy_menu_entry(&pvt->menu_entry, menu_entry)) {
2009                         ast_free(pvt);
2010                         ao2_unlock(menu);
2011                         ao2_ref(menu, -1);
2012                         return -1;
2013                 }
2014                 pvt->conference_bridge_user = conference_bridge_user;
2015                 ao2_ref(menu, +1);
2016                 pvt->menu = menu;
2017
2018                 ast_bridge_features_hook(&conference_bridge_user->features, pvt->menu_entry.dtmf, menu_hook_callback, pvt, menu_hook_destroy);
2019         }
2020
2021         ao2_unlock(menu);
2022         ao2_ref(menu, -1);
2023
2024         return 0;
2025 }
2026
2027 void conf_destroy_config(void)
2028 {
2029         ast_cli_unregister_multiple(cli_confbridge_parser, ARRAY_LEN(cli_confbridge_parser));
2030         aco_info_destroy(&cfg_info);
2031         ao2_global_obj_release(cfg_handle);
2032 }