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