Index installed sounds and implement ARI sounds queries
[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_REPLACE, 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(int replace_duplicates)
422 {
423         return ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
424                 replace_duplicates ? AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE : AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW,
425                 applicationmap_sort, NULL);
426 }
427
428 /*!
429  * \internal
430  * \brief Allocate the major configuration structure
431  *
432  * The parameter is used to determine if the applicationmap and featuregroup
433  * structures should be allocated. We only want to allocate these structures for
434  * the global features_config structure. For the datastores on channels, we don't
435  * need to allocate these structures because they are not used.
436  *
437  * \param allocate_applicationmap See previous explanation
438  * \retval NULL Failed to alloate configuration
439  * \retval non-NULL Allocated configuration
440  */
441 static struct features_config *__features_config_alloc(int allocate_applicationmap)
442 {
443         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
444
445         cfg = ao2_alloc(sizeof(*cfg), features_config_destructor);
446         if (!cfg) {
447                 return NULL;
448         }
449
450         cfg->global = global_config_alloc();;
451         if (!cfg->global) {
452                 return NULL;
453         }
454
455         cfg->featuremap = ao2_alloc(sizeof(*cfg->featuremap), featuremap_config_destructor);
456         if (!cfg->featuremap || ast_string_field_init(cfg->featuremap, 32)) {
457                 return NULL;
458         }
459
460         if (allocate_applicationmap) {
461                 cfg->applicationmap = applicationmap_alloc(1);
462                 if (!cfg->applicationmap) {
463                         return NULL;
464                 }
465
466                 cfg->featuregroups = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 11, featuregroup_hash,
467                         featuregroup_cmp);
468                 if (!cfg->featuregroups) {
469                         return NULL;
470                 }
471         }
472
473         ao2_ref(cfg, +1);
474         return cfg;
475
476 }
477
478 static void *features_config_alloc(void)
479 {
480         return __features_config_alloc(1);
481 }
482
483 static void general_copy(struct ast_features_general_config *dest, const struct ast_features_general_config *src)
484 {
485         ast_string_fields_copy(dest, src);
486         dest->featuredigittimeout = src->featuredigittimeout;
487 }
488
489 static void xfer_copy(struct ast_features_xfer_config *dest, const struct ast_features_xfer_config *src)
490 {
491         ast_string_fields_copy(dest, src);
492         dest->transferdigittimeout = src->transferdigittimeout;
493         dest->atxfernoanswertimeout = src->atxfernoanswertimeout;
494         dest->atxferloopdelay = src->atxferloopdelay;
495         dest->atxfercallbackretries = src->atxfercallbackretries;
496         dest->atxferdropcall = src->atxferdropcall;
497 }
498
499 static void pickup_copy(struct ast_features_pickup_config *dest, const struct ast_features_pickup_config *src)
500 {
501         ast_string_fields_copy(dest, src);
502 }
503
504 static void global_copy(struct features_global_config *dest, const struct features_global_config *src)
505 {
506         general_copy(dest->general, src->general);
507         xfer_copy(dest->xfer, src->xfer);
508         pickup_copy(dest->pickup, src->pickup);
509 }
510
511 static void featuremap_copy(struct ast_featuremap_config *dest, const struct ast_featuremap_config *src)
512 {
513         ast_string_fields_copy(dest, src);
514 }
515
516 static void features_copy(struct features_config *dest, const struct features_config *src)
517 {
518         global_copy(dest->global, src->global);
519         featuremap_copy(dest->featuremap, src->featuremap);
520
521         /* applicationmap and featuregroups are purposely not copied. A channel's applicationmap
522          * is produced on the fly when ast_get_chan_applicationmap() is called
523          */
524 }
525
526 static struct features_config *features_config_dup(const struct features_config *orig)
527 {
528         struct features_config *dup;
529
530         dup = __features_config_alloc(0);
531         if (!dup) {
532                 return NULL;
533         }
534
535         features_copy(dup, orig);
536
537         return dup;
538 }
539
540 static int general_set(struct ast_features_general_config *general, const char *name,
541                 const char *value)
542 {
543         int res = 0;
544
545         if (!strcasecmp(name, "featuredigittimeout")) {
546                 res = ast_parse_arg(value, PARSE_INT32, &general->featuredigittimeout);
547         } else if (!strcasecmp(name, "courtesytone")) {
548                 ast_string_field_set(general, courtesytone, value);
549         } else {
550                 /* Unrecognized option */
551                 res = -1;
552         }
553
554         return res;
555 }
556
557 static int general_get(struct ast_features_general_config *general, const char *field,
558                 char *buf, size_t len)
559 {
560         int res = 0;
561
562         if (!strcasecmp(field, "featuredigittimeout")) {
563                 snprintf(buf, len, "%u", general->featuredigittimeout);
564         } else if (!strcasecmp(field, "courtesytone")) {
565                 ast_copy_string(buf, general->courtesytone, len);
566         } else {
567                 /* Unrecognized option */
568                 res = -1;
569         }
570
571         return res;
572 }
573
574 static int xfer_set(struct ast_features_xfer_config *xfer, const char *name,
575                 const char *value)
576 {
577         int res = 0;
578
579         if (!strcasecmp(name, "transferdigittimeout")) {
580                 res = ast_parse_arg(value, PARSE_INT32, &xfer->transferdigittimeout);
581         } else if (!strcasecmp(name, "atxfernoanswertimeout")) {
582                 res = ast_parse_arg(value, PARSE_INT32, &xfer->atxfernoanswertimeout);
583         } else if (!strcasecmp(name, "atxferloopdelay")) {
584                 res = ast_parse_arg(value, PARSE_INT32, &xfer->atxferloopdelay);
585         } else if (!strcasecmp(name, "atxfercallbackretries")) {
586                 res = ast_parse_arg(value, PARSE_INT32, &xfer->atxfercallbackretries);
587         } else if (!strcasecmp(name, "atxferdropcall")) {
588                 xfer->atxferdropcall = ast_true(value);
589         } else if (!strcasecmp(name, "xfersound")) {
590                 ast_string_field_set(xfer, xfersound, value);
591         } else if (!strcasecmp(name, "xferfailsound")) {
592                 ast_string_field_set(xfer, xferfailsound, value);
593         } else if (!strcasecmp(name, "atxferabort")) {
594                 ast_string_field_set(xfer, atxferabort, value);
595         } else if (!strcasecmp(name, "atxfercomplete")) {
596                 ast_string_field_set(xfer, atxfercomplete, value);
597         } else if (!strcasecmp(name, "atxferthreeway")) {
598                 ast_string_field_set(xfer, atxferthreeway, value);
599         } else {
600                 /* Unrecognized option */
601                 res = -1;
602         }
603
604         return res;
605 }
606
607 static int xfer_get(struct ast_features_xfer_config *xfer, const char *field,
608                 char *buf, size_t len)
609 {
610         int res = 0;
611
612         if (!strcasecmp(field, "transferdigittimeout")) {
613                 snprintf(buf, len, "%u", xfer->transferdigittimeout);
614         } else if (!strcasecmp(field, "atxfernoanswertimeout")) {
615                 snprintf(buf, len, "%u", xfer->atxfernoanswertimeout);
616         } else if (!strcasecmp(field, "atxferloopdelay")) {
617                 snprintf(buf, len, "%u", xfer->atxferloopdelay);
618         } else if (!strcasecmp(field, "atxfercallbackretries")) {
619                 snprintf(buf, len, "%u", xfer->atxfercallbackretries);
620         } else if (!strcasecmp(field, "atxferdropcall")) {
621                 snprintf(buf, len, "%u", xfer->atxferdropcall);
622         } else if (!strcasecmp(field, "xfersound")) {
623                 ast_copy_string(buf, xfer->xfersound, len);
624         } else if (!strcasecmp(field, "xferfailsound")) {
625                 ast_copy_string(buf, xfer->xferfailsound, len);
626         } else if (!strcasecmp(field, "atxferabort")) {
627                 ast_copy_string(buf, xfer->atxferabort, len);
628         } else if (!strcasecmp(field, "atxfercomplete")) {
629                 ast_copy_string(buf, xfer->atxfercomplete, len);
630         } else if (!strcasecmp(field, "atxferthreeway")) {
631                 ast_copy_string(buf, xfer->atxferthreeway, len);
632         } else {
633                 /* Unrecognized option */
634                 res = -1;
635         }
636
637         return res;
638 }
639
640 static int pickup_set(struct ast_features_pickup_config *pickup, const char *name,
641                 const char *value)
642 {
643         int res = 0;
644
645         if (!strcasecmp(name, "pickupsound")) {
646                 ast_string_field_set(pickup, pickupsound, value);
647         } else if (!strcasecmp(name, "pickupfailsound")) {
648                 ast_string_field_set(pickup, pickupfailsound, value);
649         } else if (!strcasecmp(name, "pickupexten")) {
650                 ast_string_field_set(pickup, pickupexten, value);
651         } else {
652                 /* Unrecognized option */
653                 res = -1;
654         }
655
656         return res;
657 }
658
659 static int pickup_get(struct ast_features_pickup_config *pickup, const char *field,
660                 char *buf, size_t len)
661 {
662         int res = 0;
663
664         if (!strcasecmp(field, "pickupsound")) {
665                 ast_copy_string(buf, pickup->pickupsound, len);
666         } else if (!strcasecmp(field, "pickupfailsound")) {
667                 ast_copy_string(buf, pickup->pickupfailsound, len);
668         } else if (!strcasecmp(field, "pickupexten")) {
669                 ast_copy_string(buf, pickup->pickupexten, len);
670         } else {
671                 /* Unrecognized option */
672                 res = -1;
673         }
674
675         return res;
676 }
677
678 static int featuremap_set(struct ast_featuremap_config *featuremap, const char *name,
679                 const char *value)
680 {
681         int res = 0;
682
683         if (!strcasecmp(name, "blindxfer")) {
684                 ast_string_field_set(featuremap, blindxfer, value);
685         } else if (!strcasecmp(name, "disconnect")) {
686                 ast_string_field_set(featuremap, disconnect, value);
687         } else if (!strcasecmp(name, "automon")) {
688                 ast_string_field_set(featuremap, automon, value);
689         } else if (!strcasecmp(name, "atxfer")) {
690                 ast_string_field_set(featuremap, atxfer, value);
691         } else if (!strcasecmp(name, "automixmon")) {
692                 ast_string_field_set(featuremap, automixmon, value);
693         } else if (!strcasecmp(name, "parkcall")) {
694                 ast_string_field_set(featuremap, parkcall, value);
695         } else {
696                 /* Unrecognized option */
697                 res = -1;
698         }
699
700         return res;
701 }
702
703 static int featuremap_get(struct ast_featuremap_config *featuremap, const char *field,
704                 char *buf, size_t len)
705 {
706         int res = 0;
707
708         if (!strcasecmp(field, "blindxfer")) {
709                 ast_copy_string(buf, featuremap->blindxfer, len);
710         } else if (!strcasecmp(field, "disconnect")) {
711                 ast_copy_string(buf, featuremap->disconnect, len);
712         } else if (!strcasecmp(field, "automon")) {
713                 ast_copy_string(buf, featuremap->automon, len);
714         } else if (!strcasecmp(field, "atxfer")) {
715                 ast_copy_string(buf, featuremap->atxfer, len);
716         } else if (!strcasecmp(field, "automixmon")) {
717                 ast_copy_string(buf, featuremap->automixmon, len);
718         } else if (!strcasecmp(field, "parkcall")) {
719                 ast_copy_string(buf, featuremap->parkcall, len);
720         } else {
721                 /* Unrecognized option */
722                 res = -1;
723         }
724
725         return res;
726 }
727
728 static void feature_ds_destroy(void *data)
729 {
730         struct features_config *cfg = data;
731         ao2_cleanup(cfg);
732 }
733
734 static void *feature_ds_duplicate(void *data)
735 {
736         struct features_config *old_cfg = data;
737
738         return features_config_dup(old_cfg);
739 }
740
741 static const struct ast_datastore_info feature_ds_info = {
742         .type = "FEATURE",
743         .destroy = feature_ds_destroy,
744         .duplicate = feature_ds_duplicate,
745 };
746
747 /*!
748  * \internal
749  * \brief Find or create feature datastore on a channel
750  *
751  * \pre chan is locked
752  *
753  * \return the data on the FEATURE datastore, or NULL on error
754  */
755 static struct features_config *get_feature_ds(struct ast_channel *chan)
756 {
757         RAII_VAR(struct features_config *, orig, NULL, ao2_cleanup);
758         struct features_config *cfg;
759         struct ast_datastore *ds;
760
761         if ((ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
762                 cfg = ds->data;
763                 ao2_ref(cfg, +1);
764                 return cfg;
765         }
766
767         orig = ao2_global_obj_ref(globals);
768         if (!orig) {
769                 return NULL;
770         }
771
772         cfg = features_config_dup(orig);
773         if (!cfg) {
774                 return NULL;
775         }
776
777         if (!(ds = ast_datastore_alloc(&feature_ds_info, NULL))) {
778                 ao2_cleanup(cfg);
779                 return NULL;
780         }
781
782         /* Give the datastore a reference to the config */
783         ao2_ref(cfg, +1);
784         ds->data = cfg;
785
786         ast_channel_datastore_add(chan, ds);
787
788         return cfg;
789 }
790
791 static struct ast_datastore *get_feature_chan_ds(struct ast_channel *chan)
792 {
793         struct ast_datastore *ds;
794
795         if (!(ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
796                 /* Hasn't been created yet.  Trigger creation. */
797                 RAII_VAR(struct features_config *, cfg, get_feature_ds(chan), ao2_cleanup);
798                 ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL);
799         }
800
801         return ds;
802 }
803
804 struct ast_features_general_config *ast_get_chan_features_general_config(struct ast_channel *chan)
805 {
806         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
807
808         if (chan) {
809                 cfg = get_feature_ds(chan);
810         } else {
811                 cfg = ao2_global_obj_ref(globals);
812         }
813
814         if (!cfg) {
815                 return NULL;
816         }
817
818         ast_assert(cfg->global && cfg->global->general);
819
820         ao2_ref(cfg->global->general, +1);
821         return cfg->global->general;
822 }
823
824 struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_channel *chan)
825 {
826         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
827
828         if (chan) {
829                 cfg = get_feature_ds(chan);
830         } else {
831                 cfg = ao2_global_obj_ref(globals);
832         }
833
834         if (!cfg) {
835                 return NULL;
836         }
837
838         ast_assert(cfg->global && cfg->global->xfer);
839
840         ao2_ref(cfg->global->xfer, +1);
841         return cfg->global->xfer;
842 }
843
844 struct ast_features_pickup_config *ast_get_chan_features_pickup_config(struct ast_channel *chan)
845 {
846         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
847
848         if (chan) {
849                 cfg = get_feature_ds(chan);
850         } else {
851                 cfg = ao2_global_obj_ref(globals);
852         }
853
854         if (!cfg) {
855                 return NULL;
856         }
857
858         ast_assert(cfg->global && cfg->global->pickup);
859
860         ao2_ref(cfg->global->pickup, +1);
861         return cfg->global->pickup;
862 }
863
864 struct ast_featuremap_config *ast_get_chan_featuremap_config(struct ast_channel *chan)
865 {
866         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
867
868         if (chan) {
869                 cfg = get_feature_ds(chan);
870         } else {
871                 cfg = ao2_global_obj_ref(globals);
872         }
873
874         if (!cfg) {
875                 return NULL;
876         }
877
878         ast_assert(cfg->featuremap != NULL);
879
880         ao2_ref(cfg->featuremap, +1);
881         return cfg->featuremap;
882 }
883
884 int ast_get_builtin_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
885 {
886         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
887
888         if (chan) {
889                 cfg = get_feature_ds(chan);
890         } else {
891                 cfg = ao2_global_obj_ref(globals);
892         }
893
894         if (!cfg) {
895                 return -1;
896         }
897
898         return featuremap_get(cfg->featuremap, feature, buf, len);
899 }
900
901 int ast_get_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
902 {
903         RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup);
904         RAII_VAR(struct ast_applicationmap_item *, item, NULL, ao2_cleanup);
905
906         if (!ast_get_builtin_feature(chan, feature, buf, len)) {
907                 return 0;
908         }
909
910         /* Dang, must be in the application map */
911         applicationmap = ast_get_chan_applicationmap(chan);
912         if (!applicationmap) {
913                 return -1;
914         }
915
916         item = ao2_find(applicationmap, feature, OBJ_KEY);
917         if (!item) {
918                 return -1;
919         }
920
921         ast_copy_string(buf, item->dtmf, len);
922         return 0;
923 }
924
925 static struct ast_applicationmap_item *applicationmap_item_alloc(const char *name,
926                 const char *app, const char *app_data, const char *moh_class, const char *dtmf,
927                 unsigned int activate_on_self)
928 {
929         struct ast_applicationmap_item *item;
930
931         item = ao2_alloc(sizeof(*item), ast_applicationmap_item_destructor);
932
933         if (!item || ast_string_field_init(item, 64)) {
934                 return NULL;
935         }
936
937         ast_string_field_set(item, name, name);
938         ast_string_field_set(item, app, app);
939         ast_string_field_set(item, app_data, app_data);
940         ast_string_field_set(item, moh_class, moh_class);
941         ast_copy_string(item->dtmf, dtmf, sizeof(item->dtmf));
942         item->activate_on_self = activate_on_self;
943
944         return item;
945 }
946
947 static int add_item(void *obj, void *arg, int flags)
948 {
949         struct featuregroup_item *fg_item = obj;
950         struct ao2_container *applicationmap = arg;
951         RAII_VAR(struct ast_applicationmap_item *, appmap_item, NULL, ao2_cleanup);
952
953         /* If there's no DTMF override, then we can just link
954          * the applicationmap item directly. Otherwise, we need
955          * to create a copy with the DTMF override in place and
956          * link that instead
957          */
958         if (ast_strlen_zero(fg_item->dtmf_override)) {
959                 ao2_ref(fg_item->appmap_item, +1);
960                 appmap_item = fg_item->appmap_item;
961         } else {
962                 appmap_item = applicationmap_item_alloc(fg_item->appmap_item_name,
963                                 fg_item->appmap_item->app, fg_item->appmap_item->app_data,
964                                 fg_item->appmap_item->moh_class, fg_item->dtmf_override,
965                                 fg_item->appmap_item->activate_on_self);
966         }
967
968         if (!appmap_item) {
969                 return 0;
970         }
971
972         ao2_link(applicationmap, appmap_item);
973         return 0;
974 }
975
976 struct ao2_container *ast_get_chan_applicationmap(struct ast_channel *chan)
977 {
978         RAII_VAR(struct features_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
979         struct ao2_container *applicationmap;
980         char *group_names;
981         char *name;
982
983         if (!cfg) {
984                 return NULL;
985         }
986
987         if (!chan) {
988                 if (!cfg->applicationmap || ao2_container_count(cfg->applicationmap) == 0) {
989                         return NULL;
990                 }
991                 ao2_ref(cfg->applicationmap, +1);
992                 return cfg->applicationmap;
993         }
994
995         group_names = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"), ""));
996         if (ast_strlen_zero(group_names)) {
997                 return NULL;
998         }
999
1000         applicationmap = applicationmap_alloc(0);
1001         if (!applicationmap) {
1002                 return NULL;
1003         }
1004
1005         while ((name = strsep(&group_names, "#"))) {
1006                 RAII_VAR(struct featuregroup *, group, ao2_find(cfg->featuregroups, name, OBJ_KEY), ao2_cleanup);
1007
1008                 if (!group) {
1009                         RAII_VAR(struct ast_applicationmap_item *, item, ao2_find(cfg->applicationmap, name, OBJ_KEY), ao2_cleanup);
1010
1011                         if (item) {
1012                                 ao2_link(applicationmap, item);
1013                         } else {
1014                                 ast_log(LOG_WARNING, "Unknown DYNAMIC_FEATURES item '%s' on channel %s.\n",
1015                                         name, ast_channel_name(chan));
1016                         }
1017                 } else {
1018                         ao2_callback(group->items, 0, add_item, applicationmap);
1019                 }
1020         }
1021
1022         if (ao2_container_count(applicationmap) == 0) {
1023                 ao2_cleanup(applicationmap);
1024                 return NULL;
1025         }
1026
1027         return applicationmap;
1028 }
1029
1030 static int applicationmap_handler(const struct aco_option *opt,
1031                 struct ast_variable *var, void *obj)
1032 {
1033         RAII_VAR(struct ast_applicationmap_item *, item, NULL, ao2_cleanup);
1034         struct ao2_container *applicationmap = obj;
1035         AST_DECLARE_APP_ARGS(args,
1036                 AST_APP_ARG(dtmf);
1037                 AST_APP_ARG(activate_on);
1038                 AST_APP_ARG(app);
1039                 AST_APP_ARG(app_data);
1040                 AST_APP_ARG(moh_class);
1041         );
1042         char *parse = ast_strdupa(var->value);
1043         char *slash;
1044         char *paren;
1045         unsigned int activate_on_self;
1046
1047         AST_STANDARD_APP_ARGS(args, parse);
1048
1049         if (ast_strlen_zero(args.dtmf) ||
1050                         ast_strlen_zero(args.activate_on) ||
1051                         ast_strlen_zero(args.app)) {
1052                 ast_log(LOG_WARNING, "Invalid applicationmap syntax for '%s'. Missing required argument\n", var->name);
1053                 return -1;
1054         }
1055
1056         /* features.conf used to have an "activated_by" portion
1057          * in addition to activate_on. Get rid of whatever may be
1058          * there
1059          */
1060         slash = strchr(args.activate_on, '/');
1061         if (slash) {
1062                 *slash = '\0';
1063         }
1064
1065         /* Two syntaxes allowed for applicationmap:
1066          * Old: foo = *1,self,NoOp,Boo!,default
1067          * New: foo = *1,self,NoOp(Boo!),default
1068          *
1069          * We need to handle both
1070          */
1071         paren = strchr(args.app, '(');
1072         if (paren) {
1073                 /* New syntax */
1074                 char *close_paren;
1075
1076                 args.moh_class = args.app_data;
1077                 *paren++ = '\0';
1078                 close_paren = strrchr(paren, ')');
1079                 if (close_paren) {
1080                         *close_paren = '\0';
1081                 }
1082                 args.app_data = paren;
1083
1084                 /* Re-check that the application is not empty */
1085                 if (ast_strlen_zero(args.app)) {
1086                         ast_log(LOG_WARNING, "Applicationmap item '%s' does not contain an application name.\n", var->name);
1087                         return -1;
1088                 }
1089         } else if (strchr(args.app_data, '"')) {
1090                 args.app_data = ast_strip_quoted(args.app_data, "\"", "\"");
1091         }
1092
1093         /* Allow caller and callee to be specified for backwards compatibility */
1094         if (!strcasecmp(args.activate_on, "self") || !strcasecmp(args.activate_on, "caller")) {
1095                 activate_on_self = 1;
1096         } else if (!strcasecmp(args.activate_on, "peer") || !strcasecmp(args.activate_on, "callee")) {
1097                 activate_on_self = 0;
1098         } else {
1099                 ast_log(LOG_WARNING, "Invalid 'activate_on' value %s for applicationmap item %s\n",
1100                         args.activate_on, var->name);
1101                 return -1;
1102         }
1103
1104         ast_debug(1, "Allocating applicationmap item: dtmf = %s, app = %s, app_data = %s, moh_class = %s\n",
1105                         args.dtmf, args.app, args.app_data, args.moh_class);
1106
1107         item = applicationmap_item_alloc(var->name, args.app, args.app_data,
1108                         args.moh_class, args.dtmf, activate_on_self);
1109
1110         if (!item) {
1111                 return -1;
1112         }
1113
1114         if (!ao2_link(applicationmap, item)) {
1115                 return -1;
1116         }
1117
1118         return 0;
1119 }
1120
1121 static int featuregroup_handler(const struct aco_option *opt,
1122                 struct ast_variable *var, void *obj)
1123 {
1124         RAII_VAR(struct featuregroup_item *, item, NULL, ao2_cleanup);
1125         struct featuregroup *group = obj;
1126
1127         item = ao2_alloc(sizeof(*item), featuregroup_item_destructor);
1128         if (!item || ast_string_field_init(item, 32)) {
1129                 return -1;
1130         }
1131
1132         ast_string_field_set(item, appmap_item_name, var->name);
1133         ast_string_field_set(item, dtmf_override, var->value);
1134
1135         if (!ao2_link(group->items, item)) {
1136                 return -1;
1137         }
1138
1139         /* We wait to look up the application map item in the preapply callback */
1140
1141         return 0;
1142 }
1143
1144 static int general_handler(const struct aco_option *opt,
1145                 struct ast_variable *var, void *obj)
1146 {
1147         struct features_global_config *global = obj;
1148         struct ast_features_general_config *general = global->general;
1149
1150         return general_set(general, var->name, var->value);
1151 }
1152
1153 static int xfer_handler(const struct aco_option *opt,
1154                 struct ast_variable *var, void *obj)
1155 {
1156         struct features_global_config *global = obj;
1157         struct ast_features_xfer_config *xfer = global->xfer;
1158
1159         return xfer_set(xfer, var->name, var->value);
1160 }
1161
1162 static int pickup_handler(const struct aco_option *opt,
1163                 struct ast_variable *var, void *obj)
1164 {
1165         struct features_global_config *global = obj;
1166         struct ast_features_pickup_config *pickup = global->pickup;
1167
1168         return pickup_set(pickup, var->name, var->value);
1169 }
1170
1171 static int unsupported_handler(const struct aco_option *opt,
1172                 struct ast_variable *var, void *obj)
1173 {
1174         ast_log(LOG_WARNING, "The option '%s' is no longer configurable in features.conf.\n", var->name);
1175         return 0;
1176 }
1177
1178 static int featuremap_handler(const struct aco_option *opt,
1179                 struct ast_variable *var, void *obj)
1180 {
1181         struct ast_featuremap_config *featuremap = obj;
1182
1183         return featuremap_set(featuremap, var->name, var->value);
1184 }
1185
1186 static int check_featuregroup_item(void *obj, void *arg, void *data, int flags)
1187 {
1188         struct ast_applicationmap_item *appmap_item;
1189         struct featuregroup_item *fg_item = obj;
1190         int *err = arg;
1191         struct ao2_container *applicationmap = data;
1192
1193         appmap_item = ao2_find(applicationmap, fg_item->appmap_item_name, OBJ_KEY);
1194         if (!appmap_item) {
1195                 *err = 1;
1196                 return CMP_STOP;
1197         }
1198
1199         fg_item->appmap_item = appmap_item;
1200
1201         return 0;
1202 }
1203
1204 static int check_featuregroup(void *obj, void *arg, void *data, int flags)
1205 {
1206         struct featuregroup *group = obj;
1207         int *err = arg;
1208
1209         ao2_callback_data(group->items, 0, check_featuregroup_item, arg, data);
1210
1211         if (*err) {
1212                 ast_log(LOG_WARNING, "Featuregroup %s refers to non-existent applicationmap item\n",
1213                                 group->name);
1214         }
1215
1216         return *err ? CMP_STOP : 0;
1217 }
1218
1219 static int features_pre_apply_config(void);
1220
1221 CONFIG_INFO_CORE("features", cfg_info, globals, features_config_alloc,
1222         .files = ACO_FILES(&features_conf),
1223         .pre_apply_config = features_pre_apply_config,
1224 );
1225
1226 static int features_pre_apply_config(void)
1227 {
1228         struct features_config *cfg = aco_pending_config(&cfg_info);
1229         int err = 0;
1230
1231         /* Now that the entire config has been processed, we can check that the featuregroup
1232          * items refer to actual applicationmap items.
1233          */
1234
1235         ao2_callback_data(cfg->featuregroups, 0, check_featuregroup, &err, cfg->applicationmap);
1236
1237         return err;
1238 }
1239
1240 static int feature_read(struct ast_channel *chan, const char *cmd, char *data,
1241                char *buf, size_t len)
1242 {
1243         int res;
1244         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1245         SCOPED_CHANNELLOCK(lock, chan);
1246
1247         if (!strcasecmp(data, "inherit")) {
1248                 struct ast_datastore *ds = get_feature_chan_ds(chan);
1249                 unsigned int inherit = ds ? ds->inheritance : 0;
1250
1251                 snprintf(buf, len, "%s", inherit ? "yes" : "no");
1252                 return 0;
1253         }
1254
1255         cfg = get_feature_ds(chan);
1256         if (!cfg) {
1257                 return -1;
1258         }
1259
1260         res = general_get(cfg->global->general, data, buf, len) &&
1261                 xfer_get(cfg->global->xfer, data, buf, len) &&
1262                 pickup_get(cfg->global->pickup, data, buf, len);
1263
1264         if (res) {
1265                 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
1266         }
1267
1268         return res;
1269 }
1270
1271 static int feature_write(struct ast_channel *chan, const char *cmd, char *data,
1272                 const char *value)
1273 {
1274         int res;
1275         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1276         SCOPED_CHANNELLOCK(lock, chan);
1277
1278         if (!strcasecmp(data, "inherit")) {
1279                 struct ast_datastore *ds = get_feature_chan_ds(chan);
1280                 if (ds) {
1281                         ds->inheritance = ast_true(value) ? DATASTORE_INHERIT_FOREVER : 0;
1282                 }
1283                 return 0;
1284         }
1285
1286         if (!(cfg = get_feature_ds(chan))) {
1287                 return -1;
1288         }
1289
1290         res = general_set(cfg->global->general, data, value) &&
1291                 xfer_set(cfg->global->xfer, data, value) &&
1292                 pickup_set(cfg->global->pickup, data, value);
1293
1294         if (res) {
1295                 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
1296         }
1297
1298         return res;
1299 }
1300
1301 static int featuremap_read(struct ast_channel *chan, const char *cmd, char *data,
1302                char *buf, size_t len)
1303 {
1304         int res;
1305         SCOPED_CHANNELLOCK(lock, chan);
1306
1307         res = ast_get_builtin_feature(chan, data, buf, len);
1308
1309         if (res) {
1310                 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
1311         }
1312
1313         return res;
1314 }
1315
1316 static int featuremap_write(struct ast_channel *chan, const char *cmd, char *data,
1317                 const char *value)
1318 {
1319         int res;
1320         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1321         SCOPED_CHANNELLOCK(lock, chan);
1322
1323         if (!(cfg = get_feature_ds(chan))) {
1324                 return -1;
1325         }
1326
1327         res = featuremap_set(cfg->featuremap, data, value);
1328         if (res) {
1329                 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
1330                 return -1;
1331         }
1332
1333         return 0;
1334 }
1335
1336 static struct ast_custom_function feature_function = {
1337         .name = "FEATURE",
1338         .read = feature_read,
1339         .write = feature_write
1340 };
1341
1342 static struct ast_custom_function featuremap_function = {
1343         .name = "FEATUREMAP",
1344         .read = featuremap_read,
1345         .write = featuremap_write
1346 };
1347
1348 static int load_config(void)
1349 {
1350         if (aco_info_init(&cfg_info)) {
1351                 ast_log(LOG_ERROR, "Unable to initialize configuration info for features\n");
1352                 return -1;
1353         }
1354
1355         aco_option_register_custom(&cfg_info, "featuredigittimeout", ACO_EXACT, global_options,
1356                         __stringify(DEFAULT_FEATURE_DIGIT_TIMEOUT), general_handler, 0);
1357         aco_option_register_custom(&cfg_info, "courtesytone", ACO_EXACT, global_options,
1358                         __stringify(DEFAULT_COURTESY_TONE), general_handler, 0);
1359
1360         aco_option_register_custom(&cfg_info, "transferdigittimeout", ACO_EXACT, global_options,
1361                         __stringify(DEFAULT_TRANSFER_DIGIT_TIMEOUT), xfer_handler, 0)
1362         aco_option_register_custom(&cfg_info, "atxfernoanswertimeout", ACO_EXACT, global_options,
1363                         __stringify(DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER), xfer_handler, 0);
1364         aco_option_register_custom(&cfg_info, "atxferdropcall", ACO_EXACT, global_options,
1365                         __stringify(DEFAULT_ATXFER_DROP_CALL), xfer_handler, 0);
1366         aco_option_register_custom(&cfg_info, "atxferloopdelay", ACO_EXACT, global_options,
1367                         __stringify(DEFAULT_ATXFER_LOOP_DELAY), xfer_handler, 0);
1368         aco_option_register_custom(&cfg_info, "atxfercallbackretries", ACO_EXACT, global_options,
1369                         __stringify(DEFAULT_ATXFER_CALLBACK_RETRIES), xfer_handler, 0);
1370         aco_option_register_custom(&cfg_info, "xfersound", ACO_EXACT, global_options,
1371                         DEFAULT_XFERSOUND, xfer_handler, 0);
1372         aco_option_register_custom(&cfg_info, "xferfailsound", ACO_EXACT, global_options,
1373                         DEFAULT_XFERFAILSOUND, xfer_handler, 0);
1374         aco_option_register_custom(&cfg_info, "atxferabort", ACO_EXACT, global_options,
1375                         DEFAULT_ATXFER_ABORT, xfer_handler, 0);
1376         aco_option_register_custom(&cfg_info, "atxfercomplete", ACO_EXACT, global_options,
1377                         DEFAULT_ATXFER_COMPLETE, xfer_handler, 0);
1378         aco_option_register_custom(&cfg_info, "atxferthreeway", ACO_EXACT, global_options,
1379                         DEFAULT_ATXFER_THREEWAY, xfer_handler, 0);
1380
1381         aco_option_register_custom(&cfg_info, "pickupexten", ACO_EXACT, global_options,
1382                         DEFAULT_PICKUPEXTEN, pickup_handler, 0);
1383         aco_option_register_custom(&cfg_info, "pickupsound", ACO_EXACT, global_options,
1384                         DEFAULT_PICKUPSOUND, pickup_handler, 0);
1385         aco_option_register_custom(&cfg_info, "pickupfailsound", ACO_EXACT, global_options,
1386                         DEFAULT_PICKUPFAILSOUND, pickup_handler, 0);
1387
1388         aco_option_register_custom(&cfg_info, "context", ACO_EXACT, global_options,
1389                         "", unsupported_handler, 0);
1390         aco_option_register_custom(&cfg_info, "parkext", ACO_EXACT, global_options,
1391                         "", unsupported_handler, 0);
1392         aco_option_register_custom(&cfg_info, "parkext_exclusive", ACO_EXACT, global_options,
1393                         "", unsupported_handler, 0);
1394         aco_option_register_custom(&cfg_info, "parkinghints", ACO_EXACT, global_options,
1395                         "", unsupported_handler, 0);
1396         aco_option_register_custom(&cfg_info, "parkedmusicclass", ACO_EXACT, global_options,
1397                         "", unsupported_handler, 0);
1398         aco_option_register_custom(&cfg_info, "parkingtime", ACO_EXACT, global_options,
1399                         "", unsupported_handler, 0);
1400         aco_option_register_custom(&cfg_info, "parkpos", ACO_EXACT, global_options,
1401                         "", unsupported_handler, 0);
1402         aco_option_register_custom(&cfg_info, "findslot", ACO_EXACT, global_options,
1403                         "", unsupported_handler, 0);
1404         aco_option_register_custom(&cfg_info, "parkedcalltransfers", ACO_EXACT, global_options,
1405                         "", unsupported_handler, 0);
1406         aco_option_register_custom(&cfg_info, "parkedcallreparking", ACO_EXACT, global_options,
1407                         "", unsupported_handler, 0);
1408         aco_option_register_custom(&cfg_info, "parkedcallhangup", ACO_EXACT, global_options,
1409                         "", unsupported_handler, 0);
1410         aco_option_register_custom(&cfg_info, "parkedcallrecording", ACO_EXACT, global_options,
1411                         "", unsupported_handler, 0);
1412         aco_option_register_custom(&cfg_info, "comebackcontext", ACO_EXACT, global_options,
1413                         "", unsupported_handler, 0);
1414         aco_option_register_custom(&cfg_info, "comebacktoorigin", ACO_EXACT, global_options,
1415                         "", unsupported_handler, 0);
1416         aco_option_register_custom(&cfg_info, "comebackdialtime", ACO_EXACT, global_options,
1417                         "", unsupported_handler, 0);
1418         aco_option_register_custom(&cfg_info, "parkeddynamic", ACO_EXACT, global_options,
1419                         "", unsupported_handler, 0);
1420         aco_option_register_custom(&cfg_info, "adsipark", ACO_EXACT, global_options,
1421                         "", unsupported_handler, 0);
1422
1423         aco_option_register_custom(&cfg_info, "blindxfer", ACO_EXACT, featuremap_options,
1424                         DEFAULT_FEATUREMAP_BLINDXFER, featuremap_handler, 0);
1425         aco_option_register_custom(&cfg_info, "disconnect", ACO_EXACT, featuremap_options,
1426                         DEFAULT_FEATUREMAP_DISCONNECT, featuremap_handler, 0);
1427         aco_option_register_custom(&cfg_info, "automon", ACO_EXACT, featuremap_options,
1428                         DEFAULT_FEATUREMAP_AUTOMON, featuremap_handler, 0);
1429         aco_option_register_custom(&cfg_info, "atxfer", ACO_EXACT, featuremap_options,
1430                         DEFAULT_FEATUREMAP_ATXFER, featuremap_handler, 0);
1431         aco_option_register_custom(&cfg_info, "parkcall", ACO_EXACT, featuremap_options,
1432                         DEFAULT_FEATUREMAP_PARKCALL, featuremap_handler, 0);
1433         aco_option_register_custom(&cfg_info, "automixmon", ACO_EXACT, featuremap_options,
1434                         DEFAULT_FEATUREMAP_AUTOMIXMON, featuremap_handler, 0);
1435
1436         aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, applicationmap_options,
1437                         "", applicationmap_handler, 0);
1438
1439         aco_option_register_custom(&cfg_info, "^.*$", ACO_REGEX, featuregroup_options,
1440                         "", featuregroup_handler, 0);
1441
1442         if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
1443                 ast_log(LOG_ERROR, "Failed to process features.conf configuration!\n");
1444                 aco_info_destroy(&cfg_info);
1445                 ao2_global_obj_release(globals);
1446                 return -1;
1447         }
1448
1449         return 0;
1450 }
1451
1452 static int print_featuregroup(void *obj, void *arg, int flags)
1453 {
1454         struct featuregroup_item *item = obj;
1455         struct ast_cli_args *a = arg;
1456
1457         ast_cli(a->fd, "===> --> %s (%s)\n", item->appmap_item_name,
1458                         S_OR(item->dtmf_override, item->appmap_item->dtmf));
1459
1460         return 0;
1461 }
1462
1463 static int print_featuregroups(void *obj, void *arg, int flags)
1464 {
1465         struct featuregroup *group = obj;
1466         struct ast_cli_args *a = arg;
1467
1468         ast_cli(a->fd, "===> Group: %s\n", group->name);
1469
1470         ao2_callback(group->items, 0, print_featuregroup, a);
1471         return 0;
1472 }
1473
1474 #define HFS_FORMAT "%-25s %-7s %-7s\n"
1475
1476 static int print_applicationmap(void *obj, void *arg, int flags)
1477 {
1478         struct ast_applicationmap_item *item = obj;
1479         struct ast_cli_args *a = arg;
1480
1481         ast_cli(a->fd, HFS_FORMAT, item->name, "no def", item->dtmf);
1482         return 0;
1483 }
1484
1485 /*!
1486  * \brief CLI command to list configured features
1487  * \param e
1488  * \param cmd
1489  * \param a
1490  *
1491  * \retval CLI_SUCCESS on success.
1492  * \retval NULL when tab completion is used.
1493  */
1494 static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1495 {
1496         RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1497
1498         switch (cmd) {
1499
1500         case CLI_INIT:
1501                 e->command = "features show";
1502                 e->usage =
1503                         "Usage: features show\n"
1504                         "       Lists configured features\n";
1505                 return NULL;
1506         case CLI_GENERATE:
1507                 return NULL;
1508         }
1509
1510         cfg = ao2_global_obj_ref(globals);
1511
1512         ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
1513         ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
1514
1515         ast_cli(a->fd, HFS_FORMAT, "Pickup", DEFAULT_PICKUPEXTEN, cfg->global->pickup->pickupexten);
1516         ast_cli(a->fd, HFS_FORMAT, "Blind Transfer", DEFAULT_FEATUREMAP_BLINDXFER, cfg->featuremap->blindxfer);
1517         ast_cli(a->fd, HFS_FORMAT, "Attended Transfer", DEFAULT_FEATUREMAP_ATXFER, cfg->featuremap->atxfer);
1518         ast_cli(a->fd, HFS_FORMAT, "One Touch Monitor", DEFAULT_FEATUREMAP_AUTOMON, cfg->featuremap->automon);
1519         ast_cli(a->fd, HFS_FORMAT, "Disconnect Call", DEFAULT_FEATUREMAP_DISCONNECT, cfg->featuremap->disconnect);
1520         ast_cli(a->fd, HFS_FORMAT, "Park Call", DEFAULT_FEATUREMAP_PARKCALL, cfg->featuremap->parkcall);
1521         ast_cli(a->fd, HFS_FORMAT, "One Touch MixMonitor", DEFAULT_FEATUREMAP_AUTOMIXMON, cfg->featuremap->automixmon);
1522
1523         ast_cli(a->fd, "\n");
1524         ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
1525         ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
1526         if (!cfg->applicationmap || ao2_container_count(cfg->applicationmap) == 0) {
1527                 ast_cli(a->fd, "(none)\n");
1528         } else {
1529                 ao2_callback(cfg->applicationmap, 0, print_applicationmap, a);
1530         }
1531
1532         ast_cli(a->fd, "\nFeature Groups:\n");
1533         ast_cli(a->fd, "---------------\n");
1534         if (!cfg->featuregroups || ao2_container_count(cfg->featuregroups) == 0) {
1535                 ast_cli(a->fd, "(none)\n");
1536         } else {
1537                 ao2_callback(cfg->featuregroups, 0, print_featuregroups, a);
1538         }
1539
1540         ast_cli(a->fd, "\n");
1541
1542         return CLI_SUCCESS;
1543 }
1544
1545 static struct ast_cli_entry cli_features_config[] = {
1546         AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
1547 };
1548
1549 void ast_features_config_shutdown(void)
1550 {
1551         ast_custom_function_unregister(&featuremap_function);
1552         ast_custom_function_unregister(&feature_function);
1553         ast_cli_unregister_multiple(cli_features_config, ARRAY_LEN(cli_features_config));
1554         aco_info_destroy(&cfg_info);
1555         ao2_global_obj_release(globals);
1556 }
1557
1558 int ast_features_config_reload(void)
1559 {
1560         if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
1561                 return -1;
1562         }
1563         return 0;
1564 }
1565
1566 int ast_features_config_init(void)
1567 {
1568         int res;
1569
1570         res = load_config();
1571         res |= __ast_custom_function_register(&feature_function, NULL);
1572         res |= __ast_custom_function_register(&featuremap_function, NULL);
1573         res |= ast_cli_register_multiple(cli_features_config, ARRAY_LEN(cli_features_config));
1574
1575         if (res) {
1576                 ast_features_config_shutdown();
1577         }
1578
1579         return res;
1580 }