Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
res_parking.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 * Jonathan Rose <jrose@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/*! \file
20 *
21 * \brief Call Parking Resource
22 *
23 * \author Jonathan Rose <jrose@digium.com>
24 */
25
26/*** MODULEINFO
27 <depend>bridge_holding</depend>
28 <support_level>core</support_level>
29 ***/
30
31/*** DOCUMENTATION
32 <configInfo name="res_parking" language="en_US">
33 <configFile name="res_parking.conf">
34 <configObject name="globals">
35 <since>
36 <version>12.0.0</version>
37 </since>
38 <synopsis>Options that apply to every parking lot</synopsis>
39 <configOption name="parkeddynamic">
40 <since>
41 <version>12.0.0</version>
42 </since>
43 <synopsis>Enables dynamically created parkinglots.</synopsis>
44 <description>
45 <para>If the option is enabled then the following variables can
46 be used to dynamically create new parking lots.
47 </para>
48 <para>The <variable>PARKINGDYNAMIC</variable> variable specifies the
49 parking lot to use as a template to create a dynamic parking lot. It
50 is an error to specify a non-existent parking lot for the template.
51 If not set then the default parking lot is used as the template.
52 </para>
53 <para>The <variable>PARKINGDYNCONTEXT</variable> variable specifies the
54 dialplan context to use for the newly created dynamic parking lot. If
55 not set then the context from the parking lot template is used. The
56 context is created if it does not already exist and the new parking lot
57 needs to create extensions.
58 </para>
59 <para>The <variable>PARKINGDYNEXTEN</variable> variable specifies the
60 <literal>parkext</literal> to use for the newly created dynamic
61 parking lot. If not set then the <literal>parkext</literal> is used from
62 the parking lot template. If the template does not specify a
63 <literal>parkext</literal> then no extensions are created for the newly
64 created parking lot. The dynamic parking lot cannot be created if it
65 needs to create extensions that overlap existing parking lot extensions.
66 The only exception to this is for the <literal>parkext</literal>
67 extension and only if neither of the overlaping parking lot's
68 <literal>parkext</literal> is exclusive.
69 </para>
70 <para>The <variable>PARKINGDYNPOS</variable> variable specifies the
71 parking positions to use for the newly created dynamic parking lot. If
72 not set then the <literal>parkpos</literal> from the parking lot template
73 is used.
74 </para>
75 </description>
76 </configOption>
77 </configObject>
78 <configObject name="parking_lot">
79 <since>
80 <version>12.0.0</version>
81 </since>
82 <synopsis>Defined parking lots for res_parking to use to park calls on</synopsis>
83 <configOption name="context" default="parkedcalls">
84 <since>
85 <version>12.0.0</version>
86 </since>
87 <synopsis>The name of the context where calls are parked and picked up from.</synopsis>
88 <description><para>This option is only used if parkext is set.</para></description>
89 </configOption>
90 <configOption name="parkext">
91 <since>
92 <version>12.0.0</version>
93 </since>
94 <synopsis>Extension to park calls to this parking lot.</synopsis>
95 <description>
96 <para>If this option is used, this extension will automatically
97 be created to place calls into parking lots. In addition, if
98 <literal>parkext_exclusive</literal> is set for this parking
99 lot, the name of the parking lot will be included in the
100 application's arguments so that it only parks to this parking
101 lot. The extension will be created in <literal>context</literal>.
102 Using this option also creates extensions for retrieving
103 parked calls from the parking spaces in the same context.
104 </para>
105 <note>
106 <para>Generated parking extensions cannot overlap.
107 The only exception is if neither overlapping
108 <literal>parkext</literal> is exclusive.
109 </para>
110 </note>
111 </description>
112 </configOption>
113 <configOption name="parkext_exclusive" default="no">
114 <since>
115 <version>12.0.0</version>
116 </since>
117 <synopsis>If yes, the extension registered as parkext will park exclusively to this parking lot.</synopsis>
118 </configOption>
119 <configOption name="parkpos" default="701-750">
120 <since>
121 <version>12.0.0</version>
122 </since>
123 <synopsis>Numerical range of parking spaces which can be used to retrieve parked calls.</synopsis>
124 <description>
125 <para>If <literal>parkext</literal> is set, these extensions
126 will automatically be mapped in <literal>context</literal>
127 in order to pick up calls parked to these parking spaces.
128 </para>
129 </description>
130 </configOption>
131 <configOption name="parkinghints" default="no">
132 <since>
133 <version>12.0.0</version>
134 </since>
135 <synopsis>If yes, this parking lot will add hints automatically for parking spaces.</synopsis>
136 </configOption>
137 <configOption name="parkingtime" default="45">
138 <since>
139 <version>12.0.0</version>
140 </since>
141 <synopsis>Amount of time a call will remain parked before giving up (in seconds).</synopsis>
142 </configOption>
143 <configOption name="parkedmusicclass">
144 <since>
145 <version>12.0.0</version>
146 </since>
147 <synopsis>Which music class to use for parked calls. They will use the default if unspecified.</synopsis>
148 </configOption>
149 <configOption name="comebacktoorigin" default="yes">
150 <since>
151 <version>12.0.0</version>
152 </since>
153 <synopsis>Determines what should be done with the parked channel if no one picks it up before it times out.</synopsis>
154 <description><para>Valid Options:</para>
155 <enumlist>
156 <enum name="yes">
157 <para>Automatically have the parked channel dial the device that parked the call with dial
158 timeout set by the <literal>parkingtime</literal> option. When the call times out an extension
159 to dial the PARKER will automatically be created in the <literal>park-dial</literal> context with
160 an extension of the flattened parker device name. If the call is not answered, the parked channel
161 that is timing out will continue in the dial plan at that point if there are more priorities in
162 the extension (which won't be the case unless the dialplan deliberately includes such priorities
163 in the <literal>park-dial</literal> context through pattern matching or deliberately written
164 flattened peer extensions).</para>
165 </enum>
166 <enum name="no">
167 <para>Place the call into the PBX at <literal>comebackcontext</literal> instead. The extension will
168 still be set as the flattened peer name. If an extension the flattened peer name isn't available
169 then it will fall back to the <literal>s</literal> extension. If that also is unavailable it will
170 attempt to fall back to <literal>s@default</literal>. The normal dial extension will still be
171 created in the <literal>park-dial</literal> context with the extension also being the flattened
172 peer name.</para>
173 </enum>
174 </enumlist>
175 <note><para>Flattened Peer Names - Extensions can not include slash characters since those are used for pattern
176 matching. When a peer name is flattened, slashes become underscores. For example if the parker of a call
177 is called <literal>SIP/0004F2040001</literal> then flattened peer name and therefor the extensions created
178 and used on timeouts will be <literal>SIP_0004F204001</literal>.</para></note>
179 <note><para>When parking times out and the channel returns to the dial plan, the following variables are set:
180 </para></note>
181 <variablelist>
182 <variable name="PARKING_SPACE">
183 <para>extension that the call was parked in prior to timing out.</para>
184 </variable>
185 <variable name="PARKEDLOT">
186 <para>name of the lot that the call was parked in prior to timing out.</para>
187 </variable>
188 <variable name="PARKER">
189 <para>The device that parked the call</para>
190 </variable>
191 <variable name="PARKER_FLAT">
192 <para>The flat version of <variable>PARKER</variable></para>
193 </variable>
194 </variablelist>
195 </description>
196 </configOption>
197 <configOption name="comebackdialtime" default="30">
198 <since>
199 <version>12.0.0</version>
200 </since>
201 <synopsis>Timeout for the Dial extension created to call back the parker when a parked call times out.</synopsis>
202 </configOption>
203 <configOption name="comebackcontext" default="parkedcallstimeout">
204 <since>
205 <version>12.0.0</version>
206 </since>
207 <synopsis>Context where parked calls will enter the PBX on timeout when comebacktoorigin=no</synopsis>
208 <description><para>The extension the call enters will prioritize the flattened peer name in this context.
209 If the flattened peer name extension is unavailable, then the 's' extension in this context will be
210 used. If that also is unavailable, the 's' extension in the 'default' context will be used.</para>
211 </description>
212 </configOption>
213 <configOption name="courtesytone">
214 <since>
215 <version>12.0.0</version>
216 </since>
217 <synopsis>If the name of a sound file is provided, use this as the courtesy tone</synopsis>
218 <description><para>By default, this tone is only played to the caller of a parked call. Who receives the tone
219 can be changed using the <literal>parkedplay</literal> option.</para>
220 </description>
221 </configOption>
222 <configOption name="parkedplay" default="caller">
223 <since>
224 <version>12.0.0</version>
225 </since>
226 <synopsis>Who we should play the courtesytone to on the pickup of a parked call from this lot</synopsis>
227 <description>
228 <enumlist>
229 <enum name="no"><para>Apply to neither side.</para></enum>
230 <enum name="caller"><para>Apply only to the call connecting with the call coming out of the parking lot.</para></enum>
231 <enum name="callee"><para>Apply only to the call coming out of the parking lot.</para></enum>
232 <enum name="both"><para>Apply to both sides.</para></enum>
233 </enumlist>
234 <note><para>If courtesy tone is not specified then this option will be ignored.</para></note>
235 </description>
236 </configOption>
237 <configOption name="parkedcalltransfers" default="no">
238 <since>
239 <version>12.0.0</version>
240 </since>
241 <synopsis>Who to apply the DTMF transfer features to when parked calls are picked up or timeout.</synopsis>
242 <description>
243 <xi:include xpointer="xpointer(/docs/configInfo[@name='res_parking']/configFile[@name='res_parking.conf']/configObject[@name='parking_lot']/configOption[@name='parkedplay']/description/enumlist)" />
244 </description>
245 </configOption>
246 <configOption name="parkedcallreparking" default="no">
247 <since>
248 <version>12.0.0</version>
249 </since>
250 <synopsis>Who to apply the DTMF parking feature to when parked calls are picked up or timeout.</synopsis>
251 <description>
252 <xi:include xpointer="xpointer(/docs/configInfo[@name='res_parking']/configFile[@name='res_parking.conf']/configObject[@name='parking_lot']/configOption[@name='parkedplay']/description/enumlist)" />
253 </description>
254 </configOption>
255 <configOption name="parkedcallhangup" default="no">
256 <since>
257 <version>12.0.0</version>
258 </since>
259 <synopsis>Who to apply the DTMF hangup feature to when parked calls are picked up or timeout.</synopsis>
260 <description>
261 <xi:include xpointer="xpointer(/docs/configInfo[@name='res_parking']/configFile[@name='res_parking.conf']/configObject[@name='parking_lot']/configOption[@name='parkedplay']/description/enumlist)" />
262 </description>
263 </configOption>
264 <configOption name="parkedcallrecording" default="no">
265 <since>
266 <version>12.0.0</version>
267 </since>
268 <synopsis>Who to apply the DTMF MixMonitor recording feature to when parked calls are picked up or timeout.</synopsis>
269 <description>
270 <xi:include xpointer="xpointer(/docs/configInfo[@name='res_parking']/configFile[@name='res_parking.conf']/configObject[@name='parking_lot']/configOption[@name='parkedplay']/description/enumlist)" />
271 </description>
272 </configOption>
273 <configOption name="findslot" default="first">
274 <since>
275 <version>12.0.0</version>
276 </since>
277 <synopsis>Rule to use when trying to figure out which parking space a call should be parked with.</synopsis>
278 <description>
279 <enumlist>
280 <enum name="first"><para>Always try to place in the lowest available space in the parking lot</para></enum>
281 <enum name="next"><para>Track the last parking space used and always attempt to use the one immediately after.
282 </para></enum>
283 </enumlist>
284 </description>
285 </configOption>
286 </configObject>
287 </configFile>
288 </configInfo>
289 ***/
290
291#include "asterisk.h"
292
293#include "parking/res_parking.h"
294#include "asterisk/config.h"
296#include "asterisk/utils.h"
297#include "asterisk/module.h"
298#include "asterisk/cli.h"
299#include "asterisk/astobj2.h"
300#include "asterisk/features.h"
301#include "asterisk/manager.h"
302#include "asterisk/pbx.h"
303
304static int parking_lot_sort_fn(const void *obj_left, const void *obj_right, int flags)
305{
306 const struct parking_lot *left = obj_left;
307 const struct parking_lot *right = obj_right;
308 const char *right_key = obj_right;
309 int cmp;
310
311 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
312 default:
313 case OBJ_POINTER:
314 right_key = right->name;
315 /* Fall through */
316 case OBJ_KEY:
317 cmp = strcmp(left->name, right_key);
318 break;
319 case OBJ_PARTIAL_KEY:
320 cmp = strncmp(left->name, right_key, strlen(right_key));
321 }
322 return cmp;
323}
324
325/*! All parking lots that are currently alive in some fashion can be obtained from here */
327
328static void *parking_config_alloc(void);
329
330static void *parking_lot_cfg_alloc(const char *cat);
331static void *named_item_find(struct ao2_container *container, const char *name); /* XXX This is really just a generic string find. Move to astobj2.c? */
332
333static int config_parking_preapply(void);
335
338};
339
343};
344
345static struct aco_type global_option = {
346 .type = ACO_GLOBAL,
347 .name = "globals",
348 .item_offset = offsetof(struct parking_config, global),
349 .category_match = ACO_WHITELIST_EXACT,
350 .category = "general",
351};
352
354
355static struct aco_type parking_lot_type = {
356 .type = ACO_ITEM,
357 .name = "parking_lot",
358 .category_match = ACO_BLACKLIST_EXACT,
359 .category = "general",
360 .item_alloc = parking_lot_cfg_alloc,
361 .item_find = named_item_find,
362 .item_offset = offsetof(struct parking_config, parking_lots),
363};
364
366
368 .filename = "res_parking.conf",
370};
371
373
375 .files = ACO_FILES(&parking_lot_conf),
376 .pre_apply_config = config_parking_preapply,
377 .post_apply_config = link_configured_disable_marked_lots,
378);
379
380static int parking_lot_cfg_hash_fn(const void *obj, const int flags)
381{
382 const struct parking_lot_cfg *entry;
383 const char *key;
384
385 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
386 case OBJ_KEY:
387 key = obj;
388 return ast_str_hash(key);
389 case OBJ_PARTIAL_KEY:
390 ast_assert(0);
391 return 0;
392 default:
393 entry = obj;
394 return ast_str_hash(entry->name);
395 }
396}
397
398static int parking_lot_cfg_cmp_fn(void *obj, void *arg, const int flags)
399{
400 struct parking_lot_cfg *entry1 = obj;
401
402 char *key;
403 size_t key_size;
404 struct parking_lot_cfg *entry2;
405
406 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
407 case OBJ_KEY:
408 key = arg;
409 return (!strcmp(entry1->name, key)) ? CMP_MATCH : 0;
410 case OBJ_PARTIAL_KEY:
411 key = arg;
412 key_size = strlen(key);
413 return (!strncmp(entry1->name, key, key_size)) ? CMP_MATCH : 0;
414 case OBJ_POINTER:
415 entry2 = arg;
416 return (!strcmp(entry1->name, entry2->name)) ? CMP_MATCH : 0;
417 default:
418 return CMP_STOP;
419 }
420}
421
422/*! \brief destructor for parking_config */
423static void parking_config_destructor(void *obj)
424{
425 struct parking_config *cfg = obj;
427 ao2_cleanup(cfg->global);
428}
429
430/*! \brief destructor for parking_global_config */
432{
433 /* For now, do nothing. */
434}
435
436/*! \brief allocator callback for parking_config. Notice it returns void * since it is only used by the backend config code */
437static void *parking_config_alloc(void)
438{
439 RAII_VAR(struct parking_config *, cfg, NULL, ao2_cleanup);
440
441 if (!(cfg = ao2_alloc(sizeof(*cfg), parking_config_destructor))) {
442 return NULL;
443 }
444
445 cfg->parking_lots = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 37,
447 if (!cfg->parking_lots) {
448 return NULL;
449 }
450
451 if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), parking_global_config_destructor))) {
452 return NULL;
453 }
454
455 /* Bump the ref count since RAII_VAR is going to eat one */
456 ao2_ref(cfg, +1);
457 return cfg;
458}
459
461{
462 if (lot->mode != PARKINGLOT_DISABLED) {
463 return -1;
464 }
465
468 return 0;
469 }
470
471 return -1;
472}
473
474static void parking_lot_disable(struct parking_lot *lot)
475{
476 /* If a dynamic lot wasn't removed, we need to restore it to full functionality afterwards. */
477 int was_dynamic = (lot->mode == PARKINGLOT_DYNAMIC);
478
480 if (parking_lot_remove_if_unused(lot) && was_dynamic) {
482 lot->disable_mark = 0;
483 }
484}
485
486/*! \brief Destroy a parking lot cfg object */
487static void parking_lot_cfg_destructor(void *obj)
488{
489 struct parking_lot_cfg *lot_cfg = obj;
492}
493
494/* The arg just needs to have the parking space with it */
495static int parked_user_cmp_fn(void *obj, void *arg, int flags)
496{
497 int *search_space = arg;
498 struct parked_user *user = obj;
499 int object_space = user->parking_space;
500
501 if (*search_space == object_space) {
502 return CMP_MATCH;
503 }
504 return 0;
505}
506
507static int parked_user_sort_fn(const void *obj_left, const void *obj_right, int flags)
508{
509 const struct parked_user *left = obj_left;
510 const struct parked_user *right = obj_right;
511
512 return left->parking_space - right->parking_space;
513}
514
515/*!
516 * \brief create a parking lot structure
517 * \param cat name given to the parking lot
518 * \retval NULL failure
519 * \retval non-NULL successfully allocated parking lot
520 */
521static void *parking_lot_cfg_alloc(const char *cat)
522{
523 struct parking_lot_cfg *lot_cfg;
524
525 lot_cfg = ao2_alloc(sizeof(*lot_cfg), parking_lot_cfg_destructor);
526 if (!lot_cfg) {
527 return NULL;
528 }
529
530 if (ast_string_field_init(lot_cfg, 32)) {
531 ao2_cleanup(lot_cfg);
532 return NULL;
533 }
534
535 ast_string_field_set(lot_cfg, name, cat);
536
537 return lot_cfg;
538}
539
540#if defined(TEST_FRAMEWORK)
541struct parking_lot_cfg *parking_lot_cfg_create(const char *cat)
542{
543 return parking_lot_cfg_alloc(cat);
544}
545#endif
546
547/*!
548 * XXX This is actually incredibly generic and might be better placed in something like astobj2 if there isn't already an equivalent
549 * \brief find an item in a container by its name
550 *
551 * \param container ao2container where we want the item from
552 * \param name name of the item wanted to be found
553 *
554 * \return pointer to the parking lot if available.
555 * \retval NULL if not found.
556 */
557static void *named_item_find(struct ao2_container *container, const char *name)
558{
559 return ao2_find(container, name, OBJ_KEY);
560}
561
562/*!
563 * \brief Custom field handler for parking positions
564 */
565static int option_handler_parkpos(const struct aco_option *opt, struct ast_variable *var, void *obj)
566{
567 struct parking_lot_cfg *lot_cfg = obj;
568 int low;
569 int high;
570
571 if (sscanf(var->value, "%30d-%30d", &low, &high) != 2) {
572 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers\n");
573 } else if (high < low || low <= 0 || high <= 0) {
574 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a <= b\n");
575 } else {
576 lot_cfg->parking_start = low;
577 lot_cfg->parking_stop = high;
578 return 0;
579 }
580 return -1;
581}
582
583/*!
584 * \brief Custom field handler for the findslot option
585 */
586static int option_handler_findslot(const struct aco_option *opt, struct ast_variable *var, void *obj)
587{
588 struct parking_lot_cfg *lot_cfg = obj;
589
590 if (!strcmp(var->value, "first")) {
591 lot_cfg->parkfindnext = 0;
592 } else if (!strcmp(var->value, "next")) {
593 lot_cfg->parkfindnext = 1;
594 } else {
595 ast_log(LOG_WARNING, "value '%s' is not valid for findslot option.\n", var->value);
596 return -1;
597 }
598
599 return 0;
600}
601
602/*!
603 * \brief Maps string values for option_handler_parkedfeature to their ENUM values
604 */
605static int parking_feature_flag_cfg(int *param, const char *var)
606{
607 if (ast_false(var)) {
608 *param = 0;
609 } else if (!strcasecmp(var, "both")) {
611 } else if (!strcasecmp(var, "caller")) {
613 } else if (!strcasecmp(var, "callee")) {
615 } else {
616 return -1;
617 }
618
619 return 0;
620}
621
622/*!
623 * \brief Custom field handler for feature mapping on parked call pickup options
624 */
625static int option_handler_parkedfeature(const struct aco_option *opt, struct ast_variable *var, void *obj)
626{
627 struct parking_lot_cfg *cfg = obj;
629 int *parameter = NULL;
630
631 switch (option) {
632 case OPT_PARKEDPLAY:
633 parameter = &cfg->parkedplay;
634 break;
636 parameter = &cfg->parkedcalltransfers;
637 break;
639 parameter = &cfg->parkedcallreparking;
640 break;
641 case OPT_PARKEDHANGUP:
642 parameter = &cfg->parkedcallhangup;
643 break;
645 parameter = &cfg->parkedcallrecording;
646 break;
647 }
648
649 ast_assert(parameter != NULL);
650 if (!parameter || parking_feature_flag_cfg(parameter, var->value)) {
651 return -1;
652 }
653
654 return 0;
655}
656
658{
660}
661
662struct parking_lot *parking_lot_find_by_name(const char *lot_name)
663{
664 struct parking_lot *lot = named_item_find(parking_lot_container, lot_name);
665 return lot;
666}
667
669{
670 const char *name;
671
672 /* The channel variable overrides everything */
673 name = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
674 if (ast_strlen_zero(name)) {
675 /* Try the channel's parking lot. */
677 if (ast_strlen_zero(name)) {
678 /* Fall back to the default parking lot. */
680 }
681 }
682
683 return name;
684}
685
686static void parking_lot_destructor(void *obj)
687{
688 struct parking_lot *lot = obj;
689
690 if (lot->parking_bridge) {
692 }
694 ao2_cleanup(lot->cfg);
696}
697
698static struct parking_lot *alloc_new_parking_lot(struct parking_lot_cfg *lot_cfg)
699{
700 struct parking_lot *lot;
701 if (!(lot = ao2_alloc(sizeof(*lot), parking_lot_destructor))) {
702 return NULL;
703 }
704
705 if (ast_string_field_init(lot, 32)) {
706 return NULL;
707 }
708
709 /* Create parked user ordered list */
714
715 if (!lot->parked_users) {
716 ao2_cleanup(lot);
717 return NULL;
718 }
719
720 ast_string_field_set(lot, name, lot_cfg->name);
721 return lot;
722}
723
725{
726 if (!ast_strlen_zero(lot_cfg->registrar)) {
727 /* Although the function is called ast_context_destroy, the use of this funtion is
728 * intended only to remove extensions, hints, etc registered by the parking lot's registrar.
729 * It won't actually destroy the context unless that context is empty afterwards and it is
730 * unreferenced.
731 */
733 }
734
735 /* If we come back for a second pass, someone else has this registrar now. */
736 ast_string_field_set(lot_cfg, registrar, "");
737}
738
740{
742 struct parking_lot_cfg *lot_cfg;
743 struct ao2_iterator iter;
744
745 if (!cfg) {
746 return;
747 }
748
749 for (iter = ao2_iterator_init(cfg->parking_lots, 0); (lot_cfg = ao2_iterator_next(&iter)); ao2_ref(lot_cfg, -1)) {
751 }
752
754
756}
757
758/*!
759 * \internal
760 * \since 12
761 * \brief Create an extension using ast_add_extension2_nolock. This function automatically allocates a duplicate
762 * of the data string so that whatever calls it doesn't have to deal with freeing it if the ast_add_extension2_nolock
763 * fails.
764 *
765 * \param context a write locked ast_context. Make certain it is write locked prior to calling this function
766 * \param replace whether the extension should replace existing extensions
767 * \param extension name of the extension desired
768 * \param priority priority of the extension we are registering
769 * \param application name of the application being used for the extension
770 * \param data application arguments
771 * \param registrar name of the registrar you should use for the extension.
772 * Make sure this string doesn't go anywhere while there are still extensions using it.
773 */
774static int parking_add_extension(struct ast_context *context, int replace, const char *extension,
775 int priority, const char *application, const char *data, const char *registrar)
776{
777 char *data_duplicate = ast_strdup(data);
778
779 if (!data_duplicate) {
780 return -1;
781 }
782
784 application, data_duplicate, ast_free_ptr, registrar, NULL, 0)) {
785 return -1;
786 }
787
788 return 0;
789}
790
791static int extension_is_compatible(struct parking_lot_cfg *lot_cfg, const char *app_type, struct ast_exten *extension)
792{
793 const char *extension_registrar = ast_get_extension_registrar(extension);
794 const char *extension_context = ast_get_context_name(ast_get_extension_context(extension));
795 const char *extension_name = ast_get_extension_name(extension);
796 const char *extension_application = ast_get_extension_app(extension);
797
798 ast_assert(extension_registrar && extension_context && extension_name && extension_application);
799
800 if (strcmp(extension_registrar, BASE_REGISTRAR)) {
801 ast_log(LOG_ERROR, "Parking lot '%s' -- Needs an extension '%s@%s', but that extension is already owned by %s.\n",
802 lot_cfg->name, extension_name, extension_context, extension_registrar);
803 return 0;
804 }
805
806 if (strcmp(extension_application, app_type)) {
807 ast_log(LOG_ERROR, "Parking lot '%s' -- Needs an extension '%s@%s' with a non-exclusive %s application, "
808 "but a/an %s application is already registered to that extension by %s.\n",
809 lot_cfg->name, extension_name, extension_context, app_type,
810 extension_application, BASE_REGISTRAR);
811 return 0;
812 }
813
814 ast_debug(3, "Parking lot '%s' -- extension '%s@%s' with application %s is compatible.\n",
815 lot_cfg->name, extension_name, extension_context, app_type);
816 return 1;
817}
818
820{
821 int parkingspace;
822 struct ast_exten *existing_exten;
823 struct ast_context *lot_context;
824 struct pbx_find_info find_info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
825 const char *parkext_registrar_pointer; /* Used for park extension */
826 const char *parkedcall_registrar_pointer; /* Used for parkedcall extensions/hints */
827
828 if (ast_strlen_zero(lot_cfg->parkext)) {
829 return 0;
830 }
831
832 ast_string_field_build(lot_cfg, registrar, "%s/%s", BASE_REGISTRAR, lot_cfg->name);
833 parkedcall_registrar_pointer = lot_cfg->registrar;
834
835 if (lot_cfg->parkext_exclusive) {
836 parkext_registrar_pointer = lot_cfg->registrar;
837 } else {
838 parkext_registrar_pointer = BASE_REGISTRAR;
839 }
840
841 /* We need the contexts list locked to safely be able to both read and lock the specific context within */
843
844 if (!(lot_context = ast_context_find_or_create(NULL, NULL, lot_cfg->parking_con, parkext_registrar_pointer))) {
845 ast_log(LOG_ERROR, "Parking lot '%s' -- Needs a context '%s' which does not exist and Asterisk was unable to create\n",
846 lot_cfg->name, lot_cfg->parking_con);
848 return -1;
849 }
850
851 /* Once we know what context we will be modifying, we need to write lock it because we will be reading extensions
852 * and we don't want something else to destroy them while we are looking at them.
853 */
854 ast_wrlock_context(lot_context);
855
857
858 /* Handle generation/confirmation for the Park extension */
859 if ((existing_exten = pbx_find_extension(NULL, NULL, &find_info, lot_cfg->parking_con, lot_cfg->parkext, 1, NULL, NULL, E_MATCH))) {
860 if (lot_cfg->parkext_exclusive || !extension_is_compatible(lot_cfg, PARK_APPLICATION, existing_exten)) {
861 ast_unlock_context(lot_context);
862 return -1;
863 }
864 } else if (parking_add_extension(lot_context, 0, lot_cfg->parkext, 1, PARK_APPLICATION,
865 lot_cfg->parkext_exclusive ? lot_cfg->name : "", parkext_registrar_pointer)) {
866 ast_log(LOG_ERROR, "Parking lot '%s' -- Failed to add %s extension '%s@%s' to the PBX.\n",
867 lot_cfg->name, PARK_APPLICATION, lot_cfg->parkext, lot_cfg->parking_con);
868 ast_unlock_context(lot_context);
869 return -1;
870 }
871
872 /* Handle generation/confirmation for the ParkedCall extensions and hints */
873 for (parkingspace = lot_cfg->parking_start; parkingspace <= lot_cfg->parking_stop; parkingspace++) {
874 char space[AST_MAX_EXTENSION];
875 RAII_VAR(struct ast_str *, arguments_string, NULL, ast_free);
876 find_info.stacklen = 0; /* reset for pbx_find_exten */
877
878 snprintf(space, sizeof(space), "%d", parkingspace);
879
880 /* Unlike the Park extensions, ParkedCall extensions and their hints may never be shared for any reason. */
881 if ((existing_exten = pbx_find_extension(NULL, NULL, &find_info, lot_cfg->parking_con, space, 1, NULL, NULL, E_MATCH))) {
882 ast_unlock_context(lot_context);
883 return -1;
884 }
885
886 arguments_string = ast_str_create(32);
887 if (!arguments_string) {
888 ast_unlock_context(lot_context);
889 return -1;
890 }
891
892 ast_str_set(&arguments_string, 0, "%s,%s", lot_cfg->name, space);
893 if (parking_add_extension(lot_context, 0, space, 1, PARKED_CALL_APPLICATION,
894 ast_str_buffer(arguments_string), parkedcall_registrar_pointer)) {
895 ast_log(LOG_ERROR, "Parking lot '%s' -- Failed to add %s extension '%s@%s' to the PBX.\n",
896 lot_cfg->name, PARKED_CALL_APPLICATION, space, lot_cfg->parking_con);
897 ast_unlock_context(lot_context);
898 return -1;
899 }
900
901 find_info.stacklen = 0; /* reset for pbx_find_exten */
902
903 if (lot_cfg->parkaddhints) {
904 char hint_device[AST_MAX_EXTENSION];
905
906 snprintf(hint_device, sizeof(hint_device), "park:%s@%s", space, lot_cfg->parking_con);
907
908 if ((existing_exten = pbx_find_extension(NULL, NULL, &find_info, lot_cfg->parking_con, space, PRIORITY_HINT, NULL, NULL, E_MATCH))) {
909 ast_log(LOG_ERROR, "Parking lot '%s' -- Needs to add a hint '%s' at '%s@%s' but one already exists owned by %s\n",
910 lot_cfg->name, hint_device, space, lot_cfg->parking_con, ast_get_extension_registrar(existing_exten));
911 ast_unlock_context(lot_context);
912 return -1;
913 }
914
915 if (parking_add_extension(lot_context, 0, space, PRIORITY_HINT, hint_device, "", parkedcall_registrar_pointer)) {
916 ast_log(LOG_ERROR, "Parking lot '%s' -- Failed to add hint '%s@%s' to the PBX.\n",
917 lot_cfg->name, space, lot_cfg->parking_con);
918 ast_unlock_context(lot_context);
919 return -1;
920 }
921 }
922 }
923
924 ast_unlock_context(lot_context);
925
926 return 0;
927}
928
929struct parking_lot *parking_lot_build_or_update(struct parking_lot_cfg *lot_cfg, int dynamic)
930{
931 struct parking_lot *lot;
932 struct parking_lot_cfg *replaced_cfg = NULL;
933 int found = 0;
934
935 /* Start by trying to find it. If that works we can skip the rest. */
937 if (!lot) {
938 lot = alloc_new_parking_lot(lot_cfg);
939
940 /* If we still don't have a lot, we failed to alloc one. */
941 if (!lot) {
942 return NULL;
943 }
944 } else {
945 found = 1;
946
947 if (dynamic) {
948 ast_log(LOG_ERROR, "Tried to create dynamic parking lot with name '%s' but a lot with that name already exists.\n", lot_cfg->name);
949 ao2_cleanup(lot);
950 return NULL;
951 }
952 }
953
954 /* Set the configuration reference. Unref the one currently in the lot if it's there. */
955 if (lot->cfg) {
956 replaced_cfg = lot->cfg;
957 }
958
959 ao2_ref(lot_cfg, +1);
960 lot->cfg = lot_cfg;
961
962 ao2_cleanup(replaced_cfg);
963
964 /* Set the operating mode to normal since the parking lot has a configuration. */
965 lot->disable_mark = 0;
966 lot->mode = dynamic ? PARKINGLOT_DYNAMIC : PARKINGLOT_NORMAL;
967
968 if (!found) {
969 /* Link after configuration is set since a lot without configuration will cause all kinds of trouble. */
971 };
972
973 return lot;
974}
975
977{
979 struct parking_lot_cfg *lot_cfg;
980 struct ao2_iterator iter;
981
982 iter = ao2_iterator_init(cfg->parking_lots, 0);
983 for (; (lot_cfg = ao2_iterator_next(&iter)); ao2_ref(lot_cfg, -1)) {
985 }
987}
988
990{
992
993 if (!cfg) {
994 return 0;
995 }
996
997 return cfg->global->parkeddynamic;
998}
999
1000static struct parking_lot_cfg *clone_parkinglot_cfg(struct parking_lot_cfg *source, const char *name)
1001{
1003
1004 if (!cfg) {
1005 return NULL;
1006 }
1007
1008 ast_string_fields_copy(cfg, source);
1009
1010 /* Needs to be reset after being copied */
1012
1013 /* Stuff that should be cloned that isn't hit by string field copy */
1014 cfg->parking_start = source->parking_start;
1015 cfg->parking_stop = source->parking_stop;
1016 cfg->parkingtime = source->parkingtime;
1017 cfg->comebackdialtime = source->comebackdialtime;
1018 cfg->parkfindnext = source->parkfindnext;
1019 cfg->parkext_exclusive = source->parkext_exclusive;
1020 cfg->parkaddhints = source->parkaddhints;
1021 cfg->comebacktoorigin = source->comebacktoorigin;
1022 cfg->parkedplay = source->parkedplay;
1025 cfg->parkedcallhangup = source->parkedcallhangup;
1027
1028 return cfg;
1029}
1030
1031static struct parking_lot *create_dynamic_lot_full(const char *name, struct ast_channel *chan, int forced)
1032{
1034 RAII_VAR(struct parking_lot *, template_lot, NULL, ao2_cleanup);
1035
1036 struct parking_lot *lot;
1037 const char *dyn_context;
1038 const char *dyn_exten;
1039 const char *dyn_range;
1040 const char *template_name;
1041 const char *chan_template_name;
1042 int dyn_start;
1043 int dyn_end;
1044
1045 if (!forced && !parking_dynamic_lots_enabled()) {
1046 return NULL;
1047 }
1048
1049 ast_channel_lock(chan);
1050 chan_template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
1051 dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
1052 dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), ""));
1053 dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), ""));
1054 ast_channel_unlock(chan);
1055
1056 template_name = S_OR(chan_template_name, DEFAULT_PARKING_LOT);
1057
1058 template_lot = parking_lot_find_by_name(template_name);
1059 if (!template_lot) {
1060 ast_log(LOG_ERROR, "Lot %s does not exist. Can not use it as a dynamic parking lot template.\n",
1061 template_name);
1062 return NULL;
1063 }
1064
1065 cfg = clone_parkinglot_cfg(template_lot->cfg, name);
1066
1067 if (!cfg) {
1068 ast_log(LOG_ERROR, "Failed to allocate dynamic parking lot configuration.\n");
1069 return NULL;
1070 }
1071
1072 if (!ast_strlen_zero(dyn_exten)) {
1073 ast_string_field_set(cfg, parkext, dyn_exten);
1074 }
1075
1076 if (!ast_strlen_zero(dyn_context)) {
1077 ast_string_field_set(cfg, parking_con, dyn_context);
1078 }
1079
1080 if (!ast_strlen_zero(dyn_range)) {
1081 if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
1083 "Invalid parking range %s specified in PARKINGDYNPOS: could not parse minimum/maximum parking space range\n", dyn_range);
1084 return NULL;
1085 }
1086 if (dyn_end < dyn_start || dyn_start < 0) {
1088 "Invalid parking range %s specified for PARKINGDYNPOS: end parking space must be greater than starting parking space.\n", dyn_range);
1089 return NULL;
1090 }
1091
1092 cfg->parking_start = dyn_start;
1093 cfg->parking_stop = dyn_end;
1094 }
1095
1097 ast_log(LOG_ERROR, "Extensions for dynamic parking lot '%s' could not be registered. Dynamic lot creation failed.\n", name);
1098 return NULL;
1099 }
1100
1102
1103 if ((lot = parking_lot_find_by_name(name))) {
1105 ast_log(LOG_ERROR, "Started creating dynamic parking lot '%s', but a parking lot with that name already exists.\n", name);
1106 ao2_ref(lot, -1);
1107 return NULL;
1108 }
1109
1112
1113 if (!lot) {
1114 ast_log(LOG_NOTICE, "Failed to build dynamic parking lot '%s'\n", name);
1115 }
1116
1117 return lot;
1118}
1119
1120struct parking_lot *parking_create_dynamic_lot(const char *name, struct ast_channel *chan){
1121 return create_dynamic_lot_full(name, chan, 0);
1122}
1123
1124#if defined(TEST_FRAMEWORK)
1125struct parking_lot *parking_create_dynamic_lot_forced(const char *name, struct ast_channel *chan) {
1126 return create_dynamic_lot_full(name, chan, 1);
1127}
1128#endif
1129
1130/* Preapply */
1131
1133{
1134 struct parking_config *cfg = aco_pending_config(&cfg_info);
1135 RAII_VAR(struct parking_lot_cfg *, lot_cfg, NULL, ao2_cleanup);
1136
1137 if (!cfg) {
1138 return 0;
1139 }
1140
1142 if (!lot_cfg) {
1144 if (!lot_cfg) {
1145 return -1;
1146 }
1147 ast_log(AST_LOG_NOTICE, "Adding %s profile to res_parking\n", DEFAULT_PARKING_LOT);
1150 ao2_link(cfg->parking_lots, lot_cfg);
1151 }
1152
1153 return 0;
1154}
1155
1157{
1158 struct parking_lot_cfg *lot_cfg;
1159 struct ao2_iterator iter;
1160
1161 for (iter = ao2_iterator_init(cfg_pending->parking_lots, 0); (lot_cfg = ao2_iterator_next(&iter)); ao2_ref(lot_cfg, -1)) {
1163 }
1164
1165 ao2_iterator_destroy(&iter);
1166
1168
1169}
1170
1172{
1173 struct parking_config *cfg = aco_pending_config(&cfg_info);
1174 struct ao2_iterator iter;
1175 RAII_VAR(struct parking_lot_cfg *, lot_cfg, NULL, ao2_cleanup);
1176 int res = 0;
1177
1178 if (!cfg) {
1179 return 0;
1180 }
1181
1182 /* Clear existing extensions */
1184
1185 /* Attempt to build new extensions for each lot */
1186 for (iter = ao2_iterator_init(cfg->parking_lots, 0); (lot_cfg = ao2_iterator_next(&iter)); ao2_ref(lot_cfg, -1)) {
1187 if (parking_lot_cfg_create_extensions(lot_cfg)) {
1188 ao2_cleanup(lot_cfg);
1189 lot_cfg = NULL;
1190 res = -1;
1191 break;
1192 }
1193 }
1194 ao2_iterator_destroy(&iter);
1195
1196 if (res) {
1198 ast_log(LOG_ERROR, "Extension registration failed. Previously configured lot extensions were removed and can not be safely restored.\n");
1199 }
1200
1201 return res;
1202}
1203
1204static void mark_lots_as_disabled(void)
1205{
1206 struct ao2_iterator iter;
1207 struct parking_lot *lot;
1208
1209 for (iter = ao2_iterator_init(parking_lot_container, 0); (lot = ao2_iterator_next(&iter)); ao2_ref(lot, -1)) {
1210 lot->disable_mark = 1;
1211 }
1212
1213 ao2_iterator_destroy(&iter);
1214}
1215
1217{
1219
1221 return -1;
1222 }
1223
1225 return -1;
1226 }
1227
1228 return 0;
1229}
1230
1231static void disable_marked_lots(void)
1232{
1233 struct ao2_iterator iter;
1234 struct parking_lot *lot;
1235
1236 for (iter = ao2_iterator_init(parking_lot_container, 0); (lot = ao2_iterator_next(&iter)); ao2_ref(lot, -1)) {
1237 if (lot->disable_mark) {
1239 }
1240 }
1241
1242 ao2_iterator_destroy(&iter);
1243}
1244
1246{
1249}
1250
1251static int unload_module(void)
1252{
1262 aco_info_destroy(&cfg_info);
1264
1265 return 0;
1266}
1267
1268static int load_module(void)
1269{
1273 NULL);
1274 if (!parking_lot_container) {
1275 goto error;
1276 }
1277
1278 if (aco_info_init(&cfg_info)) {
1279 goto error;
1280 }
1281
1282 /* Global options */
1283 aco_option_register(&cfg_info, "parkeddynamic", ACO_EXACT, global_options, "no", OPT_BOOL_T, 1, FLDSET(struct parking_global_config, parkeddynamic));
1284
1285 /* Register the per parking lot options. */
1286 aco_option_register(&cfg_info, "parkext", ACO_EXACT, parking_lot_types, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct parking_lot_cfg, parkext));
1287 aco_option_register(&cfg_info, "context", ACO_EXACT, parking_lot_types, "parkedcalls", OPT_STRINGFIELD_T, 0, STRFLDSET(struct parking_lot_cfg, parking_con));
1288 aco_option_register(&cfg_info, "parkingtime", ACO_EXACT, parking_lot_types, "45", OPT_UINT_T, 0, FLDSET(struct parking_lot_cfg, parkingtime));
1289 aco_option_register(&cfg_info, "comebacktoorigin", ACO_EXACT, parking_lot_types, "yes", OPT_BOOL_T, 1, FLDSET(struct parking_lot_cfg, comebacktoorigin));
1290 aco_option_register(&cfg_info, "comebackcontext", ACO_EXACT, parking_lot_types, "parkedcallstimeout", OPT_STRINGFIELD_T, 0, STRFLDSET(struct parking_lot_cfg, comebackcontext));
1291 aco_option_register(&cfg_info, "comebackdialtime", ACO_EXACT, parking_lot_types, "30", OPT_UINT_T, 0, FLDSET(struct parking_lot_cfg, comebackdialtime));
1292 aco_option_register(&cfg_info, "parkedmusicclass", ACO_EXACT, parking_lot_types, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct parking_lot_cfg, mohclass));
1293 aco_option_register(&cfg_info, "parkext_exclusive", ACO_EXACT, parking_lot_types, "no", OPT_BOOL_T, 1, FLDSET(struct parking_lot_cfg, parkext_exclusive));
1294 aco_option_register(&cfg_info, "parkinghints", ACO_EXACT, parking_lot_types, "no", OPT_BOOL_T, 1, FLDSET(struct parking_lot_cfg, parkaddhints));
1295 aco_option_register(&cfg_info, "courtesytone", ACO_EXACT, parking_lot_types, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct parking_lot_cfg, courtesytone));
1296
1297 /* More complicated parking lot options that require special handling */
1305
1306 if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
1307 goto error;
1308 }
1309
1311 goto error;
1312 }
1313
1314 if (load_parking_ui()) {
1315 goto error;
1316 }
1317
1318 if (load_parking_manager()) {
1319 goto error;
1320 }
1321
1323 goto error;
1324 }
1325
1326 if (load_parking_devstate()) {
1327 goto error;
1328 }
1329
1330 if (load_parking_tests()) {
1331 goto error;
1332 }
1333
1335
1336error:
1337 unload_module();
1339}
1340
1341static int reload_module(void)
1342{
1343 if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
1345 }
1346
1347 return 0;
1348}
1349
1351 .support_level = AST_MODULE_SUPPORT_CORE,
1352 .load = load_module,
1353 .unload = unload_module,
1355 .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
#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
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#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_RWLOCK
Definition: astobj2.h:365
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
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_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#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
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#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
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#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_REJECT
Reject objects with duplicate keys in container.
Definition: astobj2.h:1188
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
Definition: bridge.c:1009
static int priority
static struct console_pvt globals
#define ast_channel_lock(chan)
Definition: channel.h:2970
const char * ast_channel_parkinglot(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2971
#define AST_MAX_EXTENSION
Definition: channel.h:134
Standard Command Line Interface.
Configuration option-handling.
@ 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.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
#define ACO_FILES(...)
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
unsigned int aco_option_get_flags(const struct aco_option *option)
Read the flags of a config option - useful when using a custom callback for a config option.
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
@ ACO_ITEM
@ ACO_GLOBAL
@ ACO_WHITELIST_EXACT
@ ACO_BLACKLIST_EXACT
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.
@ E_MATCH
Definition: extconf.h:217
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
@ AST_FEATURE_FLAG_BYBOTH
Definition: features.h:39
@ AST_FEATURE_FLAG_BYCALLER
Definition: features.h:38
@ AST_FEATURE_FLAG_BYCALLEE
Definition: features.h:37
static const char name[]
Definition: format_mp3.c:68
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:980
Configuration File Parser.
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define AST_LOG_NOTICE
#define LOG_NOTICE
#define LOG_WARNING
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_DEVSTATE_PROVIDER
Definition: module.h:343
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define PARK_APPLICATION
The default parking application that Asterisk expects.
Definition: parking.h:35
void unload_parking_applications(void)
Unregister parking applications.
int load_parking_applications(void)
Register parking applications.
void unload_parking_bridge_features(void)
Unregister features registered by load_parking_bridge_features.
int load_parking_bridge_features(void)
Register bridge features for parking.
int load_parking_devstate(void)
Register Parking devstate handler.
void unload_parking_devstate(void)
Unregister Parking devstate handler.
int load_parking_manager(void)
Register manager actions and setup subscriptions for stasis events.
void unload_parking_manager(void)
Unregister manager actions and remove subscriptions for stasis events.
void unload_parking_tests(void)
Unregister parking unit tests.
int load_parking_tests(void)
Register parking unit tests.
void unload_parking_ui(void)
Unregister CLI commands.
Definition: parking_ui.c:203
int load_parking_ui(void)
Register CLI commands.
Definition: parking_ui.c:198
Core PBX routines and definitions.
int ast_wrlock_contexts(void)
Write locks the context list.
Definition: pbx.c:8478
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
Definition: pbx.c:8496
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8572
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition: pbx.c:6164
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8506
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
struct ast_context * ast_get_extension_context(struct ast_exten *exten)
Definition: pbx.c:8519
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
Definition: pbx.c:8236
#define PRIORITY_HINT
Definition: pbx.h:54
int ast_add_extension2_nolock(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, const char *registrar_file, int registrar_line)
Same as ast_add_extension2, but assumes you have already locked context.
Definition: pbx.c:7281
struct ast_exten * pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
Definition: ael_main.c:152
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8488
const char * ast_get_extension_name(struct ast_exten *exten)
Definition: pbx.c:8524
const char * ast_get_extension_registrar(struct ast_exten *e)
Definition: pbx.c:8547
static char * registrar
Definition: pbx_ael.c:81
static int reload(void)
struct ao2_container * container
Definition: res_fax.c:531
void parking_lot_cfg_remove_extensions(struct parking_lot_cfg *lot_cfg)
Remove extensions belonging to a parking lot configuration.
Definition: res_parking.c:724
static int option_handler_parkedfeature(const struct aco_option *opt, struct ast_variable *var, void *obj)
Custom field handler for feature mapping on parked call pickup options.
Definition: res_parking.c:625
struct aco_type * global_options[]
Definition: res_parking.c:353
static int parking_add_extension(struct ast_context *context, int replace, const char *extension, int priority, const char *application, const char *data, const char *registrar)
Definition: res_parking.c:774
struct ao2_container * get_parking_lot_container(void)
Get a pointer to the parking lot container for purposes such as iteration.
Definition: res_parking.c:657
struct aco_type * parking_lot_types[]
Definition: res_parking.c:365
static int verify_default_parking_lot(void)
Definition: res_parking.c:1132
static int option_handler_findslot(const struct aco_option *opt, struct ast_variable *var, void *obj)
Custom field handler for the findslot option.
Definition: res_parking.c:586
static struct parking_lot * create_dynamic_lot_full(const char *name, struct ast_channel *chan, int forced)
Definition: res_parking.c:1031
static void link_configured_disable_marked_lots(void)
Definition: res_parking.c:1245
static int option_handler_parkpos(const struct aco_option *opt, struct ast_variable *var, void *obj)
Custom field handler for parking positions.
Definition: res_parking.c:565
static void parking_config_destructor(void *obj)
destructor for parking_config
Definition: res_parking.c:423
static int parking_lot_sort_fn(const void *obj_left, const void *obj_right, int flags)
Definition: res_parking.c:304
static struct aco_type parking_lot_type
Definition: res_parking.c:355
static AO2_GLOBAL_OBJ_STATIC(globals)
static int parked_user_cmp_fn(void *obj, void *arg, int flags)
Definition: res_parking.c:495
static void disable_marked_lots(void)
Definition: res_parking.c:1231
static struct parking_lot * alloc_new_parking_lot(struct parking_lot_cfg *lot_cfg)
Definition: res_parking.c:698
static int reload_module(void)
Definition: res_parking.c:1341
static void remove_all_configured_parking_lot_extensions(void)
Definition: res_parking.c:739
static void * parking_lot_cfg_alloc(const char *cat)
create a parking lot structure
Definition: res_parking.c:521
struct aco_file parking_lot_conf
Definition: res_parking.c:367
static struct parking_lot_cfg * clone_parkinglot_cfg(struct parking_lot_cfg *source, const char *name)
Definition: res_parking.c:1000
struct parking_lot * parking_create_dynamic_lot(const char *name, struct ast_channel *chan)
Create a dynamic parking lot.
Definition: res_parking.c:1120
static int parked_user_sort_fn(const void *obj_left, const void *obj_right, int flags)
Definition: res_parking.c:507
static void mark_lots_as_disabled(void)
Definition: res_parking.c:1204
const char * find_channel_parking_lot_name(struct ast_channel *chan)
Find parking lot name from channel.
Definition: res_parking.c:668
static void parking_global_config_destructor(void *obj)
destructor for parking_global_config
Definition: res_parking.c:431
static struct ao2_container * parking_lot_container
Definition: res_parking.c:326
struct parking_lot * parking_lot_build_or_update(struct parking_lot_cfg *lot_cfg, int dynamic)
If a parking lot exists in the parking lot list already, update its status to match the provided conf...
Definition: res_parking.c:929
static int load_module(void)
Definition: res_parking.c:1268
struct parking_lot * parking_lot_find_by_name(const char *lot_name)
Find a parking lot based on its name.
Definition: res_parking.c:662
static int config_parking_preapply(void)
Definition: res_parking.c:1216
int parking_dynamic_lots_enabled(void)
Check global configuration to see if dynamic parking is enabled.
Definition: res_parking.c:989
static int parking_feature_flag_cfg(int *param, const char *var)
Maps string values for option_handler_parkedfeature to their ENUM values.
Definition: res_parking.c:605
static int configure_parking_extensions(void)
Definition: res_parking.c:1171
static int unload_module(void)
Definition: res_parking.c:1251
static void parking_lot_destructor(void *obj)
Definition: res_parking.c:686
static void parking_lot_cfg_destructor(void *obj)
Destroy a parking lot cfg object.
Definition: res_parking.c:487
static void * parking_config_alloc(void)
allocator callback for parking_config. Notice it returns void * since it is only used by the backend ...
Definition: res_parking.c:437
int parking_lot_remove_if_unused(struct parking_lot *lot)
Remove a parking lot from the usable lists if it is no longer involved in any calls and no configurat...
Definition: res_parking.c:460
static int parking_lot_cfg_cmp_fn(void *obj, void *arg, const int flags)
Definition: res_parking.c:398
static struct aco_type global_option
Definition: res_parking.c:345
static int extension_is_compatible(struct parking_lot_cfg *lot_cfg, const char *app_type, struct ast_exten *extension)
Definition: res_parking.c:791
static void * named_item_find(struct ao2_container *container, const char *name)
find an item in a container by its name
Definition: res_parking.c:557
static void parking_lot_disable(struct parking_lot *lot)
Definition: res_parking.c:474
static void remove_pending_parking_lot_extensions(struct parking_config *cfg_pending)
Definition: res_parking.c:1156
static int parking_lot_cfg_hash_fn(const void *obj, const int flags)
Definition: res_parking.c:380
static void generate_or_link_lots_to_configs(void)
Definition: res_parking.c:976
int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg)
Add extensions for a parking lot configuration.
Definition: res_parking.c:819
CONFIG_INFO_STANDARD(cfg_info, globals, parking_config_alloc,.files=ACO_FILES(&parking_lot_conf),.pre_apply_config=config_parking_preapply,.post_apply_config=link_configured_disable_marked_lots,)
Call Parking Resource Internal API.
#define BASE_REGISTRAR
Definition: res_parking.h:36
@ PARKINGLOT_DISABLED
Definition: res_parking.h:61
@ PARKINGLOT_NORMAL
Definition: res_parking.h:57
@ PARKINGLOT_DYNAMIC
Definition: res_parking.h:59
parked_call_feature_options
Definition: res_parking.h:48
@ OPT_PARKEDREPARKING
Definition: res_parking.h:51
@ OPT_PARKEDTRANSFERS
Definition: res_parking.h:50
@ OPT_PARKEDPLAY
Definition: res_parking.h:49
@ OPT_PARKEDRECORDING
Definition: res_parking.h:53
@ OPT_PARKEDHANGUP
Definition: res_parking.h:52
#define PARKED_CALL_APPLICATION
Definition: res_parking.h:38
#define DEFAULT_PARKING_EXTEN
Definition: res_parking.h:35
#define DEFAULT_PARKING_LOT
Definition: res_parking.h:34
#define NULL
Definition: resample.c:96
#define ast_string_fields_copy(copy, orig)
Copy all string fields from one instance to another of the same structure.
Definition: stringfields.h:630
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:555
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2216
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
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
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Main Channel structure associated with a channel.
ast_context: An extension context
Definition: pbx.c:299
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
Definition: pbx.c:252
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
structure to hold extensions
int parking_space
Definition: res_parking.h:109
struct ao2_container * parking_lots
Definition: res_parking.c:342
struct parking_global_config * global
Definition: res_parking.c:341
int parkedcalltransfers
Definition: res_parking.h:76
int parkedcallreparking
Definition: res_parking.h:77
unsigned int comebacktoorigin
Definition: res_parking.h:74
unsigned int parkingtime
Definition: res_parking.h:69
unsigned int parkfindnext
Definition: res_parking.h:71
unsigned int parkext_exclusive
Definition: res_parking.h:72
const ast_string_field registrar
Definition: res_parking.h:89
const ast_string_field parkext
Definition: res_parking.h:89
unsigned int parkaddhints
Definition: res_parking.h:73
const ast_string_field name
Definition: res_parking.h:89
unsigned int comebackdialtime
Definition: res_parking.h:70
const ast_string_field parking_con
Definition: res_parking.h:89
int parkedcallrecording
Definition: res_parking.h:79
enum parking_lot_modes mode
Definition: res_parking.h:97
struct ast_bridge * parking_bridge
Definition: res_parking.h:94
struct parking_lot_cfg * cfg
Definition: res_parking.h:96
int disable_mark
Definition: res_parking.h:98
const ast_string_field name
Definition: res_parking.h:102
struct ao2_container * parked_users
Definition: res_parking.h:95
int stacklen
Definition: extconf.h:237
structure to hold users read from users.conf
static struct aco_type global
Definition: test_config.c:1445
int error(const char *format,...)
Definition: utils/frame.c:999
Utility functions.
#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:941
#define ast_assert(a)
Definition: utils.h:739