Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
features_config.c
Go to the documentation of this file.
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
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#include "features_config.h"
30
31/*** DOCUMENTATION
32 <configInfo name="features" language="en_US">
33 <synopsis>Features Configuration</synopsis>
34 <configFile name="features.conf">
35 <configObject name="globals">
36 <since>
37 <version>12.0.0</version>
38 </since>
39 <synopsis>
40 </synopsis>
41 <configOption name="featuredigittimeout" default="1000">
42 <since>
43 <version>12.0.0</version>
44 </since>
45 <synopsis>Milliseconds allowed between digit presses when entering a feature code.</synopsis>
46 </configOption>
47 <configOption name="courtesytone">
48 <since>
49 <version>12.0.0</version>
50 </since>
51 <synopsis>Sound to play when automixmon is activated</synopsis>
52 </configOption>
53 <configOption name="recordingfailsound">
54 <since>
55 <version>12.0.0</version>
56 </since>
57 <synopsis>Sound to play when automixmon is attempted but fails to start</synopsis>
58 </configOption>
59 <configOption name="transferdigittimeout" default="3">
60 <since>
61 <version>12.0.0</version>
62 </since>
63 <synopsis>Seconds allowed between digit presses when dialing a transfer destination</synopsis>
64 </configOption>
65 <configOption name="atxfernoanswertimeout" default="15">
66 <since>
67 <version>12.0.0</version>
68 </since>
69 <synopsis>Seconds to wait for attended transfer destination to answer</synopsis>
70 </configOption>
71 <configOption name="atxferdropcall" default="no">
72 <since>
73 <version>12.0.0</version>
74 </since>
75 <synopsis>Hang up the call entirely if the attended transfer fails</synopsis>
76 <description>
77 <para>When this option is set to <literal>no</literal>, then Asterisk will attempt to
78 re-call the transferrer if the call to the transfer target fails. If the call to the
79 transferrer fails, then Asterisk will wait <replaceable>atxferloopdelay</replaceable>
80 milliseconds and then attempt to dial the transfer target again. This process will
81 repeat until <replaceable>atxfercallbackretries</replaceable> attempts to re-call
82 the transferrer have occurred.</para>
83 <para>When this option is set to <literal>yes</literal>, then Asterisk will not attempt
84 to re-call the transferrer if the call to the transfer target fails. Asterisk will instead
85 hang up all channels involved in the transfer.</para>
86 </description>
87 </configOption>
88 <configOption name="atxferloopdelay" default="10">
89 <since>
90 <version>12.0.0</version>
91 </since>
92 <synopsis>Seconds to wait between attempts to re-dial transfer destination</synopsis>
93 <see-also><ref type="configOption">atxferdropcall</ref></see-also>
94 </configOption>
95 <configOption name="atxfercallbackretries" default="2">
96 <since>
97 <version>12.0.0</version>
98 </since>
99 <synopsis>Number of times to re-attempt dialing a transfer destination</synopsis>
100 <see-also><ref type="configOption">atxferdropcall</ref></see-also>
101 </configOption>
102 <configOption name="xfersound" default="beep">
103 <since>
104 <version>12.0.0</version>
105 </since>
106 <synopsis>Sound to play to during transfer and transfer-like operations.</synopsis>
107 <description>
108 <para>This sound will play to the transferrer and transfer target channels when
109 an attended transfer completes. This sound is also played to channels when performing
110 an AMI <literal>Bridge</literal> action.</para>
111 </description>
112 </configOption>
113 <configOption name="xferfailsound" default="beeperr">
114 <since>
115 <version>12.0.0</version>
116 </since>
117 <synopsis>Sound to play to a transferee when a transfer fails</synopsis>
118 </configOption>
119 <configOption name="atxferabort" default="*1">
120 <synopsis>Digits to dial to abort an attended transfer attempt</synopsis>
121 <description>
122 <para>This option is only available to the transferrer during an attended
123 transfer operation. Aborting a transfer results in the transfer being cancelled and
124 the original parties in the call being re-bridged.</para>
125 </description>
126 </configOption>
127 <configOption name="atxfercomplete" default="*2">
128 <synopsis>Digits to dial to complete an attended transfer</synopsis>
129 <description>
130 <para>This option is only available to the transferrer during an attended
131 transfer operation. Completing the transfer with a DTMF sequence is functionally
132 equivalent to hanging up the transferrer channel during an attended transfer. The
133 result is that the transfer target and transferees are bridged.</para>
134 </description>
135 </configOption>
136 <configOption name="atxferthreeway" default="*3">
137 <synopsis>Digits to dial to change an attended transfer into a three-way call</synopsis>
138 <description>
139 <para>This option is only available to the transferrer during an attended
140 transfer operation. Pressing this DTMF sequence will result in the transferrer,
141 the transferees, and the transfer target all being in a single bridge together.</para>
142 </description>
143 </configOption>
144 <configOption name="atxferswap" default="*4">
145 <synopsis>Digits to dial to toggle who the transferrer is currently bridged to during an attended transfer</synopsis>
146 <description>
147 <para>This option is only available to the transferrer during an attended
148 transfer operation. Pressing this DTMF sequence will result in the transferrer swapping
149 which party he is bridged with. For instance, if the transferrer is currently bridged with
150 the transfer target, then pressing this DTMF sequence will cause the transferrer to be
151 bridged with the transferees.</para>
152 </description>
153 </configOption>
154 <configOption name="pickupexten" default="*8">
155 <synopsis>Digits used for picking up ringing calls</synopsis>
156 <description>
157 <para>In order for the pickup attempt to be successful, the party attempting to
158 pick up the call must either have a <replaceable>namedpickupgroup</replaceable> in
159 common with a ringing party's <replaceable>namedcallgroup</replaceable> or must
160 have a <replaceable>pickupgroup</replaceable> in common with a ringing party's
161 <replaceable>callgroup</replaceable>.</para>
162 </description>
163 </configOption>
164 <configOption name="pickupsound">
165 <since>
166 <version>12.0.0</version>
167 </since>
168 <synopsis>Sound to play to picker when a call is picked up</synopsis>
169 </configOption>
170 <configOption name="pickupfailsound">
171 <since>
172 <version>12.0.0</version>
173 </since>
174 <synopsis>Sound to play to picker when a call cannot be picked up</synopsis>
175 </configOption>
176 <configOption name="transferdialattempts" default="3">
177 <since>
178 <version>13.1.0</version>
179 </since>
180 <synopsis>Number of dial attempts allowed when attempting a transfer</synopsis>
181 </configOption>
182 <configOption name="transferretrysound" default="pbx-invalid">
183 <since>
184 <version>13.1.0</version>
185 </since>
186 <synopsis>Sound that is played when an incorrect extension is dialed and the transferer should try again.</synopsis>
187 </configOption>
188 <configOption name="transferinvalidsound" default="privacy-incorrect">
189 <since>
190 <version>13.1.0</version>
191 </since>
192 <synopsis>Sound that is played when an incorrect extension is dialed and the transferer has no attempts remaining.</synopsis>
193 </configOption>
194 <configOption name="transferannouncesound" default="pbx-transfer">
195 <since>
196 <version>16.29.0</version>
197 <version>18.15.0</version>
198 <version>19.7.0</version>
199 </since>
200 <synopsis>Sound that is played to the transferer when a transfer is initiated. If empty, no sound will be played.</synopsis>
201 </configOption>
202 </configObject>
203 <configObject name="featuremap">
204 <since>
205 <version>12.0.0</version>
206 </since>
207 <synopsis>DTMF options that can be triggered during bridged calls</synopsis>
208 <configOption name="atxfer">
209 <since>
210 <version>12.0.0</version>
211 </since>
212 <synopsis>DTMF sequence to initiate an attended transfer</synopsis>
213 <description>
214 <para>The transferee parties will be placed on hold and the
215 transferrer may dial an extension to reach a transfer target. During an
216 attended transfer, the transferrer may consult with the transfer target
217 before completing the transfer. Once the transferrer has hung up or pressed
218 the <replaceable>atxfercomplete</replaceable> DTMF sequence, then the transferees
219 and transfer target will be bridged.</para>
220 </description>
221 </configOption>
222 <configOption name="blindxfer" default="#">
223 <since>
224 <version>12.0.0</version>
225 </since>
226 <synopsis>DTMF sequence to initiate a blind transfer</synopsis>
227 <description>
228 <para>The transferee parties will be placed on hold and the
229 transferrer may dial an extension to reach a transfer target. During a
230 blind transfer, as soon as the transfer target is dialed, the transferrer
231 is hung up.</para>
232 </description>
233 </configOption>
234 <configOption name="disconnect" default="*">
235 <synopsis>DTMF sequence to disconnect the current call</synopsis>
236 <description>
237 <para>Entering this DTMF sequence will cause the bridge to end, no
238 matter the number of parties present</para>
239 </description>
240 </configOption>
241 <configOption name="parkcall">
242 <since>
243 <version>12.0.0</version>
244 </since>
245 <synopsis>DTMF sequence to park a call</synopsis>
246 <description>
247 <para>The parking lot used to park the call is determined by using either the
248 <replaceable>PARKINGLOT</replaceable> channel variable or a configured value on
249 the channel (provided by the channel driver) if the variable is not present. If
250 no configured value on the channel is present, then <literal>"default"</literal>
251 is used. The call is parked in the next available space in the parking lot.</para>
252 </description>
253 </configOption>
254 <configOption name="automixmon">
255 <since>
256 <version>12.0.0</version>
257 </since>
258 <synopsis>DTMF sequence to start or stop MixMonitor on a call</synopsis>
259 <description>
260 <para>This will cause the channel that pressed the DTMF sequence
261 to be monitored by the <literal>MixMonitor</literal> application. The
262 format for the recording is determined by the <replaceable>TOUCH_MIXMONITOR_FORMAT</replaceable>
263 channel variable. If this variable is not specified, then <literal>wav</literal> is the
264 default. The filename is constructed in the following manner:</para>
265 <para> prefix-timestamp-suffix.fmt</para>
266 <para>where prefix is either the value of the <replaceable>TOUCH_MIXMONITOR_PREFIX</replaceable>
267 channel variable or <literal>auto</literal> if the variable is not set. The timestamp
268 is a UNIX timestamp. The suffix is either the value of the <replaceable>TOUCH_MIXMONITOR</replaceable>
269 channel variable or the callerID of the channels if the variable is not set.</para>
270 <para>To play a periodic beep while this call is being recorded, set the
271 <replaceable>TOUCH_MIXMONITOR_BEEP</replaceable> to the interval in seconds. The interval will default
272 to 15 seconds if invalid. The minimum interval is 5 seconds.</para>
273 <para>To override the default MixMonitor options <literal>b</literal>, the
274 <replaceable>TOUCH_MIXMONITOR_OPTIONS</replaceable> channel variable can be used. If both
275 <replaceable>TOUCH_MIXMONITOR_BEEP</replaceable> and <replaceable>TOUCH_MIXMONITOR_OPTIONS</replaceable> are set, the
276 <replaceable>TOUCH_MIXMONITOR_OPTIONS</replaceable> will take precedence.</para>
277 </description>
278 </configOption>
279 </configObject>
280 <configObject name="applicationmap">
281 <since>
282 <version>12.0.0</version>
283 </since>
284 <synopsis>Section for defining custom feature invocations during a call</synopsis>
285 <description>
286 <para>The applicationmap is an area where new custom features can be created. Items
287 defined in the applicationmap are not automatically accessible to bridged parties. Access
288 to the individual items is controlled using the <replaceable>DYNAMIC_FEATURES</replaceable> channel variable.
289 The <replaceable>DYNAMIC_FEATURES</replaceable> is a <literal>#</literal> separated list of
290 either applicationmap item names or featuregroup names.</para>
291 </description>
292 <configOption name="">
293 <synopsis>A custom feature to invoke during a bridged call</synopsis>
294 <description>
295 <para>Each item listed here is a comma-separated list of parameters that determine
296 how a feature may be invoked during a call</para>
297 <para> Example:</para>
298 <para> eggs = *5,self,Playback(hello-world),default</para>
299 <para>This would create a feature called <literal>eggs</literal> that could be invoked
300 during a call by pressing the <literal>*5</literal>. The party that presses the DTMF
301 sequence would then trigger the <literal>Playback</literal> application to play the
302 <literal>hello-world</literal> file. The application invocation would happen on the
303 party that pressed the DTMF sequence since <literal>self</literal> is specified. The
304 other parties in the bridge would hear the <literal>default</literal> music on hold
305 class during the playback.</para>
306 <para>In addition to the syntax outlined in this documentation, a backwards-compatible alternative
307 is also allowed. The following applicationmap lines are functionally identical:</para>
308 <para> eggs = *5,self,Playback(hello-world),default</para>
309 <para> eggs = *5,self,Playback,hello-world,default</para>
310 <para> eggs = *5,self,Playback,"hello-world",default</para>
311 </description>
312 <syntax argsep=",">
313 <parameter name="dtmf" required="true">
314 <para>The DTMF sequence used to trigger the option</para>
315 </parameter>
316 <parameter name="activate_on" required="true">
317 <para>The party that the feature will be invoked on</para>
318 <optionlist>
319 <option name="self"><para>Feature is invoked on party that presses the DTMF sequence</para></option>
320 <option name="peer"><para>Feature is invoked on other parties in the bridge</para></option>
321 </optionlist>
322 </parameter>
323 <parameter name="app" required="true">
324 <para>The dialplan application to run when the DTMF sequence is pressed</para>
325 <argument name="app_args" required="false">
326 <para>The arguments to the dialplan application to run</para>
327 </argument>
328 </parameter>
329 <parameter name="moh_class" required="false">
330 <para>Music on hold class to play to bridge participants that are not the target of the application invocation</para>
331 </parameter>
332 </syntax>
333 </configOption>
334 </configObject>
335 <configObject name="featuregroup">
336 <since>
337 <version>12.0.0</version>
338 </since>
339 <synopsis>Groupings of items from the applicationmap</synopsis>
340 <description>
341 <para>Feature groups allow for multiple applicationmap items to be
342 grouped together. Like with individual applicationmap items, feature groups
343 can be part of the <replaceable>DYNAMIC_FEATURES</replaceable> channel variable.
344 In addition to creating groupings, the feature group section allows for the
345 DTMF sequence used to invoke an applicationmap item to be overridden with
346 a different sequence.</para>
347 </description>
348 <configOption name="">
349 <synopsis>Applicationmap item to place in the feature group</synopsis>
350 <description>
351 <para>Each item here must be a name of an item in the applicationmap. The
352 argument may either be a new DTMF sequence to use for the item or it
353 may be left blank in order to use the DTMF sequence specified in the
354 applicationmap. For example:</para>
355 <para> eggs => *1</para>
356 <para> bacon =></para>
357 <para>would result in the applicationmap items <literal>eggs</literal> and
358 <literal>bacon</literal> being in the featuregroup. The former would have its
359 default DTMF trigger overridden with <literal>*1</literal> and the latter would
360 have the DTMF value specified in the applicationmap.</para>
361 </description>
362 </configOption>
363 </configObject>
364 </configFile>
365 </configInfo>
366 <function name="FEATURE" language="en_US">
367 <since>
368 <version>12.0.0</version>
369 </since>
370 <synopsis>
371 Get or set a feature option on a channel.
372 </synopsis>
373 <syntax>
374 <parameter name="option_name" required="true">
375 <para>The allowed values are:</para>
376 <enumlist>
377 <enum name="inherit"><para>Inherit feature settings made in FEATURE or FEATUREMAP to child channels.</para></enum>
378 <enum name="featuredigittimeout"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='featuredigittimeout']/synopsis/text())" /></para></enum>
379 <enum name="transferdigittimeout"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferdigittimeout']/synopsis/text())" /></para></enum>
380 <enum name="atxfernoanswertimeout"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxfernoanswertimeout']/synopsis/text())" /></para></enum>
381 <enum name="atxferdropcall"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxferdropcall']/synopsis/text())" /></para></enum>
382 <enum name="atxferloopdelay"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxferloopdelay']/synopsis/text())" /></para></enum>
383 <enum name="atxfercallbackretries"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxfercallbackretries']/synopsis/text())" /></para></enum>
384 <enum name="xfersound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='xfersound']/synopsis/text())" /></para></enum>
385 <enum name="xferfailsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='xferfailsound']/synopsis/text())" /></para></enum>
386 <enum name="atxferabort"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxferabort']/synopsis/text())" /></para></enum>
387 <enum name="atxfercomplete"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxfercomplete']/synopsis/text())" /></para></enum>
388 <enum name="atxferthreeway"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='atxferthreeway']/synopsis/text())" /></para></enum>
389 <enum name="pickupexten"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='pickupexten']/synopsis/text())" /></para></enum>
390 <enum name="pickupsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='pickupsound']/synopsis/text())" /></para></enum>
391 <enum name="pickupfailsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='pickupfailsound']/synopsis/text())" /></para></enum>
392 <enum name="courtesytone"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='courtesytone']/synopsis/text())" /></para></enum>
393 <enum name="recordingfailsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='recordingfailsound']/synopsis/text())" /></para></enum>
394 <enum name="transferdialattempts"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferdialattempts']/synopsis/text())" /></para></enum>
395 <enum name="transferretrysound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferretrysound']/synopsis/text())" /></para></enum>
396 <enum name="transferinvalidsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferinvalidsound']/synopsis/text())" /></para></enum>
397 <enum name="transferannouncesound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferannouncesound']/synopsis/text())" /></para></enum>
398 </enumlist>
399 </parameter>
400 </syntax>
401 <description>
402 <para>When this function is used as a read, it will get the current
403 value of the specified feature option for this channel. It will be
404 the value of this option configured in features.conf if a channel specific
405 value has not been set. This function can also be used to set a channel
406 specific value for the supported feature options.</para>
407 </description>
408 <see-also>
409 <ref type="function">FEATUREMAP</ref>
410 </see-also>
411 </function>
412 <function name="FEATUREMAP" language="en_US">
413 <since>
414 <version>12.0.0</version>
415 </since>
416 <synopsis>
417 Get or set a feature map to a given value on a specific channel.
418 </synopsis>
419 <syntax>
420 <parameter name="feature_name" required="true">
421 <para>The allowed values are:</para>
422 <enumlist>
423 <enum name="atxfer"><para>Attended Transfer</para></enum>
424 <enum name="blindxfer"><para>Blind Transfer</para></enum>
425 <enum name="disconnect"><para>Call Disconnect</para></enum>
426 <enum name="parkcall"><para>Park Call</para></enum>
427 <enum name="automixmon"><para>Auto MixMonitor</para></enum>
428 </enumlist>
429 </parameter>
430 </syntax>
431 <description>
432 <para>When this function is used as a read, it will get the current
433 digit sequence mapped to the specified feature for this channel. This
434 value will be the one configured in features.conf if a channel specific
435 value has not been set. This function can also be used to set a channel
436 specific value for a feature mapping.</para>
437 </description>
438 <see-also>
439 <ref type="function">FEATURE</ref>
440 </see-also>
441 </function>
442 ***/
443/*! Default general options */
444#define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000
445#define DEFAULT_COURTESY_TONE ""
446#define DEFAULT_RECORDING_FAIL_SOUND ""
447
448/*! Default xfer options */
449#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3
450#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15
451#define DEFAULT_ATXFER_DROP_CALL 0
452#define DEFAULT_ATXFER_LOOP_DELAY 10
453#define DEFAULT_ATXFER_CALLBACK_RETRIES 2
454#define DEFAULT_XFERSOUND "beep"
455#define DEFAULT_XFERFAILSOUND "beeperr"
456#define DEFAULT_ATXFER_ABORT "*1"
457#define DEFAULT_ATXFER_COMPLETE "*2"
458#define DEFAULT_ATXFER_THREEWAY "*3"
459#define DEFAULT_ATXFER_SWAP "*4"
460#define DEFAULT_TRANSFER_DIAL_ATTEMPTS 3
461#define DEFAULT_TRANSFER_RETRY_SOUND "pbx-invalid"
462#define DEFAULT_TRANSFER_INVALID_SOUND "privacy-incorrect"
463#define DEFAULT_TRANSFER_ANNOUNCE_SOUND "pbx-transfer"
464
465/*! Default pickup options */
466#define DEFAULT_PICKUPEXTEN "*8"
467#define DEFAULT_PICKUPSOUND ""
468#define DEFAULT_PICKUPFAILSOUND ""
469
470/*! Default featuremap options */
471#define DEFAULT_FEATUREMAP_BLINDXFER "#"
472#define DEFAULT_FEATUREMAP_DISCONNECT "*"
473#define DEFAULT_FEATUREMAP_AUTOMON ""
474#define DEFAULT_FEATUREMAP_ATXFER ""
475#define DEFAULT_FEATUREMAP_PARKCALL ""
476#define DEFAULT_FEATUREMAP_AUTOMIXMON ""
477
478/*!
479 * \brief Configuration from the "general" section of features.conf
480 */
486
488{
489 struct ast_applicationmap_item *item = obj;
490
492}
493
494static int applicationmap_sort(const void *obj, const void *arg, int flags)
495{
496 const struct ast_applicationmap_item *item1 = obj;
497 const struct ast_applicationmap_item *item2;
498 const char *key2;
499
500 switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
501 case OBJ_KEY:
502 key2 = arg;
503 return strcasecmp(item1->name, key2);
504 case OBJ_PARTIAL_KEY:
505 key2 = arg;
506 return strncasecmp(item1->name, key2, strlen(key2));
507 default:
508 case OBJ_POINTER:
509 item2 = arg;
510 return strcasecmp(item1->name, item2->name);
511 }
512}
513
514/*!
515 * \brief Entry in the container of featuregroups
516 */
519 /*! The name of the applicationmap item that we are referring to */
521 /*! Custom DTMF override to use instead of the default for the applicationmap item */
523 );
524 /*! The applicationmap item that is being referred to */
526};
527
528static void featuregroup_item_destructor(void *obj)
529{
530 struct featuregroup_item *item = obj;
531
533 ao2_cleanup(item->appmap_item);
534}
535
536static int group_item_sort(const void *obj, const void *arg, int flags)
537{
538 const struct featuregroup_item *item1 = obj;
539 const struct featuregroup_item *item2;
540 const char *key2;
541
542 switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
543 case OBJ_KEY:
544 key2 = arg;
545 return strcasecmp(item1->appmap_item_name, key2);
546 case OBJ_PARTIAL_KEY:
547 key2 = arg;
548 return strncasecmp(item1->appmap_item_name, key2, strlen(key2));
549 case OBJ_POINTER:
550 item2 = arg;
551 return strcasecmp(item1->appmap_item_name, item2->appmap_item_name);
552 default:
553 return CMP_STOP;
554 }
555}
556
557/*!
558 * \brief Featuregroup representation
559 */
561 /*! The name of the featuregroup */
562 const char *name;
563 /*! A container of featuregroup_items */
565};
566
567static int featuregroup_hash(const void *obj, int flags)
568{
569 const struct featuregroup *group;
570 const char *key;
571
572 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
573 case OBJ_KEY:
574 key = obj;
575 return ast_str_case_hash(key);
576 case OBJ_PARTIAL_KEY:
577 ast_assert(0);
578 return 0;
579 case OBJ_POINTER:
580 default:
581 group = obj;
583 }
584}
585
586static int featuregroup_cmp(void *obj, void *arg, int flags)
587{
588 struct featuregroup *group1 = obj;
589 struct featuregroup *group2;
590 const char *key2;
591
592 switch(flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
593 case OBJ_KEY:
594 key2 = arg;
595 return strcasecmp(group1->name, key2) ? 0 : CMP_MATCH;
596 case OBJ_PARTIAL_KEY:
597 key2 = arg;
598 return strncasecmp(group1->name, key2, strlen(key2)) ? 0 : CMP_MATCH;
599 case OBJ_POINTER:
600 group2 = arg;
601 return strcasecmp(group1->name, group2->name) ? 0 : CMP_MATCH;
602 default:
603 return CMP_STOP;
604 }
605}
606
607static void *featuregroup_find(struct ao2_container *group_container, const char *category)
608{
609 return ao2_find(group_container, category, OBJ_KEY);
610}
611
612static void featuregroup_destructor(void *obj)
613{
614 struct featuregroup *group = obj;
615
616 ast_free((char *) group->name);
617 ao2_cleanup(group->items);
618}
619
620static void *featuregroup_alloc(const char *cat)
621{
622 struct featuregroup *group;
623
625 if (!group) {
626 return NULL;
627 }
628
629 group->name = ast_strdup(cat);
630 if (!group->name) {
632 return NULL;
633 }
634
637 if (!group->items) {
639 return NULL;
640 }
641
642 return group;
643}
644
645/* Used for deprecated parking configuration */
647 char dummy;
648};
649
657
658static struct aco_type global_option = {
659 .type = ACO_GLOBAL,
660 .name = "globals",
661 .category_match = ACO_WHITELIST_EXACT,
662 .category = "general",
663 .item_offset = offsetof(struct features_config, global),
664};
665
667 .type = ACO_GLOBAL,
668 .name = "featuremap",
669 .category_match = ACO_WHITELIST_EXACT,
670 .category = "featuremap",
671 .item_offset = offsetof(struct features_config, featuremap),
672};
673
675 .type = ACO_GLOBAL,
676 .name = "applicationmap",
677 .category_match = ACO_WHITELIST_EXACT,
678 .category = "applicationmap",
679 .item_offset = offsetof(struct features_config, applicationmap),
680};
681
683 .type = ACO_ITEM,
684 .name = "featuregroup",
685 .category_match = ACO_BLACKLIST,
686 .category = "^(general|featuremap|applicationmap|parkinglot_.*)$",
687 .item_offset = offsetof(struct features_config, featuregroups),
688 .item_alloc = featuregroup_alloc,
689 .item_find = featuregroup_find,
690};
691
693 .type = ACO_GLOBAL,
694 .name = "parkinglot",
695 .category_match = ACO_WHITELIST,
696 .category = "^parkinglot_.*$",
697 .item_offset = offsetof(struct features_config, parkinglots),
698 .hidden = 1,
699};
700
706
711
713
714static void features_config_destructor(void *obj)
715{
716 struct features_config *cfg = obj;
717
718 ao2_cleanup(cfg->global);
723}
724
725static void featuremap_config_destructor(void *obj)
726{
727 struct ast_featuremap_config *cfg = obj;
728
730}
731
732static void global_config_destructor(void *obj)
733{
734 struct features_global_config *cfg = obj;
735
736 ao2_cleanup(cfg->general);
737 ao2_cleanup(cfg->xfer);
738 ao2_cleanup(cfg->pickup);
739}
740
741static void general_destructor(void *obj)
742{
743 struct ast_features_general_config *cfg = obj;
744
746}
747
748static void xfer_destructor(void *obj)
749{
750 struct ast_features_xfer_config *cfg = obj;
751
753}
754
755static void pickup_destructor(void *obj)
756{
757 struct ast_features_pickup_config *cfg = obj;
758
760}
761
763{
765
766 cfg = ao2_alloc(sizeof(*cfg), global_config_destructor);
767 if (!cfg) {
768 return NULL;
769 }
770
771 cfg->general = ao2_alloc(sizeof(*cfg->general), general_destructor);
772 if (!cfg->general || ast_string_field_init(cfg->general, 32)) {
773 return NULL;
774 }
775
776 cfg->xfer = ao2_alloc(sizeof(*cfg->xfer), xfer_destructor);
777 if (!cfg->xfer || ast_string_field_init(cfg->xfer, 32)) {
778 return NULL;
779 }
780
781 cfg->pickup = ao2_alloc(sizeof(*cfg->pickup), pickup_destructor);
782 if (!cfg->pickup || ast_string_field_init(cfg->pickup, 32)) {
783 return NULL;
784 }
785
786 ao2_ref(cfg, +1);
787 return cfg;
788}
789
796
797/*!
798 * \internal
799 * \brief Allocate the major configuration structure
800 *
801 * The parameter is used to determine if the applicationmap and featuregroup
802 * structures should be allocated. We only want to allocate these structures for
803 * the global features_config structure. For the datastores on channels, we don't
804 * need to allocate these structures because they are not used.
805 *
806 * \param allocate_applicationmap See previous explanation
807 * \retval NULL Failed to allocate configuration
808 * \retval non-NULL Allocated configuration
809 */
810static struct features_config *__features_config_alloc(int allocate_applicationmap)
811{
812 RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
813
814 cfg = ao2_alloc(sizeof(*cfg), features_config_destructor);
815 if (!cfg) {
816 return NULL;
817 }
818
819 cfg->global = global_config_alloc();
820 if (!cfg->global) {
821 return NULL;
822 }
823
824 cfg->featuremap = ao2_alloc(sizeof(*cfg->featuremap), featuremap_config_destructor);
825 if (!cfg->featuremap || ast_string_field_init(cfg->featuremap, 32)) {
826 return NULL;
827 }
828
829 cfg->parkinglots = ao2_alloc(sizeof(*cfg->parkinglots), NULL);
830 if (!cfg->parkinglots) {
831 return NULL;
832 }
833
834 if (allocate_applicationmap) {
835 cfg->applicationmap = applicationmap_alloc(1);
836 if (!cfg->applicationmap) {
837 return NULL;
838 }
839
840 cfg->featuregroups = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, 11,
842 if (!cfg->featuregroups) {
843 return NULL;
844 }
845 }
846
847 ao2_ref(cfg, +1);
848 return cfg;
849
850}
851
852static void *features_config_alloc(void)
853{
854 return __features_config_alloc(1);
855}
856
857static void general_copy(struct ast_features_general_config *dest, const struct ast_features_general_config *src)
858{
859 ast_string_fields_copy(dest, src);
861}
862
873
874static void pickup_copy(struct ast_features_pickup_config *dest, const struct ast_features_pickup_config *src)
875{
876 ast_string_fields_copy(dest, src);
877}
878
879static void global_copy(struct features_global_config *dest, const struct features_global_config *src)
880{
881 general_copy(dest->general, src->general);
882 xfer_copy(dest->xfer, src->xfer);
883 pickup_copy(dest->pickup, src->pickup);
884}
885
886static void featuremap_copy(struct ast_featuremap_config *dest, const struct ast_featuremap_config *src)
887{
888 ast_string_fields_copy(dest, src);
889}
890
891static void features_copy(struct features_config *dest, const struct features_config *src)
892{
893 global_copy(dest->global, src->global);
895
896 /* applicationmap and featuregroups are purposely not copied. A channel's applicationmap
897 * is produced on the fly when ast_get_chan_applicationmap() is called
898 * NOTE: This does not apply to the global cfg->applicationmap and cfg->featuregroups
899 */
900}
901
902static struct features_config *features_config_dup(const struct features_config *orig)
903{
904 struct features_config *dup;
905
907 if (!dup) {
908 return NULL;
909 }
910
911 features_copy(dup, orig);
912
913 return dup;
914}
915
916static int general_set(struct ast_features_general_config *general, const char *name,
917 const char *value)
918{
919 int res = 0;
920
921 if (!strcasecmp(name, "featuredigittimeout")) {
923 } else if (!strcasecmp(name, "courtesytone")) {
924 ast_string_field_set(general, courtesytone, value);
925 } else if (!strcasecmp(name, "recordingfailsound")) {
926 ast_string_field_set(general, recordingfailsound, value);
927 } else {
928 /* Unrecognized option */
929 res = -1;
930 }
931
932 return res;
933}
934
935static int general_get(struct ast_features_general_config *general, const char *field,
936 char *buf, size_t len)
937{
938 int res = 0;
939
940 if (!strcasecmp(field, "featuredigittimeout")) {
941 snprintf(buf, len, "%u", general->featuredigittimeout);
942 } else if (!strcasecmp(field, "courtesytone")) {
944 } else if (!strcasecmp(field, "recordingfailsound")) {
946 } else {
947 /* Unrecognized option */
948 res = -1;
949 }
950
951 return res;
952}
953
954static int xfer_set(struct ast_features_xfer_config *xfer, const char *name,
955 const char *value)
956{
957 int res = 0;
958
959 if (!strcasecmp(name, "transferdigittimeout")) {
961 } else if (!strcasecmp(name, "atxfernoanswertimeout")) {
963 } else if (!strcasecmp(name, "atxferloopdelay")) {
965 } else if (!strcasecmp(name, "atxfercallbackretries")) {
967 } else if (!strcasecmp(name, "atxferdropcall")) {
969 } else if (!strcasecmp(name, "xfersound")) {
970 ast_string_field_set(xfer, xfersound, value);
971 } else if (!strcasecmp(name, "xferfailsound")) {
972 ast_string_field_set(xfer, xferfailsound, value);
973 } else if (!strcasecmp(name, "atxferabort")) {
974 ast_string_field_set(xfer, atxferabort, value);
975 } else if (!strcasecmp(name, "atxfercomplete")) {
976 ast_string_field_set(xfer, atxfercomplete, value);
977 } else if (!strcasecmp(name, "atxferthreeway")) {
978 ast_string_field_set(xfer, atxferthreeway, value);
979 } else if (!strcasecmp(name, "atxferswap")) {
980 ast_string_field_set(xfer, atxferswap, value);
981 } else if (!strcasecmp(name, "transferdialattempts")) {
983 } else if (!strcasecmp(name, "transferretrysound")) {
984 ast_string_field_set(xfer, transferretrysound, value);
985 } else if (!strcasecmp(name, "transferinvalidsound")) {
986 ast_string_field_set(xfer, transferinvalidsound, value);
987 } else if (!strcasecmp(name, "transferannouncesound")) {
988 ast_string_field_set(xfer, transferannouncesound, value);
989 } else {
990 /* Unrecognized option */
991 res = -1;
992 }
993
994 return res;
995}
996
997static int xfer_get(struct ast_features_xfer_config *xfer, const char *field,
998 char *buf, size_t len)
999{
1000 int res = 0;
1001
1002 if (!strcasecmp(field, "transferdigittimeout")) {
1003 snprintf(buf, len, "%u", xfer->transferdigittimeout);
1004 } else if (!strcasecmp(field, "atxfernoanswertimeout")) {
1005 snprintf(buf, len, "%u", xfer->atxfernoanswertimeout);
1006 } else if (!strcasecmp(field, "atxferloopdelay")) {
1007 snprintf(buf, len, "%u", xfer->atxferloopdelay);
1008 } else if (!strcasecmp(field, "atxfercallbackretries")) {
1009 snprintf(buf, len, "%u", xfer->atxfercallbackretries);
1010 } else if (!strcasecmp(field, "atxferdropcall")) {
1011 snprintf(buf, len, "%u", xfer->atxferdropcall);
1012 } else if (!strcasecmp(field, "xfersound")) {
1014 } else if (!strcasecmp(field, "xferfailsound")) {
1016 } else if (!strcasecmp(field, "atxferabort")) {
1018 } else if (!strcasecmp(field, "atxfercomplete")) {
1020 } else if (!strcasecmp(field, "atxferthreeway")) {
1022 } else if (!strcasecmp(field, "atxferswap")) {
1024 } else if (!strcasecmp(field, "transferdialattempts")) {
1025 snprintf(buf, len, "%u", xfer->transferdialattempts);
1026 } else if (!strcasecmp(field, "transferretrysound")) {
1028 } else if (!strcasecmp(field, "transferinvalidsound")) {
1030 } else {
1031 /* Unrecognized option */
1032 res = -1;
1033 }
1034
1035 return res;
1036}
1037
1038static int pickup_set(struct ast_features_pickup_config *pickup, const char *name,
1039 const char *value)
1040{
1041 int res = 0;
1042
1043 if (!strcasecmp(name, "pickupsound")) {
1044 ast_string_field_set(pickup, pickupsound, value);
1045 } else if (!strcasecmp(name, "pickupfailsound")) {
1046 ast_string_field_set(pickup, pickupfailsound, value);
1047 } else if (!strcasecmp(name, "pickupexten")) {
1048 ast_string_field_set(pickup, pickupexten, value);
1049 } else {
1050 /* Unrecognized option */
1051 res = -1;
1052 }
1053
1054 return res;
1055}
1056
1057static int pickup_get(struct ast_features_pickup_config *pickup, const char *field,
1058 char *buf, size_t len)
1059{
1060 int res = 0;
1061
1062 if (!strcasecmp(field, "pickupsound")) {
1064 } else if (!strcasecmp(field, "pickupfailsound")) {
1066 } else if (!strcasecmp(field, "pickupexten")) {
1068 } else {
1069 /* Unrecognized option */
1070 res = -1;
1071 }
1072
1073 return res;
1074}
1075
1076static int featuremap_set(struct ast_featuremap_config *featuremap, const char *name,
1077 const char *value)
1078{
1079 int res = 0;
1080
1081 if (!strcasecmp(name, "blindxfer")) {
1083 } else if (!strcasecmp(name, "disconnect")) {
1085 } else if (!strcasecmp(name, "atxfer")) {
1087 } else if (!strcasecmp(name, "automixmon")) {
1089 } else if (!strcasecmp(name, "parkcall")) {
1091 } else {
1092 /* Unrecognized option */
1093 res = -1;
1094 }
1095
1096 return res;
1097}
1098
1099static int featuremap_get(struct ast_featuremap_config *featuremap, const char *field,
1100 char *buf, size_t len)
1101{
1102 int res = 0;
1103
1104 if (!strcasecmp(field, "blindxfer")) {
1106 } else if (!strcasecmp(field, "disconnect")) {
1108 } else if (!strcasecmp(field, "atxfer")) {
1110 } else if (!strcasecmp(field, "automixmon")) {
1112 } else if (!strcasecmp(field, "parkcall")) {
1114 } else {
1115 /* Unrecognized option */
1116 res = -1;
1117 }
1118
1119 return res;
1120}
1121
1122static void feature_ds_destroy(void *data)
1123{
1124 struct features_config *cfg = data;
1125 ao2_cleanup(cfg);
1126}
1127
1128static void *feature_ds_duplicate(void *data)
1129{
1130 struct features_config *old_cfg = data;
1131
1132 return features_config_dup(old_cfg);
1133}
1134
1136 .type = "FEATURE",
1137 .destroy = feature_ds_destroy,
1138 .duplicate = feature_ds_duplicate,
1139};
1140
1141/*!
1142 * \internal
1143 * \brief Find or create feature datastore on a channel
1144 *
1145 * \pre chan is locked
1146 *
1147 * \return the data on the FEATURE datastore, or NULL on error
1148 */
1149static struct features_config *get_feature_ds(struct ast_channel *chan)
1150{
1151 RAII_VAR(struct features_config *, orig, NULL, ao2_cleanup);
1152 struct features_config *cfg;
1153 struct ast_datastore *ds;
1154
1155 if ((ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
1156 cfg = ds->data;
1157 ao2_ref(cfg, +1);
1158 return cfg;
1159 }
1160
1162 if (!orig) {
1163 return NULL;
1164 }
1165
1166 cfg = features_config_dup(orig);
1167 if (!cfg) {
1168 return NULL;
1169 }
1170
1171 if (!(ds = ast_datastore_alloc(&feature_ds_info, NULL))) {
1172 ao2_cleanup(cfg);
1173 return NULL;
1174 }
1175
1176 /* Give the datastore a reference to the config */
1177 ao2_ref(cfg, +1);
1178 ds->data = cfg;
1179
1180 ast_channel_datastore_add(chan, ds);
1181
1182 return cfg;
1183}
1184
1186{
1187 struct ast_datastore *ds;
1188
1189 if (!(ds = ast_channel_datastore_find(chan, &feature_ds_info, NULL))) {
1190 /* Hasn't been created yet. Trigger creation. */
1192
1194 }
1195
1196 return ds;
1197}
1198
1200{
1201 RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1202
1203 if (chan) {
1204 cfg = get_feature_ds(chan);
1205 } else {
1207 }
1208
1209 if (!cfg) {
1210 return NULL;
1211 }
1212
1213 ast_assert(cfg->global && cfg->global->general);
1214
1215 ao2_ref(cfg->global->general, +1);
1216 return cfg->global->general;
1217}
1218
1220{
1221 RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1222
1223 if (chan) {
1224 cfg = get_feature_ds(chan);
1225 } else {
1227 }
1228
1229 if (!cfg) {
1230 return NULL;
1231 }
1232
1233 ast_assert(cfg->global && cfg->global->xfer);
1234
1235 ao2_ref(cfg->global->xfer, +1);
1236 return cfg->global->xfer;
1237}
1238
1240{
1241 char *res;
1243
1244 if (!cfg) {
1245 return NULL;
1246 }
1247
1248 res = ast_strdup(cfg->xferfailsound);
1249 ao2_ref(cfg, -1);
1250
1251 return res;
1252}
1253
1255{
1256 char *res;
1258
1259 if (!cfg) {
1260 return NULL;
1261 }
1262
1263 res = ast_strdup(cfg->atxferabort);
1264 ao2_ref(cfg, -1);
1265
1266 return res;
1267}
1268
1270{
1271 RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1272
1273 if (chan) {
1274 cfg = get_feature_ds(chan);
1275 } else {
1277 }
1278
1279 if (!cfg) {
1280 return NULL;
1281 }
1282
1283 ast_assert(cfg->global && cfg->global->pickup);
1284
1285 ao2_ref(cfg->global->pickup, +1);
1286 return cfg->global->pickup;
1287}
1288
1290{
1291 RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1292
1293 if (chan) {
1294 cfg = get_feature_ds(chan);
1295 } else {
1297 }
1298
1299 if (!cfg) {
1300 return NULL;
1301 }
1302
1303 ast_assert(cfg->featuremap != NULL);
1304
1305 ao2_ref(cfg->featuremap, +1);
1306 return cfg->featuremap;
1307}
1308
1309int ast_get_builtin_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
1310{
1311 RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1312
1313 if (chan) {
1314 cfg = get_feature_ds(chan);
1315 } else {
1317 }
1318
1319 if (!cfg) {
1320 return -1;
1321 }
1322
1323 return featuremap_get(cfg->featuremap, feature, buf, len);
1324}
1325
1326int ast_get_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
1327{
1328 RAII_VAR(struct ao2_container *, applicationmap, NULL, ao2_cleanup);
1330
1331 if (!ast_get_builtin_feature(chan, feature, buf, len)) {
1332 return 0;
1333 }
1334
1335 /* Dang, must be in the application map */
1336 applicationmap = ast_get_chan_applicationmap(chan);
1337 if (!applicationmap) {
1338 return -1;
1339 }
1340
1341 item = ao2_find(applicationmap, feature, OBJ_KEY);
1342 if (!item) {
1343 return -1;
1344 }
1345
1346 ast_copy_string(buf, item->dtmf, len);
1347 return 0;
1348}
1349
1351 const char *app, const char *app_data, const char *moh_class, const char *dtmf,
1352 unsigned int activate_on_self)
1353{
1355
1357
1358 if (!item || ast_string_field_init(item, 64)) {
1359 return NULL;
1360 }
1361
1366 ast_copy_string(item->dtmf, dtmf, sizeof(item->dtmf));
1367 item->activate_on_self = activate_on_self;
1368
1369 return item;
1370}
1371
1372static int add_item(void *obj, void *arg, int flags)
1373{
1374 struct featuregroup_item *fg_item = obj;
1375 struct ao2_container *applicationmap = arg;
1376 RAII_VAR(struct ast_applicationmap_item *, appmap_item, NULL, ao2_cleanup);
1377
1378 /* If there's no DTMF override, then we can just link
1379 * the applicationmap item directly. Otherwise, we need
1380 * to create a copy with the DTMF override in place and
1381 * link that instead
1382 */
1383 if (ast_strlen_zero(fg_item->dtmf_override)) {
1384 ao2_ref(fg_item->appmap_item, +1);
1385 appmap_item = fg_item->appmap_item;
1386 } else {
1387 appmap_item = applicationmap_item_alloc(fg_item->appmap_item_name,
1388 fg_item->appmap_item->app, fg_item->appmap_item->app_data,
1389 fg_item->appmap_item->moh_class, fg_item->dtmf_override,
1390 fg_item->appmap_item->activate_on_self);
1391 }
1392
1393 if (!appmap_item) {
1394 return 0;
1395 }
1396
1397 ao2_link(applicationmap, appmap_item);
1398 return 0;
1399}
1400
1402{
1404 struct ao2_container *applicationmap;
1405 char *group_names;
1406 char *name;
1407
1408 if (!cfg) {
1409 return NULL;
1410 }
1411
1412 if (!chan) {
1413 if (!cfg->applicationmap || ao2_container_count(cfg->applicationmap) == 0) {
1414 return NULL;
1415 }
1416 ao2_ref(cfg->applicationmap, +1);
1417 return cfg->applicationmap;
1418 }
1419
1420 group_names = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"), ""));
1421 if (ast_strlen_zero(group_names)) {
1422 return NULL;
1423 }
1424
1425 applicationmap = applicationmap_alloc(0);
1426 if (!applicationmap) {
1427 return NULL;
1428 }
1429
1430 /* global config must be initialized */
1431 ast_assert(cfg->featuregroups != NULL);
1432 ast_assert(cfg->applicationmap != NULL);
1433 while ((name = strsep(&group_names, "#"))) {
1434 RAII_VAR(struct featuregroup *, group, ao2_find(cfg->featuregroups, name, OBJ_KEY), ao2_cleanup);
1435
1436 if (!group) {
1437 RAII_VAR(struct ast_applicationmap_item *, item, ao2_find(cfg->applicationmap, name, OBJ_KEY), ao2_cleanup);
1438
1439 if (item) {
1440 ao2_link(applicationmap, item);
1441 } else {
1442 ast_log(LOG_WARNING, "Unknown DYNAMIC_FEATURES item '%s' on channel %s.\n",
1443 name, ast_channel_name(chan));
1444 }
1445 } else {
1446 ao2_callback(group->items, 0, add_item, applicationmap);
1447 }
1448 }
1449
1450 if (ao2_container_count(applicationmap) == 0) {
1451 ao2_cleanup(applicationmap);
1452 return NULL;
1453 }
1454
1455 return applicationmap;
1456}
1457
1458static int applicationmap_handler(const struct aco_option *opt,
1459 struct ast_variable *var, void *obj)
1460{
1462 struct ao2_container *applicationmap = obj;
1464 AST_APP_ARG(dtmf);
1465 AST_APP_ARG(activate_on);
1468 AST_APP_ARG(moh_class);
1469 );
1470 char *parse = ast_strdupa(var->value);
1471 char *slash;
1472 char *paren;
1473 unsigned int activate_on_self;
1474
1476
1477 if (ast_strlen_zero(args.dtmf) ||
1478 ast_strlen_zero(args.activate_on) ||
1479 ast_strlen_zero(args.app)) {
1480 ast_log(LOG_WARNING, "Invalid applicationmap syntax for '%s'. Missing required argument\n", var->name);
1481 return -1;
1482 }
1483
1484 /* features.conf used to have an "activated_by" portion
1485 * in addition to activate_on. Get rid of whatever may be
1486 * there
1487 */
1488 slash = strchr(args.activate_on, '/');
1489 if (slash) {
1490 *slash = '\0';
1491 }
1492
1493 /* Some applications do not require arguments. */
1494 if (!args.app_data) {
1495 args.app_data = "";
1496 }
1497
1498 /* Two syntaxes allowed for applicationmap:
1499 * Old: foo = *1,self,NoOp,Boo!,default
1500 * New: foo = *1,self,NoOp(Boo!),default
1501 *
1502 * We need to handle both
1503 */
1504 paren = strchr(args.app, '(');
1505 if (paren) {
1506 /* New syntax */
1507 char *close_paren;
1508
1509 args.moh_class = args.app_data;
1510 *paren++ = '\0';
1511 close_paren = strrchr(paren, ')');
1512 if (close_paren) {
1513 *close_paren = '\0';
1514 }
1515 args.app_data = paren;
1516
1517 /* Re-check that the application is not empty */
1518 if (ast_strlen_zero(args.app)) {
1519 ast_log(LOG_WARNING, "Applicationmap item '%s' does not contain an application name.\n", var->name);
1520 return -1;
1521 }
1522 } else if (strchr(args.app_data, '"')) {
1523 args.app_data = ast_strip_quoted(args.app_data, "\"", "\"");
1524 }
1525
1526 /* Allow caller and callee to be specified for backwards compatibility */
1527 if (!strcasecmp(args.activate_on, "self") || !strcasecmp(args.activate_on, "caller")) {
1528 activate_on_self = 1;
1529 } else if (!strcasecmp(args.activate_on, "peer") || !strcasecmp(args.activate_on, "callee")) {
1530 activate_on_self = 0;
1531 } else {
1532 ast_log(LOG_WARNING, "Invalid 'activate_on' value %s for applicationmap item %s\n",
1533 args.activate_on, var->name);
1534 return -1;
1535 }
1536
1537 ast_debug(1, "Allocating applicationmap item: dtmf = %s, app = %s, app_data = %s, moh_class = %s\n",
1538 args.dtmf, args.app, args.app_data, args.moh_class);
1539
1540 item = applicationmap_item_alloc(var->name, args.app, args.app_data,
1541 args.moh_class, args.dtmf, activate_on_self);
1542
1543 if (!item) {
1544 return -1;
1545 }
1546
1547 if (!ao2_link(applicationmap, item)) {
1548 return -1;
1549 }
1550
1551 return 0;
1552}
1553
1554static int featuregroup_handler(const struct aco_option *opt,
1555 struct ast_variable *var, void *obj)
1556{
1558 struct featuregroup *group = obj;
1559
1561 if (!item || ast_string_field_init(item, 32)) {
1562 return -1;
1563 }
1564
1565 ast_string_field_set(item, appmap_item_name, var->name);
1566 ast_string_field_set(item, dtmf_override, var->value);
1567
1568 if (!ao2_link(group->items, item)) {
1569 return -1;
1570 }
1571
1572 /* We wait to look up the application map item in the preapply callback */
1573
1574 return 0;
1575}
1576
1577static int general_handler(const struct aco_option *opt,
1578 struct ast_variable *var, void *obj)
1579{
1580 struct features_global_config *global = obj;
1581 struct ast_features_general_config *general = global->general;
1582
1583 return general_set(general, var->name, var->value);
1584}
1585
1586static int xfer_handler(const struct aco_option *opt,
1587 struct ast_variable *var, void *obj)
1588{
1589 struct features_global_config *global = obj;
1590 struct ast_features_xfer_config *xfer = global->xfer;
1591
1592 return xfer_set(xfer, var->name, var->value);
1593}
1594
1595static int pickup_handler(const struct aco_option *opt,
1596 struct ast_variable *var, void *obj)
1597{
1598 struct features_global_config *global = obj;
1599 struct ast_features_pickup_config *pickup = global->pickup;
1600
1601 return pickup_set(pickup, var->name, var->value);
1602}
1603
1604static int parking_warning = 0;
1605static int unsupported_handler(const struct aco_option *opt,
1606 struct ast_variable *var, void *obj)
1607{
1608 if (!parking_warning) {
1609 ast_log(LOG_WARNING, "Parkinglots are no longer configurable in features.conf; "
1610 "parking is now handled by res_parking.conf\n");
1611 parking_warning = 1;
1612 }
1613 ast_log(LOG_WARNING, "The option '%s' is no longer configurable in features.conf.\n", var->name);
1614 return 0;
1615}
1616
1617static int featuremap_handler(const struct aco_option *opt,
1618 struct ast_variable *var, void *obj)
1619{
1620 struct ast_featuremap_config *featuremap = obj;
1621
1622 return featuremap_set(featuremap, var->name, var->value);
1623}
1624
1625static int check_featuregroup_item(void *obj, void *arg, void *data, int flags)
1626{
1627 struct ast_applicationmap_item *appmap_item;
1628 struct featuregroup_item *fg_item = obj;
1629 int *err = arg;
1630 struct ao2_container *applicationmap = data;
1631
1632 appmap_item = ao2_find(applicationmap, fg_item->appmap_item_name, OBJ_KEY);
1633 if (!appmap_item) {
1634 *err = 1;
1635 return CMP_STOP;
1636 }
1637
1638 fg_item->appmap_item = appmap_item;
1639
1640 return 0;
1641}
1642
1643static int check_featuregroup(void *obj, void *arg, void *data, int flags)
1644{
1645 struct featuregroup *group = obj;
1646 int *err = arg;
1647
1648 ao2_callback_data(group->items, 0, check_featuregroup_item, arg, data);
1649
1650 if (*err) {
1651 ast_log(LOG_WARNING, "Featuregroup %s refers to non-existent applicationmap item\n",
1652 group->name);
1653 }
1654
1655 return *err ? CMP_STOP : 0;
1656}
1657
1658static int features_pre_apply_config(void);
1659
1661 .files = ACO_FILES(&features_conf),
1662 .pre_apply_config = features_pre_apply_config,
1663);
1664
1666{
1667 struct features_config *cfg = aco_pending_config(&cfg_info);
1668 int err = 0;
1669
1670 /* Now that the entire config has been processed, we can check that the featuregroup
1671 * items refer to actual applicationmap items.
1672 */
1673
1674 /* global config must be initialized */
1675 ast_assert(cfg->featuregroups != NULL);
1678
1679 return err;
1680}
1681
1682static int internal_feature_read(struct ast_channel *chan, const char *cmd, char *data,
1683 char *buf, size_t len)
1684{
1685 int res;
1686 RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1687 SCOPED_CHANNELLOCK(lock, chan);
1688
1689 if (!strcasecmp(data, "inherit")) {
1690 struct ast_datastore *ds = get_feature_chan_ds(chan);
1691 unsigned int inherit = ds ? ds->inheritance : 0;
1692
1693 snprintf(buf, len, "%s", inherit ? "yes" : "no");
1694 return 0;
1695 }
1696
1697 cfg = get_feature_ds(chan);
1698 if (!cfg) {
1699 return -1;
1700 }
1701
1702 res = general_get(cfg->global->general, data, buf, len) &&
1703 xfer_get(cfg->global->xfer, data, buf, len) &&
1704 pickup_get(cfg->global->pickup, data, buf, len);
1705
1706 if (res) {
1707 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
1708 }
1709
1710 return res;
1711}
1712
1713static int internal_feature_write(struct ast_channel *chan, const char *cmd, char *data,
1714 const char *value)
1715{
1716 int res;
1717 RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1718 SCOPED_CHANNELLOCK(lock, chan);
1719
1720 if (!strcasecmp(data, "inherit")) {
1721 struct ast_datastore *ds = get_feature_chan_ds(chan);
1722 if (ds) {
1724 }
1725 return 0;
1726 }
1727
1728 if (!(cfg = get_feature_ds(chan))) {
1729 return -1;
1730 }
1731
1732 res = general_set(cfg->global->general, data, value) &&
1733 xfer_set(cfg->global->xfer, data, value) &&
1734 pickup_set(cfg->global->pickup, data, value);
1735
1736 if (res) {
1737 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATURE()\n", data);
1738 }
1739
1740 return res;
1741}
1742
1743static int internal_featuremap_read(struct ast_channel *chan, const char *cmd, char *data,
1744 char *buf, size_t len)
1745{
1746 int res;
1747 SCOPED_CHANNELLOCK(lock, chan);
1748
1749 res = ast_get_builtin_feature(chan, data, buf, len);
1750
1751 if (res) {
1752 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
1753 }
1754
1755 return res;
1756}
1757
1758static int internal_featuremap_write(struct ast_channel *chan, const char *cmd, char *data,
1759 const char *value)
1760{
1761 int res;
1762 RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
1763 SCOPED_CHANNELLOCK(lock, chan);
1764
1765 if (!(cfg = get_feature_ds(chan))) {
1766 return -1;
1767 }
1768
1769 res = featuremap_set(cfg->featuremap, data, value);
1770 if (res) {
1771 ast_log(LOG_WARNING, "Invalid argument '%s' to FEATUREMAP()\n", data);
1772 return -1;
1773 }
1774
1775 return 0;
1776}
1777
1778static int feature_read(struct ast_channel *chan, const char *cmd, char *data,
1779 char *buf, size_t len)
1780{
1781 if (!chan) {
1782 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1783 return -1;
1784 }
1785
1786 return internal_feature_read(chan, cmd, data, buf, len);
1787}
1788
1789static int feature_write(struct ast_channel *chan, const char *cmd, char *data,
1790 const char *value)
1791{
1792 if (!chan) {
1793 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1794 return -1;
1795 }
1796
1797 return internal_feature_write(chan, cmd, data, value);
1798}
1799
1800static int featuremap_read(struct ast_channel *chan, const char *cmd, char *data,
1801 char *buf, size_t len)
1802{
1803 if (!chan) {
1804 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1805 return -1;
1806 }
1807
1808 return internal_featuremap_read(chan, cmd, data, buf, len);
1809}
1810
1811static int featuremap_write(struct ast_channel *chan, const char *cmd, char *data,
1812 const char *value)
1813{
1814 if (!chan) {
1815 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1816 return -1;
1817 }
1818
1819 return internal_featuremap_write(chan, cmd, data, value);
1820}
1821
1823 .name = "FEATURE",
1824 .read = feature_read,
1825 .write = feature_write
1826};
1827
1829 .name = "FEATUREMAP",
1830 .read = featuremap_read,
1831 .write = featuremap_write
1832};
1833
1834static int load_config(void)
1835{
1836 if (aco_info_init(&cfg_info)) {
1837 ast_log(LOG_ERROR, "Unable to initialize configuration info for features\n");
1838 return -1;
1839 }
1840
1841 aco_option_register_custom(&cfg_info, "featuredigittimeout", ACO_EXACT, global_options,
1843 aco_option_register_custom(&cfg_info, "recordingfailsound", ACO_EXACT, global_options,
1845 aco_option_register_custom(&cfg_info, "courtesytone", ACO_EXACT, global_options,
1847
1848 aco_option_register_custom(&cfg_info, "transferdigittimeout", ACO_EXACT, global_options,
1850 aco_option_register_custom(&cfg_info, "atxfernoanswertimeout", ACO_EXACT, global_options,
1852 aco_option_register_custom(&cfg_info, "atxferdropcall", ACO_EXACT, global_options,
1854 aco_option_register_custom(&cfg_info, "atxferloopdelay", ACO_EXACT, global_options,
1856 aco_option_register_custom(&cfg_info, "atxfercallbackretries", ACO_EXACT, global_options,
1858 aco_option_register_custom(&cfg_info, "xfersound", ACO_EXACT, global_options,
1860 aco_option_register_custom(&cfg_info, "xferfailsound", ACO_EXACT, global_options,
1862 aco_option_register_custom(&cfg_info, "atxferabort", ACO_EXACT, global_options,
1864 aco_option_register_custom(&cfg_info, "atxfercomplete", ACO_EXACT, global_options,
1866 aco_option_register_custom(&cfg_info, "atxferthreeway", ACO_EXACT, global_options,
1868 aco_option_register_custom(&cfg_info, "atxferswap", ACO_EXACT, global_options,
1870 aco_option_register_custom(&cfg_info, "transferdialattempts", ACO_EXACT, global_options,
1872 aco_option_register_custom(&cfg_info, "transferretrysound", ACO_EXACT, global_options,
1874 aco_option_register_custom(&cfg_info, "transferinvalidsound", ACO_EXACT, global_options,
1876 aco_option_register_custom(&cfg_info, "transferannouncesound", ACO_EXACT, global_options,
1878
1879 aco_option_register_custom(&cfg_info, "pickupexten", ACO_EXACT, global_options,
1881 aco_option_register_custom(&cfg_info, "pickupsound", ACO_EXACT, global_options,
1883 aco_option_register_custom(&cfg_info, "pickupfailsound", ACO_EXACT, global_options,
1885
1887 "", unsupported_handler, 0);
1889 "", unsupported_handler, 0);
1890 aco_option_register_custom_nodoc(&cfg_info, "parkext_exclusive", ACO_EXACT, global_options,
1891 "", unsupported_handler, 0);
1892 aco_option_register_custom_nodoc(&cfg_info, "parkinghints", ACO_EXACT, global_options,
1893 "", unsupported_handler, 0);
1894 aco_option_register_custom_nodoc(&cfg_info, "parkedmusicclass", ACO_EXACT, global_options,
1895 "", unsupported_handler, 0);
1897 "", unsupported_handler, 0);
1899 "", unsupported_handler, 0);
1901 "", unsupported_handler, 0);
1902 aco_option_register_custom_nodoc(&cfg_info, "parkedcalltransfers", ACO_EXACT, global_options,
1903 "", unsupported_handler, 0);
1904 aco_option_register_custom_nodoc(&cfg_info, "parkedcallreparking", ACO_EXACT, global_options,
1905 "", unsupported_handler, 0);
1906 aco_option_register_custom_nodoc(&cfg_info, "parkedcallhangup", ACO_EXACT, global_options,
1907 "", unsupported_handler, 0);
1908 aco_option_register_custom_nodoc(&cfg_info, "parkedcallrecording", ACO_EXACT, global_options,
1909 "", unsupported_handler, 0);
1910 aco_option_register_custom_nodoc(&cfg_info, "comebackcontext", ACO_EXACT, global_options,
1911 "", unsupported_handler, 0);
1912 aco_option_register_custom_nodoc(&cfg_info, "comebacktoorigin", ACO_EXACT, global_options,
1913 "", unsupported_handler, 0);
1914 aco_option_register_custom_nodoc(&cfg_info, "comebackdialtime", ACO_EXACT, global_options,
1915 "", unsupported_handler, 0);
1916 aco_option_register_custom_nodoc(&cfg_info, "parkeddynamic", ACO_EXACT, global_options,
1917 "", unsupported_handler, 0);
1919 "", unsupported_handler, 0);
1920
1931
1933 "", applicationmap_handler, 0);
1934
1936 "", featuregroup_handler, 0);
1937
1939 "", unsupported_handler, 0);
1940
1941 if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
1942 RAII_VAR(struct features_config *, features_cfg, features_config_alloc(), ao2_cleanup);
1943
1944 if (aco_set_defaults(&global_option, "general", features_cfg->global) ||
1945 aco_set_defaults(&featuremap_option, "featuremap", features_cfg->featuremap)) {
1946 ast_log(LOG_ERROR, "Failed to load features.conf and failed to initialize defaults.\n");
1947 return -1;
1948 }
1949
1950 ast_log(LOG_NOTICE, "Could not load features config; using defaults\n");
1952 }
1953
1954 return 0;
1955}
1956
1957static int print_featuregroup(void *obj, void *arg, int flags)
1958{
1959 struct featuregroup_item *item = obj;
1960 struct ast_cli_args *a = arg;
1961
1962 ast_cli(a->fd, "===> --> %s (%s)\n", item->appmap_item_name,
1963 S_OR(item->dtmf_override, item->appmap_item->dtmf));
1964
1965 return 0;
1966}
1967
1968static int print_featuregroups(void *obj, void *arg, int flags)
1969{
1970 struct featuregroup *group = obj;
1971 struct ast_cli_args *a = arg;
1972
1973 ast_cli(a->fd, "===> Group: %s\n", group->name);
1974
1976 return 0;
1977}
1978
1979#define HFS_FORMAT "%-25s %-7s %-7s\n"
1980
1981static int print_applicationmap(void *obj, void *arg, int flags)
1982{
1983 struct ast_applicationmap_item *item = obj;
1984 struct ast_cli_args *a = arg;
1985
1986 ast_cli(a->fd, HFS_FORMAT, item->name, "no def", item->dtmf);
1987 return 0;
1988}
1989
1990/*!
1991 * \brief CLI command to list configured features
1992 * \param e
1993 * \param cmd
1994 * \param a
1995 *
1996 * \retval CLI_SUCCESS on success.
1997 * \retval NULL when tab completion is used.
1998 */
1999static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2000{
2001 RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
2002
2003 switch (cmd) {
2004
2005 case CLI_INIT:
2006 e->command = "features show";
2007 e->usage =
2008 "Usage: features show\n"
2009 " Lists configured features\n";
2010 return NULL;
2011 case CLI_GENERATE:
2012 return NULL;
2013 }
2014
2016
2017 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
2018 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
2019
2020 ast_cli(a->fd, HFS_FORMAT, "Pickup", DEFAULT_PICKUPEXTEN, cfg->global->pickup->pickupexten);
2021 ast_cli(a->fd, HFS_FORMAT, "Blind Transfer", DEFAULT_FEATUREMAP_BLINDXFER, cfg->featuremap->blindxfer);
2022 ast_cli(a->fd, HFS_FORMAT, "Attended Transfer", DEFAULT_FEATUREMAP_ATXFER, cfg->featuremap->atxfer);
2023 ast_cli(a->fd, HFS_FORMAT, "Disconnect Call", DEFAULT_FEATUREMAP_DISCONNECT, cfg->featuremap->disconnect);
2024 ast_cli(a->fd, HFS_FORMAT, "Park Call", DEFAULT_FEATUREMAP_PARKCALL, cfg->featuremap->parkcall);
2025 ast_cli(a->fd, HFS_FORMAT, "One Touch MixMonitor", DEFAULT_FEATUREMAP_AUTOMIXMON, cfg->featuremap->automixmon);
2026
2027 ast_cli(a->fd, "\n");
2028 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
2029 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
2030 if (!cfg->applicationmap || ao2_container_count(cfg->applicationmap) == 0) {
2031 ast_cli(a->fd, "(none)\n");
2032 } else {
2033 ao2_callback(cfg->applicationmap, 0, print_applicationmap, a);
2034 }
2035
2036 ast_cli(a->fd, "\nFeature Groups:\n");
2037 ast_cli(a->fd, "---------------\n");
2038 if (!cfg->featuregroups || ao2_container_count(cfg->featuregroups) == 0) {
2039 ast_cli(a->fd, "(none)\n");
2040 } else {
2041 ao2_callback(cfg->featuregroups, 0, print_featuregroups, a);
2042 }
2043
2044 return CLI_SUCCESS;
2045}
2046
2048 AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
2049};
2050
2059
2061{
2062 /* Rearm the parking config options have moved warning. */
2063 parking_warning = 0;
2064
2065 if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
2066 return -1;
2067 }
2068 return 0;
2069}
2070
#define paren
Definition ael_lex.c:962
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
static const char app[]
ast_mutex_t lock
Definition app_sla.c:337
#define var
Definition ast_expr2f.c:605
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define __stringify(x)
Definition asterisk.h:216
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_log
Definition astobj2.c:42
#define AO2_GLOBAL_OBJ_STATIC(name)
Define a global object holder to be used to hold an ao2 object, statically initialized.
Definition astobj2.h:847
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
@ CMP_MATCH
Definition astobj2.h:1027
@ CMP_STOP
Definition astobj2.h:1028
#define OBJ_KEY
Definition astobj2.h:1151
#define OBJ_POINTER
Definition astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition astobj2.h:901
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition astobj2.h:1723
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition astobj2.h:918
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define OBJ_PARTIAL_KEY
Definition astobj2.h:1152
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition astobj2.h:859
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition astobj2.h:1303
@ AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW
Allow objects with duplicate keys in container.
Definition astobj2.h:1181
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE
Replace objects with duplicate keys in container.
Definition astobj2.h:1211
static struct console_pvt globals
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition channel.c:2376
#define DATASTORE_INHERIT_FOREVER
Definition channel.h:194
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition channel.c:2390
Standard Command Line Interface.
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
Configuration option-handling.
@ ACO_PREFIX
@ ACO_EXACT
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
#define ACO_FILES(...)
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
@ ACO_ITEM
@ ACO_GLOBAL
#define aco_option_register_custom_nodoc(info, name, matchtype, types, default_val, handler, flags)
Register a config option with no expected documentation.
@ ACO_BLACKLIST
@ ACO_WHITELIST_EXACT
@ ACO_WHITELIST
#define CONFIG_INFO_CORE(mod, name, arr, alloc,...)
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
Asterisk datastore objects.
#define ast_datastore_alloc(info, uid)
Definition datastore.h:85
char buf[BUFSIZE]
Definition eagi_proxy.c:66
static struct ao2_container * applicationmap_alloc(int replace_duplicates)
static void * featuregroup_alloc(const char *cat)
static void xfer_copy(struct ast_features_xfer_config *dest, const struct ast_features_xfer_config *src)
static struct aco_type * global_options[]
static int feature_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
#define HFS_FORMAT
static int check_featuregroup_item(void *obj, void *arg, void *data, int flags)
static int pickup_set(struct ast_features_pickup_config *pickup, const char *name, const char *value)
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER
static struct ast_applicationmap_item * applicationmap_item_alloc(const char *name, const char *app, const char *app_data, const char *moh_class, const char *dtmf, unsigned int activate_on_self)
static char * handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command to list configured features.
static int check_featuregroup(void *obj, void *arg, void *data, int flags)
#define DEFAULT_FEATUREMAP_BLINDXFER
static struct aco_type featuregroup_option
struct ast_features_general_config * ast_get_chan_features_general_config(struct ast_channel *chan)
Get the general configuration options for a channel.
static struct features_config * get_feature_ds(struct ast_channel *chan)
#define DEFAULT_TRANSFER_INVALID_SOUND
static struct ast_datastore * get_feature_chan_ds(struct ast_channel *chan)
#define DEFAULT_ATXFER_LOOP_DELAY
static void xfer_destructor(void *obj)
static struct ast_custom_function feature_function
static int group_item_sort(const void *obj, const void *arg, int flags)
static void * feature_ds_duplicate(void *data)
static int pickup_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int features_pre_apply_config(void)
static void ast_applicationmap_item_destructor(void *obj)
static int feature_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
#define DEFAULT_ATXFER_ABORT
static void pickup_destructor(void *obj)
#define DEFAULT_TRANSFER_ANNOUNCE_SOUND
struct ast_featuremap_config * ast_get_chan_featuremap_config(struct ast_channel *chan)
Get the featuremap configuration options for a channel.
static int internal_featuremap_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
#define DEFAULT_ATXFER_SWAP
char * ast_get_chan_features_xferfailsound(struct ast_channel *chan)
Get the transfer configuration option xferfailsound.
static void global_copy(struct features_global_config *dest, const struct features_global_config *src)
static void general_destructor(void *obj)
static struct features_config * features_config_dup(const struct features_config *orig)
static void featuremap_copy(struct ast_featuremap_config *dest, const struct ast_featuremap_config *src)
#define DEFAULT_PICKUPFAILSOUND
static const struct ast_datastore_info feature_ds_info
static int internal_feature_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int general_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
struct ast_features_xfer_config * ast_get_chan_features_xfer_config(struct ast_channel *chan)
Get the transfer configuration options for a channel.
#define DEFAULT_COURTESY_TONE
static int featuregroup_hash(const void *obj, int flags)
static int featuremap_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
#define DEFAULT_ATXFER_THREEWAY
static int featuremap_set(struct ast_featuremap_config *featuremap, const char *name, const char *value)
static int unsupported_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
#define DEFAULT_ATXFER_CALLBACK_RETRIES
static int featuremap_get(struct ast_featuremap_config *featuremap, const char *field, char *buf, size_t len)
static void features_config_destructor(void *obj)
static void * features_config_alloc(void)
#define DEFAULT_FEATUREMAP_DISCONNECT
static void global_config_destructor(void *obj)
static int featuregroup_cmp(void *obj, void *arg, int flags)
static int print_featuregroups(void *obj, void *arg, int flags)
static struct aco_type * parkinglot_options[]
#define DEFAULT_FEATURE_DIGIT_TIMEOUT
static int general_set(struct ast_features_general_config *general, const char *name, const char *value)
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT
static void featuregroup_item_destructor(void *obj)
struct ast_features_pickup_config * ast_get_chan_features_pickup_config(struct ast_channel *chan)
Get the pickup configuration options for a channel.
static void featuremap_config_destructor(void *obj)
#define DEFAULT_TRANSFER_RETRY_SOUND
static int internal_feature_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
static void featuregroup_destructor(void *obj)
int ast_get_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
Get the DTMF code for a call feature.
static void feature_ds_destroy(void *data)
int ast_get_builtin_feature(struct ast_channel *chan, const char *feature, char *buf, size_t len)
Get the DTMF code for a builtin feature.
static int applicationmap_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static struct aco_file features_conf
static int xfer_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
#define DEFAULT_ATXFER_DROP_CALL
#define DEFAULT_PICKUPSOUND
void unload_features_config(void)
#define DEFAULT_FEATUREMAP_ATXFER
int load_features_config(void)
static struct aco_type * applicationmap_options[]
static struct ast_cli_entry cli_features_config[]
static struct ast_custom_function featuremap_function
static int xfer_set(struct ast_features_xfer_config *xfer, const char *name, const char *value)
static struct aco_type parkinglot_option
#define DEFAULT_FEATUREMAP_PARKCALL
static int xfer_get(struct ast_features_xfer_config *xfer, const char *field, char *buf, size_t len)
#define DEFAULT_ATXFER_COMPLETE
static int featuregroup_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static struct features_config * __features_config_alloc(int allocate_applicationmap)
static int add_item(void *obj, void *arg, int flags)
static int print_applicationmap(void *obj, void *arg, int flags)
static int print_featuregroup(void *obj, void *arg, int flags)
char * ast_get_chan_features_atxferabort(struct ast_channel *chan)
Get the transfer configuration option atxferabort.
static int parking_warning
static int pickup_get(struct ast_features_pickup_config *pickup, const char *field, char *buf, size_t len)
static void pickup_copy(struct ast_features_pickup_config *dest, const struct ast_features_pickup_config *src)
static void features_copy(struct features_config *dest, const struct features_config *src)
static struct features_global_config * global_config_alloc(void)
static struct aco_type * featuregroup_options[]
static int featuremap_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
static void * featuregroup_find(struct ao2_container *group_container, const char *category)
#define DEFAULT_TRANSFER_DIAL_ATTEMPTS
#define DEFAULT_PICKUPEXTEN
static int applicationmap_sort(const void *obj, const void *arg, int flags)
struct ao2_container * ast_get_chan_applicationmap(struct ast_channel *chan)
Get the applicationmap for a given channel.
#define DEFAULT_XFERFAILSOUND
static void general_copy(struct ast_features_general_config *dest, const struct ast_features_general_config *src)
static int general_get(struct ast_features_general_config *general, const char *field, char *buf, size_t len)
static struct aco_type featuremap_option
static struct aco_type applicationmap_option
static int featuremap_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
#define DEFAULT_FEATUREMAP_AUTOMIXMON
static struct aco_type global_option
int reload_features_config(void)
static int load_config(void)
#define DEFAULT_RECORDING_FAIL_SOUND
#define DEFAULT_XFERSOUND
static struct aco_type * featuremap_options[]
static int internal_featuremap_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
static const char name[]
Definition format_mp3.c:68
static struct ao2_container * group_container
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *p_result,...)
The argument parsing routine.
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
Definition lock.h:626
Core PBX routines and definitions.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
Register a custom function.
static struct @522 args
#define NULL
Definition resample.c:96
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define AST_STRING_FIELD(name)
Declare a string field.
#define ast_string_fields_copy(copy, orig)
Copy all string fields from one instance to another of the same structure.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition utils.c:2233
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
Definition utils.c:1852
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition strings.h:1303
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
The representation of a single configuration file to be processed.
const char * filename
Type information about a category-level configurable object.
enum aco_type_t type
const char * name
Generic container type.
An applicationmap configuration item.
Main Channel structure associated with a channel.
descriptor for a cli entry.
Definition cli.h:171
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
Data structure associated with a custom dialplan function.
Definition pbx.h:118
const char * name
Definition pbx.h:119
Structure for a data store type.
Definition datastore.h:31
const char * type
Definition datastore.h:32
Structure for a data store object.
Definition datastore.h:64
void * data
Definition datastore.h:66
unsigned int inheritance
Definition datastore.h:69
Configuration for the builtin features.
General features configuration items.
Configuration relating to call pickup.
Feature configuration relating to transfers.
Structure for variables, used for configurations and for channel variables.
Entry in the container of featuregroups.
struct ast_applicationmap_item * appmap_item
const ast_string_field dtmf_override
const ast_string_field appmap_item_name
Featuregroup representation.
const char * name
struct ao2_container * items
struct ast_featuremap_config * featuremap
struct ao2_container * applicationmap
struct ao2_container * featuregroups
struct features_global_config * global
struct dummy_config * parkinglots
Configuration from the "general" section of features.conf.
struct ast_features_pickup_config * pickup
struct ast_features_general_config * general
struct ast_features_xfer_config * xfer
char name[AST_MAX_EXTENSION]
int value
Definition syslog.c:37
static struct aco_type global
static struct aco_type item
static struct test_val a
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
#define ARRAY_LEN(a)
Definition utils.h:706