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