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