app_confbridge / bridge_softmix: Add ability to configure REMB interval.
[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 #include "asterisk/logger.h"
33 #include "asterisk/config.h"
34 #include "asterisk/config_options.h"
35 #include "include/confbridge.h"
36 #include "asterisk/astobj2.h"
37 #include "asterisk/cli.h"
38 #include "asterisk/bridge_features.h"
39 #include "asterisk/stringfields.h"
40 #include "asterisk/pbx.h"
41
42
43 /*** DOCUMENTATION
44         <configInfo name="app_confbridge" language="en_US">
45                 <synopsis>Conference Bridge Application</synopsis>
46                 <configFile name="confbridge.conf">
47                         <configObject name="global">
48                                 <synopsis>Unused, but reserved.</synopsis>
49                         </configObject>
50                         <configObject name="user_profile">
51                                 <synopsis>A named profile to apply to specific callers.</synopsis>
52                                 <description><para>Callers in a ConfBridge have a profile associated with them
53                                 that determine their options. A configuration section is determined to be a
54                                 user_profile when the <literal>type</literal> parameter has a value
55                                 of <literal>user</literal>.
56                                 </para></description>
57                                 <configOption name="type">
58                                         <synopsis>Define this configuration category as a user profile.</synopsis>
59                                         <description><para>The type parameter determines how a context in the
60                                         configuration file is interpreted.</para>
61                                         <enumlist>
62                                                 <enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
63                                                 <enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
64                                                 <enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
65                                         </enumlist>
66                                         </description>
67                                 </configOption>
68                                 <configOption name="admin">
69                                         <synopsis>Sets if the user is an admin or not</synopsis>
70                                 </configOption>
71                                 <configOption name="marked">
72                                         <synopsis>Sets if this is a marked user or not</synopsis>
73                                 </configOption>
74                                 <configOption name="startmuted">
75                                         <synopsis>Sets if all users should start out muted</synopsis>
76                                 </configOption>
77                                 <configOption name="music_on_hold_when_empty">
78                                         <synopsis>Play MOH when user is alone or waiting on a marked user</synopsis>
79                                 </configOption>
80                                 <configOption name="quiet">
81                                         <synopsis>Silence enter/leave prompts and user intros for this user</synopsis>
82                                 </configOption>
83                                 <configOption name="announce_user_count">
84                                         <synopsis>Sets if the number of users should be announced to the user</synopsis>
85                                 </configOption>
86                                 <configOption name="announce_user_count_all">
87                                         <synopsis>Announce user count to all the other users when this user joins</synopsis>
88                                         <description><para>Sets if the number of users should be announced to all the other users
89                                         in the conference when this user joins. This option can be either set to 'yes' or
90                                         a number. When set to a number, the announcement will only occur once the user
91                                         count is above the specified number.
92                                         </para></description>
93                                 </configOption>
94                                 <configOption name="announce_only_user">
95                                         <synopsis>Announce to a user when they join an empty conference</synopsis>
96                                 </configOption>
97                                 <configOption name="wait_marked">
98                                         <synopsis>Sets if the user must wait for a marked user to enter before joining a conference</synopsis>
99                                 </configOption>
100                                 <configOption name="end_marked">
101                                         <synopsis>Kick the user from the conference when the last marked user leaves</synopsis>
102                                 </configOption>
103                                 <configOption name="talk_detection_events">
104                                         <synopsis>Set whether or not notifications of when a user begins and ends talking should be sent out as events over AMI</synopsis>
105                                 </configOption>
106                                 <configOption name="dtmf_passthrough">
107                                         <synopsis>Sets whether or not DTMF should pass through the conference</synopsis>
108                                 </configOption>
109                                 <configOption name="announce_join_leave">
110                                         <synopsis>Prompt user for their name when joining a conference and play it to the conference when they enter</synopsis>
111                                 </configOption>
112                                 <configOption name="announce_join_leave_review">
113                                         <synopsis>Prompt user for their name when joining a conference and play it to the conference when they enter.
114                                         The user will be asked to review the recording of their name before entering the conference.</synopsis>
115                                 </configOption>
116                                 <configOption name="pin">
117                                         <synopsis>Sets a PIN the user must enter before joining the conference</synopsis>
118                                 </configOption>
119                                 <configOption name="music_on_hold_class">
120                                         <synopsis>The MOH class to use for this user</synopsis>
121                                 </configOption>
122                                 <configOption name="announcement">
123                                         <synopsis>Sound file to play to the user when they join a conference</synopsis>
124                                 </configOption>
125                                 <configOption name="denoise">
126                                         <synopsis>Apply a denoise filter to the audio before mixing</synopsis>
127                                         <description><para>Sets whether or not a denoise filter should be applied
128                                         to the audio before mixing or not.  Off by default. Requires
129                                         <literal>codec_speex</literal> to be built and installed.  Do not confuse this option
130                                         with <replaceable>drop_silence</replaceable>.  Denoise is useful if there is a lot of background
131                                         noise for a user as it attempts to remove the noise while preserving
132                                         the speech.  This option does NOT remove silence from being mixed into
133                                         the conference and does come at the cost of a slight performance hit.
134                                         </para></description>
135                                 </configOption>
136                                 <configOption name="dsp_drop_silence">
137                                         <synopsis>Drop what Asterisk detects as silence from audio sent to the bridge</synopsis>
138                                         <description><para>
139                                         This option drops what Asterisk detects as silence from
140                                         entering into the bridge.  Enabling this option will drastically
141                                         improve performance and help remove the buildup of background
142                                         noise from the conference. Highly recommended for large conferences
143                                         due to its performance enhancements.
144                                         </para></description>
145                                 </configOption>
146                                 <configOption name="dsp_silence_threshold">
147                                         <synopsis>The number of milliseconds of silence necessary to declare talking stopped.</synopsis>
148                                         <description>
149                                                 <para>The time in milliseconds of sound falling below the
150                                                 <replaceable>dsp_talking_threshold</replaceable> option when
151                                                 a user is considered to stop talking.  This value affects several
152                                                 operations and should not be changed unless the impact on call
153                                                 quality is fully understood.
154                                                 </para>
155                                                 <para>What this value affects internally:
156                                                 </para>
157                                                 <para>1. When talk detection AMI events are enabled, this value
158                                                 determines when the user has stopped talking after a
159                                                 period of talking.  If this value is set too low
160                                                 AMI events indicating the user has stopped talking
161                                                 may get falsely sent out when the user briefly pauses
162                                                 during mid sentence.
163                                                 </para>
164                                                 <para>2. The <replaceable>drop_silence</replaceable> option
165                                                 depends on this value to determine when the user's audio should
166                                                 begin to be dropped from the conference bridge after the user
167                                                 stops talking.  If this value is set too low the user's
168                                                 audio stream may sound choppy to the other participants.  This
169                                                 is caused by the user transitioning constantly from silence to
170                                                 talking during mid sentence.
171                                                 </para>
172                                                 <para>The best way to approach this option is to set it slightly
173                                                 above the maximum amount of milliseconds of silence a user may
174                                                 generate during natural speech.
175                                                 </para>
176                                                 <para>Valid values are 1 through 2^31.</para>
177                                         </description>
178                                 </configOption>
179                                 <configOption name="dsp_talking_threshold">
180                                         <synopsis>Average magnitude threshold to determine talking.</synopsis>
181                                         <description>
182                                                 <para>The minimum average magnitude per sample in a frame
183                                                 for the DSP to consider talking/noise present.  A value below
184                                                 this level is considered silence.  This value affects several
185                                                 operations and should not be changed unless the impact on call
186                                                 quality is fully understood.
187                                                 </para>
188                                                 <para>What this value affects internally:
189                                                 </para>
190                                                 <para>1. Audio is only mixed out of a user's incoming audio
191                                                 stream if talking is detected.  If this value is set too
192                                                 high the user will hear himself talking.
193                                                 </para>
194                                                 <para>2. When talk detection AMI events are enabled, this value
195                                                 determines when talking has begun which results in
196                                                 an AMI event to fire.  If this value is set too low
197                                                 AMI events may be falsely triggered by variants in
198                                                 room noise.
199                                                 </para>
200                                                 <para>3. The <replaceable>drop_silence</replaceable> option
201                                                 depends on this value to determine when the user's audio should
202                                                 be mixed into the bridge after periods of silence.  If this value
203                                                 is too high the user's speech will get discarded as they will
204                                                 be considered silent.
205                                                 </para>
206                                                 <para>Valid values are 1 through 2^15.</para>
207                                         </description>
208                                 </configOption>
209                                 <configOption name="jitterbuffer">
210                                         <synopsis>Place a jitter buffer on the user's audio stream before audio mixing is performed</synopsis>
211                                         <description><para>
212                                                 Enabling this option places a jitterbuffer on the user's audio stream
213                                                 before audio mixing is performed.  This is highly recommended but will
214                                                 add a slight delay to the audio.  This option is using the <literal>JITTERBUFFER</literal>
215                                                 dialplan function's default adaptive jitterbuffer.  For a more fine tuned
216                                                 jitterbuffer, disable this option and use the <literal>JITTERBUFFER</literal> dialplan function
217                                                 on the user before entering the ConfBridge application.
218                                         </para></description>
219                                 </configOption>
220                                 <configOption name="template">
221                                         <synopsis>When using the CONFBRIDGE dialplan function, use a user profile as a template for creating a new temporary profile</synopsis>
222                                 </configOption>
223                                 <configOption name="timeout">
224                                         <synopsis>Kick the user out of the conference after this many seconds. 0 means there is no timeout for the user.</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="language" default="en">
261                                         <synopsis>The language used for announcements to the conference.</synopsis>
262                                         <description><para>
263                                                 By default, announcements to a conference use English.  Which means
264                                                 the prompts played to all users within the conference will be
265                                                 English.  By changing the language of a bridge, this will change
266                                                 the language of the prompts played to all users.
267                                         </para></description>
268                                 </configOption>
269                                 <configOption name="mixing_interval">
270                                         <synopsis>Sets the internal mixing interval in milliseconds for the bridge</synopsis>
271                                         <description><para>
272                                                 Sets the internal mixing interval in milliseconds for the bridge.  This
273                                                 number reflects how tight or loose the mixing will be for the conference.
274                                                 In order to improve performance a larger mixing interval such as 40ms may
275                                                 be chosen.  Using a larger mixing interval comes at the cost of introducing
276                                                 larger amounts of delay into the bridge.  Valid values here are 10, 20, 40,
277                                                 or 80.
278                                         </para></description>
279                                 </configOption>
280                                 <configOption name="binaural_active">
281                                         <synopsis>If true binaural conferencing with stereo audio is active</synopsis>
282                                         <description><para>
283                                                 Activates binaural mixing for a conference bridge.
284                                                 Binaural features are disabled by default.
285                                         </para></description>
286                                 </configOption>
287                                 <configOption name="record_conference">
288                                         <synopsis>Record the conference starting with the first active user's entrance and ending with the last active user's exit</synopsis>
289                                         <description><para>
290                                                 Records the conference call starting when the first user
291                                                 enters the room, and ending when the last user exits the room.
292                                                 The default recorded filename is
293                                                 <filename>'confbridge-${name of conference bridge}-${start time}.wav'</filename>
294                                                 and the default format is 8khz slinear.  This file will be
295                                                 located in the configured monitoring directory in <filename>asterisk.conf</filename>.
296                                         </para></description>
297                                 </configOption>
298                                 <configOption name="record_file" default="confbridge-${name of conference bridge}-${start time}.wav">
299                                         <synopsis>The filename of the conference recording</synopsis>
300                                         <description><para>
301                                                 When <replaceable>record_conference</replaceable> is set to yes, the specific name of the
302                                                 record file can be set using this option.  Note that since multiple
303                                                 conferences may use the same bridge profile, this may cause issues
304                                                 depending on the configuration.  It is recommended to only use this
305                                                 option dynamically with the <literal>CONFBRIDGE()</literal> dialplan function. This
306                                                 allows the record name to be specified and a unique name to be chosen.
307                                                 By default, the record_file is stored in Asterisk's spool/monitor directory
308                                                 with a unique filename starting with the 'confbridge' prefix.
309                                         </para></description>
310                                 </configOption>
311                                 <configOption name="record_file_append" default="yes">
312                                         <synopsis>Append to record file when starting/stopping on same conference recording</synopsis>
313                                         <description><para>
314                                                 When <replaceable>record_file_append</replaceable> is set to yes, stopping and starting recording on a
315                                                 conference adds the new portion to end of current record_file. When this is
316                                                 set to no, a new <replaceable>record_file</replaceable> is generated every time you start then stop recording
317                                                 on a conference.
318                                         </para></description>
319                                 </configOption>
320                                 <configOption name="record_file_timestamp" default="yes">
321                                         <synopsis>Append the start time to the record_file name so that it is unique.</synopsis>
322                                         <description><para>
323                                                 When <replaceable>record_file_timestamp</replaceable> is set to yes, the start time is appended to
324                                                 <replaceable>record_file</replaceable> so that the filename is unique. This allows you to specify
325                                                 a <replaceable>record_file</replaceable> but not overwrite existing recordings.
326                                         </para></description>
327                                 </configOption>
328                                 <configOption name="record_options" default="">
329                                         <synopsis>Pass additional options to MixMonitor when recording</synopsis>
330                                         <description><para>
331                                                 Pass additional options to MixMonitor when <replaceable>record_conference</replaceable> is set to yes.
332                                                 See <literal>MixMonitor</literal> for available options.
333                                         </para></description>
334                                 </configOption>
335                                 <configOption name="record_command" default="">
336                                         <synopsis>Execute a command after recording ends</synopsis>
337                                         <description><para>
338                                                 Executes the specified command when recording ends. Any strings matching <literal>^{X}</literal> will be
339                                                 unescaped to <variable>X</variable>. All variables will be evaluated at the time ConfBridge is called.
340                                         </para></description>
341                                 </configOption>
342                                 <configOption name="regcontext">
343                                         <synopsis>The name of the context into which to register the name of the conference bridge as NoOP() at priority 1</synopsis>
344                                         <description><para>
345                                                 When set this will cause the name of the created conference to be registered
346                                                 into the named context at priority 1 with an operation of NoOP().  This can
347                                                 then be used in other parts of the dialplan to test for the existence of a
348                                                 specific conference bridge.
349                                                 You should be aware that there are potential races between testing for the
350                                                 existence of a bridge, and taking action upon that information, consider
351                                                 for example two callers executing the check simultaniously, and then taking
352                                                 special action as "first caller" into the bridge.  The same for exiting,
353                                                 directly after the check the bridge can be destroyed before the new caller
354                                                 enters (creating a new bridge), for example, and the "first member" actions
355                                                 could thus be missed.
356                                         </para></description>
357                                 </configOption>
358                                 <configOption name="video_mode">
359                                         <synopsis>Sets how confbridge handles video distribution to the conference participants</synopsis>
360                                         <description><para>
361                                                 Sets how confbridge handles video distribution to the conference participants.
362                                                 Note that participants wanting to view and be the source of a video feed
363                                                 <emphasis>MUST</emphasis> be sharing the same video codec.  Also, using video in conjunction with
364                                                 with the jitterbuffer currently results in the audio being slightly out of sync
365                                                 with the video.  This is a result of the jitterbuffer only working on the audio
366                                                 stream.  It is recommended to disable the jitterbuffer when video is used.</para>
367                                                 <enumlist>
368                                                         <enum name="none">
369                                                                 <para>No video sources are set by default in the conference. It is still
370                                                                 possible for a user to be set as a video source via AMI or DTMF action
371                                                                 at any time.</para>
372                                                         </enum>
373                                                         <enum name="follow_talker">
374                                                                 <para>The video feed will follow whoever is talking and providing video.</para>
375                                                         </enum>
376                                                         <enum name="last_marked">
377                                                                 <para>The last marked user to join the conference with video capabilities
378                                                                 will be the single source of video distributed to all participants.
379                                                                 If multiple marked users are capable of video, the last one to join
380                                                                 is always the source, when that user leaves it goes to the one who
381                                                                 joined before them.</para>
382                                                         </enum>
383                                                         <enum name="first_marked">
384                                                                 <para>The first marked user to join the conference with video capabilities
385                                                                 is the single source of video distribution among all participants. If
386                                                                 that user leaves, the marked user to join after them becomes the source.</para>
387                                                         </enum>
388                                                         <enum name="sfu">
389                                                                 <para>Selective Forwarding Unit - Sets multi-stream
390                                                                 operation for a multi-party video conference.</para>
391                                                         </enum>
392                                                 </enumlist>
393                                         </description>
394                                 </configOption>
395                                 <configOption name="max_members">
396                                         <synopsis>Limit the maximum number of participants for a single conference</synopsis>
397                                         <description><para>
398                                                 This option limits the number of participants for a single
399                                                 conference to a specific number.  By default conferences
400                                                 have no participant limit. After the limit is reached, the
401                                                 conference will be locked until someone leaves.  Note however
402                                                 that an Admin user will always be alowed to join the conference
403                                                 regardless if this limit is reached or not.
404                                         </para></description>
405                                 </configOption>
406                                 <configOption name="sound_">
407                                         <synopsis>Override the various conference bridge sound files</synopsis>
408                                         <description><para>
409                                                 All sounds in the conference are customizable using the bridge profile options below.
410                                                 Simply state the option followed by the filename or full path of the filename after
411                                                 the option.  Example: <literal>sound_had_joined=conf-hasjoin</literal>  This will play the <literal>conf-hasjoin</literal>
412                                                 sound file found in the sounds directory when announcing someone's name is joining the
413                                                 conference.</para>
414                                                 <enumlist>
415                                                         <enum name="sound_join"><para>The sound played to everyone when someone enters the conference.</para></enum>
416                                                         <enum name="sound_leave"><para>The sound played to everyone when someone leaves the conference.</para></enum>
417                                                         <enum name="sound_has_joined"><para>The sound played before announcing someone's name has
418                                                                                 joined the conference. This is used for user intros.
419                                                                                 Example <literal>"_____ has joined the conference"</literal></para></enum>
420                                                         <enum name="sound_has_left"><para>The sound played when announcing someone's name has
421                                                                                 left the conference. This is used for user intros.
422                                                                                 Example <literal>"_____ has left the conference"</literal></para></enum>
423                                                         <enum name="sound_kicked"><para>The sound played to a user who has been kicked from the conference.</para></enum>
424                                                         <enum name="sound_muted"><para>The sound played when the mute option it toggled on.</para></enum>
425                                                         <enum name="sound_unmuted"><para>The sound played when the mute option it toggled off.</para></enum>
426                                                         <enum name="sound_binaural_on"><para>The sound played when binaural auudio is turned on.</para></enum>
427                                                         <enum name="sound_binaural_off"><para>The sound played when the binaural audio is turned off.</para></enum>
428                                                         <enum name="sound_only_person"><para>The sound played when the user is the only person in the conference.</para></enum>
429                                                         <enum name="sound_only_one"><para>The sound played to a user when there is only one other
430                                                                                 person is in the conference.</para></enum>
431                                                         <enum name="sound_there_are"><para>The sound played when announcing how many users there
432                                                                                 are in a conference.</para></enum>
433                                                         <enum name="sound_other_in_party"><para>This file is used in conjunction with <literal>sound_there_are</literal>
434                                                                                 when announcing how many users there are in the conference.
435                                                                                 The sounds are stringed together like this.
436                                                                                 <literal>"sound_there_are" ${number of participants} "sound_other_in_party"</literal></para></enum>
437                                                         <enum name="sound_place_into_conference"><para>The sound played when someone is placed into the conference
438                                                                                 after waiting for a marked user.</para></enum>
439                                                         <enum name="sound_wait_for_leader"><para>The sound played when a user is placed into a conference that
440                                                                                 can not start until a marked user enters.</para></enum>
441                                                         <enum name="sound_leader_has_left"><para>The sound played when the last marked user leaves the conference.</para></enum>
442                                                         <enum name="sound_get_pin"><para>The sound played when prompting for a conference pin number.</para></enum>
443                                                         <enum name="sound_invalid_pin"><para>The sound played when an invalid pin is entered too many times.</para></enum>
444                                                         <enum name="sound_locked"><para>The sound played to a user trying to join a locked conference.</para></enum>
445                                                         <enum name="sound_locked_now"><para>The sound played to an admin after toggling the conference to locked mode.</para></enum>
446                                                         <enum name="sound_unlocked_now"><para>The sound played to an admin after toggling the conference to unlocked mode.</para></enum>
447                                                         <enum name="sound_error_menu"><para>The sound played when an invalid menu option is entered.</para></enum>
448                                                 </enumlist>
449                                         </description>
450                                 </configOption>
451                                 <configOption name="video_update_discard" default="2000">
452                                         <synopsis>Sets the amount of time in milliseconds after sending a video update to discard subsequent video updates</synopsis>
453                                         <description><para>
454                                                 Sets the amount of time in milliseconds after sending a video update request
455                                                 that subsequent video updates should be discarded. This means that if we
456                                                 send a video update we will discard any other video update requests until
457                                                 after the configured amount of time has elapsed. This prevents flooding of
458                                                 video update requests from clients.
459                                         </para></description>
460                                 </configOption>
461                                 <configOption name="remb_send_interval" default="0">
462                                         <synopsis>Sets the interval in milliseconds that a combined REMB frame will be sent to video sources</synopsis>
463                                         <description><para>
464                                                 Sets the interval in milliseconds that a combined REMB frame will be sent
465                                                 to video sources. This is done by taking all REMB frames that have been
466                                                 received since the last REMB frame was sent, making a combined value,
467                                                 and sending it to the source. A REMB frame contains receiver estimated
468                                                 maximum bitrate information. By creating a combined REMB frame the
469                                                 sender of video can be influenced on the bitrate they choose, allowing
470                                                 better quality for all receivers.
471                                         </para></description>
472                                 </configOption>
473                                 <configOption name="template">
474                                         <synopsis>When using the CONFBRIDGE dialplan function, use a bridge profile as a template for creating a new temporary profile</synopsis>
475                                 </configOption>
476                         </configObject>
477                         <configObject name="menu">
478                                 <synopsis>A conference user menu</synopsis>
479                                 <description>
480                                         <para>Conference users, as defined by a <replaceable>conf_user</replaceable>,
481                                         can have a DTMF menu assigned to their profile when they enter the
482                                         <literal>ConfBridge</literal> application.</para>
483                                 </description>
484                                 <configOption name="type">
485                                         <synopsis>Define this configuration category as a menu</synopsis>
486                                         <description><para>The type parameter determines how a context in the
487                                         configuration file is interpreted.</para>
488                                         <enumlist>
489                                                 <enum name="user"><para>Configure the context as a <replaceable>user_profile</replaceable></para></enum>
490                                                 <enum name="bridge"><para>Configure the context as a <replaceable>bridge_profile</replaceable></para></enum>
491                                                 <enum name="menu"><para>Configure the context as a <replaceable>menu</replaceable></para></enum>
492                                         </enumlist>
493                                         </description>
494                                 </configOption>
495                                 <configOption name="template">
496                                         <synopsis>When using the CONFBRIDGE dialplan function, use a menu profile as a template for creating a new temporary profile</synopsis>
497                                 </configOption>
498                                 <configOption name="^[0-9A-D*#]+$">
499                                         <synopsis>DTMF sequences to assign various confbridge actions to</synopsis>
500                                         <description>
501                                         <para>The ConfBridge application also has the ability to apply custom DTMF menus to
502                                         each channel using the application.  Like the User and Bridge profiles a menu
503                                         is passed in to ConfBridge as an argument in the dialplan.</para>
504                                         <para>Below is a list of menu actions that can be assigned to a DTMF sequence.</para>
505                                         <note><para>
506                                                 To have the first DTMF digit in a sequence be the '#' character, you need to
507                                                 escape it.  If it is not escaped then normal config file processing will
508                                                 think it is a directive like #include.  For example: The mute setting is
509                                                 toggled when <literal>#1</literal> is pressed.</para>
510                                                 <para><literal>\#1=toggle_mute</literal></para>
511                                         </note>
512                                         <note><para>
513                                         A single DTMF sequence can have multiple actions associated with it. This is
514                                         accomplished by stringing the actions together and using a <literal>,</literal> as the
515                                         delimiter.  Example:  Both listening and talking volume is reset when <literal>5</literal> is
516                                         pressed.  <literal>5=reset_talking_volume, reset_listening_volume</literal></para></note>
517                                         <enumlist>
518                                                 <enum name="playback(filename&amp;filename2&amp;...)"><para>
519                                                         <literal>playback</literal> will play back an audio file to a channel
520                                                         and then immediately return to the conference.
521                                                         This file can not be interupted by DTMF.
522                                                         Multiple files can be chained together using the
523                                                         <literal>&amp;</literal> character.</para></enum>
524                                                 <enum name="playback_and_continue(filename&amp;filename2&amp;...)"><para>
525                                                         <literal>playback_and_continue</literal> will
526                                                         play back a prompt while continuing to
527                                                         collect the dtmf sequence.  This is useful
528                                                         when using a menu prompt that describes all
529                                                         the menu options.  Note however that any DTMF
530                                                         during this action will terminate the prompts
531                                                         playback.  Prompt files can be chained together
532                                                         using the <literal>&amp;</literal> character as a delimiter.</para></enum>
533                                                 <enum name="toggle_mute"><para>
534                                                         Toggle turning on and off mute.  Mute will make the user silent
535                                                         to everyone else, but the user will still be able to listen in.
536                                                         </para></enum>
537                                                 <enum name="toggle_binaural"><para>
538                                                         Toggle turning on and off binaural audio processing.
539                                                         </para></enum>
540                                                 <enum name="no_op"><para>
541                                                         This action does nothing (No Operation). Its only real purpose exists for
542                                                         being able to reserve a sequence in the config as a menu exit sequence.</para></enum>
543                                                 <enum name="decrease_listening_volume"><para>
544                                                         Decreases the channel's listening volume.</para></enum>
545                                                 <enum name="increase_listening_volume"><para>
546                                                         Increases the channel's listening volume.</para></enum>
547                                                 <enum name="reset_listening_volume"><para>
548                                                         Reset channel's listening volume to default level.</para></enum>
549                                                 <enum name="decrease_talking_volume"><para>
550                                                         Decreases the channel's talking volume.</para></enum>
551                                                 <enum name="increase_talking_volume"><para>
552                                                         Increases the channel's talking volume.</para></enum>
553                                                 <enum name="reset_talking_volume"><para>
554                                                         Reset channel's talking volume to default level.</para></enum>
555                                                 <enum name="dialplan_exec(context,exten,priority)"><para>
556                                                         The <literal>dialplan_exec</literal> action allows a user
557                                                         to escape from the conference and execute
558                                                         commands in the dialplan.  Once the dialplan
559                                                         exits the user will be put back into the
560                                                         conference.  The possibilities are endless!</para></enum>
561                                                 <enum name="leave_conference"><para>
562                                                         This action allows a user to exit the conference and continue
563                                                         execution in the dialplan.</para></enum>
564                                                 <enum name="admin_kick_last"><para>
565                                                         This action allows an Admin to kick the last participant from the
566                                                         conference. This action will only work for admins which allows
567                                                         a single menu to be used for both users and admins.</para></enum>
568                                                 <enum name="admin_toggle_conference_lock"><para>
569                                                         This action allows an Admin to toggle locking and
570                                                         unlocking the conference.  Non admins can not use
571                                                         this action even if it is in their menu.</para></enum>
572                                                 <enum name="set_as_single_video_src"><para>
573                                                         This action allows any user to set themselves as the
574                                                         single video source distributed to all participants.
575                                                         This will make the video feed stick to them regardless
576                                                         of what the <literal>video_mode</literal> is set to.</para></enum>
577                                                 <enum name="release_as_single_video_src"><para>
578                                                         This action allows a user to release themselves as
579                                                         the video source.  If <literal>video_mode</literal> is not set to <literal>none</literal>
580                                                         this action will result in the conference returning to
581                                                         whatever video mode the bridge profile is using.</para>
582                                                         <para>Note that this action will have no effect if the user
583                                                         is not currently the video source.  Also, the user is
584                                                         not guaranteed by using this action that they will not
585                                                         become the video source again.  The bridge will return
586                                                         to whatever operation the <literal>video_mode</literal> option is set to
587                                                         upon release of the video src.</para></enum>
588                                                 <enum name="admin_toggle_mute_participants"><para>
589                                                         This action allows an administrator to toggle the mute
590                                                         state for all non-admins within a conference.  All
591                                                         admin users are unaffected by this option.  Note that all
592                                                         users, regardless of their admin status, are notified
593                                                         that the conference is muted.</para></enum>
594                                                 <enum name="participant_count"><para>
595                                                         This action plays back the number of participants currently
596                                                         in a conference</para></enum>
597                                                 </enumlist>
598                                         </description>
599                                 </configOption>
600                         </configObject>
601                 </configFile>
602         </configInfo>
603 ***/
604
605 struct confbridge_cfg {
606         struct ao2_container *bridge_profiles;
607         struct ao2_container *user_profiles;
608         struct ao2_container *menus;
609 };
610
611 static int verify_default_profiles(void);
612 static void *bridge_profile_alloc(const char *category);
613 static void *bridge_profile_find(struct ao2_container *container, const char *category);
614 static struct bridge_profile_sounds *bridge_profile_sounds_alloc(void);
615
616 static void bridge_profile_destructor(void *obj)
617 {
618         struct bridge_profile *b_profile = obj;
619         ao2_cleanup(b_profile->sounds);
620 }
621
622 static void *bridge_profile_alloc(const char *category)
623 {
624         struct bridge_profile *b_profile;
625
626         if (!(b_profile = ao2_alloc(sizeof(*b_profile), bridge_profile_destructor))) {
627                 return NULL;
628         }
629
630         if (!(b_profile->sounds = bridge_profile_sounds_alloc())) {
631                 ao2_ref(b_profile, -1);
632                 return NULL;
633         }
634
635         ast_copy_string(b_profile->name, category, sizeof(b_profile->name));
636
637         return b_profile;
638 }
639
640 static void *bridge_profile_find(struct ao2_container *container, const char *category)
641 {
642         return ao2_find(container, category, OBJ_KEY);
643 }
644
645 static struct aco_type bridge_type = {
646         .type = ACO_ITEM,
647         .name = "bridge_profile",
648         .category_match = ACO_BLACKLIST_EXACT,
649         .category = "general",
650         .matchfield = "type",
651         .matchvalue = "bridge",
652         .item_alloc = bridge_profile_alloc,
653         .item_find = bridge_profile_find,
654         .item_offset = offsetof(struct confbridge_cfg, bridge_profiles),
655 };
656
657 static void *user_profile_alloc(const char *category);
658 static void *user_profile_find(struct ao2_container *container, const char *category);
659 static void user_profile_destructor(void *obj)
660 {
661         return;
662 }
663
664 static void *user_profile_alloc(const char *category)
665 {
666         struct user_profile *u_profile;
667
668         if (!(u_profile = ao2_alloc(sizeof(*u_profile), user_profile_destructor))) {
669                 return NULL;
670         }
671
672         ast_copy_string(u_profile->name, category, sizeof(u_profile->name));
673
674         return u_profile;
675 }
676
677 static void *user_profile_find(struct ao2_container *container, const char *category)
678 {
679         return ao2_find(container, category, OBJ_KEY);
680 }
681
682 static struct aco_type user_type = {
683         .type = ACO_ITEM,
684         .name  = "user_profile",
685         .category_match = ACO_BLACKLIST_EXACT,
686         .category = "general",
687         .matchfield = "type",
688         .matchvalue = "user",
689         .item_alloc = user_profile_alloc,
690         .item_find = user_profile_find,
691         .item_offset = offsetof(struct confbridge_cfg, user_profiles),
692 };
693
694 static void *menu_alloc(const char *category);
695 static void *menu_find(struct ao2_container *container, const char *category);
696 static void menu_destructor(void *obj);
697
698 static void *menu_alloc(const char *category)
699 {
700         struct conf_menu *menu;
701         if (!(menu = ao2_alloc(sizeof(*menu), menu_destructor))) {
702                 return NULL;
703         }
704         ast_copy_string(menu->name, category, sizeof(menu->name));
705         return menu;
706 }
707
708 static void *menu_find(struct ao2_container *container, const char *category)
709 {
710         return ao2_find(container, category, OBJ_KEY);
711 }
712
713 static struct aco_type menu_type = {
714         .type = ACO_ITEM,
715         .name = "menu",
716         .category_match = ACO_BLACKLIST_EXACT,
717         .category = "general",
718         .matchfield = "type",
719         .matchvalue = "menu",
720         .item_alloc = menu_alloc,
721         .item_find = menu_find,
722         .item_offset = offsetof(struct confbridge_cfg, menus),
723 };
724
725 /* Used to pass to aco_option_register */
726 static struct aco_type *bridge_types[] = ACO_TYPES(&bridge_type);
727 static struct aco_type *menu_types[] = ACO_TYPES(&menu_type);
728 static struct aco_type *user_types[] = ACO_TYPES(&user_type);
729
730 /* The general category is reserved, but unused */
731 static struct aco_type general_type = {
732         .type = ACO_GLOBAL,
733         .name = "global",
734         .category_match = ACO_WHITELIST_EXACT,
735         .category = "general",
736 };
737
738 static struct aco_file confbridge_conf = {
739         .filename = "confbridge.conf",
740         .types = ACO_TYPES(&bridge_type, &user_type, &menu_type, &general_type),
741 };
742
743 static AO2_GLOBAL_OBJ_STATIC(cfg_handle);
744
745 static void *confbridge_cfg_alloc(void);
746
747 CONFIG_INFO_STANDARD(cfg_info, cfg_handle, confbridge_cfg_alloc,
748         .files = ACO_FILES(&confbridge_conf),
749         .pre_apply_config = verify_default_profiles,
750 );
751
752 /*! bridge profile container functions */
753 static int bridge_cmp_cb(void *obj, void *arg, int flags)
754 {
755         const struct bridge_profile *left = obj;
756         const struct bridge_profile *right = arg;
757         const char *right_name = arg;
758         int cmp;
759
760         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
761         default:
762         case OBJ_POINTER:
763                 right_name = right->name;
764                 /* Fall through */
765         case OBJ_KEY:
766                 cmp = strcasecmp(left->name, right_name);
767                 break;
768         case OBJ_PARTIAL_KEY:
769                 cmp = strncasecmp(left->name, right_name, strlen(right_name));
770                 break;
771         }
772         return cmp ? 0 : CMP_MATCH;
773 }
774
775 static int bridge_hash_cb(const void *obj, const int flags)
776 {
777         const struct bridge_profile *b_profile = obj;
778         const char *name = obj;
779         int hash;
780
781         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
782         default:
783         case OBJ_POINTER:
784                 name = b_profile->name;
785                 /* Fall through */
786         case OBJ_KEY:
787                 hash = ast_str_case_hash(name);
788                 break;
789         case OBJ_PARTIAL_KEY:
790                 /* Should never happen in hash callback. */
791                 ast_assert(0);
792                 hash = 0;
793                 break;
794         }
795         return hash;
796 }
797
798 /*! menu container functions */
799 static int menu_cmp_cb(void *obj, void *arg, int flags)
800 {
801         const struct conf_menu *left = obj;
802         const struct conf_menu *right = arg;
803         const char *right_name = arg;
804         int cmp;
805
806         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
807         default:
808         case OBJ_POINTER:
809                 right_name = right->name;
810                 /* Fall through */
811         case OBJ_KEY:
812                 cmp = strcasecmp(left->name, right_name);
813                 break;
814         case OBJ_PARTIAL_KEY:
815                 cmp = strncasecmp(left->name, right_name, strlen(right_name));
816                 break;
817         }
818         return cmp ? 0 : CMP_MATCH;
819 }
820
821 static int menu_hash_cb(const void *obj, const int flags)
822 {
823         const struct conf_menu *menu = obj;
824         const char *name = obj;
825         int hash;
826
827         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
828         default:
829         case OBJ_POINTER:
830                 name = menu->name;
831                 /* Fall through */
832         case OBJ_KEY:
833                 hash = ast_str_case_hash(name);
834                 break;
835         case OBJ_PARTIAL_KEY:
836                 /* Should never happen in hash callback. */
837                 ast_assert(0);
838                 hash = 0;
839                 break;
840         }
841         return hash;
842 }
843
844 static void menu_destructor(void *obj)
845 {
846         struct conf_menu *menu = obj;
847         struct conf_menu_entry *entry = NULL;
848
849         while ((entry = AST_LIST_REMOVE_HEAD(&menu->entries, entry))) {
850                 conf_menu_entry_destroy(entry);
851                 ast_free(entry);
852         }
853 }
854
855 /*! User profile container functions */
856 static int user_cmp_cb(void *obj, void *arg, int flags)
857 {
858         const struct user_profile *left = obj;
859         const struct user_profile *right = arg;
860         const char *right_name = arg;
861         int cmp;
862
863         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
864         default:
865         case OBJ_POINTER:
866                 right_name = right->name;
867                 /* Fall through */
868         case OBJ_KEY:
869                 cmp = strcasecmp(left->name, right_name);
870                 break;
871         case OBJ_PARTIAL_KEY:
872                 cmp = strncasecmp(left->name, right_name, strlen(right_name));
873                 break;
874         }
875         return cmp ? 0 : CMP_MATCH;
876 }
877
878 static int user_hash_cb(const void *obj, const int flags)
879 {
880         const struct user_profile *u_profile = obj;
881         const char *name = obj;
882         int hash;
883
884         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
885         default:
886         case OBJ_POINTER:
887                 name = u_profile->name;
888                 /* Fall through */
889         case OBJ_KEY:
890                 hash = ast_str_case_hash(name);
891                 break;
892         case OBJ_PARTIAL_KEY:
893                 /* Should never happen in hash callback. */
894                 ast_assert(0);
895                 hash = 0;
896                 break;
897         }
898         return hash;
899 }
900
901 /*! Bridge Profile Sounds functions */
902 static void bridge_profile_sounds_destroy_cb(void *obj)
903 {
904         struct bridge_profile_sounds *sounds = obj;
905         ast_string_field_free_memory(sounds);
906 }
907
908 static struct bridge_profile_sounds *bridge_profile_sounds_alloc(void)
909 {
910         struct bridge_profile_sounds *sounds = ao2_alloc(sizeof(*sounds), bridge_profile_sounds_destroy_cb);
911
912         if (!sounds) {
913                 return NULL;
914         }
915         if (ast_string_field_init(sounds, 512)) {
916                 ao2_ref(sounds, -1);
917                 return NULL;
918         }
919
920         return sounds;
921 }
922
923 static int set_sound(const char *sound_name, const char *sound_file, struct bridge_profile *b_profile)
924 {
925         struct bridge_profile_sounds *sounds = b_profile->sounds;
926         if (ast_strlen_zero(sound_file)) {
927                 return -1;
928         }
929
930         if (!strcasecmp(sound_name, "sound_only_person")) {
931                 ast_string_field_set(sounds, onlyperson, sound_file);
932         } else if (!strcasecmp(sound_name, "sound_only_one")) {
933                 ast_string_field_set(sounds, onlyone, sound_file);
934         } else if (!strcasecmp(sound_name, "sound_has_joined")) {
935                 ast_string_field_set(sounds, hasjoin, sound_file);
936         } else if (!strcasecmp(sound_name, "sound_has_left")) {
937                 ast_string_field_set(sounds, hasleft, sound_file);
938         } else if (!strcasecmp(sound_name, "sound_kicked")) {
939                 ast_string_field_set(sounds, kicked, sound_file);
940         } else if (!strcasecmp(sound_name, "sound_muted")) {
941                 ast_string_field_set(sounds, muted, sound_file);
942         } else if (!strcasecmp(sound_name, "sound_unmuted")) {
943                 ast_string_field_set(sounds, unmuted, sound_file);
944         } else if (!strcasecmp(sound_name, "sound_binaural_on")) {
945                 ast_string_field_set(sounds, binauralon, sound_file);
946         } else if (!strcasecmp(sound_name, "sound_binaural_off")) {
947                 ast_string_field_set(sounds, binauraloff, sound_file);
948         } else if (!strcasecmp(sound_name, "sound_there_are")) {
949                 ast_string_field_set(sounds, thereare, sound_file);
950         } else if (!strcasecmp(sound_name, "sound_other_in_party")) {
951                 ast_string_field_set(sounds, otherinparty, sound_file);
952         } else if (!strcasecmp(sound_name, "sound_place_into_conference")) {
953                 static int deprecation_warning = 1;
954                 if (deprecation_warning) {
955                         ast_log(LOG_WARNING, "sound_place_into_conference is deprecated"
956                                 " and unused. Use sound_begin for similar functionality.");
957                         deprecation_warning = 0;
958                 }
959                 ast_string_field_set(sounds, placeintoconf, sound_file);
960         } else if (!strcasecmp(sound_name, "sound_wait_for_leader")) {
961                 ast_string_field_set(sounds, waitforleader, sound_file);
962         } else if (!strcasecmp(sound_name, "sound_leader_has_left")) {
963                 ast_string_field_set(sounds, leaderhasleft, sound_file);
964         } else if (!strcasecmp(sound_name, "sound_get_pin")) {
965                 ast_string_field_set(sounds, getpin, sound_file);
966         } else if (!strcasecmp(sound_name, "sound_invalid_pin")) {
967                 ast_string_field_set(sounds, invalidpin, sound_file);
968         } else if (!strcasecmp(sound_name, "sound_locked")) {
969                 ast_string_field_set(sounds, locked, sound_file);
970         } else if (!strcasecmp(sound_name, "sound_unlocked_now")) {
971                 ast_string_field_set(sounds, unlockednow, sound_file);
972         } else if (!strcasecmp(sound_name, "sound_locked_now")) {
973                 ast_string_field_set(sounds, lockednow, sound_file);
974         } else if (!strcasecmp(sound_name, "sound_error_menu")) {
975                 ast_string_field_set(sounds, errormenu, sound_file);
976         } else if (!strcasecmp(sound_name, "sound_join")) {
977                 ast_string_field_set(sounds, join, sound_file);
978         } else if (!strcasecmp(sound_name, "sound_leave")) {
979                 ast_string_field_set(sounds, leave, sound_file);
980         } else if (!strcasecmp(sound_name, "sound_participants_muted")) {
981                 ast_string_field_set(sounds, participantsmuted, sound_file);
982         } else if (!strcasecmp(sound_name, "sound_participants_unmuted")) {
983                 ast_string_field_set(sounds, participantsunmuted, sound_file);
984         } else if (!strcasecmp(sound_name, "sound_begin")) {
985                 ast_string_field_set(sounds, begin, sound_file);
986         } else {
987                 return -1;
988         }
989
990         return 0;
991 }
992
993 /*! CONFBRIDGE dialplan function functions and channel datastore. */
994 struct func_confbridge_data {
995         struct bridge_profile b_profile;
996         struct user_profile u_profile;
997         struct conf_menu *menu;
998         unsigned int b_usable:1; /*!< Tells if bridge profile is usable or not */
999         unsigned int u_usable:1; /*!< Tells if user profile is usable or not */
1000         unsigned int m_usable:1; /*!< Tells if menu profile is usable or not */
1001 };
1002
1003 static void func_confbridge_data_destructor(struct func_confbridge_data *b_data)
1004 {
1005         conf_bridge_profile_destroy(&b_data->b_profile);
1006         ao2_cleanup(b_data->menu);
1007         ast_free(b_data);
1008 }
1009
1010 static void func_confbridge_destroy_cb(void *data)
1011 {
1012         struct func_confbridge_data *b_data = data;
1013         func_confbridge_data_destructor(b_data);
1014 };
1015
1016 static const struct ast_datastore_info confbridge_datastore = {
1017         .type = "confbridge",
1018         .destroy = func_confbridge_destroy_cb
1019 };
1020
1021 int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1022 {
1023         struct ast_datastore *datastore;
1024         struct func_confbridge_data *b_data;
1025         char *parse;
1026         struct ast_variable tmpvar = { 0, };
1027         struct ast_variable template = {
1028                 .name = "template",
1029                 .file = "CONFBRIDGE"
1030         };
1031         AST_DECLARE_APP_ARGS(args,
1032                 AST_APP_ARG(type);
1033                 AST_APP_ARG(option);
1034         );
1035
1036         if (!chan) {
1037                 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1038                 return -1;
1039         }
1040
1041         /* parse all the required arguments and make sure they exist. */
1042         if (ast_strlen_zero(data)) {
1043                 return -1;
1044         }
1045         parse = ast_strdupa(data);
1046         AST_STANDARD_APP_ARGS(args, parse);
1047         if (ast_strlen_zero(args.type) || ast_strlen_zero(args.option)) {
1048                 return -1;
1049         }
1050
1051         ast_channel_lock(chan);
1052         datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
1053         if (!datastore) {
1054                 datastore = ast_datastore_alloc(&confbridge_datastore, NULL);
1055                 if (!datastore) {
1056                         ast_channel_unlock(chan);
1057                         return 0;
1058                 }
1059                 b_data = ast_calloc(1, sizeof(*b_data));
1060                 if (!b_data) {
1061                         ast_channel_unlock(chan);
1062                         ast_datastore_free(datastore);
1063                         return 0;
1064                 }
1065                 datastore->data = b_data;
1066                 b_data->b_profile.sounds = bridge_profile_sounds_alloc();
1067                 if (!b_data->b_profile.sounds) {
1068                         ast_channel_unlock(chan);
1069                         ast_datastore_free(datastore);
1070                         return 0;
1071                 }
1072                 if (!(b_data->menu = menu_alloc("dialplan"))) {
1073                         ast_channel_unlock(chan);
1074                         ast_datastore_free(datastore);
1075                         return 0;
1076                 }
1077                 ast_channel_datastore_add(chan, datastore);
1078         } else {
1079                 b_data = datastore->data;
1080         }
1081         ast_channel_unlock(chan);
1082
1083         /* SET(CONFBRIDGE(type,option)=value) */
1084         if (!value) {
1085                 value = "";
1086         }
1087         tmpvar.name = args.option;
1088         tmpvar.value = value;
1089         tmpvar.file = "CONFBRIDGE";
1090         if (!strcasecmp(args.type, "bridge")) {
1091                 if (!strcasecmp(args.option, "clear")) {
1092                         b_data->b_usable = 0;
1093                         conf_bridge_profile_destroy(&b_data->b_profile);
1094                         memset(&b_data->b_profile, 0, sizeof(b_data->b_profile)) ;
1095                         if (!(b_data->b_profile.sounds = bridge_profile_sounds_alloc())) {
1096                                 /* If this reallocation fails, the datastore has become unusable and must be destroyed. */
1097                                 ast_channel_lock(chan);
1098                                 ast_channel_datastore_remove(chan, datastore);
1099                                 ast_channel_unlock(chan);
1100                                 ast_datastore_free(datastore);
1101                         }
1102                         return 0;
1103                 }
1104
1105                 if (b_data && !b_data->b_usable && strcasecmp(args.option, "template")) {
1106                         template.value = DEFAULT_BRIDGE_PROFILE;
1107                         aco_process_var(&bridge_type, "dialplan", &template, &b_data->b_profile);
1108                 }
1109
1110                 if (!aco_process_var(&bridge_type, "dialplan", &tmpvar, &b_data->b_profile)) {
1111                         b_data->b_usable = 1;
1112                         return 0;
1113                 }
1114         } else if (!strcasecmp(args.type, "user")) {
1115                 if (!strcasecmp(args.option, "clear")) {
1116                         b_data->u_usable = 0;
1117                         user_profile_destructor(&b_data->u_profile);
1118                         memset(&b_data->u_profile, 0, sizeof(b_data->u_profile));
1119                         return 0;
1120                 }
1121
1122                 if (b_data && !b_data->u_usable && strcasecmp(args.option, "template")) {
1123                         template.value = DEFAULT_USER_PROFILE;
1124                         aco_process_var(&user_type, "dialplan", &template, &b_data->u_profile);
1125                 }
1126
1127                 if (!aco_process_var(&user_type, "dialplan", &tmpvar, &b_data->u_profile)) {
1128                         b_data->u_usable = 1;
1129                         return 0;
1130                 }
1131         } else if (!strcasecmp(args.type, "menu")) {
1132                 if (!strcasecmp(args.option, "clear")) {
1133                         b_data->m_usable = 0;
1134                         ao2_cleanup(b_data->menu);
1135                         if (!(b_data->menu = menu_alloc("dialplan"))) {
1136                                 /* If this reallocation fails, the datastore has become unusable and must be destroyed */
1137                                 ast_channel_lock(chan);
1138                                 ast_channel_datastore_remove(chan, datastore);
1139                                 ast_channel_unlock(chan);
1140                                 ast_datastore_free(datastore);
1141                         }
1142                         return 0;
1143                 }
1144
1145                 if (b_data && !b_data->m_usable && strcasecmp(args.option, "template")) {
1146                         template.value = DEFAULT_MENU_PROFILE;
1147                         aco_process_var(&menu_type, "dialplan", &template, &b_data->menu);
1148                 }
1149
1150                 if (!aco_process_var(&menu_type, "dialplan", &tmpvar, b_data->menu)) {
1151                         b_data->m_usable = 1;
1152                         return 0;
1153                 }
1154         }
1155
1156         ast_log(LOG_WARNING, "%s(%s,%s) cannot be set to '%s'. Invalid type, option, or value.\n",
1157                 cmd, args.type, args.option, value);
1158         return -1;
1159 }
1160
1161 static int add_action_to_menu_entry(struct conf_menu_entry *menu_entry, enum conf_menu_action_id id, char *databuf)
1162 {
1163         struct conf_menu_action *menu_action = ast_calloc(1, sizeof(*menu_action));
1164
1165         if (!menu_action) {
1166                 return -1;
1167         }
1168         menu_action->id = id;
1169
1170         switch (id) {
1171         case MENU_ACTION_NOOP:
1172         case MENU_ACTION_TOGGLE_MUTE:
1173         case MENU_ACTION_TOGGLE_BINAURAL:
1174         case MENU_ACTION_INCREASE_LISTENING:
1175         case MENU_ACTION_DECREASE_LISTENING:
1176         case MENU_ACTION_INCREASE_TALKING:
1177         case MENU_ACTION_DECREASE_TALKING:
1178         case MENU_ACTION_RESET_LISTENING:
1179         case MENU_ACTION_RESET_TALKING:
1180         case MENU_ACTION_ADMIN_TOGGLE_LOCK:
1181         case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS:
1182         case MENU_ACTION_PARTICIPANT_COUNT:
1183         case MENU_ACTION_ADMIN_KICK_LAST:
1184         case MENU_ACTION_LEAVE:
1185         case MENU_ACTION_SET_SINGLE_VIDEO_SRC:
1186         case MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC:
1187                 break;
1188         case MENU_ACTION_PLAYBACK:
1189         case MENU_ACTION_PLAYBACK_AND_CONTINUE:
1190                 if (!(ast_strlen_zero(databuf))) {
1191                         ast_copy_string(menu_action->data.playback_file, databuf, sizeof(menu_action->data.playback_file));
1192                 } else {
1193                         ast_free(menu_action);
1194                         return -1;
1195                 }
1196                 break;
1197         case MENU_ACTION_DIALPLAN_EXEC:
1198                 if (!(ast_strlen_zero(databuf))) {
1199                         AST_DECLARE_APP_ARGS(args,
1200                                 AST_APP_ARG(context);
1201                                 AST_APP_ARG(exten);
1202                                 AST_APP_ARG(priority);
1203                         );
1204                         AST_STANDARD_APP_ARGS(args, databuf);
1205                         if (!ast_strlen_zero(args.context)) {
1206                                 ast_copy_string(menu_action->data.dialplan_args.context,
1207                                         args.context,
1208                                         sizeof(menu_action->data.dialplan_args.context));
1209                         }
1210                         if (!ast_strlen_zero(args.exten)) {
1211                                 ast_copy_string(menu_action->data.dialplan_args.exten,
1212                                         args.exten,
1213                                         sizeof(menu_action->data.dialplan_args.exten));
1214                         }
1215                         menu_action->data.dialplan_args.priority = 1; /* 1 by default */
1216                         if (!ast_strlen_zero(args.priority) &&
1217                                 (sscanf(args.priority, "%30d", &menu_action->data.dialplan_args.priority) != 1)) {
1218                                 /* invalid priority */
1219                                 ast_free(menu_action);
1220                                 return -1;
1221                         }
1222                 } else {
1223                         ast_free(menu_action);
1224                         return -1;
1225                 }
1226         };
1227
1228         AST_LIST_INSERT_TAIL(&menu_entry->actions, menu_action, action);
1229
1230         return 0;
1231 }
1232
1233 static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char *action_names)
1234 {
1235         struct conf_menu_entry *menu_entry = NULL, *cur = NULL;
1236         int res = 0;
1237         char *tmp_action_names = ast_strdupa(action_names);
1238         char *action = NULL;
1239         char *action_args;
1240         char *tmp;
1241         char buf[PATH_MAX];
1242         char *delimiter = ",";
1243
1244         if (!(menu_entry = ast_calloc(1, sizeof(*menu_entry)))) {
1245                 return -1;
1246         }
1247
1248         for (;;) {
1249                 char *comma;
1250                 char *startbrace;
1251                 char *endbrace;
1252                 unsigned int action_len;
1253
1254                 if (ast_strlen_zero(tmp_action_names)) {
1255                         break;
1256                 }
1257                 startbrace = strchr(tmp_action_names, '(');
1258                 endbrace = strchr(tmp_action_names, ')');
1259                 comma = strchr(tmp_action_names, ',');
1260
1261                 /* If the next action has brackets with comma delimited arguments in it,
1262                  * make the delimeter ')' instead of a comma to preserve the argments */
1263                 if (startbrace && endbrace && comma && (comma > startbrace && comma < endbrace)) {
1264                         delimiter = ")";
1265                 } else {
1266                         delimiter = ",";
1267                 }
1268
1269                 if (!(action = strsep(&tmp_action_names, delimiter))) {
1270                         break;
1271                 }
1272
1273                 action = ast_strip(action);
1274                 if (ast_strlen_zero(action)) {
1275                         continue;
1276                 }
1277
1278                 action_len = strlen(action);
1279                 ast_copy_string(menu_entry->dtmf, dtmf, sizeof(menu_entry->dtmf));
1280                 if (!strcasecmp(action, "toggle_mute")) {
1281                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_TOGGLE_MUTE, NULL);
1282                 } else if (!strcasecmp(action, "toggle_binaural")) {
1283                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_TOGGLE_BINAURAL, NULL);
1284                 } else if (!strcasecmp(action, "no_op")) {
1285                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_NOOP, NULL);
1286                 } else if (!strcasecmp(action, "increase_listening_volume")) {
1287                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_INCREASE_LISTENING, NULL);
1288                 } else if (!strcasecmp(action, "decrease_listening_volume")) {
1289                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_DECREASE_LISTENING, NULL);
1290                 } else if (!strcasecmp(action, "increase_talking_volume")) {
1291                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_INCREASE_TALKING, NULL);
1292                 } else if (!strcasecmp(action, "reset_listening_volume")) {
1293                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_RESET_LISTENING, NULL);
1294                 } else if (!strcasecmp(action, "reset_talking_volume")) {
1295                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_RESET_TALKING, NULL);
1296                 } else if (!strcasecmp(action, "decrease_talking_volume")) {
1297                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_DECREASE_TALKING, NULL);
1298                 } else if (!strcasecmp(action, "admin_toggle_conference_lock")) {
1299                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_ADMIN_TOGGLE_LOCK, NULL);
1300                 } else if (!strcasecmp(action, "admin_toggle_mute_participants")) {
1301                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS, NULL);
1302                 } else if (!strcasecmp(action, "participant_count")) {
1303                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PARTICIPANT_COUNT, NULL);
1304                 } else if (!strcasecmp(action, "admin_kick_last")) {
1305                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_ADMIN_KICK_LAST, NULL);
1306                 } else if (!strcasecmp(action, "leave_conference")) {
1307                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_LEAVE, NULL);
1308                 } else if (!strcasecmp(action, "set_as_single_video_src")) {
1309                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_SET_SINGLE_VIDEO_SRC, NULL);
1310                 } else if (!strcasecmp(action, "release_as_single_video_src")) {
1311                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC, NULL);
1312                 } else if (!strncasecmp(action, "dialplan_exec(", 14)) {
1313                         ast_copy_string(buf, action, sizeof(buf));
1314                         action_args = buf;
1315                         if ((action_args = strchr(action, '('))) {
1316                                 action_args++;
1317                         }
1318                         /* it is possible that this argument may or may not
1319                          * have a closing brace at this point, it all depends on if
1320                          * comma delimited arguments were provided */
1321                         if ((tmp = strchr(action, ')'))) {
1322                                 *tmp = '\0';
1323                         }
1324                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_DIALPLAN_EXEC, action_args);
1325                 } else if (action_len >= 21 && !strncasecmp(action, "playback_and_continue(", 22)) {
1326                         ast_copy_string(buf, action, sizeof(buf));
1327                         action_args = buf;
1328                         if ((action_args = strchr(action, '(')) && (tmp = strrchr(action_args, ')'))) {
1329                                 *tmp = '\0';
1330                                 action_args++;
1331                         }
1332                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PLAYBACK_AND_CONTINUE, action_args);
1333                 } else if (action_len >= 8 && !strncasecmp(action, "playback(", 9)) {
1334                         ast_copy_string(buf, action, sizeof(buf));
1335                         action_args = buf;
1336                         if ((action_args = strchr(action, '(')) && (tmp = strrchr(action_args, ')'))) {
1337                                 *tmp = '\0';
1338                                 action_args++;
1339                         }
1340                         res |= add_action_to_menu_entry(menu_entry, MENU_ACTION_PLAYBACK, action_args);
1341                 }
1342         }
1343
1344         /* if adding any of the actions failed, bail */
1345         if (res) {
1346                 struct conf_menu_action *menu_action;
1347                 while ((menu_action = AST_LIST_REMOVE_HEAD(&menu_entry->actions, action))) {
1348                         ast_free(menu_action);
1349                 }
1350                 ast_free(menu_entry);
1351                 return -1;
1352         }
1353
1354         /* remove any list entry with an identical DTMF sequence for overrides */
1355         AST_LIST_TRAVERSE_SAFE_BEGIN(&menu->entries, cur, entry) {
1356                 if (!strcasecmp(cur->dtmf, menu_entry->dtmf)) {
1357                         AST_LIST_REMOVE_CURRENT(entry);
1358                         ast_free(cur);
1359                         break;
1360                 }
1361         }
1362         AST_LIST_TRAVERSE_SAFE_END;
1363
1364         AST_LIST_INSERT_TAIL(&menu->entries, menu_entry, entry);
1365
1366         return 0;
1367 }
1368
1369 static char *complete_user_profile_name(const char *line, const char *word, int pos, int state)
1370 {
1371         int which = 0;
1372         char *res = NULL;
1373         int wordlen = strlen(word);
1374         struct ao2_iterator i;
1375         struct user_profile *u_profile = NULL;
1376         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
1377
1378         if (!cfg) {
1379                 return NULL;
1380         }
1381
1382         i = ao2_iterator_init(cfg->user_profiles, 0);
1383         while ((u_profile = ao2_iterator_next(&i))) {
1384                 if (!strncasecmp(u_profile->name, word, wordlen) && ++which > state) {
1385                         res = ast_strdup(u_profile->name);
1386                         ao2_ref(u_profile, -1);
1387                         break;
1388                 }
1389                 ao2_ref(u_profile, -1);
1390         }
1391         ao2_iterator_destroy(&i);
1392
1393         return res;
1394 }
1395
1396 static char *handle_cli_confbridge_show_user_profiles(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1397 {
1398         struct ao2_iterator it;
1399         struct user_profile *u_profile;
1400         RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1401
1402         switch (cmd) {
1403         case CLI_INIT:
1404                 e->command = "confbridge show profile users";
1405                 e->usage =
1406                         "Usage: confbridge show profile users\n";
1407                 return NULL;
1408         case CLI_GENERATE:
1409                 return NULL;
1410         }
1411
1412         if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1413                 return NULL;
1414         }
1415
1416         ast_cli(a->fd,"--------- User Profiles -----------\n");
1417         ao2_lock(cfg->user_profiles);
1418         it = ao2_iterator_init(cfg->user_profiles, 0);
1419         while ((u_profile = ao2_iterator_next(&it))) {
1420                 ast_cli(a->fd,"%s\n", u_profile->name);
1421                 ao2_ref(u_profile, -1);
1422         }
1423         ao2_iterator_destroy(&it);
1424         ao2_unlock(cfg->user_profiles);
1425
1426         return CLI_SUCCESS;
1427 }
1428 static char *handle_cli_confbridge_show_user_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1429 {
1430         struct user_profile u_profile;
1431
1432         switch (cmd) {
1433         case CLI_INIT:
1434                 e->command = "confbridge show profile user";
1435                 e->usage =
1436                         "Usage: confbridge show profile user [<profile name>]\n";
1437                 return NULL;
1438         case CLI_GENERATE:
1439                 if (a->pos == 4) {
1440                         return complete_user_profile_name(a->line, a->word, a->pos, a->n);
1441                 }
1442                 return NULL;
1443         }
1444
1445         if (a->argc != 5) {
1446                 return CLI_SHOWUSAGE;
1447         }
1448
1449         if (!(conf_find_user_profile(NULL, a->argv[4], &u_profile))) {
1450                 ast_cli(a->fd, "No conference user profile named '%s' found!\n", a->argv[4]);
1451                 return CLI_SUCCESS;
1452         }
1453
1454         ast_cli(a->fd,"--------------------------------------------\n");
1455         ast_cli(a->fd,"Name:                    %s\n",
1456                 u_profile.name);
1457         ast_cli(a->fd,"Admin:                   %s\n",
1458                 u_profile.flags & USER_OPT_ADMIN ?
1459                 "true" : "false");
1460         ast_cli(a->fd,"Marked User:             %s\n",
1461                 u_profile.flags & USER_OPT_MARKEDUSER ?
1462                 "true" : "false");
1463         ast_cli(a->fd,"Start Muted:             %s\n",
1464                 u_profile.flags & USER_OPT_STARTMUTED?
1465                 "true" : "false");
1466         ast_cli(a->fd,"MOH When Empty:          %s\n",
1467                 u_profile.flags & USER_OPT_MUSICONHOLD ?
1468                 "enabled" : "disabled");
1469         ast_cli(a->fd,"MOH Class:               %s\n",
1470                 ast_strlen_zero(u_profile.moh_class) ?
1471                 "default" : u_profile.moh_class);
1472         ast_cli(a->fd,"Announcement:            %s\n",
1473                 u_profile.announcement);
1474         ast_cli(a->fd,"Quiet:                   %s\n",
1475                 u_profile.flags & USER_OPT_QUIET ?
1476                 "enabled" : "disabled");
1477         ast_cli(a->fd,"Wait Marked:             %s\n",
1478                 u_profile.flags & USER_OPT_WAITMARKED ?
1479                 "enabled" : "disabled");
1480         ast_cli(a->fd,"END Marked:              %s\n",
1481                 u_profile.flags & USER_OPT_ENDMARKED ?
1482                 "enabled" : "disabled");
1483         ast_cli(a->fd,"Drop_silence:            %s\n",
1484                 u_profile.flags & USER_OPT_DROP_SILENCE ?
1485                 "enabled" : "disabled");
1486         ast_cli(a->fd,"Silence Threshold:       %ums\n",
1487                 u_profile.silence_threshold);
1488         ast_cli(a->fd,"Talking Threshold:       %u\n",
1489                 u_profile.talking_threshold);
1490         ast_cli(a->fd,"Denoise:                 %s\n",
1491                 u_profile.flags & USER_OPT_DENOISE ?
1492                 "enabled" : "disabled");
1493         ast_cli(a->fd,"Jitterbuffer:            %s\n",
1494                 u_profile.flags & USER_OPT_JITTERBUFFER ?
1495                 "enabled" : "disabled");
1496         ast_cli(a->fd,"Talk Detect Events:      %s\n",
1497                 u_profile.flags & USER_OPT_TALKER_DETECT ?
1498                 "enabled" : "disabled");
1499         ast_cli(a->fd,"DTMF Pass Through:       %s\n",
1500                 u_profile.flags & USER_OPT_DTMF_PASS ?
1501                 "enabled" : "disabled");
1502         ast_cli(a->fd,"PIN:                     %s\n",
1503                 ast_strlen_zero(u_profile.pin) ?
1504                 "None" : u_profile.pin);
1505         ast_cli(a->fd,"Announce User Count:     %s\n",
1506                 u_profile.flags & USER_OPT_ANNOUNCEUSERCOUNT ?
1507                 "enabled" : "disabled");
1508         ast_cli(a->fd,"Announce join/leave:     %s\n",
1509                 u_profile.flags & (USER_OPT_ANNOUNCE_JOIN_LEAVE | USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW) ?
1510                 u_profile.flags & USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW ?
1511                 "enabled (with review)" : "enabled" : "disabled");
1512         ast_cli(a->fd,"Announce User Count all: %s\n",
1513                 u_profile.flags & USER_OPT_ANNOUNCEUSERCOUNTALL ?
1514                 "enabled" : "disabled");
1515                 ast_cli(a->fd,"\n");
1516
1517         return CLI_SUCCESS;
1518 }
1519
1520 static char *complete_bridge_profile_name(const char *line, const char *word, int pos, int state)
1521 {
1522         int which = 0;
1523         char *res = NULL;
1524         int wordlen = strlen(word);
1525         struct ao2_iterator i;
1526         struct bridge_profile *b_profile = NULL;
1527         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
1528
1529         if (!cfg) {
1530                 return NULL;
1531         }
1532
1533         i = ao2_iterator_init(cfg->bridge_profiles, 0);
1534         while ((b_profile = ao2_iterator_next(&i))) {
1535                 if (!strncasecmp(b_profile->name, word, wordlen) && ++which > state) {
1536                         res = ast_strdup(b_profile->name);
1537                         ao2_ref(b_profile, -1);
1538                         break;
1539                 }
1540                 ao2_ref(b_profile, -1);
1541         }
1542         ao2_iterator_destroy(&i);
1543
1544         return res;
1545 }
1546
1547 static char *handle_cli_confbridge_show_bridge_profiles(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1548 {
1549         struct ao2_iterator it;
1550         struct bridge_profile *b_profile;
1551         RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1552
1553         switch (cmd) {
1554         case CLI_INIT:
1555                 e->command = "confbridge show profile bridges";
1556                 e->usage =
1557                         "Usage: confbridge show profile bridges\n";
1558                 return NULL;
1559         case CLI_GENERATE:
1560                 return NULL;
1561         }
1562
1563         if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1564                 return NULL;
1565         }
1566
1567         ast_cli(a->fd,"--------- Bridge Profiles -----------\n");
1568         ao2_lock(cfg->bridge_profiles);
1569         it = ao2_iterator_init(cfg->bridge_profiles, 0);
1570         while ((b_profile = ao2_iterator_next(&it))) {
1571                 ast_cli(a->fd,"%s\n", b_profile->name);
1572                 ao2_ref(b_profile, -1);
1573         }
1574         ao2_iterator_destroy(&it);
1575         ao2_unlock(cfg->bridge_profiles);
1576
1577         return CLI_SUCCESS;
1578 }
1579
1580 static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1581 {
1582         struct bridge_profile b_profile;
1583         char tmp[64];
1584
1585         switch (cmd) {
1586         case CLI_INIT:
1587                 e->command = "confbridge show profile bridge";
1588                 e->usage =
1589                         "Usage: confbridge show profile bridge <profile name>\n";
1590                 return NULL;
1591         case CLI_GENERATE:
1592                 if (a->pos == 4) {
1593                         return complete_bridge_profile_name(a->line, a->word, a->pos, a->n);
1594                 }
1595                 return NULL;
1596         }
1597
1598         if (a->argc != 5) {
1599                 return CLI_SHOWUSAGE;
1600         }
1601
1602         if (!(conf_find_bridge_profile(NULL, a->argv[4], &b_profile))) {
1603                 ast_cli(a->fd, "No conference bridge profile named '%s' found!\n", a->argv[4]);
1604                 return CLI_SUCCESS;
1605         }
1606
1607         ast_cli(a->fd,"--------------------------------------------\n");
1608         ast_cli(a->fd,"Name:                 %s\n", b_profile.name);
1609         ast_cli(a->fd,"Language:             %s\n", b_profile.language);
1610
1611         if (b_profile.internal_sample_rate) {
1612                 snprintf(tmp, sizeof(tmp), "%u", b_profile.internal_sample_rate);
1613         } else {
1614                 ast_copy_string(tmp, "auto", sizeof(tmp));
1615         }
1616         ast_cli(a->fd,"Internal Sample Rate: %s\n", tmp);
1617
1618         if (b_profile.mix_interval) {
1619                 ast_cli(a->fd,"Mixing Interval:      %u\n", b_profile.mix_interval);
1620         } else {
1621                 ast_cli(a->fd,"Mixing Interval:      Default 20ms\n");
1622         }
1623
1624         ast_cli(a->fd,"Record Conference:    %s\n",
1625                 b_profile.flags & BRIDGE_OPT_RECORD_CONFERENCE ?
1626                 "yes" : "no");
1627
1628         ast_cli(a->fd,"Record File Append:    %s\n",
1629                 b_profile.flags & BRIDGE_OPT_RECORD_FILE_APPEND ?
1630                 "yes" : "no");
1631
1632         ast_cli(a->fd,"Record File Timestamp: %s\n",
1633                 b_profile.flags & BRIDGE_OPT_RECORD_FILE_TIMESTAMP ?
1634                 "yes" : "no");
1635
1636         ast_cli(a->fd,"Record File:          %s\n",
1637                 ast_strlen_zero(b_profile.rec_file) ? "Auto Generated" :
1638                 b_profile.rec_file);
1639
1640         ast_cli(a->fd,"Record Options:       %s\n",
1641                 b_profile.rec_options);
1642
1643         ast_cli(a->fd,"Record Command:       %s\n",
1644                 b_profile.rec_command);
1645
1646         if (b_profile.max_members) {
1647                 ast_cli(a->fd,"Max Members:          %u\n", b_profile.max_members);
1648         } else {
1649                 ast_cli(a->fd,"Max Members:          No Limit\n");
1650         }
1651
1652         ast_cli(a->fd,"Registration context: %s\n", b_profile.regcontext);
1653
1654         switch (b_profile.flags
1655                 & (BRIDGE_OPT_VIDEO_SRC_LAST_MARKED | BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED
1656                         | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
1657         case BRIDGE_OPT_VIDEO_SRC_LAST_MARKED:
1658                 ast_cli(a->fd, "Video Mode:           last_marked\n");
1659                 break;
1660         case BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED:
1661                 ast_cli(a->fd, "Video Mode:           first_marked\n");
1662                 break;
1663         case BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER:
1664                 ast_cli(a->fd, "Video Mode:           follow_talker\n");
1665                 break;
1666         case 0:
1667                 ast_cli(a->fd, "Video Mode:           no video\n");
1668                 break;
1669         default:
1670                 /* Opps.  We have more than one video mode flag set. */
1671                 ast_assert(0);
1672                 break;
1673         }
1674
1675         ast_cli(a->fd,"Video Update Discard: %u\n", b_profile.video_update_discard);
1676         ast_cli(a->fd,"REMB Send Interval: %u\n", b_profile.remb_send_interval);
1677
1678         ast_cli(a->fd,"sound_only_person:    %s\n", conf_get_sound(CONF_SOUND_ONLY_PERSON, b_profile.sounds));
1679         ast_cli(a->fd,"sound_only_one:       %s\n", conf_get_sound(CONF_SOUND_ONLY_ONE, b_profile.sounds));
1680         ast_cli(a->fd,"sound_has_joined:     %s\n", conf_get_sound(CONF_SOUND_HAS_JOINED, b_profile.sounds));
1681         ast_cli(a->fd,"sound_has_left:       %s\n", conf_get_sound(CONF_SOUND_HAS_LEFT, b_profile.sounds));
1682         ast_cli(a->fd,"sound_kicked:         %s\n", conf_get_sound(CONF_SOUND_KICKED, b_profile.sounds));
1683         ast_cli(a->fd,"sound_muted:          %s\n", conf_get_sound(CONF_SOUND_MUTED, b_profile.sounds));
1684         ast_cli(a->fd,"sound_unmuted:        %s\n", conf_get_sound(CONF_SOUND_UNMUTED, b_profile.sounds));
1685         ast_cli(a->fd,"sound_binaural_on:    %s\n", conf_get_sound(CONF_SOUND_BINAURAL_ON, b_profile.sounds));
1686         ast_cli(a->fd,"sound_binaural_off:   %s\n", conf_get_sound(CONF_SOUND_BINAURAL_OFF, b_profile.sounds));
1687         ast_cli(a->fd,"sound_there_are:      %s\n", conf_get_sound(CONF_SOUND_THERE_ARE, b_profile.sounds));
1688         ast_cli(a->fd,"sound_other_in_party: %s\n", conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, b_profile.sounds));
1689         ast_cli(a->fd,"sound_place_into_conference: %s\n", conf_get_sound(CONF_SOUND_PLACE_IN_CONF, b_profile.sounds));
1690         ast_cli(a->fd,"sound_wait_for_leader:       %s\n", conf_get_sound(CONF_SOUND_WAIT_FOR_LEADER, b_profile.sounds));
1691         ast_cli(a->fd,"sound_leader_has_left:       %s\n", conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, b_profile.sounds));
1692         ast_cli(a->fd,"sound_get_pin:        %s\n", conf_get_sound(CONF_SOUND_GET_PIN, b_profile.sounds));
1693         ast_cli(a->fd,"sound_invalid_pin:    %s\n", conf_get_sound(CONF_SOUND_INVALID_PIN, b_profile.sounds));
1694         ast_cli(a->fd,"sound_locked:         %s\n", conf_get_sound(CONF_SOUND_LOCKED, b_profile.sounds));
1695         ast_cli(a->fd,"sound_unlocked_now:   %s\n", conf_get_sound(CONF_SOUND_UNLOCKED_NOW, b_profile.sounds));
1696         ast_cli(a->fd,"sound_lockednow:      %s\n", conf_get_sound(CONF_SOUND_LOCKED_NOW, b_profile.sounds));
1697         ast_cli(a->fd,"sound_error_menu:     %s\n", conf_get_sound(CONF_SOUND_ERROR_MENU, b_profile.sounds));
1698         ast_cli(a->fd,"sound_join:           %s\n", conf_get_sound(CONF_SOUND_JOIN, b_profile.sounds));
1699         ast_cli(a->fd,"sound_leave:          %s\n", conf_get_sound(CONF_SOUND_LEAVE, b_profile.sounds));
1700         ast_cli(a->fd,"sound_participants_muted:     %s\n", conf_get_sound(CONF_SOUND_PARTICIPANTS_MUTED, b_profile.sounds));
1701         ast_cli(a->fd,"sound_participants_unmuted:     %s\n", conf_get_sound(CONF_SOUND_PARTICIPANTS_UNMUTED, b_profile.sounds));
1702         ast_cli(a->fd,"sound_begin:          %s\n", conf_get_sound(CONF_SOUND_BEGIN, b_profile.sounds));
1703         ast_cli(a->fd,"\n");
1704
1705         conf_bridge_profile_destroy(&b_profile);
1706         return CLI_SUCCESS;
1707 }
1708
1709 static char *complete_menu_name(const char *line, const char *word, int pos, int state)
1710 {
1711         int which = 0;
1712         char *res = NULL;
1713         int wordlen = strlen(word);
1714         struct ao2_iterator i;
1715         struct conf_menu *menu = NULL;
1716         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
1717
1718         if (!cfg) {
1719                 return NULL;
1720         }
1721
1722         i = ao2_iterator_init(cfg->menus, 0);
1723         while ((menu = ao2_iterator_next(&i))) {
1724                 if (!strncasecmp(menu->name, word, wordlen) && ++which > state) {
1725                         res = ast_strdup(menu->name);
1726                         ao2_ref(menu, -1);
1727                         break;
1728                 }
1729                 ao2_ref(menu, -1);
1730         }
1731         ao2_iterator_destroy(&i);
1732
1733         return res;
1734 }
1735
1736 static char *handle_cli_confbridge_show_menus(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1737 {
1738         struct ao2_iterator it;
1739         struct conf_menu *menu;
1740         RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1741
1742         switch (cmd) {
1743         case CLI_INIT:
1744                 e->command = "confbridge show menus";
1745                 e->usage =
1746                         "Usage: confbridge show profile menus\n";
1747                 return NULL;
1748         case CLI_GENERATE:
1749                 return NULL;
1750         }
1751
1752         if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1753                 return NULL;
1754         }
1755
1756         ast_cli(a->fd,"--------- Menus -----------\n");
1757         ao2_lock(cfg->menus);
1758         it = ao2_iterator_init(cfg->menus, 0);
1759         while ((menu = ao2_iterator_next(&it))) {
1760                 ast_cli(a->fd,"%s\n", menu->name);
1761                 ao2_ref(menu, -1);
1762         }
1763         ao2_iterator_destroy(&it);
1764         ao2_unlock(cfg->menus);
1765
1766         return CLI_SUCCESS;
1767 }
1768
1769 static char *handle_cli_confbridge_show_menu(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1770 {
1771         RAII_VAR(struct conf_menu *, menu, NULL, ao2_cleanup);
1772         RAII_VAR(struct confbridge_cfg *, cfg, NULL, ao2_cleanup);
1773         struct conf_menu_entry *menu_entry = NULL;
1774         struct conf_menu_action *menu_action = NULL;
1775
1776         switch (cmd) {
1777         case CLI_INIT:
1778                 e->command = "confbridge show menu";
1779                 e->usage =
1780                         "Usage: confbridge show menu [<menu name>]\n";
1781                 return NULL;
1782         case CLI_GENERATE:
1783                 if (a->pos == 3) {
1784                         return complete_menu_name(a->line, a->word, a->pos, a->n);
1785                 }
1786                 return NULL;
1787         }
1788
1789         if (a->argc != 4) {
1790                 return CLI_SHOWUSAGE;
1791         }
1792
1793         if (!(cfg = ao2_global_obj_ref(cfg_handle))) {
1794                 return NULL;
1795         }
1796
1797         if (!(menu = menu_find(cfg->menus, a->argv[3]))) {
1798                 ast_cli(a->fd, "No conference menu named '%s' found!\n", a->argv[3]);
1799                 return CLI_SUCCESS;
1800         }
1801         ao2_lock(menu);
1802
1803         ast_cli(a->fd,"Name: %s\n", menu->name);
1804         AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
1805                 int action_num = 0;
1806                 ast_cli(a->fd, "%s=", menu_entry->dtmf);
1807                 AST_LIST_TRAVERSE(&menu_entry->actions, menu_action, action) {
1808                         if (action_num) {
1809                                 ast_cli(a->fd, ", ");
1810                         }
1811                         switch (menu_action->id) {
1812                         case MENU_ACTION_TOGGLE_MUTE:
1813                                 ast_cli(a->fd, "toggle_mute");
1814                                 break;
1815                         case MENU_ACTION_TOGGLE_BINAURAL:
1816                                 ast_cli(a->fd, "toggle_binaural");
1817                                 break;
1818                         case MENU_ACTION_NOOP:
1819                                 ast_cli(a->fd, "no_op");
1820                                 break;
1821                         case MENU_ACTION_INCREASE_LISTENING:
1822                                 ast_cli(a->fd, "increase_listening_volume");
1823                                 break;
1824                         case MENU_ACTION_DECREASE_LISTENING:
1825                                 ast_cli(a->fd, "decrease_listening_volume");
1826                                 break;
1827                         case MENU_ACTION_RESET_LISTENING:
1828                                 ast_cli(a->fd, "reset_listening_volume");
1829                                 break;
1830                         case MENU_ACTION_RESET_TALKING:
1831                                 ast_cli(a->fd, "reset_talking_volume");
1832                                 break;
1833                         case MENU_ACTION_INCREASE_TALKING:
1834                                 ast_cli(a->fd, "increase_talking_volume");
1835                                 break;
1836                         case MENU_ACTION_DECREASE_TALKING:
1837                                 ast_cli(a->fd, "decrease_talking_volume");
1838                                 break;
1839                         case MENU_ACTION_PLAYBACK:
1840                                 ast_cli(a->fd, "playback(%s)", menu_action->data.playback_file);
1841                                 break;
1842                         case MENU_ACTION_PLAYBACK_AND_CONTINUE:
1843                                 ast_cli(a->fd, "playback_and_continue(%s)", menu_action->data.playback_file);
1844                                 break;
1845                         case MENU_ACTION_DIALPLAN_EXEC:
1846                                 ast_cli(a->fd, "dialplan_exec(%s,%s,%d)",
1847                                         menu_action->data.dialplan_args.context,
1848                                         menu_action->data.dialplan_args.exten,
1849                                         menu_action->data.dialplan_args.priority);
1850                                 break;
1851                         case MENU_ACTION_ADMIN_TOGGLE_LOCK:
1852                                 ast_cli(a->fd, "admin_toggle_conference_lock");
1853                                 break;
1854                         case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS:
1855                                 ast_cli(a->fd, "admin_toggle_mute_participants");
1856                                 break;
1857                         case MENU_ACTION_PARTICIPANT_COUNT:
1858                                 ast_cli(a->fd, "participant_count");
1859                                 break;
1860                         case MENU_ACTION_ADMIN_KICK_LAST:
1861                                 ast_cli(a->fd, "admin_kick_last");
1862                                 break;
1863                         case MENU_ACTION_LEAVE:
1864                                 ast_cli(a->fd, "leave_conference");
1865                                 break;
1866                         case MENU_ACTION_SET_SINGLE_VIDEO_SRC:
1867                                 ast_cli(a->fd, "set_as_single_video_src");
1868                                 break;
1869                         case MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC:
1870                                 ast_cli(a->fd, "release_as_single_video_src");
1871                                 break;
1872                         }
1873                         action_num++;
1874                 }
1875                 ast_cli(a->fd,"\n");
1876         }
1877
1878
1879         ao2_unlock(menu);
1880         return CLI_SUCCESS;
1881 }
1882
1883 static struct ast_cli_entry cli_confbridge_parser[] = {
1884         AST_CLI_DEFINE(handle_cli_confbridge_show_user_profile, "Show a conference user profile."),
1885         AST_CLI_DEFINE(handle_cli_confbridge_show_bridge_profile, "Show a conference bridge profile."),
1886         AST_CLI_DEFINE(handle_cli_confbridge_show_menu, "Show a conference menu"),
1887         AST_CLI_DEFINE(handle_cli_confbridge_show_user_profiles, "Show a list of conference user profiles."),
1888         AST_CLI_DEFINE(handle_cli_confbridge_show_bridge_profiles, "Show a list of conference bridge profiles."),
1889         AST_CLI_DEFINE(handle_cli_confbridge_show_menus, "Show a list of conference menus"),
1890
1891 };
1892
1893 static void confbridge_cfg_destructor(void *obj)
1894 {
1895         struct confbridge_cfg *cfg = obj;
1896         ao2_cleanup(cfg->user_profiles);
1897         ao2_cleanup(cfg->bridge_profiles);
1898         ao2_cleanup(cfg->menus);
1899 }
1900
1901 void *confbridge_cfg_alloc(void)
1902 {
1903         struct confbridge_cfg *cfg;
1904
1905         if (!(cfg = ao2_alloc(sizeof(*cfg), confbridge_cfg_destructor))) {
1906                 return NULL;
1907         }
1908
1909         if (!(cfg->user_profiles = ao2_container_alloc(283, user_hash_cb, user_cmp_cb))) {
1910                 goto error;
1911         }
1912
1913         if (!(cfg->bridge_profiles = ao2_container_alloc(283, bridge_hash_cb, bridge_cmp_cb))) {
1914                 goto error;
1915         }
1916
1917         if (!(cfg->menus = ao2_container_alloc(283, menu_hash_cb, menu_cmp_cb))) {
1918                 goto error;
1919         }
1920
1921         return cfg;
1922 error:
1923         ao2_ref(cfg, -1);
1924         return NULL;
1925 }
1926
1927 static int announce_user_count_all_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1928 {
1929         struct user_profile *u_profile = obj;
1930
1931         if (strcasecmp(var->name, "announce_user_count_all")) {
1932                 return -1;
1933         }
1934         if (ast_true(var->value)) {
1935                 u_profile->flags = u_profile->flags | USER_OPT_ANNOUNCEUSERCOUNTALL;
1936         } else if (ast_false(var->value)) {
1937                 u_profile->flags = u_profile->flags & ~USER_OPT_ANNOUNCEUSERCOUNTALL;
1938         } else if (sscanf(var->value, "%30u", &u_profile->announce_user_count_all_after) == 1) {
1939                 u_profile->flags = u_profile->flags | USER_OPT_ANNOUNCEUSERCOUNTALL;
1940         } else {
1941                 return -1;
1942         }
1943         return 0;
1944 }
1945
1946 static int mix_interval_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1947 {
1948         struct bridge_profile *b_profile = obj;
1949
1950         if (strcasecmp(var->name, "mixing_interval")) {
1951                 return -1;
1952         }
1953         if (sscanf(var->value, "%30u", &b_profile->mix_interval) != 1) {
1954                 return -1;
1955         }
1956         switch (b_profile->mix_interval) {
1957         case 10:
1958         case 20:
1959         case 40:
1960         case 80:
1961                 return 0;
1962         default:
1963                 return -1;
1964         }
1965 }
1966
1967 static int video_mode_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1968 {
1969         struct bridge_profile *b_profile = obj;
1970
1971         if (strcasecmp(var->name, "video_mode")) {
1972                 return -1;
1973         }
1974         if (!strcasecmp(var->value, "first_marked")) {
1975                 ast_set_flags_to(b_profile,
1976                         BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED
1977                                 | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED
1978                                 | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER
1979                                 | BRIDGE_OPT_VIDEO_SRC_SFU,
1980                         BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED);
1981         } else if (!strcasecmp(var->value, "last_marked")) {
1982                 ast_set_flags_to(b_profile,
1983                         BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED
1984                                 | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED
1985                                 | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER
1986                                 | BRIDGE_OPT_VIDEO_SRC_SFU,
1987                         BRIDGE_OPT_VIDEO_SRC_LAST_MARKED);
1988         } else if (!strcasecmp(var->value, "follow_talker")) {
1989                 ast_set_flags_to(b_profile,
1990                         BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED
1991                                 | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED
1992                                 | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER
1993                                 | BRIDGE_OPT_VIDEO_SRC_SFU,
1994                         BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER);
1995         } else if (!strcasecmp(var->value, "none")) {
1996                 ast_clear_flag(b_profile,
1997                         BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED
1998                                 | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED
1999                                 | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER
2000                                 | BRIDGE_OPT_VIDEO_SRC_SFU);
2001         } else if (!strcasecmp(var->value, "sfu")) {
2002                 ast_set_flags_to(b_profile,
2003                         BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED
2004                                 | BRIDGE_OPT_VIDEO_SRC_LAST_MARKED
2005                                 | BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER
2006                                 | BRIDGE_OPT_VIDEO_SRC_SFU,
2007                         BRIDGE_OPT_VIDEO_SRC_SFU);
2008         } else {
2009                 return -1;
2010         }
2011         return 0;
2012 }
2013
2014 static int user_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2015 {
2016         struct user_profile *u_profile = obj;
2017
2018         return conf_find_user_profile(NULL, var->value, u_profile) ? 0 : -1;
2019 }
2020
2021 static int bridge_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2022 {
2023         struct bridge_profile *b_profile = obj;
2024         struct bridge_profile_sounds *sounds = bridge_profile_sounds_alloc();
2025         struct bridge_profile_sounds *oldsounds = b_profile->sounds;
2026
2027         if (!sounds) {
2028                 return -1;
2029         }
2030         if (!(conf_find_bridge_profile(NULL, var->value, b_profile))) {
2031                 ao2_ref(sounds, -1);
2032                 return -1;
2033         }
2034         /* Using a bridge profile as a template is a little complicated due to the sounds. Since the sounds
2035          * structure of a dynamic profile will need to be altered, a completely new sounds structure must be
2036          * created instead of simply holding a reference to the one built by the config file. */
2037         ast_string_field_set(sounds, onlyperson, b_profile->sounds->onlyperson);
2038         ast_string_field_set(sounds, onlyone, b_profile->sounds->onlyone);
2039         ast_string_field_set(sounds, hasjoin, b_profile->sounds->hasjoin);
2040         ast_string_field_set(sounds, hasleft, b_profile->sounds->hasleft);
2041         ast_string_field_set(sounds, kicked, b_profile->sounds->kicked);
2042         ast_string_field_set(sounds, muted, b_profile->sounds->muted);
2043         ast_string_field_set(sounds, unmuted, b_profile->sounds->unmuted);
2044         ast_string_field_set(sounds, thereare, b_profile->sounds->thereare);
2045         ast_string_field_set(sounds, otherinparty, b_profile->sounds->otherinparty);
2046         ast_string_field_set(sounds, placeintoconf, b_profile->sounds->placeintoconf);
2047         ast_string_field_set(sounds, waitforleader, b_profile->sounds->waitforleader);
2048         ast_string_field_set(sounds, leaderhasleft, b_profile->sounds->leaderhasleft);
2049         ast_string_field_set(sounds, getpin, b_profile->sounds->getpin);
2050         ast_string_field_set(sounds, invalidpin, b_profile->sounds->invalidpin);
2051         ast_string_field_set(sounds, locked, b_profile->sounds->locked);
2052         ast_string_field_set(sounds, unlockednow, b_profile->sounds->unlockednow);
2053         ast_string_field_set(sounds, lockednow, b_profile->sounds->lockednow);
2054         ast_string_field_set(sounds, errormenu, b_profile->sounds->errormenu);
2055         ast_string_field_set(sounds, join, b_profile->sounds->join);
2056         ast_string_field_set(sounds, leave, b_profile->sounds->leave);
2057         ast_string_field_set(sounds, participantsmuted, b_profile->sounds->participantsmuted);
2058         ast_string_field_set(sounds, participantsunmuted, b_profile->sounds->participantsunmuted);
2059         ast_string_field_set(sounds, begin, b_profile->sounds->begin);
2060
2061         ao2_ref(b_profile->sounds, -1); /* sounds struct copied over to it from the template by reference only. */
2062         ao2_ref(oldsounds, -1);    /* original sounds struct we don't need anymore */
2063         b_profile->sounds = sounds;     /* the new sounds struct that is a deep copy of the one from the template. */
2064
2065         return 0;
2066 }
2067
2068 static int copy_menu_entry(struct conf_menu_entry *dst, struct conf_menu_entry *src)
2069 {
2070         struct conf_menu_action *menu_action;
2071         struct conf_menu_action *new_menu_action;
2072
2073         ast_copy_string(dst->dtmf, src->dtmf, sizeof(dst->dtmf));
2074         AST_LIST_HEAD_INIT_NOLOCK(&dst->actions);
2075
2076         AST_LIST_TRAVERSE(&src->actions, menu_action, action) {
2077                 if (!(new_menu_action = ast_calloc(1, sizeof(*new_menu_action)))) {
2078                         return -1;
2079                 }
2080                 memcpy(new_menu_action, menu_action, sizeof(*new_menu_action));
2081                 AST_LIST_NEXT(new_menu_action, action) = NULL;
2082                 AST_LIST_INSERT_TAIL(&dst->actions, new_menu_action, action);
2083         }
2084
2085         return 0;
2086 }
2087
2088 static int conf_menu_profile_copy(struct conf_menu *dst, struct conf_menu *src)
2089 {
2090         /* Copy each menu item to the dst struct */
2091         struct conf_menu_entry *cur;
2092
2093         AST_LIST_TRAVERSE(&src->entries, cur, entry) {
2094                 struct conf_menu_entry *cpy;
2095
2096                 if (!(cpy = ast_calloc(1, sizeof(*cpy)))) {
2097                         return -1;
2098                 }
2099
2100                 if (copy_menu_entry(cpy, cur)) {
2101                         conf_menu_entry_destroy(cpy);
2102                         ast_free(cpy);
2103                         return -1;
2104                 }
2105                 AST_LIST_INSERT_TAIL(&dst->entries, cpy, entry);
2106         }
2107
2108         return 0;
2109 }
2110
2111 static int menu_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2112 {
2113         struct conf_menu *dst_menu = obj;
2114         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
2115         RAII_VAR(struct conf_menu *, src_menu, NULL, ao2_cleanup);
2116
2117         if (!cfg) {
2118                 return 0;
2119         }
2120
2121         if (!(src_menu = ao2_find(cfg->menus, var->value, OBJ_KEY))) {
2122                 return -1;
2123         }
2124
2125         if (conf_menu_profile_copy(dst_menu, src_menu)) {
2126                 return -1;
2127         }
2128
2129         return 0;
2130 }
2131
2132 static int sound_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2133 {
2134         set_sound(var->name, var->value, obj);
2135         return 0;
2136 }
2137
2138 static int menu_option_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2139 {
2140         add_menu_entry(obj, var->name, var->value);
2141         return 0;
2142 }
2143
2144 static int verify_default_profiles(void)
2145 {
2146         RAII_VAR(struct user_profile *, user_profile, NULL, ao2_cleanup);
2147         RAII_VAR(struct bridge_profile *, bridge_profile, NULL, ao2_cleanup);
2148         RAII_VAR(struct conf_menu *, menu_profile, NULL, ao2_cleanup);
2149         /* We can only be called as a result of an aco_process_config so this is safe */
2150         struct confbridge_cfg *cfg = aco_pending_config(&cfg_info);
2151
2152         if (!cfg) {
2153                 return 0;
2154         }
2155
2156         bridge_profile = ao2_find(cfg->bridge_profiles, DEFAULT_BRIDGE_PROFILE, OBJ_KEY);
2157         if (!bridge_profile) {
2158                 bridge_profile = bridge_profile_alloc(DEFAULT_BRIDGE_PROFILE);
2159                 if (!bridge_profile) {
2160                         return -1;
2161                 }
2162                 ast_log(AST_LOG_NOTICE, "Adding %s profile to app_confbridge\n", DEFAULT_BRIDGE_PROFILE);
2163                 aco_set_defaults(&bridge_type, DEFAULT_BRIDGE_PROFILE, bridge_profile);
2164                 ao2_link(cfg->bridge_profiles, bridge_profile);
2165         }
2166
2167         user_profile = ao2_find(cfg->user_profiles, DEFAULT_USER_PROFILE, OBJ_KEY);
2168         if (!user_profile) {
2169                 user_profile = user_profile_alloc(DEFAULT_USER_PROFILE);
2170                 if (!user_profile) {
2171                         return -1;
2172                 }
2173                 ast_log(AST_LOG_NOTICE, "Adding %s profile to app_confbridge\n", DEFAULT_USER_PROFILE);
2174                 aco_set_defaults(&user_type, DEFAULT_USER_PROFILE, user_profile);
2175                 ao2_link(cfg->user_profiles, user_profile);
2176         }
2177
2178         menu_profile = ao2_find(cfg->menus, DEFAULT_MENU_PROFILE, OBJ_KEY);
2179         if (!menu_profile) {
2180                 menu_profile = menu_alloc(DEFAULT_MENU_PROFILE);
2181                 if (!menu_profile) {
2182                         return -1;
2183                 }
2184                 ast_log(AST_LOG_NOTICE, "Adding %s menu to app_confbridge\n", DEFAULT_MENU_PROFILE);
2185                 aco_set_defaults(&menu_type, DEFAULT_MENU_PROFILE, menu_profile);
2186                 ao2_link(cfg->menus, menu_profile);
2187         }
2188
2189         return 0;
2190 }
2191
2192 int conf_load_config(void)
2193 {
2194         if (aco_info_init(&cfg_info)) {
2195                 return -1;
2196         }
2197
2198         /* User options */
2199         aco_option_register(&cfg_info, "type", ACO_EXACT, user_types, NULL, OPT_NOOP_T, 0, 0);
2200         aco_option_register(&cfg_info, "admin", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ADMIN);
2201         aco_option_register(&cfg_info, "marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_MARKEDUSER);
2202         aco_option_register(&cfg_info, "startmuted", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_STARTMUTED);
2203         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);
2204         aco_option_register(&cfg_info, "quiet", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_QUIET);
2205         aco_option_register_custom(&cfg_info, "announce_user_count_all", ACO_EXACT, user_types, "no", announce_user_count_all_handler, 0);
2206         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);
2207         /* Negative logic. Defaults to "yes" and evaluates with ast_false(). If !ast_false(), USER_OPT_NOONLYPERSON is cleared */
2208         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);
2209         aco_option_register(&cfg_info, "wait_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_WAITMARKED);
2210         aco_option_register(&cfg_info, "end_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ENDMARKED);
2211         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);
2212         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);
2213         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);
2214         aco_option_register(&cfg_info, "announce_join_leave_review", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW);
2215         aco_option_register(&cfg_info, "pin", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, pin));
2216         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));
2217         aco_option_register(&cfg_info, "announcement", ACO_EXACT, user_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct user_profile, announcement));
2218         aco_option_register(&cfg_info, "denoise", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_DENOISE);
2219         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);
2220         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));
2221         aco_option_register(&cfg_info, "dsp_talking_threshold", ACO_EXACT, user_types, __stringify(DEFAULT_TALKING_THRESHOLD), OPT_UINT_T, 0, FLDSET(struct user_profile, talking_threshold));
2222         aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_JITTERBUFFER);
2223         aco_option_register(&cfg_info, "timeout", ACO_EXACT, user_types, "0", OPT_UINT_T, 0, FLDSET(struct user_profile, timeout));
2224         /* This option should only be used with the CONFBRIDGE dialplan function */
2225         aco_option_register_custom(&cfg_info, "template", ACO_EXACT, user_types, NULL, user_template_handler, 0);
2226
2227 /* XXX ASTERISK-21271 need a user supplied bridge merge_priority to merge ConfBridges (default = 1, range 1-INT_MAX) */
2228         /* Bridge options */
2229         aco_option_register(&cfg_info, "type", ACO_EXACT, bridge_types, NULL, OPT_NOOP_T, 0, 0);
2230         aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), USER_OPT_JITTERBUFFER);
2231         /* "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 */
2232         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);
2233         aco_option_register(&cfg_info, "binaural_active", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_BINAURAL_ACTIVE);
2234         aco_option_register_custom(&cfg_info, "mixing_interval", ACO_EXACT, bridge_types, "20", mix_interval_handler, 0);
2235         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);
2236         aco_option_register_custom(&cfg_info, "video_mode", ACO_EXACT, bridge_types, NULL, video_mode_handler, 0);
2237         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);
2238         aco_option_register(&cfg_info, "record_file_timestamp", ACO_EXACT, bridge_types, "yes", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_RECORD_FILE_TIMESTAMP);
2239         aco_option_register(&cfg_info, "max_members", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, max_members));
2240         aco_option_register(&cfg_info, "record_file", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_file));
2241         aco_option_register(&cfg_info, "record_options", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_options));
2242         aco_option_register(&cfg_info, "record_command", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, rec_command));
2243         aco_option_register(&cfg_info, "regcontext", ACO_EXACT, bridge_types, NULL, OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, regcontext));
2244         aco_option_register(&cfg_info, "language", ACO_EXACT, bridge_types, "en", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct bridge_profile, language));
2245         aco_option_register_custom(&cfg_info, "sound_", ACO_PREFIX, bridge_types, NULL, sound_option_handler, 0);
2246         aco_option_register(&cfg_info, "video_update_discard", ACO_EXACT, bridge_types, "2000", OPT_UINT_T, 0, FLDSET(struct bridge_profile, video_update_discard));
2247         aco_option_register(&cfg_info, "remb_send_interval", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, remb_send_interval));
2248         /* This option should only be used with the CONFBRIDGE dialplan function */
2249         aco_option_register_custom(&cfg_info, "template", ACO_EXACT, bridge_types, NULL, bridge_template_handler, 0);
2250
2251         /* Menu options */
2252         aco_option_register(&cfg_info, "type", ACO_EXACT, menu_types, NULL, OPT_NOOP_T, 0, 0);
2253         /* This option should only be used with the CONFBRIDGE dialplan function */
2254         aco_option_register_custom(&cfg_info, "template", ACO_EXACT, menu_types, NULL, menu_template_handler, 0);
2255         aco_option_register_custom(&cfg_info, "^[0-9A-D*#]+$", ACO_REGEX, menu_types, NULL, menu_option_handler, 0);
2256
2257         if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
2258                 goto error;
2259         }
2260
2261         if (ast_cli_register_multiple(cli_confbridge_parser, ARRAY_LEN(cli_confbridge_parser))) {
2262                 goto error;
2263         }
2264
2265         return 0;
2266 error:
2267         conf_destroy_config();
2268         return -1;
2269 }
2270
2271 int conf_reload_config(void)
2272 {
2273         if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
2274                 /* On a reload, just keep the config we already have in place. */
2275                 return -1;
2276         }
2277         return 0;
2278 }
2279
2280 static void conf_user_profile_copy(struct user_profile *dst, struct user_profile *src)
2281 {
2282         *dst = *src;
2283 }
2284
2285 const struct user_profile *conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result)
2286 {
2287         struct user_profile *tmp2;
2288         struct ast_datastore *datastore = NULL;
2289         struct func_confbridge_data *b_data = NULL;
2290         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
2291
2292         if (chan && ast_strlen_zero(user_profile_name)) {
2293                 ast_channel_lock(chan);
2294                 datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
2295                 ast_channel_unlock(chan);
2296                 if (datastore) {
2297                         b_data = datastore->data;
2298                         if (b_data->u_usable) {
2299                                 conf_user_profile_copy(result, &b_data->u_profile);
2300                                 return result;
2301                         }
2302                 }
2303         }
2304
2305         if (!cfg) {
2306                 return NULL;
2307         }
2308         if (ast_strlen_zero(user_profile_name)) {
2309                 user_profile_name = DEFAULT_USER_PROFILE;
2310         }
2311         if (!(tmp2 = ao2_find(cfg->user_profiles, user_profile_name, OBJ_KEY))) {
2312                 return NULL;
2313         }
2314         ao2_lock(tmp2);
2315         conf_user_profile_copy(result, tmp2);
2316         ao2_unlock(tmp2);
2317         ao2_ref(tmp2, -1);
2318
2319         return result;
2320 }
2321
2322 void conf_bridge_profile_copy(struct bridge_profile *dst, struct bridge_profile *src)
2323 {
2324         *dst = *src;
2325         if (src->sounds) {
2326                 ao2_ref(src->sounds, +1);
2327         }
2328 }
2329
2330 void conf_bridge_profile_destroy(struct bridge_profile *b_profile)
2331 {
2332         if (b_profile->sounds) {
2333                 ao2_ref(b_profile->sounds, -1);
2334                 b_profile->sounds = NULL;
2335         }
2336 }
2337
2338 const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan, const char *bridge_profile_name, struct bridge_profile *result)
2339 {
2340         struct bridge_profile *tmp2;
2341         struct ast_datastore *datastore = NULL;
2342         struct func_confbridge_data *b_data = NULL;
2343         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
2344
2345         if (chan && ast_strlen_zero(bridge_profile_name)) {
2346                 ast_channel_lock(chan);
2347                 datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
2348                 ast_channel_unlock(chan);
2349                 if (datastore) {
2350                         b_data = datastore->data;
2351                         if (b_data->b_usable) {
2352                                 conf_bridge_profile_copy(result, &b_data->b_profile);
2353                                 return result;
2354                         }
2355                 }
2356         }
2357
2358         if (!cfg) {
2359                 return NULL;
2360         }
2361         if (ast_strlen_zero(bridge_profile_name)) {
2362                 bridge_profile_name = DEFAULT_BRIDGE_PROFILE;
2363         }
2364         if (!(tmp2 = ao2_find(cfg->bridge_profiles, bridge_profile_name, OBJ_KEY))) {
2365                 return NULL;
2366         }
2367         ao2_lock(tmp2);
2368         conf_bridge_profile_copy(result, tmp2);
2369         ao2_unlock(tmp2);
2370         ao2_ref(tmp2, -1);
2371
2372         return result;
2373 }
2374
2375 struct dtmf_menu_hook_pvt {
2376         struct confbridge_user *user;
2377         struct conf_menu_entry menu_entry;
2378         struct conf_menu *menu;
2379 };
2380
2381 static void menu_hook_destroy(void *hook_pvt)
2382 {
2383         struct dtmf_menu_hook_pvt *pvt = hook_pvt;
2384         struct conf_menu_action *action = NULL;
2385
2386         ao2_cleanup(pvt->menu);
2387
2388         while ((action = AST_LIST_REMOVE_HEAD(&pvt->menu_entry.actions, action))) {
2389                 ast_free(action);
2390         }
2391         ast_free(pvt);
2392 }
2393
2394 static int menu_hook_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
2395 {
2396         struct dtmf_menu_hook_pvt *pvt = hook_pvt;
2397
2398         return conf_handle_dtmf(bridge_channel, pvt->user, &pvt->menu_entry, pvt->menu);
2399 }
2400
2401 void conf_menu_entry_destroy(struct conf_menu_entry *menu_entry)
2402 {
2403         struct conf_menu_action *menu_action = NULL;
2404         while ((menu_action = AST_LIST_REMOVE_HEAD(&menu_entry->actions, action))) {
2405                 ast_free(menu_action);
2406         }
2407 }
2408
2409 int conf_find_menu_entry_by_sequence(const char *dtmf_sequence, struct conf_menu *menu, struct conf_menu_entry *result)
2410 {
2411         struct conf_menu_entry *menu_entry = NULL;
2412
2413         ao2_lock(menu);
2414         AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
2415                 if (!strcasecmp(menu_entry->dtmf, dtmf_sequence)) {
2416                         copy_menu_entry(result, menu_entry);
2417                         ao2_unlock(menu);
2418                         return 1;
2419                 }
2420         }
2421         ao2_unlock(menu);
2422
2423         return 0;
2424 }
2425
2426 static int apply_menu_to_user(struct confbridge_user *user, struct conf_menu *menu)
2427 {
2428         struct conf_menu_entry *menu_entry;
2429
2430         SCOPED_AO2LOCK(menu_lock, menu);
2431         AST_LIST_TRAVERSE(&menu->entries, menu_entry, entry) {
2432                 struct dtmf_menu_hook_pvt *pvt;
2433
2434                 if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
2435                         return -1;
2436                 }
2437                 pvt->user = user;
2438                 pvt->menu = ao2_bump(menu);
2439
2440                 if (copy_menu_entry(&pvt->menu_entry, menu_entry)) {
2441                         menu_hook_destroy(pvt);
2442                         return -1;
2443                 }
2444
2445                 if (ast_bridge_dtmf_hook(&user->features, pvt->menu_entry.dtmf,
2446                         menu_hook_callback, pvt, menu_hook_destroy, 0)) {
2447                         menu_hook_destroy(pvt);
2448                 }
2449         }
2450         strcpy(user->menu_name, menu->name); /* Safe */
2451
2452         return 0;
2453 }
2454
2455 int conf_set_menu_to_user(struct ast_channel *chan, struct confbridge_user *user, const char *menu_profile_name)
2456 {
2457         RAII_VAR(struct confbridge_cfg *, cfg, ao2_global_obj_ref(cfg_handle), ao2_cleanup);
2458         RAII_VAR(struct conf_menu *, menu, NULL, ao2_cleanup);
2459
2460         if (chan && ast_strlen_zero(menu_profile_name)) {
2461                 struct ast_datastore *datastore;
2462                 struct func_confbridge_data *b_data;
2463
2464                 ast_channel_lock(chan);
2465                 datastore = ast_channel_datastore_find(chan, &confbridge_datastore, NULL);
2466                 ast_channel_unlock(chan);
2467                 if (datastore) {
2468                         /* If a menu exists in the CONFBRIDGE function datastore, use it. */
2469                         b_data = datastore->data;
2470                         if (b_data->m_usable) {
2471                                 menu = ao2_bump(b_data->menu);
2472                                 return apply_menu_to_user(user, menu);
2473                         }
2474                 }
2475         }
2476
2477         /* Otherwise, we need to get whatever menu profile is specified to use (or default). */
2478         if (!cfg) {
2479                 return -1;
2480         }
2481
2482         if (ast_strlen_zero(menu_profile_name)) {
2483                 menu_profile_name = DEFAULT_MENU_PROFILE;
2484         }
2485
2486         if (!(menu = ao2_find(cfg->menus, menu_profile_name, OBJ_KEY))) {
2487                 return -1;
2488         }
2489
2490         return apply_menu_to_user(user, menu);
2491 }
2492
2493 void conf_destroy_config(void)
2494 {
2495         ast_cli_unregister_multiple(cli_confbridge_parser, ARRAY_LEN(cli_confbridge_parser));
2496         aco_info_destroy(&cfg_info);
2497         ao2_global_obj_release(cfg_handle);
2498 }