bridge_features: Support One touch Monitor/MixMonitor
[asterisk/asterisk.git] / main / features_config.c
1 /*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Mark Michelson <mmichelson@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 #include "asterisk.h"
20
21 #include "asterisk/features_config.h"
22 #include "asterisk/config_options.h"
23 #include "asterisk/datastore.h"
24 #include "asterisk/channel.h"
25 #include "asterisk/pbx.h"
26 #include "asterisk/app.h"
27 #include "asterisk/cli.h"
28
29 /*** DOCUMENTATION
30         <configInfo name="features" language="en_US">
31                 <synopsis>Features Configuration</synopsis>
32                 <configFile name="features.conf">
33                         <configObject name="globals">
34                                 <synopsis>
35                                 </synopsis>
36                                 <configOption name="featuredigittimeout" default="1000">
37                                         <synopsis>Milliseconds allowed between digit presses when entering a feature code.</synopsis>
38                                 </configOption>
39                                 <configOption name="courtesytone">
40                                         <synopsis>Sound to play when automon or automixmon is activated</synopsis>
41                                 </configOption>
42                                 <configOption name="recordingfailsound">
43                                         <synopsis>Sound to play when automon or automixmon is attempted but fails to start</synopsis>
44                                 </configOption>
45                                 <configOption name="transferdigittimeout" default="3000">
46                                         <synopsis>Milliseconds allowed between digit presses when dialing a transfer destination</synopsis>
47                                 </configOption>
48                                 <configOption name="atxfernoanswertimeout" default="15000">
49                                         <synopsis>Milliseconds to wait for attended transfer destination to answer</synopsis>
50                                 </configOption>
51                                 <configOption name="atxferdropcall" default="no">
52                                         <synopsis>Hang up the call entirely if the attended transfer fails</synopsis>
53                                         <description>
54                                                 <para>When this option is set to <literal>no</literal>, then Asterisk will attempt to
55                                                 re-call the transferrer if the call to the transfer target fails. If the call to the
56                                                 transferrer fails, then Asterisk will wait <replaceable>atxferloopdelay</replaceable>
57                                                 milliseconds and then attempt to dial the transfer target again. This process will
58                                                 repeat until <replaceable>atxfercallbackretries</replaceable> attempts to re-call
59                                                 the transferrer have occurred.</para>
60                                                 <para>When this option is set to <literal>yes</literal>, then Asterisk will not attempt
61                                                 to re-call the transferrer if the call to the transfer target fails. Asterisk will instead
62                                                 hang up all channels involved in the transfer.</para>
63                                         </description>
64                                 </configOption>
65                                 <configOption name="atxferloopdelay" default="10000">
66                                         <synopsis>Milliseconds to wait between attempts to re-dial transfer destination</synopsis>
67                                         <see-also><ref type="configOption">atxferdropcall</ref></see-also>
68                                 </configOption>
69                                 <configOption name="atxfercallbackretries" default="2">
70                                         <synopsis>Number of times to re-attempt dialing a transfer destination</synopsis>
71                                         <see-also><ref type="configOption">atxferdropcall</ref></see-also>
72                                 </configOption>
73                                 <configOption name="xfersound" default="beep">
74                                         <synopsis>Sound to play to during transfer and transfer-like operations.</synopsis>
75                                         <description>
76                                                 <para>This sound will play to the transferrer and transfer target channels when
77                                                 an attended transfer completes. This sound is also played to channels when performing
78                                                 an AMI <literal>Bridge</literal> action.</para>
79                                         </description>
80                                 </configOption>
81                                 <configOption name="xferfailsound" default="beeperr">
82                                         <synopsis>Sound to play to a transferee when a transfer fails</synopsis>
83                                 </configOption>
84                                 <configOption name="atxferabort" default="*1">
85                                         <synopsis>Digits to dial to abort an attended transfer attempt</synopsis>
86                                         <description>
87                                                 <para>This option is only available to the transferrer during an attended
88                                                 transfer operation. Aborting a transfer results in the transfer being cancelled and
89                                                 the original parties in the call being re-bridged.</para>
90                                         </description>
91                                 </configOption>
92                                 <configOption name="atxfercomplete" default="*2">
93                                         <synopsis>Digits to dial to complete an attended transfer</synopsis>
94                                         <description>
95                                                 <para>This option is only available to the transferrer during an attended
96                                                 transfer operation. Completing the transfer with a DTMF sequence is functionally
97                                                 equivalent to hanging up the transferrer channel during an attended transfer. The
98                                                 result is that the transfer target and transferees are bridged.</para>
99                                         </description>
100                                 </configOption>
101                                 <configOption name="atxferthreeway" default="*3">
102                                         <synopsis>Digits to dial to change an attended transfer into a three-way call</synopsis>
103                                         <description>
104                                                 <para>This option is only available to the transferrer during an attended
105                                                 transfer operation. Pressing this DTMF sequence will result in the transferrer,
106                                                 the transferees, and the transfer target all being in a single bridge together.</para>
107                                         </description>
108                                 </configOption>
109                                 <configOption name="pickupexten" default="*8">
110                                         <synopsis>Digits used for picking up ringing calls</synopsis>
111                                         <description>
112                                                 <para>In order for the pickup attempt to be successful, the party attempting to
113                                                 pick up the call must either have a <replaceable>namedpickupgroup</replaceable> in
114                                                 common with a ringing party's <replaceable>namedcallgroup</replaceable> or must
115                                                 have a <replaceable>pickupgroup</replaceable> in common with a ringing party's
116                                                 <replaceable>callgroup</replaceable>.</para>
117                                         </description>
118                                 </configOption>
119                                 <configOption name="pickupsound">
120                                         <synopsis>Sound to play to picker when a call is picked up</synopsis>
121                                 </configOption>
122                                 <configOption name="pickupfailsound">
123                                         <synopsis>Sound to play to picker when a call cannot be picked up</synopsis>
124                                 </configOption>
125                         </configObject>
126                         <configObject name="featuremap">
127                                 <synopsis>DTMF options that can be triggered during bridged calls</synopsis>
128                                 <configOption name="atxfer">
129                                         <synopsis>DTMF sequence to initiate an attended transfer</synopsis>
130                                         <description>
131                                                 <para>The transferee parties will be placed on hold and the
132                                                 transferrer may dial an extension to reach a transfer target. During an
133                                                 attended transfer, the transferrer may consult with the transfer target
134                                                 before completing the transfer. Once the transferrer has hung up or pressed
135                                                 the <replaceable>atxfercomplete</replaceable> DTMF sequence, then the transferees
136                                                 and transfer target will be bridged.</para>
137                                         </description>
138                                 </configOption>
139                                 <configOption name="blindxfer" default="#">
140                                         <synopsis>DTMF sequence to initiate a blind transfer</synopsis>
141                                         <description>
142                                                 <para>The transferee parties will be placed on hold and the
143                                                 transferrer may dial an extension to reach a transfer target. During a
144                                                 blind transfer, as soon as the transfer target is dialed, the transferrer
145                                                 is hung up.</para>
146                                         </description>
147                                 </configOption>
148                                 <configOption name="disconnect" default="*">
149                                         <synopsis>DTMF sequence to disconnect the current call</synopsis>
150                                         <description>
151                                                 <para>Entering this DTMF sequence will cause the bridge to end, no
152                                                 matter the number of parties present</para>
153                                         </description>
154                                 </configOption>
155                                 <configOption name="parkcall">
156                                         <synopsis>DTMF sequence to park a call</synopsis>
157                                         <description>
158                                                 <para>The parking lot used to park the call is determined by using either the
159                                                 <replaceable>PARKINGLOT</replaceable> channel variable or a configured value on
160                                                 the channel (provided by the channel driver) if the variable is not present. If
161                                                 no configured value on the channel is present, then <literal>"default"</literal>
162                                                 is used. The call is parked in the next available space in the parking lot.</para>
163                                         </description>
164                                 </configOption>
165                                 <configOption name="automon">
166                                         <synopsis>DTMF sequence to start or stop monitoring a call</synopsis>
167                                         <description>
168                                                 <para>This will cause the channel that pressed the DTMF sequence
169                                                 to be monitored by the <literal>Monitor</literal> application. The
170                                                 format for the recording is determined by the <replaceable>TOUCH_MONITOR_FORMAT</replaceable>
171                                                 channel variable. If this variable is not specified, then <literal>wav</literal> is the
172                                                 default. The filename is constructed in the following manner:</para>
173                                                         
174                                                 <para>    prefix-timestamp-filename</para>
175
176                                                 <para>where prefix is either the value of the <replaceable>TOUCH_MONITOR_PREFIX</replaceable>
177                                                 channel variable or <literal>auto</literal> if the variable is not set. The timestamp
178                                                 is a UNIX timestamp. The filename is either the value of the <replaceable>TOUCH_MONITOR</replaceable>
179                                                 channel variable or the callerID of the channels if the variable is not set.</para>
180                                         </description>
181                                 </configOption>
182                                 <configOption name="automixmon">
183                                         <synopsis>DTMF sequence to start or stop mixmonitoring a call </synopsis>
184                                         <description>
185                                                 <para>Operation of the automixmon is similar to the <literal> automon </literal>
186                                                 feature, with the following exceptions:
187                                                         <replaceable>TOUCH_MIXMONITOR</replaceable> is used in place of <replaceable>TOUCH_MONITOR</replaceable>
188                                                         <replaceable>TOUCH_MIXMONITOR_FORMAT</replaceable> is used in place of <replaceable>TOUCH_MIXMONITOR</replaceable>
189                                                         There is no equivalent for <replaceable>TOUCH_MONITOR_PREFIX</replaceable>. <literal>"auto"</literal> is always how the filename begins.</para>
190                                         </description>
191                                         <see-also><ref type="configOption">automon</ref></see-also>
192                                 </configOption>
193                         </configObject>
194                         <configObject name="applicationmap">
195                                 <synopsis>Section for defining custom feature invocations during a call</synopsis>
196                                 <description>
197                                         <para>The applicationmap is an area where new custom features can be created. Items
198                                         defined in the applicationmap are not automatically accessible to bridged parties. Access
199                                         to the individual items is controled using the <replaceable>DYNAMIC_FEATURES</replaceable> channel variable.
200                                         The <replaceable>DYNAMIC_FEATURES</replaceable> is a <literal>#</literal> separated list of
201                                         either applicationmap item names or featuregroup names.</para>
202                                 </description>
203                                 <configOption name="^.*$" regex="true">
204                                         <synopsis>A custom feature to invoke during a bridged call</synopsis>
205                                         <description>
206                                                 <para>Each item listed here is a comma-separated list of parameters that determine
207                                                 how a feature may be invoked during a call</para>
208                                                 <para>    Example:</para>
209                                                 <para>    eggs = *5,self,Playback(hello-world),default</para>
210                                                 <para>This would create a feature called <literal>eggs</literal> that could be invoked
211                                                 during a call by pressing the <literal>*5</literal>. The party that presses the DTMF
212                                                 sequence would then trigger the <literal>Playback</literal> application to play the
213                                                 <literal>hello-world</literal> file. The application invocation would happen on the
214                                                 party that pressed the DTMF sequence since <literal>self</literal> is specified. The
215                                                 other parties in the bridge would hear the <literal>default</literal> music on hold
216                                                 class during the playback.</para>
217                                                 <para>In addition to the syntax outlined in this documentation, a backwards-compatible alternative
218                                                 is also allowed. The following applicationmap lines are functionally identical:</para>
219                                                 <para>    eggs = *5,self,Playback(hello-world),default</para>
220                                                 <para>    eggs = *5,self,Playback,hello-world,default</para>
221                                                 <para>    eggs = *5,self,Playback,"hello-world",default</para>
222                                         </description>
223                                         <syntax argsep=",">
224                                                 <parameter name="dtmf" required="true">
225                                                         <para>The DTMF sequence used to trigger the option</para>
226                                                 </parameter>
227                                                 <parameter name="activate_on" required="true">
228                                                         <para>The party that the feature will be invoked on</para>
229                                                         <optionlist>
230                                                                 <option name="self"><para>Feature is invoked on party that presses the DTMF sequence</para></option>
231                                                                 <option name="peer"><para>Feature is invoked on other parties in the bridge</para></option>
232                                                         </optionlist>
233                                                 </parameter>
234                                                 <parameter name="app" required="true">
235                                                         <para>The dialplan application to run when the DTMF sequence is pressed</para>
236                                                         <argument name="app_args" required="false">
237                                                                 <para>The arguments to the dialplan application to run</para>
238                                                         </argument>
239                                                 </parameter>
240                                                 <parameter name="moh_class" required="false">
241                                                         <para>Music on hold class to play to bridge participants that are not the target of the application invocation</para>
242                                                 </parameter>
243                                         </syntax>
244                                 </configOption>
245                         </configObject>
246                         <configObject name="featuregroup">
247                                 <synopsis>Groupings of items from the applicationmap</synopsis>
248                                 <description>
249                                         <para>Feature groups allow for multiple applicationmap items to be
250                                         grouped together. Like with individual applicationmap items, feature groups
251                                         can be part of the <replaceable>DYNAMIC_FEATURES</replaceable> channel variable.
252                                         In addition to creating groupings, the feature group section allows for the
253                                         DTMF sequence used to invoke an applicationmap item to be overridden with
254                                         a different sequence.</para>
255                                 </description>
256                                 <configOption name="^.*$" regex="true">
257                                         <synopsis>Applicationmap item to place in the feature group</synopsis>
258                                         <description>
259                                                 <para>Each item here must be a name of an item in the applicationmap. The
260                                                 argument may either be a new DTMF sequence to use for the item or it
261                                                 may be left blank in order to use the DTMF sequence specified in the
262                                                 applicationmap. For example:</para>
263                                                 <para>  eggs => *1</para>
264                                                 <para>  bacon =></para>
265                                                 <para>would result in the applicationmap items <literal>eggs</literal> and
266                                                 <literal>bacon</literal> being in the featuregroup. The former would have its
267                                                 default DTMF trigger overridden with <literal>*1</literal> and the latter would
268                                                 have the DTMF value specified in the applicationmap.</para>
269                                         </description>
270                                 </configOption>
271                         </configObject>
272                 </configFile>
273         </configInfo>
274         <function name="FEATURE" language="en_US">
275                 <synopsis>
276                         Get or set a feature option on a channel.
277                 </synopsis>
278                 <syntax>
279                         <parameter name="option_name" required="true">
280                                 <para>The allowed values are:</para>
281                                 <enumlist>
282                                         <enum name="inherit"><para>Inherit feature settings made in FEATURE or FEATUREMAP to child channels.</para></enum>
283                                         <enum name="featuredigittimeout"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='featuredigittimeout']/synopsis/text())" /></para></enum>
284                                         <enum name="transferdigittimeout"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferdigittimeout']/synopsis/text())" /></para></enum>
285                                         <enum name="atxfernoanswertimeout"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxfernoanswertimeout']/synopsis/text())" /></para></enum>
286                                         <enum name="atxferdropcall"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxferdropcall']/synopsis/text())" /></para></enum>
287                                         <enum name="atxferloopdelay"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxferloopdelay']/synopsis/text())" /></para></enum>
288                                         <enum name="atxfercallbackretries"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxfercallbackretries']/synopsis/text())" /></para></enum>
289                                         <enum name="xfersound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='xfersound']/synopsis/text())" /></para></enum>
290                                         <enum name="xferfailsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='xferfailsound']/synopsis/text())" /></para></enum>
291                                         <enum name="atxferabort"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxferabort']/synopsis/text())" /></para></enum>
292                                         <enum name="atxfercomplete"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxfercomplete']/synopsis/text())" /></para></enum>
293                                         <enum name="atxferthreeway"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxferthreeway']/synopsis/text())" /></para></enum>
294                                         <enum name="pickupexten"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='pickupexten']/synopsis/text())" /></para></enum>
295                                         <enum name="pickupsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='pickupsound']/synopsis/text())" /></para></enum>
296                                         <enum name="pickupfailsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='pickupfailsound']/synopsis/text())" /></para></enum>
297                                         <enum name="courtesytone"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='courtesytone']/synopsis/text())" /></para></enum>
298                                         <enum name="recordingfailsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='recordingfailsound']/synopsis/text())" /></para></enum>
299                                 </enumlist>
300                         </parameter>
301                 </syntax>
302                 <description>
303                         <para>When this function is used as a read, it will get the current
304                         value of the specified feature option for this channel.  It will be
305                         the value of this option configured in features.conf if a channel specific
306                         value has not been set.  This function can also be used to set a channel
307                         specific value for the supported feature options.</para>
308                 </description>
309                 <see-also>
310                         <ref type="function">FEATUREMAP</ref>
311                 </see-also>
312         </function>
313         <function name="FEATUREMAP" language="en_US">
314                 <synopsis>
315                         Get or set a feature map to a given value on a specific channel.
316                 </synopsis>
317                 <syntax>
318                         <parameter name="feature_name" required="true">
319                                 <para>The allowed values are:</para>
320                                 <enumlist>
321                                         <enum name="atxfer"><para>Attended Transfer</para></enum>
322                                         <enum name="blindxfer"><para>Blind Transfer</para></enum>
323                                         <enum name="automon"><para>Auto Monitor</para></enum>
324                                         <enum name="disconnect"><para>Call Disconnect</para></enum>
325                                         <enum name="parkcall"><para>Park Call</para></enum>
326                                         <enum name="automixmon"><para>Auto MixMonitor</para></enum>
327                                 </enumlist>
328                         </parameter>
329                 </syntax>
330                 <description>
331                         <para>When this function is used as a read, it will get the current
332                         digit sequence mapped to the specified feature for this channel.  This
333                         value will be the one configured in features.conf if a channel specific
334                         value has not been set.  This function can also be used to set a channel
335                         specific value for a feature mapping.</para>
336                 </description>
337                 <see-also>
338                         <ref type="function">FEATURE</ref>
339                 </see-also>
340         </function>
341  ***/
342 /*! Default general options */
343 #define DEFAULT_FEATURE_DIGIT_TIMEOUT               1000
344 #define DEFAULT_COURTESY_TONE                       ""
345 #define DEFAULT_RECORDING_FAIL_SOUND                ""
346
347 /*! Default xfer options */
348 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT              3000
349 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER  15000
350 #define DEFAULT_ATXFER_DROP_CALL                    0
351 #define DEFAULT_ATXFER_LOOP_DELAY                   10000
352 #define DEFAULT_ATXFER_CALLBACK_RETRIES             2
353 #define DEFAULT_XFERSOUND                           "beep"
354 #define DEFAULT_XFERFAILSOUND                       "beeperr"
355 #define DEFAULT_ATXFER_ABORT                        "*1"
356 #define DEFAULT_ATXFER_COMPLETE                     "*2"
357 #define DEFAULT_ATXFER_THREEWAY                     "*3"
358
359 /*! Default pickup options */
360 #define DEFAULT_PICKUPEXTEN                         "*8"
361 #define DEFAULT_PICKUPSOUND                         ""
362 #define DEFAULT_PICKUPFAILSOUND                     ""
363
364 /*! Default featuremap options */
365 #define DEFAULT_FEATUREMAP_BLINDXFER                "#"
366 #define DEFAULT_FEATUREMAP_DISCONNECT               "*"
367 #define DEFAULT_FEATUREMAP_AUTOMON                  ""
368 #define DEFAULT_FEATUREMAP_ATXFER                   ""
369 #define DEFAULT_FEATUREMAP_PARKCALL                 ""
370 #define DEFAULT_FEATUREMAP_AUTOMIXMON               ""
371
372 /*!
373  * \brief Configuration from the "general" section of features.conf
374  */
375 struct features_global_config {
376         struct ast_features_general_config *general;
377         struct ast_features_xfer_config *xfer;
378         struct ast_features_pickup_config *pickup;
379 };
380
381 static void ast_applicationmap_item_destructor(void *obj)
382 {
383         struct ast_applicationmap_item *item = obj;
384
385         ast_string_field_free_memory(item);
386 }
387
388 static int applicationmap_sort(const void *obj, const void *arg, int flags)
389 {
390         const struct ast_applicationmap_item *item1 = obj;
391         const struct ast_applicationmap_item *item2;
392         const char *key2;
393
394         switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
395         case OBJ_KEY:
396                 key2 = arg;
397                 return strcasecmp(item1->name, key2);
398         case OBJ_PARTIAL_KEY:
399                 key2 = arg;
400                 return strncasecmp(item1->name, key2, strlen(key2));
401         default:
402         case OBJ_POINTER:
403                 item2 = arg;
404                 return strcasecmp(item1->name, item2->name);
405         }
406 }
407
408 /*!
409  * \brief Entry in the container of featuregroups
410  */
411 struct featuregroup_item {
412         AST_DECLARE_STRING_FIELDS(
413                 /*! The name of the applicationmap item that we are referring to */
414                 AST_STRING_FIELD(appmap_item_name);
415                 /*! Custom DTMF override to use instead of the default for the applicationmap item */
416                 AST_STRING_FIELD(dtmf_override);
417         );
418         /*! The applicationmap item that is being referred to */
419         struct ast_applicationmap_item *appmap_item;
420 };
421
422 static void featuregroup_item_destructor(void *obj)
423 {
424         struct featuregroup_item *item = obj;
425
426         ast_string_field_free_memory(item);
427         ao2_cleanup(item->appmap_item);
428 }
429
430 static int group_item_sort(const void *obj, const void *arg, int flags)
431 {
432         const struct featuregroup_item *item1 = obj;
433         const struct featuregroup_item *item2;
434         const char *key2;
435
436         switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
437         case OBJ_KEY:
438                 key2 = arg;
439                 return strcasecmp(item1->appmap_item_name, key2);
440         case OBJ_PARTIAL_KEY:
441                 key2 = arg;
442                 return strncasecmp(item1->appmap_item_name, key2, strlen(key2));
443         case OBJ_POINTER:
444                 item2 = arg;
445                 return strcasecmp(item1->appmap_item_name, item2->appmap_item_name);
446         default:
447                 return CMP_STOP;
448         }
449 }
450
451 /*!
452  * \brief Featuregroup representation
453  */
454 struct featuregroup {
455         /*! The name of the featuregroup */
456         const char *name;
457         /*! A container of featuregroup_items */
458         struct ao2_container *items;
459 };
460
461 static int featuregroup_hash(const void *obj, int flags)
462 {
463         const struct featuregroup *group;
464         const char *key;
465
466         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
467         case OBJ_KEY:
468                 key = obj;
469                 return ast_str_case_hash(key);
470         case OBJ_PARTIAL_KEY:
471                 ast_assert(0);
472                 return 0;
473         case OBJ_POINTER:
474         default:
475                 group = obj;
476                 return ast_str_case_hash(group->name);
477         }
478 }
479
480 static int featuregroup_cmp(void *obj, void *arg, int flags)
481 {
482         struct featuregroup *group1 = obj;
483         struct featuregroup *group2;
484         const char *key2;
485
486         switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
487         case OBJ_KEY:
488                 key2 = arg;
489                 return strcasecmp(group1->name, key2) ? 0 : CMP_MATCH;
490         case OBJ_PARTIAL_KEY:
491                 key2 = arg;
492                 return strncasecmp(group1->name, key2, strlen(key2)) ? 0 : CMP_MATCH;
493         case OBJ_POINTER:
494                 group2 = arg;
495                 return strcasecmp(group1->name, group2->name) ? 0 : CMP_MATCH;
496         default:
497                 return CMP_STOP;
498         }
499 }
500
501 static void *featuregroup_find(struct ao2_container *group_container, const char *category)
502 {
503         return ao2_find(group_container, category, OBJ_KEY);
504 }
505
506 static void featuregroup_destructor(void *obj)
507 {
508         struct featuregroup *group = obj;
509
510         ast_free((char *) group->name);
511         ao2_cleanup(group->items);
512 }
513
514 static void *featuregroup_alloc(const char *cat)
515 {
516         struct featuregroup *group;
517
518         group = ao2_alloc(sizeof(*group), featuregroup_destructor);
519         if (!group) {
520                 return NULL;
521         }
522
523         group->name = ast_strdup(cat);
524         if (!group->name) {
525                 ao2_cleanup(group);
526                 return NULL;
527         }
528
529         group->items = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
530                 AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, group_item_sort, NULL);
531         if (!group->items) {
532                 ao2_cleanup(group);
533                 return NULL;
534         }
535
536         return group;
537 }
538
539 struct features_config {
540         struct features_global_config *global;
541         struct ast_featuremap_config *featuremap;
542         struct ao2_container *applicationmap;
543         struct ao2_container *featuregroups;
544 };
545
546 static struct aco_type global_option = {
547         .type = ACO_GLOBAL,
548         .name = "globals",
549         .category_match = ACO_WHITELIST,
550         .category = "^general$",
551         .item_offset = offsetof(struct features_config, global),
552 };
553
554 static struct aco_type featuremap_option = {
555         .type = ACO_GLOBAL,
556         .name = "featuremap",
557         .category_match = ACO_WHITELIST,
558         .category = "^featuremap$",
559         .item_offset = offsetof(struct features_config, featuremap),
560 };
561
562 static struct aco_type applicationmap_option = {
563         .type = ACO_GLOBAL,
564         .name = "applicationmap",
565         .category_match = ACO_WHITELIST,
566         .category = "^applicationmap$",
567         .item_offset = offsetof(struct features_config, applicationmap),
568 };
569
570 static struct aco_type featuregroup_option = {
571         .type = ACO_ITEM,
572         .name = "featuregroup",
573         .category_match = ACO_BLACKLIST,
574         .category = "^(general|featuremap|applicationmap|parkinglot_.*)$",
575         .item_offset = offsetof(struct features_config, featuregroups),
576         .item_alloc = featuregroup_alloc,
577         .item_find = featuregroup_find,
578 };
579
580 static struct aco_type *global_options[] = ACO_TYPES(&global_option);
581 static struct aco_type *featuremap_options[] = ACO_TYPES(&featuremap_option);
582 static struct aco_type *applicationmap_options[] = ACO_TYPES(&applicationmap_option);
583 static struct aco_type *featuregroup_options[] = ACO_TYPES(&featuregroup_option);
584
585 static struct aco_file features_conf = {
586         .filename = "features.conf",
587         .types = ACO_TYPES(&global_option, &featuremap_option, &applicationmap_option, &featuregroup_option),
588 };
589
590 AO2_GLOBAL_OBJ_STATIC(globals);
591
592 static void features_config_destructor(void *obj)
593 {
594         struct features_config *cfg = obj;
595
596         ao2_cleanup(cfg->global);
597         ao2_cleanup(cfg->featuremap);
598         ao2_cleanup(cfg->applicationmap);
599         ao2_cleanup(cfg->featuregroups);
600 }
601
602 static void featuremap_config_destructor(void *obj)
603 {
604         struct ast_featuremap_config *cfg = obj;
605
606         ast_string_field_free_memory(cfg);
607 }
608
609 static void global_config_destructor(void *obj)
610 {
611         struct features_global_config *cfg = obj;
612
613         ao2_cleanup(cfg->general);
614         ao2_cleanup(cfg->xfer);
615         ao2_cleanup(cfg->pickup);
616 }
617
618 static void general_destructor(void *obj)
619 {
620         struct ast_features_general_config *cfg = obj;
621
622         ast_string_field_free_memory(cfg);
623 }
624
625 static void xfer_destructor(void *obj)
626 {
627         struct ast_features_xfer_config *cfg = obj;
628
629         ast_string_field_free_memory(cfg);
630 }
631
632 static void pickup_destructor(void *obj)
633 {
634         struct ast_features_pickup_config *cfg = obj;
635
636         ast_string_field_free_memory(cfg);
637 }
638
639 static struct features_global_config *global_config_alloc(void)
640 {
641         RAII_VAR(struct features_global_config *, cfg, NULL, ao2_cleanup);
642
643         cfg = ao2_alloc(sizeof(*cfg), global_config_destructor);
644         if (!cfg) {
645                 return NULL;
646         }
647
648         cfg->general = ao2_alloc(sizeof(*cfg->general), general_destructor);
649         if (!cfg->general || ast_string_field_init(cfg->general, 32)) {
650                 return NULL;
651         }
652
653         cfg->xfer = ao2_alloc(sizeof(*cfg->xfer), xfer_destructor);
654         if (!cfg->xfer || ast_string_field_init(cfg->xfer, 32)) {
655                 return NULL;
656         }
657
658         cfg->pickup = ao2_alloc(sizeof(*cfg->pickup), pickup_destructor);
659         if (!cfg->pickup || ast_string_field_init(cfg->pickup, 32)) {
660                 return NULL;
661         }
662
663         ao2_ref(cfg, +1);
664         return cfg;
665 }
666
667 static struct ao2_container *applicationmap_alloc(int replace_duplicates)
668 {
669         return ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
670                 replace_duplicates ? AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE : AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW,
671                 applicationmap_sort, NULL);
672 }
673
674 /*!
675  * \internal
676  * \brief Allocate the major configuration structure
677  *
678  * The parameter is used to determine if the applicationmap and featuregroup
679  * structures should be allocated. We only want to allocate these structures for
680  * the global features_config structure. For the datastores on channels, we don't
681  * need to allocate these structures because they are not used.
682  *
683  * \param allocate_applicationmap See previous explanation
684  * \retval NULL Failed to alloate configuration
685  * \retval non-NULL Allocated configuration
686  */
687 static struct features_config *__features_config_alloc(int allocate_applicationmap)
688 {
689         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
690
691         cfg = ao2_alloc(sizeof(*cfg), features_config_destructor);
692         if (!cfg) {
693                 return NULL;
694         }
695
696         cfg->global = global_config_alloc();;
697         if (!cfg->global) {
698                 return NULL;
699         }
700
701         cfg->featuremap = ao2_alloc(sizeof(*cfg->featuremap), featuremap_config_destructor);
702         if (!cfg->featuremap || ast_string_field_init(cfg->featuremap, 32)) {
703                 return NULL;
704         }
705
706         if (allocate_applicationmap) {
707                 cfg->applicationmap = applicationmap_alloc(1);
708                 if (!cfg->applicationmap) {
709                         return NULL;
710                 }
711
712                 cfg->featuregroups = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 11, featuregroup_hash,
713                         featuregroup_cmp);
714                 if (!cfg->featuregroups) {
715                         return NULL;
716                 }
717         }
718
719         ao2_ref(cfg, +1);
720         return cfg;
721
722 }
723
724 static void *features_config_alloc(void)
725 {
726         return __features_config_alloc(1);
727 }
728
729 static void general_copy(struct ast_features_general_config *dest, const struct ast_features_general_config *src)
730 {
731         ast_string_fields_copy(dest, src);
732         dest->featuredigittimeout = src->featuredigittimeout;
733 }
734
735 static void xfer_copy(struct ast_features_xfer_config *dest, const struct ast_features_xfer_config *src)
736 {
737         ast_string_fields_copy(dest, src);
738         dest->transferdigittimeout = src->transferdigittimeout;
739         dest->atxfernoanswertimeout = src->atxfernoanswertimeout;
740         dest->atxferloopdelay = src->atxferloopdelay;
741         dest->atxfercallbackretries = src->atxfercallbackretries;
742         dest->atxferdropcall = src->atxferdropcall;
743 }
744
745 static void pickup_copy(struct ast_features_pickup_config *dest, const struct ast_features_pickup_config *src)
746 {
747         ast_string_fields_copy(dest, src);
748 }
749
750 static void global_copy(struct features_global_config *dest, const struct features_global_config *src)
751 {
752         general_copy(dest->general, src->general);
753         xfer_copy(dest->xfer, src->xfer);
754         pickup_copy(dest->pickup, src->pickup);
755 }
756
757 static void featuremap_copy(struct ast_featuremap_config *dest, const struct ast_featuremap_config *src)
758 {
759         ast_string_fields_copy(dest, src);
760 }
761
762 static void features_copy(struct features_config *dest, const struct features_config *src)
763 {
764         global_copy(dest->global, src->global);
765         featuremap_copy(dest->featuremap, src->featuremap);
766
767         /* applicationmap and featuregroups are purposely not copied. A channel's applicationmap
768          * is produced on the fly when ast_get_chan_applicationmap() is called
769          */
770 }
771
772 static struct features_config *features_config_dup(const struct features_config *orig)
773 {
774         struct features_config *dup;
775
776         dup = __features_config_alloc(0);
777         if (!dup) {
778                 return NULL;
779         }
780
781         features_copy(dup, orig);
782
783         return dup;
784 }
785
786 static int general_set(struct ast_features_general_config *general, const char *name,
787                 const char *value)
788 {
789         int res = 0;
790
791         if (!strcasecmp(name, "featuredigittimeout")) {
792                 res = ast_parse_arg(value, PARSE_INT32, &general->featuredigittimeout);
793         } else if (!strcasecmp(name, "courtesytone")) {
794                 ast_string_field_set(general, courtesytone, value);
795         } else if (!strcasecmp(name, "recordingfailsound")) {
796                 ast_string_field_set(general, recordingfailsound, value);
797         } else {
798                 /* Unrecognized option */
799                 res = -1;
800         }
801
802         return res;
803 }
804
805 static int general_get(struct ast_features_general_config *general, const char *field,
806                 char *buf, size_t len)
807 {
808         int res = 0;
809
810         if (!strcasecmp(field, "featuredigittimeout")) {
811                 snprintf(buf, len, "%u", general->featuredigittimeout);
812         } else if (!strcasecmp(field, "courtesytone")) {
813                 ast_copy_string(buf, general->courtesytone, len);
814         } else if (!strcasecmp(field, "recordingfailsound")) {
815                 ast_copy_string(buf, general->recordingfailsound, len);
816         } else {
817                 /* Unrecognized option */
818                 res = -1;
819         }
820
821         return res;
822 }
823
824 static int xfer_set(struct ast_features_xfer_config *xfer, const char *name,
825                 const char *value)
826 {
827         int res = 0;
828
829         if (!strcasecmp(name, "transferdigittimeout")) {
830                 res = ast_parse_arg(value, PARSE_INT32, &xfer->transferdigittimeout);
831         } else if (!strcasecmp(name, "atxfernoanswertimeout")) {
832                 res = ast_parse_arg(value, PARSE_INT32, &xfer->atxfernoanswertimeout);
833         } else if (!strcasecmp(name, "atxferloopdelay")) {
834                 res = ast_parse_arg(value, PARSE_INT32, &xfer->atxferloopdelay);
835         } else if (!strcasecmp(name, "atxfercallbackretries")) {
836                 res = ast_parse_arg(value, PARSE_INT32, &xfer->atxfercallbackretries);
837         } else if (!strcasecmp(name, "atxferdropcall")) {
838                 xfer->atxferdropcall = ast_true(value);
839         } else if (!strcasecmp(name, "xfersound")) {
840                 ast_string_field_set(xfer, xfersound, value);
841         } else if (!strcasecmp(name, "xferfailsound")) {
842                 ast_string_field_set(xfer, xferfailsound, value);
843         } else if (!strcasecmp(name, "atxferabort")) {
844                 ast_string_field_set(xfer, atxferabort, value);
845         } else if (!strcasecmp(name, "atxfercomplete")) {
846                 ast_string_field_set(xfer, atxfercomplete, value);
847         } else if (!strcasecmp(name, "atxferthreeway")) {
848                 ast_string_field_set(xfer, atxferthreeway, value);
849         } else {
850                 /* Unrecognized option */
851                 res = -1;
852         }
853
854         return res;
855 }
856
857 static int xfer_get(struct ast_features_xfer_config *xfer, const char *field,
858                 char *buf, size_t len)
859 {
860         int res = 0;
861
862         if (!strcasecmp(field, "transferdigittimeout")) {
863                 snprintf(buf, len, "%u", xfer->transferdigittimeout);
864         } else if (!strcasecmp(field, "atxfernoanswertimeout")) {
865                 snprintf(buf, len, "%u", xfer->atxfernoanswertimeout);
866         } else if (!strcasecmp(field, "atxferloopdelay")) {
867                 snprintf(buf, len, "%u", xfer->atxferloopdelay);
868         } else if (!strcasecmp(field, "atxfercallbackretries")) {
869                 snprintf(buf, len, "%u", xfer->atxfercallbackretries);
870         } else if (!strcasecmp(field, "atxferdropcall")) {
871                 snprintf(buf, len, "%u", xfer->atxferdropcall);
872         } else if (!strcasecmp(field, "xfersound")) {
873                 ast_copy_string(buf, xfer->xfersound, len);
874         } else if (!strcasecmp(field, "xferfailsound")) {
875                 ast_copy_string(buf, xfer->xferfailsound, len);
876         } else if (!strcasecmp(field, "atxferabort")) {
877                 ast_copy_string(buf, xfer->atxferabort, len);
878         } else if (!strcasecmp(field, "atxfercomplete")) {
879                 ast_copy_string(buf, xfer->atxfercomplete, len);
880         } else if (!strcasecmp(field, "atxferthreeway")) {
881                 ast_copy_string(buf, xfer->atxferthreeway, len);
882         } else {
883                 /* Unrecognized option */
884                 res = -1;
885         }
886
887         return res;
888 }
889
890 static int pickup_set(struct ast_features_pickup_config *pickup, const char *name,
891                 const char *value)
892 {
893         int res = 0;
894
895         if (!strcasecmp(name, "pickupsound")) {
896                 ast_string_field_set(pickup, pickupsound, value);
897         } else if (!strcasecmp(name, "pickupfailsound")) {
898                 ast_string_field_set(pickup, pickupfailsound, value);
899         } else if (!strcasecmp(name, "pickupexten")) {
900                 ast_string_field_set(pickup, pickupexten, value);
901         } else {
902                 /* Unrecognized option */
903                 res = -1;
904         }
905
906         return res;
907 }
908
909 static int pickup_get(struct ast_features_pickup_config *pickup, const char *field,
910                 char *buf, size_t len)
911 {
912         int res = 0;
913
914         if (!strcasecmp(field, "pickupsound")) {
915                 ast_copy_string(buf, pickup->pickupsound, len);
916         } else if (!strcasecmp(field, "pickupfailsound")) {
917                 ast_copy_string(buf, pickup->pickupfailsound, len);
918         } else if (!strcasecmp(field, "pickupexten")) {
919                 ast_copy_string(buf, pickup->pickupexten, len);
920         } else {
921                 /* Unrecognized option */
922                 res = -1;
923         }
924
925         return res;
926 }
927
928 static int featuremap_set(struct ast_featuremap_config *featuremap, const char *name,
929                 const char *value)
930 {
931         int res = 0;
932
933         if (!strcasecmp(name, "blindxfer")) {
934                 ast_string_field_set(featuremap, blindxfer, value);
935         } else if (!strcasecmp(name, "disconnect")) {
936                 ast_string_field_set(featuremap, disconnect, value);
937         } else if (!strcasecmp(name, "automon")) {
938                 ast_string_field_set(featuremap, automon, value);
939         } else if (!strcasecmp(name, "atxfer")) {
940                 ast_string_field_set(featuremap, atxfer, value);
941         } else if (!strcasecmp(name, "automixmon")) {
942                 ast_string_field_set(featuremap, automixmon, value);
943         } else if (!strcasecmp(name, "parkcall")) {
944                 ast_string_field_set(featuremap, parkcall, value);
945         } else {
946                 /* Unrecognized option */
947                 res = -1;
948         }
949
950         return res;
951 }
952
953 static int featuremap_get(struct ast_featuremap_config *featuremap, const char *field,
954                 char *buf, size_t len)
955 {
956         int res = 0;
957
958         if (!strcasecmp(field, "blindxfer")) {
959                 ast_copy_string(buf, featuremap->blindxfer, len);
960         } else if (!strcasecmp(field, "disconnect")) {
961                 ast_copy_string(buf, featuremap->disconnect, len);
962         } else if (!strcasecmp(field, "automon")) {
963                 ast_copy_string(buf, featuremap->automon, len);
964         } else if (!strcasecmp(field, "atxfer")) {
965                 ast_copy_string(buf, featuremap->atxfer, len);
966         } else if (!strcasecmp(field, "automixmon")) {
967                 ast_copy_string(buf, featuremap->automixmon, len);
968         } else if (!strcasecmp(field, "parkcall")) {
969                 ast_copy_string(buf, featuremap->parkcall, len);
970         } else {
971                 /* Unrecognized option */
972                 res = -1;
973         }
974
975         return res;
976 }
977
978 static void feature_ds_destroy(void *data)
979 {
980         struct features_config *cfg = data;
981         ao2_cleanup(cfg);
982 }
983
984 static void *feature_ds_duplicate(void *data)
985 {
986         struct features_config *old_cfg = data;
987
988         return features_config_dup(old_cfg);
989 }
990
991 static const struct ast_datastore_info feature_ds_info = {
992         .type = "FEATURE",
993         .destroy = feature_ds_destroy,
994         .duplicate = feature_ds_duplicate,
995 };
996
997 /*!
998  * \internal
999  * \brief Find or create feature datastore on a channel
1000  *
1001  * \pre chan is locked
1002  *
1003  * \return the data on the FEATURE datastore, or NULL on error
1004  */
1005 static struct features_config *get_feature_ds(struct ast_channel *chan)
1006 {
1007         RAII_VAR(struct features_config *, orig, NULL, ao2_cleanup);
1008         struct features_config *cfg;
1009         struct ast_datastore *ds;
1010
1011         if ((ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
1012                 cfg = ds->data;
1013                 ao2_ref(cfg, +1);
1014                 return cfg;
1015         }
1016
1017         orig = ao2_global_obj_ref(globals);
1018         if (!orig) {
1019                 return NULL;
1020         }
1021
1022         cfg = features_config_dup(orig);
1023         if (!cfg) {
1024                 return NULL;
1025         }
1026
1027         if (!(ds = ast_datastore_alloc(&feature_ds_info, NULL))) {
1028                 ao2_cleanup(cfg);
1029                 return NULL;
1030         }
1031
1032         /* Give the datastore a reference to the config */
1033         ao2_ref(cfg, +1);
1034         ds->data = cfg;
1035
1036         ast_channel_datastore_add(chan, ds);
1037
1038         return cfg;
1039 }
1040
1041 static struct ast_datastore *get_feature_chan_ds(struct ast_channel *chan)
1042 {
1043         struct ast_datastore *ds;
1044
1045         if (!(ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
1046                 /* Hasn't been created yet.  Trigger creation. */
1047                 RAII_VAR(struct features_config *, cfg, get_feature_ds(chan), ao2_cleanup);
1048                 ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL);
1049         }
1050
1051         return ds;
1052 }
1053
1054 struct ast_features_general_config *ast_get_chan_features_general_config(struct ast_channel *chan)
1055 {
1056         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1057
1058         if (chan) {
1059                 cfg = get_feature_ds(chan);
1060         } else {
1061                 cfg = ao2_global_obj_ref(globals);
1062         }
1063
1064         if (!cfg) {
1065                 return NULL;
1066         }
1067
1068         ast_assert(cfg->global && cfg->global->general);
1069
1070         ao2_ref(cfg->global->general, +1);
1071         return cfg->global->general;
1072 }
1073
1074 struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_channel *chan)
1075 {
1076         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1077
1078         if (chan) {
1079                 cfg = get_feature_ds(chan);
1080         } else {
1081                 cfg = ao2_global_obj_ref(globals);
1082         }
1083
1084         if (!cfg) {
1085                 return NULL;
1086         }
1087
1088         ast_assert(cfg->global && cfg->global->xfer);
1089
1090         ao2_ref(cfg->global->xfer, +1);
1091         return cfg->global->xfer;
1092 }
1093
1094 struct ast_features_pickup_config *ast_get_chan_features_pickup_config(struct ast_channel *chan)
1095 {
1096         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1097
1098         if (chan) {
1099                 cfg = get_feature_ds(chan);
1100         } else {
1101                 cfg = ao2_global_obj_ref(globals);
1102         }
1103
1104         if (!cfg) {
1105                 return NULL;
1106         }
1107
1108         ast_assert(cfg->global && cfg->global->pickup);
1109
1110         ao2_ref(cfg->global->pickup, +1);
1111         return cfg->global->pickup;
1112 }
1113
1114 struct ast_featuremap_config *ast_get_chan_featuremap_config(struct ast_channel *chan)
1115 {
1116         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1117
1118         if (chan) {
1119                 cfg = get_feature_ds(chan);
1120         } else {
1121                 cfg = ao2_global_obj_ref(globals);
1122         }
1123
1124         if (!cfg) {
1125                 return NULL;
1126         }
1127
1128         ast_assert(cfg->featuremap != NULL);
1129
1130         ao2_ref(cfg->featuremap, +1);
1131         return cfg->featuremap;
1132 }
1133
1134 int ast_get_builtin_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
1135 {
1136         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1137
1138         if (chan) {
1139                 cfg = get_feature_ds(chan);
1140         } else {
1141                 cfg = ao2_global_obj_ref(globals);
1142         }
1143
1144         if (!cfg) {
1145                 return -1;
1146         }
1147
1148         return featuremap_get(cfg->featuremap, feature, buf, len);
1149 }
1150
1151 int ast_get_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
1152 {
1153         RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup);
1154         RAII_VAR(struct ast_applicationmap_item *, item, NULL, ao2_cleanup);
1155
1156         if (!ast_get_builtin_feature(chan, feature, buf, len)) {
1157                 return 0;
1158         }
1159
1160         /* Dang, must be in the application map */
1161         applicationmap = ast_get_chan_applicationmap(chan);
1162         if (!applicationmap) {
1163                 return -1;
1164         }
1165
1166         item = ao2_find(applicationmap, feature, OBJ_KEY);
1167         if (!item) {
1168                 return -1;
1169         }
1170
1171         ast_copy_string(buf, item->dtmf, len);
1172         return 0;
1173 }
1174
1175 static struct ast_applicationmap_item *applicationmap_item_alloc(const char *name,
1176                 const char *app, const char *app_data, const char *moh_class, const char *dtmf,
1177                 unsigned int activate_on_self)
1178 {
1179         struct ast_applicationmap_item *item;
1180
1181         item = ao2_alloc(sizeof(*item), ast_applicationmap_item_destructor);
1182
1183         if (!item || ast_string_field_init(item, 64)) {
1184                 return NULL;
1185         }
1186
1187         ast_string_field_set(item, name, name);
1188         ast_string_field_set(item, app, app);
1189         ast_string_field_set(item, app_data, app_data);
1190         ast_string_field_set(item, moh_class, moh_class);
1191         ast_copy_string(item->dtmf, dtmf, sizeof(item->dtmf));
1192         item->activate_on_self = activate_on_self;
1193
1194         return item;
1195 }
1196
1197 static int add_item(void *obj, void *arg, int flags)
1198 {
1199         struct featuregroup_item *fg_item = obj;
1200         struct ao2_container *applicationmap = arg;
1201         RAII_VAR(struct ast_applicationmap_item *, appmap_item, NULL, ao2_cleanup);
1202
1203         /* If there's no DTMF override, then we can just link
1204          * the applicationmap item directly. Otherwise, we need
1205          * to create a copy with the DTMF override in place and
1206          * link that instead
1207          */
1208         if (ast_strlen_zero(fg_item->dtmf_override)) {
1209                 ao2_ref(fg_item->appmap_item, +1);
1210                 appmap_item = fg_item->appmap_item;
1211         } else {
1212                 appmap_item = applicationmap_item_alloc(fg_item->appmap_item_name,
1213                                 fg_item->appmap_item->app, fg_item->appmap_item->app_data,
1214                                 fg_item->appmap_item->moh_class, fg_item->dtmf_override,
1215                                 fg_item->appmap_item->activate_on_self);
1216         }
1217
1218         if (!appmap_item) {
1219                 return 0;
1220         }
1221
1222         ao2_link(applicationmap, appmap_item);
1223         return 0;
1224 }
1225
1226 struct ao2_container *ast_get_chan_applicationmap(struct ast_channel *chan)
1227 {
1228         RAII_VAR(struct features_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1229         struct ao2_container *applicationmap;
1230         char *group_names;
1231         char *name;
1232
1233         if (!cfg) {
1234                 return NULL;
1235         }
1236
1237         if (!chan) {
1238                 if (!cfg->applicationmap || ao2_container_count(cfg->applicationmap) == 0) {
1239                         return NULL;
1240                 }
1241                 ao2_ref(cfg->applicationmap, +1);
1242                 return cfg->applicationmap;
1243         }
1244
1245         group_names = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"), ""));
1246         if (ast_strlen_zero(group_names)) {
1247                 return NULL;
1248         }
1249
1250         applicationmap = applicationmap_alloc(0);
1251         if (!applicationmap) {
1252                 return NULL;
1253         }
1254
1255         while ((name = strsep(&group_names, "#"))) {
1256                 RAII_VAR(struct featuregroup *, group, ao2_find(cfg->featuregroups, name, OBJ_KEY), ao2_cleanup);
1257
1258                 if (!group) {
1259                         RAII_VAR(struct ast_applicationmap_item *, item, ao2_find(cfg->applicationmap, name, OBJ_KEY), ao2_cleanup);
1260
1261                         if (item) {
1262                                 ao2_link(applicationmap, item);
1263                         } else {
1264                                 ast_log(LOG_WARNING, "Unknown DYNAMIC_FEATURES item '%s' on channel %s.\n",
1265                                         name, ast_channel_name(chan));
1266                         }
1267                 } else {
1268                         ao2_callback(group->items, 0, add_item, applicationmap);
1269                 }
1270         }
1271
1272         if (ao2_container_count(applicationmap) == 0) {
1273                 ao2_cleanup(applicationmap);
1274                 return NULL;
1275         }
1276
1277         return applicationmap;
1278 }
1279
1280 static int applicationmap_handler(const struct aco_option *opt,
1281                 struct ast_variable *var, void *obj)
1282 {
1283         RAII_VAR(struct ast_applicationmap_item *, item, NULL, ao2_cleanup);
1284         struct ao2_container *applicationmap = obj;
1285         AST_DECLARE_APP_ARGS(args,
1286                 AST_APP_ARG(dtmf);
1287                 AST_APP_ARG(activate_on);
1288                 AST_APP_ARG(app);
1289                 AST_APP_ARG(app_data);
1290                 AST_APP_ARG(moh_class);
1291         );
1292         char *parse = ast_strdupa(var->value);
1293         char *slash;
1294         char *paren;
1295         unsigned int activate_on_self;
1296
1297         AST_STANDARD_APP_ARGS(args, parse);
1298
1299         if (ast_strlen_zero(args.dtmf) ||
1300                         ast_strlen_zero(args.activate_on) ||
1301                         ast_strlen_zero(args.app)) {
1302                 ast_log(LOG_WARNING, "Invalid applicationmap syntax for '%s'. Missing required argument\n", var->name);
1303                 return -1;
1304         }
1305
1306         /* features.conf used to have an "activated_by" portion
1307          * in addition to activate_on. Get rid of whatever may be
1308          * there
1309          */
1310         slash = strchr(args.activate_on, '/');
1311         if (slash) {
1312                 *slash = '\0';
1313         }
1314
1315         /* Two syntaxes allowed for applicationmap:
1316          * Old: foo = *1,self,NoOp,Boo!,default
1317          * New: foo = *1,self,NoOp(Boo!),default
1318          *
1319          * We need to handle both
1320          */
1321         paren = strchr(args.app, '(');
1322         if (paren) {
1323                 /* New syntax */
1324                 char *close_paren;
1325
1326                 args.moh_class = args.app_data;
1327                 *paren++ = '\0';
1328                 close_paren = strrchr(paren, ')');
1329                 if (close_paren) {
1330                         *close_paren = '\0';
1331                 }
1332                 args.app_data = paren;
1333
1334                 /* Re-check that the application is not empty */
1335                 if (ast_strlen_zero(args.app)) {
1336                         ast_log(LOG_WARNING, "Applicationmap item '%s' does not contain an application name.\n", var->name);
1337                         return -1;
1338                 }
1339         } else if (strchr(args.app_data, '"')) {
1340                 args.app_data = ast_strip_quoted(args.app_data, "\"", "\"");
1341         }
1342
1343         /* Allow caller and callee to be specified for backwards compatibility */
1344         if (!strcasecmp(args.activate_on, "self") || !strcasecmp(args.activate_on, "caller")) {
1345                 activate_on_self = 1;
1346         } else if (!strcasecmp(args.activate_on, "peer") || !strcasecmp(args.activate_on, "callee")) {
1347                 activate_on_self = 0;
1348         } else {
1349                 ast_log(LOG_WARNING, "Invalid 'activate_on' value %s for applicationmap item %s\n",
1350                         args.activate_on, var->name);
1351                 return -1;
1352         }
1353
1354         ast_debug(1, "Allocating applicationmap item: dtmf = %s, app = %s, app_data = %s, moh_class = %s\n",
1355                         args.dtmf, args.app, args.app_data, args.moh_class);
1356
1357         item = applicationmap_item_alloc(var->name, args.app, args.app_data,
1358                         args.moh_class, args.dtmf, activate_on_self);
1359
1360         if (!item) {
1361                 return -1;
1362         }
1363
1364         if (!ao2_link(applicationmap, item)) {
1365                 return -1;
1366         }
1367
1368         return 0;
1369 }
1370
1371 static int featuregroup_handler(const struct aco_option *opt,
1372                 struct ast_variable *var, void *obj)
1373 {
1374         RAII_VAR(struct featuregroup_item *, item, NULL, ao2_cleanup);
1375         struct featuregroup *group = obj;
1376
1377         item = ao2_alloc(sizeof(*item), featuregroup_item_destructor);
1378         if (!item || ast_string_field_init(item, 32)) {
1379                 return -1;
1380         }
1381
1382         ast_string_field_set(item, appmap_item_name, var->name);
1383         ast_string_field_set(item, dtmf_override, var->value);
1384
1385         if (!ao2_link(group->items, item)) {
1386                 return -1;
1387         }
1388
1389         /* We wait to look up the application map item in the preapply callback */
1390
1391         return 0;
1392 }
1393
1394 static int general_handler(const struct aco_option *opt,
1395                 struct ast_variable *var, void *obj)
1396 {
1397         struct features_global_config *global = obj;
1398         struct ast_features_general_config *general = global->general;
1399
1400         return general_set(general, var->name, var->value);
1401 }
1402
1403 static int xfer_handler(const struct aco_option *opt,
1404                 struct ast_variable *var, void *obj)
1405 {
1406         struct features_global_config *global = obj;
1407         struct ast_features_xfer_config *xfer = global->xfer;
1408
1409         return xfer_set(xfer, var->name, var->value);
1410 }
1411
1412 static int pickup_handler(const struct aco_option *opt,
1413                 struct ast_variable *var, void *obj)
1414 {
1415         struct features_global_config *global = obj;
1416         struct ast_features_pickup_config *pickup = global->pickup;
1417
1418         return pickup_set(pickup, var->name, var->value);
1419 }
1420
1421 static int unsupported_handler(const struct aco_option *opt,
1422                 struct ast_variable *var, void *obj)
1423 {
1424         ast_log(LOG_WARNING, "The option '%s' is no longer configurable in features.conf.\n", var->name);
1425         return 0;
1426 }
1427
1428 static int featuremap_handler(const struct aco_option *opt,
1429                 struct ast_variable *var, void *obj)
1430 {
1431         struct ast_featuremap_config *featuremap = obj;
1432
1433         return featuremap_set(featuremap, var->name, var->value);
1434 }
1435
1436 static int check_featuregroup_item(void *obj, void *arg, void *data, int flags)
1437 {
1438         struct ast_applicationmap_item *appmap_item;
1439         struct featuregroup_item *fg_item = obj;
1440         int *err = arg;
1441         struct ao2_container *applicationmap = data;
1442
1443         appmap_item = ao2_find(applicationmap, fg_item->appmap_item_name, OBJ_KEY);
1444         if (!appmap_item) {
1445                 *err = 1;
1446                 return CMP_STOP;
1447         }
1448
1449         fg_item->appmap_item = appmap_item;
1450
1451         return 0;
1452 }
1453
1454 static int check_featuregroup(void *obj, void *arg, void *data, int flags)
1455 {
1456         struct featuregroup *group = obj;
1457         int *err = arg;
1458
1459         ao2_callback_data(group->items, 0, check_featuregroup_item, arg, data);
1460
1461         if (*err) {
1462                 ast_log(LOG_WARNING, "Featuregroup %s refers to non-existent applicationmap item\n",
1463                                 group->name);
1464         }
1465
1466         return *err ? CMP_STOP : 0;
1467 }
1468
1469 static int features_pre_apply_config(void);
1470
1471 CONFIG_INFO_CORE("features", cfg_info, globals, features_config_alloc,
1472         .files = ACO_FILES(&features_conf),
1473         .pre_apply_config = features_pre_apply_config,
1474 );
1475
1476 static int features_pre_apply_config(void)
1477 {
1478         struct features_config *cfg = aco_pending_config(&cfg_info);
1479         int err = 0;
1480
1481         /* Now that the entire config has been processed, we can check that the featuregroup
1482          * items refer to actual applicationmap items.
1483          */
1484
1485         ao2_callback_data(cfg->featuregroups, 0, check_featuregroup, &err, cfg->applicationmap);
1486
1487         return err;
1488 }
1489
1490 static int feature_read(struct ast_channel *chan, const char *cmd, char *data,
1491                char *buf, size_t len)
1492 {
1493         int res;
1494         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1495         SCOPED_CHANNELLOCK(lock, chan);
1496
1497         if (!strcasecmp(data, "inherit")) {
1498                 struct ast_datastore *ds = get_feature_chan_ds(chan);
1499                 unsigned int inherit = ds ? ds->inheritance : 0;
1500
1501                 snprintf(buf, len, "%s", inherit ? "yes" : "no");
1502                 return 0;
1503         }
1504
1505         cfg = get_feature_ds(chan);
1506         if (!cfg) {
1507                 return -1;
1508         }
1509
1510         res = general_get(cfg->global->general, data, buf, len) &&
1511                 xfer_get(cfg->global->xfer, data, buf, len) &&
1512                 pickup_get(cfg->global->pickup, data, buf, len);
1513
1514         if (res) {
1515                 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
1516         }
1517
1518         return res;
1519 }
1520
1521 static int feature_write(struct ast_channel *chan, const char *cmd, char *data,
1522                 const char *value)
1523 {
1524         int res;
1525         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1526         SCOPED_CHANNELLOCK(lock, chan);
1527
1528         if (!strcasecmp(data, "inherit")) {
1529                 struct ast_datastore *ds = get_feature_chan_ds(chan);
1530                 if (ds) {
1531                         ds->inheritance = ast_true(value) ? DATASTORE_INHERIT_FOREVER : 0;
1532                 }
1533                 return 0;
1534         }
1535
1536         if (!(cfg = get_feature_ds(chan))) {
1537                 return -1;
1538         }
1539
1540         res = general_set(cfg->global->general, data, value) &&
1541                 xfer_set(cfg->global->xfer, data, value) &&
1542                 pickup_set(cfg->global->pickup, data, value);
1543
1544         if (res) {
1545                 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
1546         }
1547
1548         return res;
1549 }
1550
1551 static int featuremap_read(struct ast_channel *chan, const char *cmd, char *data,
1552                char *buf, size_t len)
1553 {
1554         int res;
1555         SCOPED_CHANNELLOCK(lock, chan);
1556
1557         res = ast_get_builtin_feature(chan, data, buf, len);
1558
1559         if (res) {
1560                 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
1561         }
1562
1563         return res;
1564 }
1565
1566 static int featuremap_write(struct ast_channel *chan, const char *cmd, char *data,
1567                 const char *value)
1568 {
1569         int res;
1570         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1571         SCOPED_CHANNELLOCK(lock, chan);
1572
1573         if (!(cfg = get_feature_ds(chan))) {
1574                 return -1;
1575         }
1576
1577         res = featuremap_set(cfg->featuremap, data, value);
1578         if (res) {
1579                 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
1580                 return -1;
1581         }
1582
1583         return 0;
1584 }
1585
1586 static struct ast_custom_function feature_function = {
1587         .name = "FEATURE",
1588         .read = feature_read,
1589         .write = feature_write
1590 };
1591
1592 static struct ast_custom_function featuremap_function = {
1593         .name = "FEATUREMAP",
1594         .read = featuremap_read,
1595         .write = featuremap_write
1596 };
1597
1598 static int load_config(void)
1599 {
1600         if (aco_info_init(&cfg_info)) {
1601                 ast_log(LOG_ERROR, "Unable to initialize configuration info for features\n");
1602                 return -1;
1603         }
1604
1605         aco_option_register_custom(&cfg_info, "featuredigittimeout", ACO_EXACT, global_options,
1606                         __stringify(DEFAULT_FEATURE_DIGIT_TIMEOUT), general_handler, 0);
1607         aco_option_register_custom(&cfg_info, "recordingfailsound", ACO_EXACT, global_options,
1608                         DEFAULT_RECORDING_FAIL_SOUND, general_handler, 0);
1609         aco_option_register_custom(&cfg_info, "courtesytone", ACO_EXACT, global_options,
1610                         DEFAULT_COURTESY_TONE, general_handler, 0);
1611
1612         aco_option_register_custom(&cfg_info, "transferdigittimeout", ACO_EXACT, global_options,
1613                         __stringify(DEFAULT_TRANSFER_DIGIT_TIMEOUT), xfer_handler, 0)
1614         aco_option_register_custom(&cfg_info, "atxfernoanswertimeout", ACO_EXACT, global_options,
1615                         __stringify(DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER), xfer_handler, 0);
1616         aco_option_register_custom(&cfg_info, "atxferdropcall", ACO_EXACT, global_options,
1617                         __stringify(DEFAULT_ATXFER_DROP_CALL), xfer_handler, 0);
1618         aco_option_register_custom(&cfg_info, "atxferloopdelay", ACO_EXACT, global_options,
1619                         __stringify(DEFAULT_ATXFER_LOOP_DELAY), xfer_handler, 0);
1620         aco_option_register_custom(&cfg_info, "atxfercallbackretries", ACO_EXACT, global_options,
1621                         __stringify(DEFAULT_ATXFER_CALLBACK_RETRIES), xfer_handler, 0);
1622         aco_option_register_custom(&cfg_info, "xfersound", ACO_EXACT, global_options,
1623                         DEFAULT_XFERSOUND, xfer_handler, 0);
1624         aco_option_register_custom(&cfg_info, "xferfailsound", ACO_EXACT, global_options,
1625                         DEFAULT_XFERFAILSOUND, xfer_handler, 0);
1626         aco_option_register_custom(&cfg_info, "atxferabort", ACO_EXACT, global_options,
1627                         DEFAULT_ATXFER_ABORT, xfer_handler, 0);
1628         aco_option_register_custom(&cfg_info, "atxfercomplete", ACO_EXACT, global_options,
1629                         DEFAULT_ATXFER_COMPLETE, xfer_handler, 0);
1630         aco_option_register_custom(&cfg_info, "atxferthreeway", ACO_EXACT, global_options,
1631                         DEFAULT_ATXFER_THREEWAY, xfer_handler, 0);
1632
1633         aco_option_register_custom(&cfg_info, "pickupexten", ACO_EXACT, global_options,
1634                         DEFAULT_PICKUPEXTEN, pickup_handler, 0);
1635         aco_option_register_custom(&cfg_info, "pickupsound", ACO_EXACT, global_options,
1636                         DEFAULT_PICKUPSOUND, pickup_handler, 0);
1637         aco_option_register_custom(&cfg_info, "pickupfailsound", ACO_EXACT, global_options,
1638                         DEFAULT_PICKUPFAILSOUND, pickup_handler, 0);
1639
1640         aco_option_register_custom(&cfg_info, "context", ACO_EXACT, global_options,
1641                         "", unsupported_handler, 0);
1642         aco_option_register_custom(&cfg_info, "parkext", ACO_EXACT, global_options,
1643                         "", unsupported_handler, 0);
1644         aco_option_register_custom(&cfg_info, "parkext_exclusive", ACO_EXACT, global_options,
1645                         "", unsupported_handler, 0);
1646         aco_option_register_custom(&cfg_info, "parkinghints", ACO_EXACT, global_options,
1647                         "", unsupported_handler, 0);
1648         aco_option_register_custom(&cfg_info, "parkedmusicclass", ACO_EXACT, global_options,
1649                         "", unsupported_handler, 0);
1650         aco_option_register_custom(&cfg_info, "parkingtime", ACO_EXACT, global_options,
1651                         "", unsupported_handler, 0);
1652         aco_option_register_custom(&cfg_info, "parkpos", ACO_EXACT, global_options,
1653                         "", unsupported_handler, 0);
1654         aco_option_register_custom(&cfg_info, "findslot", ACO_EXACT, global_options,
1655                         "", unsupported_handler, 0);
1656         aco_option_register_custom(&cfg_info, "parkedcalltransfers", ACO_EXACT, global_options,
1657                         "", unsupported_handler, 0);
1658         aco_option_register_custom(&cfg_info, "parkedcallreparking", ACO_EXACT, global_options,
1659                         "", unsupported_handler, 0);
1660         aco_option_register_custom(&cfg_info, "parkedcallhangup", ACO_EXACT, global_options,
1661                         "", unsupported_handler, 0);
1662         aco_option_register_custom(&cfg_info, "parkedcallrecording", ACO_EXACT, global_options,
1663                         "", unsupported_handler, 0);
1664         aco_option_register_custom(&cfg_info, "comebackcontext", ACO_EXACT, global_options,
1665                         "", unsupported_handler, 0);
1666         aco_option_register_custom(&cfg_info, "comebacktoorigin", ACO_EXACT, global_options,
1667                         "", unsupported_handler, 0);
1668         aco_option_register_custom(&cfg_info, "comebackdialtime", ACO_EXACT, global_options,
1669                         "", unsupported_handler, 0);
1670         aco_option_register_custom(&cfg_info, "parkeddynamic", ACO_EXACT, global_options,
1671                         "", unsupported_handler, 0);
1672         aco_option_register_custom(&cfg_info, "adsipark", ACO_EXACT, global_options,
1673                         "", unsupported_handler, 0);
1674
1675         aco_option_register_custom(&cfg_info, "blindxfer", ACO_EXACT, featuremap_options,
1676                         DEFAULT_FEATUREMAP_BLINDXFER, featuremap_handler, 0);
1677         aco_option_register_custom(&cfg_info, "disconnect", ACO_EXACT, featuremap_options,
1678                         DEFAULT_FEATUREMAP_DISCONNECT, featuremap_handler, 0);
1679         aco_option_register_custom(&cfg_info, "automon", ACO_EXACT, featuremap_options,
1680                         DEFAULT_FEATUREMAP_AUTOMON, featuremap_handler, 0);
1681         aco_option_register_custom(&cfg_info, "atxfer", ACO_EXACT, featuremap_options,
1682                         DEFAULT_FEATUREMAP_ATXFER, featuremap_handler, 0);
1683         aco_option_register_custom(&cfg_info, "parkcall", ACO_EXACT, featuremap_options,
1684                         DEFAULT_FEATUREMAP_PARKCALL, featuremap_handler, 0);
1685         aco_option_register_custom(&cfg_info, "automixmon", ACO_EXACT, featuremap_options,
1686                         DEFAULT_FEATUREMAP_AUTOMIXMON, featuremap_handler, 0);
1687
1688         aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, applicationmap_options,
1689                         "", applicationmap_handler, 0);
1690
1691         aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, featuregroup_options,
1692                         "", featuregroup_handler, 0);
1693
1694         if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
1695                 ast_log(LOG_ERROR, "Failed to process features.conf configuration!\n");
1696                 aco_info_destroy(&cfg_info);
1697                 ao2_global_obj_release(globals);
1698                 return -1;
1699         }
1700
1701         return 0;
1702 }
1703
1704 static int print_featuregroup(void *obj, void *arg, int flags)
1705 {
1706         struct featuregroup_item *item = obj;
1707         struct ast_cli_args *a = arg;
1708
1709         ast_cli(a->fd, "===> --> %s (%s)\n", item->appmap_item_name,
1710                         S_OR(item->dtmf_override, item->appmap_item->dtmf));
1711
1712         return 0;
1713 }
1714
1715 static int print_featuregroups(void *obj, void *arg, int flags)
1716 {
1717         struct featuregroup *group = obj;
1718         struct ast_cli_args *a = arg;
1719
1720         ast_cli(a->fd, "===> Group: %s\n", group->name);
1721
1722         ao2_callback(group->items, 0, print_featuregroup, a);
1723         return 0;
1724 }
1725
1726 #define HFS_FORMAT "%-25s %-7s %-7s\n"
1727
1728 static int print_applicationmap(void *obj, void *arg, int flags)
1729 {
1730         struct ast_applicationmap_item *item = obj;
1731         struct ast_cli_args *a = arg;
1732
1733         ast_cli(a->fd, HFS_FORMAT, item->name, "no def", item->dtmf);
1734         return 0;
1735 }
1736
1737 /*!
1738  * \brief CLI command to list configured features
1739  * \param e
1740  * \param cmd
1741  * \param a
1742  *
1743  * \retval CLI_SUCCESS on success.
1744  * \retval NULL when tab completion is used.
1745  */
1746 static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1747 {
1748         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1749
1750         switch (cmd) {
1751
1752         case CLI_INIT:
1753                 e->command = "features show";
1754                 e->usage =
1755                         "Usage: features show\n"
1756                         "       Lists configured features\n";
1757                 return NULL;
1758         case CLI_GENERATE:
1759                 return NULL;
1760         }
1761
1762         cfg = ao2_global_obj_ref(globals);
1763
1764         ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
1765         ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
1766
1767         ast_cli(a->fd, HFS_FORMAT, "Pickup", DEFAULT_PICKUPEXTEN, cfg->global->pickup->pickupexten);
1768         ast_cli(a->fd, HFS_FORMAT, "Blind Transfer", DEFAULT_FEATUREMAP_BLINDXFER, cfg->featuremap->blindxfer);
1769         ast_cli(a->fd, HFS_FORMAT, "Attended Transfer", DEFAULT_FEATUREMAP_ATXFER, cfg->featuremap->atxfer);
1770         ast_cli(a->fd, HFS_FORMAT, "One Touch Monitor", DEFAULT_FEATUREMAP_AUTOMON, cfg->featuremap->automon);
1771         ast_cli(a->fd, HFS_FORMAT, "Disconnect Call", DEFAULT_FEATUREMAP_DISCONNECT, cfg->featuremap->disconnect);
1772         ast_cli(a->fd, HFS_FORMAT, "Park Call", DEFAULT_FEATUREMAP_PARKCALL, cfg->featuremap->parkcall);
1773         ast_cli(a->fd, HFS_FORMAT, "One Touch MixMonitor", DEFAULT_FEATUREMAP_AUTOMIXMON, cfg->featuremap->automixmon);
1774
1775         ast_cli(a->fd, "\n");
1776         ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
1777         ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
1778         if (!cfg->applicationmap || ao2_container_count(cfg->applicationmap) == 0) {
1779                 ast_cli(a->fd, "(none)\n");
1780         } else {
1781                 ao2_callback(cfg->applicationmap, 0, print_applicationmap, a);
1782         }
1783
1784         ast_cli(a->fd, "\nFeature Groups:\n");
1785         ast_cli(a->fd, "---------------\n");
1786         if (!cfg->featuregroups || ao2_container_count(cfg->featuregroups) == 0) {
1787                 ast_cli(a->fd, "(none)\n");
1788         } else {
1789                 ao2_callback(cfg->featuregroups, 0, print_featuregroups, a);
1790         }
1791
1792         ast_cli(a->fd, "\n");
1793
1794         return CLI_SUCCESS;
1795 }
1796
1797 static struct ast_cli_entry cli_features_config[] = {
1798         AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
1799 };
1800
1801 void ast_features_config_shutdown(void)
1802 {
1803         ast_custom_function_unregister(&featuremap_function);
1804         ast_custom_function_unregister(&feature_function);
1805         ast_cli_unregister_multiple(cli_features_config, ARRAY_LEN(cli_features_config));
1806         aco_info_destroy(&cfg_info);
1807         ao2_global_obj_release(globals);
1808 }
1809
1810 int ast_features_config_reload(void)
1811 {
1812         if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
1813                 return -1;
1814         }
1815         return 0;
1816 }
1817
1818 int ast_features_config_init(void)
1819 {
1820         int res;
1821
1822         res = load_config();
1823         res |= __ast_custom_function_register(&feature_function, NULL);
1824         res |= __ast_custom_function_register(&featuremap_function, NULL);
1825         res |= ast_cli_register_multiple(cli_features_config, ARRAY_LEN(cli_features_config));
1826
1827         if (res) {
1828                 ast_features_config_shutdown();
1829         }
1830
1831         return res;
1832 }