Refactor the features configuration scheme.
[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 /* BUGBUG XML Documentation is still needed for configuration options */
30 /*** DOCUMENTATION
31         <function name="FEATURE" language="en_US">
32                 <synopsis>
33                         Get or set a feature option on a channel.
34                 </synopsis>
35                 <syntax>
36                         <parameter name="option_name" required="true">
37                                 <para>The allowed values are:</para>
38                                 <enumlist>
39                                         <enum name="inherit"><para>Inherit feature settings made in FEATURE or FEATUREMAP to child channels.</para></enum>
40                                         <enum name="featuredigittimeout"><para>Milliseconds allowed between digits when entering a feature code.</para></enum>
41                                         <enum name="transferdigittimeout"><para>Milliseconds allowed between digits when dialing a transfer destination</para></enum>
42                                         <enum name="atxfernoanswertimeout"><para>Milliseconds to wait for transfer destination to answer</para></enum>
43                                         <enum name="atxferdropcall"><para>Hang up the call entirely if the attended transfer fails</para></enum>
44                                         <enum name="atxferloopdelay"><para>Milliseconds to wait between attempts to re-dial transfer destination</para></enum>
45                                         <enum name="atxfercallbackretries"><para>Number of times to re-attempt dialing a transfer destination</para></enum>
46                                         <enum name="xfersound"><para>Sound to play to a transferee when a transfer completes</para></enum>
47                                         <enum name="xferfailsound"><para>Sound to play to a transferee when a transfer fails</para></enum>
48                                         <enum name="atxferabort"><para>Digits to dial to abort an attended transfer attempt</para></enum>
49                                         <enum name="atxfercomplete"><para>Digits to dial to complete an attended transfer</para></enum>
50                                         <enum name="atxferthreeway"><para>Digits to dial to change an attended transfer into a three-way call</para></enum>
51                                         <enum name="pickupexten"><para>Digits used for picking up ringing calls</para></enum>
52                                         <enum name="pickupsound"><para>Sound to play to picker when a call is picked up</para></enum>
53                                         <enum name="pickupfailsound"><para>Sound to play to picker when a call cannot be picked up</para></enum>
54                                         <enum name="courtesytone"><para>Sound to play when automon or automixmon is activated</para></enum>
55                                 </enumlist>
56                         </parameter>
57                 </syntax>
58                 <description>
59                         <para>When this function is used as a read, it will get the current
60                         value of the specified feature option for this channel.  It will be
61                         the value of this option configured in features.conf if a channel specific
62                         value has not been set.  This function can also be used to set a channel
63                         specific value for the supported feature options.</para>
64                 </description>
65                 <see-also>
66                         <ref type="function">FEATUREMAP</ref>
67                 </see-also>
68         </function>
69         <function name="FEATUREMAP" language="en_US">
70                 <synopsis>
71                         Get or set a feature map to a given value on a specific channel.
72                 </synopsis>
73                 <syntax>
74                         <parameter name="feature_name" required="true">
75                                 <para>The allowed values are:</para>
76                                 <enumlist>
77                                         <enum name="atxfer"><para>Attended Transfer</para></enum>
78                                         <enum name="blindxfer"><para>Blind Transfer</para></enum>
79                                         <enum name="automon"><para>Auto Monitor</para></enum>
80                                         <enum name="disconnect"><para>Call Disconnect</para></enum>
81                                         <enum name="parkcall"><para>Park Call</para></enum>
82                                         <enum name="automixmon"><para>Auto MixMonitor</para></enum>
83                                 </enumlist>
84                         </parameter>
85                 </syntax>
86                 <description>
87                         <para>When this function is used as a read, it will get the current
88                         digit sequence mapped to the specified feature for this channel.  This
89                         value will be the one configured in features.conf if a channel specific
90                         value has not been set.  This function can also be used to set a channel
91                         specific value for a feature mapping.</para>
92                 </description>
93                 <see-also>
94                         <ref type="function">FEATURE</ref>
95                 </see-also>
96         </function>
97  ***/
98 /*! Default general options */
99 #define DEFAULT_FEATURE_DIGIT_TIMEOUT               1000
100
101 /*! Default xfer options */
102 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT              3000
103 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER  15000
104 #define DEFAULT_ATXFER_DROP_CALL                    0
105 #define DEFAULT_ATXFER_LOOP_DELAY                   10000
106 #define DEFAULT_ATXFER_CALLBACK_RETRIES             2
107 #define DEFAULT_XFERSOUND                           "beep"
108 #define DEFAULT_XFERFAILSOUND                       "beeperr"
109 #define DEFAULT_ATXFER_ABORT                        "*1"
110 #define DEFAULT_ATXFER_COMPLETE                     "*2"
111 #define DEFAULT_ATXFER_THREEWAY                     "*3"
112
113 /*! Default pickup options */
114 #define DEFAULT_PICKUPEXTEN                         "*8"
115 #define DEFAULT_PICKUPSOUND                         ""
116 #define DEFAULT_PICKUPFAILSOUND                     ""
117
118 /*! Default featuremap options */
119 #define DEFAULT_FEATUREMAP_BLINDXFER                "#"
120 #define DEFAULT_FEATUREMAP_DISCONNECT               "*"
121 #define DEFAULT_FEATUREMAP_AUTOMON                  ""
122 #define DEFAULT_FEATUREMAP_ATXFER                   ""
123 #define DEFAULT_FEATUREMAP_PARKCALL                 ""
124 #define DEFAULT_FEATUREMAP_AUTOMIXMON               ""
125
126 /*!
127  * \brief Configuration from the "general" section of features.conf
128  */
129 struct features_global_config {
130         struct ast_features_general_config *general;
131         struct ast_features_xfer_config *xfer;
132         struct ast_features_pickup_config *pickup;
133 };
134
135 static void ast_applicationmap_item_destructor(void *obj)
136 {
137         struct ast_applicationmap_item *item = obj;
138
139         ast_string_field_free_memory(item);
140 }
141
142 static int applicationmap_sort(const void *obj, const void *arg, int flags)
143 {
144         const struct ast_applicationmap_item *item1 = obj;
145         const struct ast_applicationmap_item *item2;
146         const char *key2;
147
148         switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
149         case OBJ_KEY:
150                 key2 = arg;
151                 return strcasecmp(item1->name, key2);
152         case OBJ_PARTIAL_KEY:
153                 key2 = arg;
154                 return strncasecmp(item1->name, key2, strlen(key2));
155         default:
156         case OBJ_POINTER:
157                 item2 = arg;
158                 return strcasecmp(item1->name, item2->name);
159         }
160 }
161
162 /*!
163  * \brief Entry in the container of featuregroups
164  */
165 struct featuregroup_item {
166         AST_DECLARE_STRING_FIELDS(
167                 /*! The name of the applicationmap item that we are referring to */
168                 AST_STRING_FIELD(appmap_item_name);
169                 /*! Custom DTMF override to use instead of the default for the applicationmap item */
170                 AST_STRING_FIELD(dtmf_override);
171         );
172         /*! The applicationmap item that is being referred to */
173         struct ast_applicationmap_item *appmap_item;
174 };
175
176 static void featuregroup_item_destructor(void *obj)
177 {
178         struct featuregroup_item *item = obj;
179
180         ast_string_field_free_memory(item);
181         ao2_cleanup(item->appmap_item);
182 }
183
184 static int group_item_sort(const void *obj, const void *arg, int flags)
185 {
186         const struct featuregroup_item *item1 = obj;
187         const struct featuregroup_item *item2;
188         const char *key2;
189
190         switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
191         case OBJ_KEY:
192                 key2 = arg;
193                 return strcasecmp(item1->appmap_item_name, key2);
194         case OBJ_PARTIAL_KEY:
195                 key2 = arg;
196                 return strncasecmp(item1->appmap_item_name, key2, strlen(key2));
197         case OBJ_POINTER:
198                 item2 = arg;
199                 return strcasecmp(item1->appmap_item_name, item2->appmap_item_name);
200         default:
201                 return CMP_STOP;
202         }
203 }
204
205 /*!
206  * \brief Featuregroup representation
207  */
208 struct featuregroup {
209         /*! The name of the featuregroup */
210         const char *name;
211         /*! A container of featuregroup_items */
212         struct ao2_container *items;
213 };
214
215 static int featuregroup_hash(const void *obj, int flags)
216 {
217         const struct featuregroup *group;
218         const char *key;
219
220         switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
221         case OBJ_KEY:
222                 key = obj;
223                 return ast_str_case_hash(key);
224         case OBJ_PARTIAL_KEY:
225                 ast_assert(0);
226                 return 0;
227         case OBJ_POINTER:
228         default:
229                 group = obj;
230                 return ast_str_case_hash(group->name);
231         }
232 }
233
234 static int featuregroup_cmp(void *obj, void *arg, int flags)
235 {
236         struct featuregroup *group1 = obj;
237         struct featuregroup *group2;
238         const char *key2;
239
240         switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
241         case OBJ_KEY:
242                 key2 = arg;
243                 return strcasecmp(group1->name, key2) ? 0 : CMP_MATCH;
244         case OBJ_PARTIAL_KEY:
245                 key2 = arg;
246                 return strncasecmp(group1->name, key2, strlen(key2)) ? 0 : CMP_MATCH;
247         case OBJ_POINTER:
248                 group2 = arg;
249                 return strcasecmp(group1->name, group2->name) ? 0 : CMP_MATCH;
250         default:
251                 return CMP_STOP;
252         }
253 }
254
255 static void *featuregroup_find(struct ao2_container *group_container, const char *category)
256 {
257         return ao2_find(group_container, category, OBJ_KEY);
258 }
259
260 static void featuregroup_destructor(void *obj)
261 {
262         struct featuregroup *group = obj;
263
264         ast_free((char *) group->name);
265         ao2_cleanup(group->items);
266 }
267
268 static void *featuregroup_alloc(const char *cat)
269 {
270         struct featuregroup *group;
271
272         group = ao2_alloc(sizeof(*group), featuregroup_destructor);
273         if (!group) {
274                 return NULL;
275         }
276
277         group->name = ast_strdup(cat);
278         if (!group->name) {
279                 ao2_cleanup(group);
280                 return NULL;
281         }
282
283         group->items = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
284                         AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, group_item_sort, NULL);
285         if (!group->items) {
286                 ao2_cleanup(group);
287                 return NULL;
288         }
289
290         return group;
291 }
292
293 struct features_config {
294         struct features_global_config *global;
295         struct ast_featuremap_config *featuremap;
296         struct ao2_container *applicationmap;
297         struct ao2_container *featuregroups;
298 };
299
300 static struct aco_type global_option = {
301         .type = ACO_GLOBAL,
302         .name = "globals",
303         .category_match = ACO_WHITELIST,
304         .category = "^general$",
305         .item_offset = offsetof(struct features_config, global),
306 };
307
308 static struct aco_type featuremap_option = {
309         .type = ACO_GLOBAL,
310         .name = "featuremap",
311         .category_match = ACO_WHITELIST,
312         .category = "^featuremap$",
313         .item_offset = offsetof(struct features_config, featuremap),
314 };
315
316 static struct aco_type applicationmap_option = {
317         .type = ACO_GLOBAL,
318         .name = "applicationmap",
319         .category_match = ACO_WHITELIST,
320         .category = "^applicationmap$",
321         .item_offset = offsetof(struct features_config, applicationmap),
322 };
323
324 static struct aco_type featuregroup_option = {
325         .type = ACO_ITEM,
326         .name = "featuregroup",
327         .category_match = ACO_BLACKLIST,
328         .category = "^(general|featuremap|applicationmap|parkinglot_.*)$",
329         .item_offset = offsetof(struct features_config, featuregroups),
330         .item_alloc = featuregroup_alloc,
331         .item_find = featuregroup_find,
332 };
333
334 static struct aco_type *global_options[] = ACO_TYPES(&global_option);
335 static struct aco_type *featuremap_options[] = ACO_TYPES(&featuremap_option);
336 static struct aco_type *applicationmap_options[] = ACO_TYPES(&applicationmap_option);
337 static struct aco_type *featuregroup_options[] = ACO_TYPES(&featuregroup_option);
338
339 static struct aco_file features_conf = {
340         .filename = "features.conf",
341         .types = ACO_TYPES(&global_option, &featuremap_option, &applicationmap_option, &featuregroup_option),
342 };
343
344 AO2_GLOBAL_OBJ_STATIC(globals);
345
346 static void features_config_destructor(void *obj)
347 {
348         struct features_config *cfg = obj;
349
350         ao2_cleanup(cfg->global);
351         ao2_cleanup(cfg->featuremap);
352         ao2_cleanup(cfg->applicationmap);
353         ao2_cleanup(cfg->featuregroups);
354 }
355
356 static void featuremap_config_destructor(void *obj)
357 {
358         struct ast_featuremap_config *cfg = obj;
359
360         ast_string_field_free_memory(cfg);
361 }
362
363 static void global_config_destructor(void *obj)
364 {
365         struct features_global_config *cfg = obj;
366
367         ao2_cleanup(cfg->general);
368         ao2_cleanup(cfg->xfer);
369         ao2_cleanup(cfg->pickup);
370 }
371
372 static void general_destructor(void *obj)
373 {
374         struct ast_features_general_config *cfg = obj;
375
376         ast_string_field_free_memory(cfg);
377 }
378
379 static void xfer_destructor(void *obj)
380 {
381         struct ast_features_xfer_config *cfg = obj;
382
383         ast_string_field_free_memory(cfg);
384 }
385
386 static void pickup_destructor(void *obj)
387 {
388         struct ast_features_pickup_config *cfg = obj;
389
390         ast_string_field_free_memory(cfg);
391 }
392
393 static struct features_global_config *global_config_alloc(void)
394 {
395         RAII_VAR(struct features_global_config *, cfg, NULL, ao2_cleanup);
396
397         cfg = ao2_alloc(sizeof(*cfg), global_config_destructor);
398         if (!cfg) {
399                 return NULL;
400         }
401
402         cfg->general = ao2_alloc(sizeof(*cfg->general), general_destructor);
403         if (!cfg->general || ast_string_field_init(cfg->general, 32)) {
404                 return NULL;
405         }
406
407         cfg->xfer = ao2_alloc(sizeof(*cfg->xfer), xfer_destructor);
408         if (!cfg->xfer || ast_string_field_init(cfg->xfer, 32)) {
409                 return NULL;
410         }
411
412         cfg->pickup = ao2_alloc(sizeof(*cfg->pickup), pickup_destructor);
413         if (!cfg->pickup || ast_string_field_init(cfg->pickup, 32)) {
414                 return NULL;
415         }
416
417         ao2_ref(cfg, +1);
418         return cfg;
419 }
420
421 static struct ao2_container *applicationmap_alloc(void)
422 {
423         return ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
424                         AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, applicationmap_sort, NULL);
425 }
426
427 /*!
428  * \internal
429  * \brief Allocate the major configuration structure
430  *
431  * The parameter is used to determine if the applicationmap and featuregroup
432  * structures should be allocated. We only want to allocate these structures for
433  * the global features_config structure. For the datastores on channels, we don't
434  * need to allocate these structures because they are not used.
435  *
436  * \param allocate_applicationmap See previous explanation
437  * \retval NULL Failed to alloate configuration
438  * \retval non-NULL Allocated configuration
439  */
440 static struct features_config *__features_config_alloc(int allocate_applicationmap)
441 {
442         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
443
444         cfg = ao2_alloc(sizeof(*cfg), features_config_destructor);
445         if (!cfg) {
446                 return NULL;
447         }
448
449         cfg->global = global_config_alloc();;
450         if (!cfg->global) {
451                 return NULL;
452         }
453
454         cfg->featuremap = ao2_alloc(sizeof(*cfg->featuremap), featuremap_config_destructor);
455         if (!cfg->featuremap || ast_string_field_init(cfg->featuremap, 32)) {
456                 return NULL;
457         }
458
459         if (allocate_applicationmap) {
460                 cfg->applicationmap = applicationmap_alloc();
461                 if (!cfg->applicationmap) {
462                         return NULL;
463                 }
464
465                 cfg->featuregroups = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 11, featuregroup_hash,
466                         featuregroup_cmp);
467                 if (!cfg->featuregroups) {
468                         return NULL;
469                 }
470         }
471
472         ao2_ref(cfg, +1);
473         return cfg;
474
475 }
476
477 static void *features_config_alloc(void)
478 {
479         return __features_config_alloc(1);
480 }
481
482 static void general_copy(struct ast_features_general_config *dest, const struct ast_features_general_config *src)
483 {
484         ast_string_fields_copy(dest, src);
485         dest->featuredigittimeout = src->featuredigittimeout;
486 }
487
488 static void xfer_copy(struct ast_features_xfer_config *dest, const struct ast_features_xfer_config *src)
489 {
490         ast_string_fields_copy(dest, src);
491         dest->transferdigittimeout = src->transferdigittimeout;
492         dest->atxfernoanswertimeout = src->atxfernoanswertimeout;
493         dest->atxferloopdelay = src->atxferloopdelay;
494         dest->atxfercallbackretries = src->atxfercallbackretries;
495         dest->atxferdropcall = src->atxferdropcall;
496 }
497
498 static void pickup_copy(struct ast_features_pickup_config *dest, const struct ast_features_pickup_config *src)
499 {
500         ast_string_fields_copy(dest, src);
501 }
502
503 static void global_copy(struct features_global_config *dest, const struct features_global_config *src)
504 {
505         general_copy(dest->general, src->general);
506         xfer_copy(dest->xfer, src->xfer);
507         pickup_copy(dest->pickup, src->pickup);
508 }
509
510 static void featuremap_copy(struct ast_featuremap_config *dest, const struct ast_featuremap_config *src)
511 {
512         ast_string_fields_copy(dest, src);
513 }
514
515 static void features_copy(struct features_config *dest, const struct features_config *src)
516 {
517         global_copy(dest->global, src->global);
518         featuremap_copy(dest->featuremap, src->featuremap);
519
520         /* applicationmap and featuregroups are purposely not copied. A channel's applicationmap
521          * is produced on the fly when ast_get_chan_applicationmap() is called
522          */
523 }
524
525 static struct features_config *features_config_dup(const struct features_config *orig)
526 {
527         struct features_config *dup;
528
529         dup = __features_config_alloc(0);
530         if (!dup) {
531                 return NULL;
532         }
533
534         features_copy(dup, orig);
535
536         return dup;
537 }
538
539 static int general_set(struct ast_features_general_config *general, const char *name,
540                 const char *value)
541 {
542         int res = 0;
543
544         if (!strcasecmp(name, "featuredigittimeout")) {
545                 res = ast_parse_arg(value, PARSE_INT32, &general->featuredigittimeout);
546         } else if (!strcasecmp(name, "courtesytone")) {
547                 ast_string_field_set(general, courtesytone, value);
548         } else {
549                 /* Unrecognized option */
550                 res = -1;
551         }
552
553         return res;
554 }
555
556 static int general_get(struct ast_features_general_config *general, const char *field,
557                 char *buf, size_t len)
558 {
559         int res = 0;
560
561         if (!strcasecmp(field, "featuredigittimeout")) {
562                 snprintf(buf, len, "%u", general->featuredigittimeout);
563         } else if (!strcasecmp(field, "courtesytone")) {
564                 ast_copy_string(buf, general->courtesytone, len);
565         } else {
566                 /* Unrecognized option */
567                 res = -1;
568         }
569
570         return res;
571 }
572
573 static int xfer_set(struct ast_features_xfer_config *xfer, const char *name,
574                 const char *value)
575 {
576         int res = 0;
577
578         if (!strcasecmp(name, "transferdigittimeout")) {
579                 res = ast_parse_arg(value, PARSE_INT32, &xfer->transferdigittimeout);
580         } else if (!strcasecmp(name, "atxfernoanswertimeout")) {
581                 res = ast_parse_arg(value, PARSE_INT32, &xfer->atxfernoanswertimeout);
582         } else if (!strcasecmp(name, "atxferloopdelay")) {
583                 res = ast_parse_arg(value, PARSE_INT32, &xfer->atxferloopdelay);
584         } else if (!strcasecmp(name, "atxfercallbackretries")) {
585                 res = ast_parse_arg(value, PARSE_INT32, &xfer->atxfercallbackretries);
586         } else if (!strcasecmp(name, "atxferdropcall")) {
587                 xfer->atxferdropcall = ast_true(value);
588         } else if (!strcasecmp(name, "xfersound")) {
589                 ast_string_field_set(xfer, xfersound, value);
590         } else if (!strcasecmp(name, "xferfailsound")) {
591                 ast_string_field_set(xfer, xferfailsound, value);
592         } else if (!strcasecmp(name, "atxferabort")) {
593                 ast_string_field_set(xfer, atxferabort, value);
594         } else if (!strcasecmp(name, "atxfercomplete")) {
595                 ast_string_field_set(xfer, atxfercomplete, value);
596         } else if (!strcasecmp(name, "atxferthreeway")) {
597                 ast_string_field_set(xfer, atxferthreeway, value);
598         } else {
599                 /* Unrecognized option */
600                 res = -1;
601         }
602
603         return res;
604 }
605
606 static int xfer_get(struct ast_features_xfer_config *xfer, const char *field,
607                 char *buf, size_t len)
608 {
609         int res = 0;
610
611         if (!strcasecmp(field, "transferdigittimeout")) {
612                 snprintf(buf, len, "%u", xfer->transferdigittimeout);
613         } else if (!strcasecmp(field, "atxfernoanswertimeout")) {
614                 snprintf(buf, len, "%u", xfer->atxfernoanswertimeout);
615         } else if (!strcasecmp(field, "atxferloopdelay")) {
616                 snprintf(buf, len, "%u", xfer->atxferloopdelay);
617         } else if (!strcasecmp(field, "atxfercallbackretries")) {
618                 snprintf(buf, len, "%u", xfer->atxfercallbackretries);
619         } else if (!strcasecmp(field, "atxferdropcall")) {
620                 snprintf(buf, len, "%u", xfer->atxferdropcall);
621         } else if (!strcasecmp(field, "xfersound")) {
622                 ast_copy_string(buf, xfer->xfersound, len);
623         } else if (!strcasecmp(field, "xferfailsound")) {
624                 ast_copy_string(buf, xfer->xferfailsound, len);
625         } else if (!strcasecmp(field, "atxferabort")) {
626                 ast_copy_string(buf, xfer->atxferabort, len);
627         } else if (!strcasecmp(field, "atxfercomplete")) {
628                 ast_copy_string(buf, xfer->atxfercomplete, len);
629         } else if (!strcasecmp(field, "atxferthreeway")) {
630                 ast_copy_string(buf, xfer->atxferthreeway, len);
631         } else {
632                 /* Unrecognized option */
633                 res = -1;
634         }
635
636         return res;
637 }
638
639 static int pickup_set(struct ast_features_pickup_config *pickup, const char *name,
640                 const char *value)
641 {
642         int res = 0;
643
644         if (!strcasecmp(name, "pickupsound")) {
645                 ast_string_field_set(pickup, pickupsound, value);
646         } else if (!strcasecmp(name, "pickupfailsound")) {
647                 ast_string_field_set(pickup, pickupfailsound, value);
648         } else if (!strcasecmp(name, "pickupexten")) {
649                 ast_string_field_set(pickup, pickupexten, value);
650         } else {
651                 /* Unrecognized option */
652                 res = -1;
653         }
654
655         return res;
656 }
657
658 static int pickup_get(struct ast_features_pickup_config *pickup, const char *field,
659                 char *buf, size_t len)
660 {
661         int res = 0;
662
663         if (!strcasecmp(field, "pickupsound")) {
664                 ast_copy_string(buf, pickup->pickupsound, len);
665         } else if (!strcasecmp(field, "pickupfailsound")) {
666                 ast_copy_string(buf, pickup->pickupfailsound, len);
667         } else if (!strcasecmp(field, "pickupexten")) {
668                 ast_copy_string(buf, pickup->pickupexten, len);
669         } else {
670                 /* Unrecognized option */
671                 res = -1;
672         }
673
674         return res;
675 }
676
677 static int featuremap_set(struct ast_featuremap_config *featuremap, const char *name,
678                 const char *value)
679 {
680         int res = 0;
681
682         if (!strcasecmp(name, "blindxfer")) {
683                 ast_string_field_set(featuremap, blindxfer, value);
684         } else if (!strcasecmp(name, "disconnect")) {
685                 ast_string_field_set(featuremap, disconnect, value);
686         } else if (!strcasecmp(name, "automon")) {
687                 ast_string_field_set(featuremap, automon, value);
688         } else if (!strcasecmp(name, "atxfer")) {
689                 ast_string_field_set(featuremap, atxfer, value);
690         } else if (!strcasecmp(name, "automixmon")) {
691                 ast_string_field_set(featuremap, automixmon, value);
692         } else if (!strcasecmp(name, "parkcall")) {
693                 ast_string_field_set(featuremap, parkcall, value);
694         } else {
695                 /* Unrecognized option */
696                 res = -1;
697         }
698
699         return res;
700 }
701
702 static int featuremap_get(struct ast_featuremap_config *featuremap, const char *field,
703                 char *buf, size_t len)
704 {
705         int res = 0;
706
707         if (!strcasecmp(field, "blindxfer")) {
708                 ast_copy_string(buf, featuremap->blindxfer, len);
709         } else if (!strcasecmp(field, "disconnect")) {
710                 ast_copy_string(buf, featuremap->disconnect, len);
711         } else if (!strcasecmp(field, "automon")) {
712                 ast_copy_string(buf, featuremap->automon, len);
713         } else if (!strcasecmp(field, "atxfer")) {
714                 ast_copy_string(buf, featuremap->atxfer, len);
715         } else if (!strcasecmp(field, "automixmon")) {
716                 ast_copy_string(buf, featuremap->automixmon, len);
717         } else if (!strcasecmp(field, "parkcall")) {
718                 ast_copy_string(buf, featuremap->parkcall, len);
719         } else {
720                 /* Unrecognized option */
721                 res = -1;
722         }
723
724         return res;
725 }
726
727 static void feature_ds_destroy(void *data)
728 {
729         struct features_config *cfg = data;
730         ao2_cleanup(cfg);
731 }
732
733 static void *feature_ds_duplicate(void *data)
734 {
735         struct features_config *old_cfg = data;
736
737         return features_config_dup(old_cfg);
738 }
739
740 static const struct ast_datastore_info feature_ds_info = {
741         .type = "FEATURE",
742         .destroy = feature_ds_destroy,
743         .duplicate = feature_ds_duplicate,
744 };
745
746 /*!
747  * \internal
748  * \brief Find or create feature datastore on a channel
749  *
750  * \pre chan is locked
751  *
752  * \return the data on the FEATURE datastore, or NULL on error
753  */
754 static struct features_config *get_feature_ds(struct ast_channel *chan)
755 {
756         RAII_VAR(struct features_config *, orig, NULL, ao2_cleanup);
757         struct features_config *cfg;
758         struct ast_datastore *ds;
759
760         if ((ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
761                 cfg = ds->data;
762                 ao2_ref(cfg, +1);
763                 return cfg;
764         }
765
766         orig = ao2_global_obj_ref(globals);
767         if (!orig) {
768                 return NULL;
769         }
770
771         cfg = features_config_dup(orig);
772         if (!cfg) {
773                 return NULL;
774         }
775
776         if (!(ds = ast_datastore_alloc(&feature_ds_info, NULL))) {
777                 ao2_cleanup(cfg);
778                 return NULL;
779         }
780
781         /* Give the datastore a reference to the config */
782         ao2_ref(cfg, +1);
783         ds->data = cfg;
784
785         ast_channel_datastore_add(chan, ds);
786
787         return cfg;
788 }
789
790 static struct ast_datastore *get_feature_chan_ds(struct ast_channel *chan)
791 {
792         struct ast_datastore *ds;
793
794         if (!(ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
795                 /* Hasn't been created yet.  Trigger creation. */
796                 RAII_VAR(struct features_config *, cfg, get_feature_ds(chan), ao2_cleanup);
797                 ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL);
798         }
799
800         return ds;
801 }
802
803 struct ast_features_general_config *ast_get_chan_features_general_config(struct ast_channel *chan)
804 {
805         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
806
807         if (chan) {
808                 cfg = get_feature_ds(chan);
809         } else {
810                 cfg = ao2_global_obj_ref(globals);
811         }
812
813         if (!cfg) {
814                 return NULL;
815         }
816
817         ast_assert(cfg->global && cfg->global->general);
818
819         ao2_ref(cfg->global->general, +1);
820         return cfg->global->general;
821 }
822
823 struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_channel *chan)
824 {
825         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
826
827         if (chan) {
828                 cfg = get_feature_ds(chan);
829         } else {
830                 cfg = ao2_global_obj_ref(globals);
831         }
832
833         if (!cfg) {
834                 return NULL;
835         }
836
837         ast_assert(cfg->global && cfg->global->xfer);
838
839         ao2_ref(cfg->global->xfer, +1);
840         return cfg->global->xfer;
841 }
842
843 struct ast_features_pickup_config *ast_get_chan_features_pickup_config(struct ast_channel *chan)
844 {
845         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
846
847         if (chan) {
848                 cfg = get_feature_ds(chan);
849         } else {
850                 cfg = ao2_global_obj_ref(globals);
851         }
852
853         if (!cfg) {
854                 return NULL;
855         }
856
857         ast_assert(cfg->global && cfg->global->pickup);
858
859         ao2_ref(cfg->global->pickup, +1);
860         return cfg->global->pickup;
861 }
862
863 struct ast_featuremap_config *ast_get_chan_featuremap_config(struct ast_channel *chan)
864 {
865         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
866
867         if (chan) {
868                 cfg = get_feature_ds(chan);
869         } else {
870                 cfg = ao2_global_obj_ref(globals);
871         }
872
873         if (!cfg) {
874                 return NULL;
875         }
876
877         ast_assert(cfg->featuremap != NULL);
878
879         ao2_ref(cfg->featuremap, +1);
880         return cfg->featuremap;
881 }
882
883 int ast_get_builtin_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
884 {
885         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
886
887         if (chan) {
888                 cfg = get_feature_ds(chan);
889         } else {
890                 cfg = ao2_global_obj_ref(globals);
891         }
892
893         if (!cfg) {
894                 return -1;
895         }
896
897         return featuremap_get(cfg->featuremap, feature, buf, len);
898 }
899
900 int ast_get_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
901 {
902         RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup);
903         RAII_VAR(struct ast_applicationmap_item *, item, NULL, ao2_cleanup);
904         if (!ast_get_builtin_feature(chan, feature, buf, len)) {
905                 return 0;
906         }
907
908         /* Dang, must be in the application map */
909         applicationmap = ast_get_chan_applicationmap(chan);
910
911         if (!applicationmap) {
912                 return -1;
913         }
914
915         item = ao2_find(applicationmap, feature, OBJ_KEY);
916         if (!item) {
917                 return -1;
918         }
919
920         ast_copy_string(buf, item->dtmf, len);
921         return 0;
922 }
923
924 static struct ast_applicationmap_item *applicationmap_item_alloc(const char *name,
925                 const char *app, const char *app_data, const char *moh_class, const char *dtmf,
926                 unsigned int activate_on_self)
927 {
928         struct ast_applicationmap_item *item;
929
930         item = ao2_alloc(sizeof(*item), ast_applicationmap_item_destructor);
931
932         if (!item || ast_string_field_init(item, 64)) {
933                 return NULL;
934         }
935
936         ast_string_field_set(item, name, name);
937         ast_string_field_set(item, app, app);
938         ast_string_field_set(item, app_data, app_data);
939         ast_string_field_set(item, moh_class, moh_class);
940         ast_copy_string(item->dtmf, dtmf, sizeof(item->dtmf));
941         item->activate_on_self = activate_on_self;
942
943         return item;
944 }
945
946 static int add_item(void *obj, void *arg, int flags)
947 {
948         struct featuregroup_item *fg_item = obj;
949         struct ao2_container *applicationmap = arg;
950         RAII_VAR(struct ast_applicationmap_item *, appmap_item, NULL, ao2_cleanup);
951
952         /* If there's no DTMF override, then we can just link
953          * the applicationmap item directly. Otherwise, we need
954          * to create a copy with the DTMF override in place and
955          * link that instead
956          */
957         if (ast_strlen_zero(fg_item->dtmf_override)) {
958                 ao2_ref(fg_item->appmap_item, +1);
959                 appmap_item = fg_item->appmap_item;
960         } else {
961                 appmap_item = applicationmap_item_alloc(fg_item->appmap_item_name,
962                                 fg_item->appmap_item->app, fg_item->appmap_item->app_data,
963                                 fg_item->appmap_item->moh_class, fg_item->dtmf_override,
964                                 fg_item->appmap_item->activate_on_self);
965         }
966
967         if (!appmap_item) {
968                 return 0;
969         }
970
971         if (!ao2_link(applicationmap, appmap_item)) {
972                 ast_log(LOG_WARNING, "Unable to add applicationmap item %s. Possible duplicate\n",
973                                 fg_item->appmap_item_name);
974         }
975         return 0;
976 }
977
978 struct ao2_container *ast_get_chan_applicationmap(struct ast_channel *chan)
979 {
980         RAII_VAR(struct features_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
981         struct ao2_container *applicationmap;
982         char *group_names;
983         char *name;
984
985         if (!cfg) {
986                 return NULL;
987         }
988
989         if (!chan) {
990                 if (!cfg->applicationmap || ao2_container_count(cfg->applicationmap) == 0) {
991                         return NULL;
992                 }
993                 ao2_ref(cfg->applicationmap, +1);
994                 return cfg->applicationmap;
995         }
996
997         group_names = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"), ""));
998         if (ast_strlen_zero(group_names)) {
999                 return NULL;
1000         }
1001
1002         applicationmap = applicationmap_alloc();
1003         if (!applicationmap) {
1004                 return NULL;
1005         }
1006
1007         while ((name = strsep(&group_names, "#"))) {
1008                 RAII_VAR(struct featuregroup *, group, ao2_find(cfg->featuregroups, name, OBJ_KEY), ao2_cleanup);
1009                 if (!group) {
1010                         RAII_VAR(struct ast_applicationmap_item *, item, ao2_find(cfg->applicationmap, name, OBJ_KEY), ao2_cleanup);
1011                         if (item && !ao2_link(applicationmap, item)) {
1012                                 ast_log(LOG_WARNING, "Unable to add applicationmap item %s. Possible duplicate.\n", item->name);
1013                         }
1014                 } else {
1015                         ao2_callback(group->items, 0, add_item, applicationmap);
1016                 }
1017         }
1018
1019         if (ao2_container_count(applicationmap) == 0) {
1020                 ao2_cleanup(applicationmap);
1021                 return NULL;
1022         }
1023
1024         return applicationmap;
1025 }
1026
1027 static int applicationmap_handler(const struct aco_option *opt,
1028                 struct ast_variable *var, void *obj)
1029 {
1030         RAII_VAR(struct ast_applicationmap_item *, item, NULL, ao2_cleanup);
1031         struct ao2_container *applicationmap = obj;
1032         AST_DECLARE_APP_ARGS(args,
1033                 AST_APP_ARG(dtmf);
1034                 AST_APP_ARG(activate_on);
1035                 AST_APP_ARG(app);
1036                 AST_APP_ARG(app_data);
1037                 AST_APP_ARG(moh_class);
1038         );
1039         char *parse = ast_strdupa(var->value);
1040         char *slash;
1041         char *paren;
1042         unsigned int activate_on_self;
1043
1044         AST_STANDARD_APP_ARGS(args, parse);
1045
1046         if (ast_strlen_zero(args.dtmf) ||
1047                         ast_strlen_zero(args.activate_on) ||
1048                         ast_strlen_zero(args.app)) {
1049                 ast_log(LOG_WARNING, "Invalid applicationmap syntax for '%s'. Missing required argument\n", var->name);
1050                 return -1;
1051         }
1052
1053         /* features.conf used to have an "activated_by" portion
1054          * in addition to activate_on. Get rid of whatever may be
1055          * there
1056          */
1057         slash = strchr(args.activate_on, '/');
1058         if (slash) {
1059                 *slash = '\0';
1060         }
1061
1062         /* Two syntaxes allowed for applicationmap:
1063          * Old: foo = *1,self,NoOp,Boo!,default
1064          * New: foo = *1,self,NoOp(Boo!),default
1065          *
1066          * We need to handle both
1067          */
1068         paren = strchr(args.app, '(');
1069         if (paren) {
1070                 /* New syntax */
1071                 char *close_paren;
1072
1073                 args.moh_class = args.app_data;
1074                 *paren++ = '\0';
1075                 close_paren = strrchr(paren, ')');
1076                 if (close_paren) {
1077                         *close_paren = '\0';
1078                 }
1079                 args.app_data = paren;
1080
1081                 /* Re-check that the application is not empty */
1082                 if (ast_strlen_zero(args.app)) {
1083                         ast_log(LOG_WARNING, "Applicationmap item '%s' does not contain an application name.\n", var->name);
1084                         return -1;
1085                 }
1086         } else if (strchr(args.app_data, '"')) {
1087                 args.app_data = ast_strip_quoted(args.app_data, "\"", "\"");
1088         }
1089
1090         /* Allow caller and callee to be specified for backwards compatibility */
1091         if (!strcasecmp(args.activate_on, "self") || !strcasecmp(args.activate_on, "caller")) {
1092                 activate_on_self = 1;
1093         } else if (!strcasecmp(args.activate_on, "peer") || !strcasecmp(args.activate_on, "callee")) {
1094                 activate_on_self = 0;
1095         } else {
1096                 ast_log(LOG_WARNING, "Invalid 'activate_on' value %s for applicationmap item %s\n",
1097                         args.activate_on, var->name);
1098                 return -1;
1099         }
1100
1101         ast_debug(1, "Allocating applicationmap item: dtmf = %s, app = %s, app_data = %s, moh_class = %s\n",
1102                         args.dtmf, args.app, args.app_data, args.moh_class);
1103
1104         item = applicationmap_item_alloc(var->name, args.app, args.app_data,
1105                         args.moh_class, args.dtmf, activate_on_self);
1106
1107         if (!item) {
1108                 return -1;
1109         }
1110
1111         if (!ao2_link(applicationmap, item)) {
1112                 ast_log(LOG_WARNING, "Unable to add applicationmap item %s. Possible duplicate\n", item->name);
1113         }
1114
1115         return 0;
1116 }
1117
1118 static int featuregroup_handler(const struct aco_option *opt,
1119                 struct ast_variable *var, void *obj)
1120 {
1121         RAII_VAR(struct featuregroup_item *, item, NULL, ao2_cleanup);
1122         struct featuregroup *group = obj;
1123
1124         item = ao2_alloc(sizeof(*item), featuregroup_item_destructor);
1125         if (!item || ast_string_field_init(item, 32)) {
1126                 return -1;
1127         }
1128
1129         ast_string_field_set(item, appmap_item_name, var->name);
1130         ast_string_field_set(item, dtmf_override, var->value);
1131
1132         if (!ao2_link(group->items, item)) {
1133                 ast_log(LOG_WARNING, "Unable to add featuregroup item %s. Possible duplicate\n", item->appmap_item_name);
1134         }
1135
1136         /* We wait to look up the application map item in the preapply callback */
1137
1138         return 0;
1139 }
1140
1141 static int general_handler(const struct aco_option *opt,
1142                 struct ast_variable *var, void *obj)
1143 {
1144         struct features_global_config *global = obj;
1145         struct ast_features_general_config *general = global->general;
1146
1147         return general_set(general, var->name, var->value);
1148 }
1149
1150 static int xfer_handler(const struct aco_option *opt,
1151                 struct ast_variable *var, void *obj)
1152 {
1153         struct features_global_config *global = obj;
1154         struct ast_features_xfer_config *xfer = global->xfer;
1155
1156         return xfer_set(xfer, var->name, var->value);
1157 }
1158
1159 static int pickup_handler(const struct aco_option *opt,
1160                 struct ast_variable *var, void *obj)
1161 {
1162         struct features_global_config *global = obj;
1163         struct ast_features_pickup_config *pickup = global->pickup;
1164
1165         return pickup_set(pickup, var->name, var->value);
1166 }
1167
1168 static int featuremap_handler(const struct aco_option *opt,
1169                 struct ast_variable *var, void *obj)
1170 {
1171         struct ast_featuremap_config *featuremap = obj;
1172
1173         return featuremap_set(featuremap, var->name, var->value);
1174 }
1175
1176 static int check_featuregroup_item(void *obj, void *arg, void *data, int flags)
1177 {
1178         struct ast_applicationmap_item *appmap_item;
1179         struct featuregroup_item *fg_item = obj;
1180         int *err = arg;
1181         struct ao2_container *applicationmap = data;
1182
1183         appmap_item = ao2_find(applicationmap, fg_item->appmap_item_name, OBJ_KEY);
1184         if (!appmap_item) {
1185                 *err = 1;
1186                 return CMP_STOP;
1187         }
1188
1189         fg_item->appmap_item = appmap_item;
1190
1191         return 0;
1192 }
1193
1194 static int check_featuregroup(void *obj, void *arg, void *data, int flags)
1195 {
1196         struct featuregroup *group = obj;
1197         int *err = arg;
1198
1199         ao2_callback_data(group->items, 0, check_featuregroup_item, arg, data);
1200
1201         if (*err) {
1202                 ast_log(LOG_WARNING, "Featuregroup %s refers to non-existent applicationmap item\n",
1203                                 group->name);
1204         }
1205
1206         return *err ? CMP_STOP : 0;
1207 }
1208
1209 static int features_pre_apply_config(void);
1210
1211 CONFIG_INFO_CORE("features", cfg_info, globals, features_config_alloc,
1212         .files = ACO_FILES(&features_conf),
1213         .pre_apply_config = features_pre_apply_config,
1214 );
1215
1216 static int features_pre_apply_config(void)
1217 {
1218         struct features_config *cfg = aco_pending_config(&cfg_info);
1219         int err = 0;
1220
1221         /* Now that the entire config has been processed, we can check that the featuregroup
1222          * items refer to actual applicationmap items.
1223          */
1224
1225         ao2_callback_data(cfg->featuregroups, 0, check_featuregroup, &err, cfg->applicationmap);
1226
1227         return err;
1228 }
1229
1230 static int feature_read(struct ast_channel *chan, const char *cmd, char *data,
1231                char *buf, size_t len)
1232 {
1233         int res;
1234         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1235         SCOPED_CHANNELLOCK(lock, chan);
1236
1237         if (!strcasecmp(data, "inherit")) {
1238                 struct ast_datastore *ds = get_feature_chan_ds(chan);
1239                 unsigned int inherit = ds ? ds->inheritance : 0;
1240
1241                 snprintf(buf, len, "%s", inherit ? "yes" : "no");
1242                 return 0;
1243         }
1244
1245         cfg = get_feature_ds(chan);
1246         if (!cfg) {
1247                 return -1;
1248         }
1249
1250         res = general_get(cfg->global->general, data, buf, len) &&
1251                 xfer_get(cfg->global->xfer, data, buf, len) &&
1252                 pickup_get(cfg->global->pickup, data, buf, len);
1253
1254         if (res) {
1255                 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
1256         }
1257
1258         return res;
1259 }
1260
1261 static int feature_write(struct ast_channel *chan, const char *cmd, char *data,
1262                 const char *value)
1263 {
1264         int res;
1265         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1266         SCOPED_CHANNELLOCK(lock, chan);
1267
1268         if (!strcasecmp(data, "inherit")) {
1269                 struct ast_datastore *ds = get_feature_chan_ds(chan);
1270                 if (ds) {
1271                         ds->inheritance = ast_true(value) ? DATASTORE_INHERIT_FOREVER : 0;
1272                 }
1273                 return 0;
1274         }
1275
1276         if (!(cfg = get_feature_ds(chan))) {
1277                 return -1;
1278         }
1279
1280         res = general_set(cfg->global->general, data, value) &&
1281                 xfer_set(cfg->global->xfer, data, value) &&
1282                 pickup_set(cfg->global->pickup, data, value);
1283
1284         if (res) {
1285                 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
1286         }
1287
1288         return res;
1289 }
1290
1291 static int featuremap_read(struct ast_channel *chan, const char *cmd, char *data,
1292                char *buf, size_t len)
1293 {
1294         int res;
1295         SCOPED_CHANNELLOCK(lock, chan);
1296
1297         res = ast_get_builtin_feature(chan, data, buf, len);
1298
1299         if (res) {
1300                 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
1301         }
1302
1303         return res;
1304 }
1305
1306 static int featuremap_write(struct ast_channel *chan, const char *cmd, char *data,
1307                 const char *value)
1308 {
1309         int res;
1310         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1311         SCOPED_CHANNELLOCK(lock, chan);
1312
1313         if (!(cfg = get_feature_ds(chan))) {
1314                 return -1;
1315         }
1316
1317         res = featuremap_set(cfg->featuremap, data, value);
1318         if (res) {
1319                 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
1320                 return -1;
1321         }
1322
1323         return 0;
1324 }
1325
1326 static struct ast_custom_function feature_function = {
1327         .name = "FEATURE",
1328         .read = feature_read,
1329         .write = feature_write
1330 };
1331
1332 static struct ast_custom_function featuremap_function = {
1333         .name = "FEATUREMAP",
1334         .read = featuremap_read,
1335         .write = featuremap_write
1336 };
1337
1338 static int load_config(int reload)
1339 {
1340         if (!reload && aco_info_init(&cfg_info)) {
1341                 ast_log(LOG_ERROR, "Unable to initialize configuration info for features\n");
1342                 return -1;
1343         }
1344
1345         aco_option_register_custom(&cfg_info, "featuredigittimeout", ACO_EXACT, global_options,
1346                         __stringify(DEFAULT_FEATURE_DIGIT_TIMEOUT), general_handler, 0);
1347         aco_option_register_custom(&cfg_info, "courtesytone", ACO_EXACT, global_options,
1348                         __stringify(DEFAULT_COURTESY_TONE), general_handler, 0);
1349
1350         aco_option_register_custom(&cfg_info, "transferdigittimeout", ACO_EXACT, global_options,
1351                         __stringify(DEFAULT_TRANSFER_DIGIT_TIMEOUT), xfer_handler, 0)
1352         aco_option_register_custom(&cfg_info, "atxfernoanswertimeout", ACO_EXACT, global_options,
1353                         __stringify(DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER), xfer_handler, 0);
1354         aco_option_register_custom(&cfg_info, "atxferdropcall", ACO_EXACT, global_options,
1355                         __stringify(DEFAULT_ATXFER_DROP_CALL), xfer_handler, 0);
1356         aco_option_register_custom(&cfg_info, "atxferloopdelay", ACO_EXACT, global_options,
1357                         __stringify(DEFAULT_ATXFER_LOOP_DELAY), xfer_handler, 0);
1358         aco_option_register_custom(&cfg_info, "atxfercallbackretries", ACO_EXACT, global_options,
1359                         __stringify(DEFAULT_ATXFER_CALLBACK_RETRIES), xfer_handler, 0);
1360         aco_option_register_custom(&cfg_info, "xfersound", ACO_EXACT, global_options,
1361                         DEFAULT_XFERSOUND, xfer_handler, 0);
1362         aco_option_register_custom(&cfg_info, "xferfailsound", ACO_EXACT, global_options,
1363                         DEFAULT_XFERFAILSOUND, xfer_handler, 0);
1364         aco_option_register_custom(&cfg_info, "atxferabort", ACO_EXACT, global_options,
1365                         DEFAULT_ATXFER_ABORT, xfer_handler, 0);
1366         aco_option_register_custom(&cfg_info, "atxfercomplete", ACO_EXACT, global_options,
1367                         DEFAULT_ATXFER_COMPLETE, xfer_handler, 0);
1368         aco_option_register_custom(&cfg_info, "atxferthreeway", ACO_EXACT, global_options,
1369                         DEFAULT_ATXFER_THREEWAY, xfer_handler, 0);
1370
1371         aco_option_register_custom(&cfg_info, "pickupexten", ACO_EXACT, global_options,
1372                         DEFAULT_PICKUPEXTEN, pickup_handler, 0);
1373         aco_option_register_custom(&cfg_info, "pickupsound", ACO_EXACT, global_options,
1374                         DEFAULT_PICKUPSOUND, pickup_handler, 0);
1375         aco_option_register_custom(&cfg_info, "pickupfailsound", ACO_EXACT, global_options,
1376                         DEFAULT_PICKUPFAILSOUND, pickup_handler, 0);
1377
1378         aco_option_register_custom(&cfg_info, "blindxfer", ACO_EXACT, featuremap_options,
1379                         DEFAULT_FEATUREMAP_BLINDXFER, featuremap_handler, 0);
1380         aco_option_register_custom(&cfg_info, "disconnect", ACO_EXACT, featuremap_options,
1381                         DEFAULT_FEATUREMAP_DISCONNECT, featuremap_handler, 0);
1382         aco_option_register_custom(&cfg_info, "automon", ACO_EXACT, featuremap_options,
1383                         DEFAULT_FEATUREMAP_AUTOMON, featuremap_handler, 0);
1384         aco_option_register_custom(&cfg_info, "atxfer", ACO_EXACT, featuremap_options,
1385                         DEFAULT_FEATUREMAP_ATXFER, featuremap_handler, 0);
1386         aco_option_register_custom(&cfg_info, "parkcall", ACO_EXACT, featuremap_options,
1387                         DEFAULT_FEATUREMAP_PARKCALL, featuremap_handler, 0);
1388         aco_option_register_custom(&cfg_info, "automixmon", ACO_EXACT, featuremap_options,
1389                         DEFAULT_FEATUREMAP_AUTOMIXMON, featuremap_handler, 0);
1390
1391         aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, applicationmap_options,
1392                         "", applicationmap_handler, 0);
1393
1394         aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, featuregroup_options,
1395                         "", featuregroup_handler, 0);
1396
1397         if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
1398                 ast_log(LOG_ERROR, "Failed to process features.conf configuration!\n");
1399                 if (!reload) {
1400                         aco_info_destroy(&cfg_info);
1401                         ao2_global_obj_release(globals);
1402                 }
1403                 return -1;
1404         }
1405
1406         return 0;
1407 }
1408
1409 static int print_featuregroup(void *obj, void *arg, int flags)
1410 {
1411         struct featuregroup_item *item = obj;
1412         struct ast_cli_args *a = arg;
1413
1414         ast_cli(a->fd, "===> --> %s (%s)\n", item->appmap_item_name,
1415                         S_OR(item->dtmf_override, item->appmap_item->dtmf));
1416
1417         return 0;
1418 }
1419
1420 static int print_featuregroups(void *obj, void *arg, int flags)
1421 {
1422         struct featuregroup *group = obj;
1423         struct ast_cli_args *a = arg;
1424
1425         ast_cli(a->fd, "===> Group: %s\n", group->name);
1426
1427         ao2_callback(group->items, 0, print_featuregroup, a);
1428         return 0;
1429 }
1430
1431 #define HFS_FORMAT "%-25s %-7s %-7s\n"
1432
1433 static int print_applicationmap(void *obj, void *arg, int flags)
1434 {
1435         struct ast_applicationmap_item *item = obj;
1436         struct ast_cli_args *a = arg;
1437
1438         ast_cli(a->fd, HFS_FORMAT, item->name, "no def", item->dtmf);
1439         return 0;
1440 }
1441
1442 /*!
1443  * \brief CLI command to list configured features
1444  * \param e
1445  * \param cmd
1446  * \param a
1447  *
1448  * \retval CLI_SUCCESS on success.
1449  * \retval NULL when tab completion is used.
1450  */
1451 static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1452 {
1453         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1454
1455         switch (cmd) {
1456
1457         case CLI_INIT:
1458                 e->command = "features show";
1459                 e->usage =
1460                         "Usage: features show\n"
1461                         "       Lists configured features\n";
1462                 return NULL;
1463         case CLI_GENERATE:
1464                 return NULL;
1465         }
1466
1467         cfg = ao2_global_obj_ref(globals);
1468
1469         ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
1470         ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
1471
1472         ast_cli(a->fd, HFS_FORMAT, "Pickup", DEFAULT_PICKUPEXTEN, cfg->global->pickup->pickupexten);
1473         ast_cli(a->fd, HFS_FORMAT, "Blind Transfer", DEFAULT_FEATUREMAP_BLINDXFER, cfg->featuremap->blindxfer);
1474         ast_cli(a->fd, HFS_FORMAT, "Attended Transfer", DEFAULT_FEATUREMAP_ATXFER, cfg->featuremap->atxfer);
1475         ast_cli(a->fd, HFS_FORMAT, "One Touch Monitor", DEFAULT_FEATUREMAP_AUTOMON, cfg->featuremap->automon);
1476         ast_cli(a->fd, HFS_FORMAT, "Disconnect Call", DEFAULT_FEATUREMAP_DISCONNECT, cfg->featuremap->disconnect);
1477         ast_cli(a->fd, HFS_FORMAT, "Park Call", DEFAULT_FEATUREMAP_PARKCALL, cfg->featuremap->parkcall);
1478         ast_cli(a->fd, HFS_FORMAT, "One Touch MixMonitor", DEFAULT_FEATUREMAP_AUTOMIXMON, cfg->featuremap->automixmon);
1479
1480         ast_cli(a->fd, "\n");
1481         ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
1482         ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
1483         if (!cfg->applicationmap || ao2_container_count(cfg->applicationmap) == 0) {
1484                 ast_cli(a->fd, "(none)\n");
1485         } else {
1486                 ao2_callback(cfg->applicationmap, 0, print_applicationmap, a);
1487         }
1488
1489         ast_cli(a->fd, "\nFeature Groups:\n");
1490         ast_cli(a->fd, "---------------\n");
1491         if (!cfg->featuregroups || ao2_container_count(cfg->featuregroups) == 0) {
1492                 ast_cli(a->fd, "(none)\n");
1493         } else {
1494                 ao2_callback(cfg->featuregroups, 0, print_featuregroups, a);
1495         }
1496
1497         ast_cli(a->fd, "\n");
1498
1499         return CLI_SUCCESS;
1500 }
1501
1502 static struct ast_cli_entry cli_features_config[] = {
1503         AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
1504 };
1505
1506 void ast_features_config_shutdown(void)
1507 {
1508         ast_custom_function_unregister(&featuremap_function);
1509         ast_custom_function_unregister(&feature_function);
1510         ast_cli_unregister_multiple(cli_features_config, ARRAY_LEN(cli_features_config));
1511         aco_info_destroy(&cfg_info);
1512         ao2_global_obj_release(globals);
1513 }
1514
1515 int ast_features_config_reload(void)
1516 {
1517         return load_config(1);
1518 }
1519
1520 int ast_features_config_init(void)
1521 {
1522         int res;
1523
1524         res = load_config(0);
1525         res |= __ast_custom_function_register(&feature_function, NULL);
1526         res |= __ast_custom_function_register(&featuremap_function, NULL);
1527         res |= ast_cli_register_multiple(cli_features_config, ARRAY_LEN(cli_features_config));
1528
1529         if (res) {
1530                 ast_features_config_shutdown();
1531         }
1532
1533         return res;
1534 }