Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Functions
parking_controller.c File Reference

Parking Entry, Exit, and other assorted controls. More...

#include "asterisk.h"
#include "asterisk/logger.h"
#include "res_parking.h"
#include "asterisk/astobj2.h"
#include "asterisk/utils.h"
#include "asterisk/manager.h"
#include "asterisk/test.h"
#include "asterisk/features.h"
#include "asterisk/bridge_basic.h"
Include dependency graph for parking_controller.c:

Go to the source code of this file.

Data Structures

struct  parking_limits_pvt
 

Functions

int comeback_goto (struct parked_user *pu, struct parking_lot *lot)
 Set a channel's position in the PBX after timeout using the parking lot settings. More...
 
void flatten_dial_string (char *dialstring)
 Flattens a dial string so that it can be written to/found from PBX extensions. More...
 
void parked_call_retrieve_enable_features (struct ast_channel *chan, struct parking_lot *lot, int recipient_mode)
 Apply features based on the parking lot feature options. More...
 
int parking_channel_set_roles (struct ast_channel *chan, struct parking_lot *lot, int force_ringing)
 Set necessary bridge roles on a channel that is about to enter a parking lot. More...
 
struct ast_bridgeparking_lot_get_bridge (struct parking_lot *lot)
 Get a reference to a parking lot's bridge. If it doesn't exist, create it and get a reference. More...
 
int parking_lot_get_space (struct parking_lot *lot, int target_override)
 Get an available parking space within a parking lot. More...
 
struct parked_userparking_lot_inspect_parked_user (struct parking_lot *lot, int target)
 Determine if there is a parked user in a parking space and return it if there is. More...
 
struct parked_userparking_lot_retrieve_parked_user (struct parking_lot *lot, int target)
 Determine if there is a parked user in a parking space and pull it from the parking lot if there is. More...
 
static int retrieve_parked_user_targeted (void *obj, void *arg, int flags)
 
int unpark_parked_user (struct parked_user *pu)
 Pull a parked user out of its parking lot. Use this when you don't want to use the parked user afterwards. More...
 

Detailed Description

Parking Entry, Exit, and other assorted controls.

Author
Jonathan Rose jrose.nosp@m.@dig.nosp@m.ium.c.nosp@m.om

Definition in file parking_controller.c.

Function Documentation

◆ comeback_goto()

int comeback_goto ( struct parked_user pu,
struct parking_lot lot 
)

Set a channel's position in the PBX after timeout using the parking lot settings.

Since
12.0.0
Parameters
puParked user who is entering/reentering the PBX
lotParking lot the user was removed from.
Return values
0Position set successfully
-1Failed to set the position

Definition at line 261 of file parking_controller.c.

References ast_async_goto(), ast_channel_name(), ast_exists_extension(), ast_log, ast_strdupa, ast_verb, parking_lot::cfg, parked_user::chan, parking_lot_cfg::comebackcontext, parking_lot_cfg::comebacktoorigin, flatten_dial_string(), LOG_ERROR, NULL, PARK_DIAL_CONTEXT, and parked_user::parker_dial_string.

Referenced by parking_duration_callback().

262 {
263  struct ast_channel *chan = pu->chan;
264  char *peername_flat = ast_strdupa(pu->parker_dial_string);
265 
266  /* Flatten the peername so that it can be used for performing the timeout PBX operations */
267  flatten_dial_string(peername_flat);
268 
269  if (lot->cfg->comebacktoorigin) {
270  if (ast_exists_extension(chan, PARK_DIAL_CONTEXT, peername_flat, 1, NULL)) {
271  ast_async_goto(chan, PARK_DIAL_CONTEXT, peername_flat, 1);
272  return 0;
273  } else {
274  ast_log(LOG_ERROR, "Can not start %s at %s,%s,1 because extension does not exist. Terminating call.\n",
275  ast_channel_name(chan), PARK_DIAL_CONTEXT, peername_flat);
276  return -1;
277  }
278  }
279 
280  if (ast_exists_extension(chan, lot->cfg->comebackcontext, peername_flat, 1, NULL)) {
281  ast_async_goto(chan, lot->cfg->comebackcontext, peername_flat, 1);
282  return 0;
283  }
284 
285  if (ast_exists_extension(chan, lot->cfg->comebackcontext, "s", 1, NULL)) {
286  ast_verb(2, "Could not start %s at %s,%s,1. Using 's@%s' instead.\n", ast_channel_name(chan),
287  lot->cfg->comebackcontext, peername_flat, lot->cfg->comebackcontext);
288  ast_async_goto(chan, lot->cfg->comebackcontext, "s", 1);
289  return 0;
290  }
291 
292  ast_verb(2, "Can not start %s at %s,%s,1 and exten 's@%s' does not exist. Using 's@default'\n",
293  ast_channel_name(chan),
294  lot->cfg->comebackcontext, peername_flat, lot->cfg->comebackcontext);
295  ast_async_goto(chan, "default", "s", 1);
296 
297  return 0;
298 }
Main Channel structure associated with a channel.
#define PARK_DIAL_CONTEXT
Definition: res_parking.h:37
const ast_string_field comebackcontext
Definition: res_parking.h:89
void flatten_dial_string(char *dialstring)
Flattens a dial string so that it can be written to/found from PBX extensions.
#define NULL
Definition: resample.c:96
#define ast_verb(level,...)
Definition: logger.h:463
#define ast_log
Definition: astobj2.c:42
char * parker_dial_string
Definition: res_parking.h:109
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4179
unsigned int comebacktoorigin
Definition: res_parking.h:74
#define LOG_ERROR
Definition: logger.h:285
const char * ast_channel_name(const struct ast_channel *chan)
int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Set the channel to next execute the specified dialplan location.
Definition: pbx.c:7011
struct ast_channel * chan
Definition: res_parking.h:104
struct parking_lot_cfg * cfg
Definition: res_parking.h:96

◆ flatten_dial_string()

void flatten_dial_string ( char *  dialstring)

Flattens a dial string so that it can be written to/found from PBX extensions.

Since
12.0.0
Parameters
peernameunflattened dial string. This will be flattened in place.

Definition at line 249 of file parking_controller.c.

Referenced by comeback_goto(), and parking_duration_callback().

250 {
251  int i;
252 
253  for (i = 0; dialstring[i]; i++) {
254  if (dialstring[i] == '/') {
255  /* The underscore is the flattest character of all. */
256  dialstring[i] = '_';
257  }
258  }
259 }

◆ parked_call_retrieve_enable_features()

void parked_call_retrieve_enable_features ( struct ast_channel chan,
struct parking_lot lot,
int  recipient_mode 
)

Apply features based on the parking lot feature options.

Since
12.0.0
Parameters
chanWhich channel's feature set is being modified
lotparking lot which establishes the features used
recipient_modeAST_FEATURE_FLAG_BYCALLER if the user is the retriever AST_FEATURE_FLAG_BYCALLEE if the user is the parkee

Definition at line 215 of file parking_controller.c.

References ast_bridge_features_ds_get(), ast_bridge_features_ds_set(), ast_channel_lock, ast_channel_unlock, AST_FEATURE_AUTOMIXMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_set_flag, parking_lot::cfg, parking_lot_cfg::parkedcallhangup, parking_lot_cfg::parkedcallrecording, parking_lot_cfg::parkedcallreparking, and parking_lot_cfg::parkedcalltransfers.

Referenced by bridge_parking_pull(), and parked_call_app_exec().

216 {
217  /* Enabling features here should be additive to features that are already on the channel. */
218  struct ast_flags feature_flags = { 0 };
219  struct ast_flags *existing_features;
220 
221  ast_channel_lock(chan);
222  existing_features = ast_bridge_features_ds_get(chan);
223  if (existing_features) {
224  feature_flags = *existing_features;
225  }
226 
227  if (lot->cfg->parkedcalltransfers & recipient_mode) {
228  ast_set_flag(&feature_flags, AST_FEATURE_REDIRECT);
229  }
230 
231  if (lot->cfg->parkedcallreparking & recipient_mode) {
232  ast_set_flag(&feature_flags, AST_FEATURE_PARKCALL);
233  }
234 
235  if (lot->cfg->parkedcallhangup & recipient_mode) {
236  ast_set_flag(&feature_flags, AST_FEATURE_DISCONNECT);
237  }
238 
239  if (lot->cfg->parkedcallrecording & recipient_mode) {
240  ast_set_flag(&feature_flags, AST_FEATURE_AUTOMIXMON);
241  }
242 
243  ast_bridge_features_ds_set(chan, &feature_flags);
244  ast_channel_unlock(chan);
245 
246  return;
247 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
int parkedcallreparking
Definition: res_parking.h:77
#define ast_set_flag(p, flag)
Definition: utils.h:70
int ast_bridge_features_ds_set(struct ast_channel *chan, struct ast_flags *flags)
Set basic bridge DTMF feature flags datastore on the channel.
Definition: bridge_basic.c:258
struct ast_flags * ast_bridge_features_ds_get(struct ast_channel *chan)
Get DTMF feature flags from the channel.
Definition: bridge_basic.c:268
#define ast_channel_unlock(chan)
Definition: channel.h:2946
Structure used to handle boolean flags.
Definition: utils.h:199
int parkedcalltransfers
Definition: res_parking.h:76
int parkedcallrecording
Definition: res_parking.h:79
struct parking_lot_cfg * cfg
Definition: res_parking.h:96

◆ parking_channel_set_roles()

int parking_channel_set_roles ( struct ast_channel chan,
struct parking_lot lot,
int  force_ringing 
)

Set necessary bridge roles on a channel that is about to enter a parking lot.

Since
12.0.0
Parameters
chanEntering channel
lotThe parking lot the channel will be entering
force_ringingUse ringing instead of music on hold
Return values
0on success
non-zeroon failure

Definition at line 57 of file parking_controller.c.

References ast_channel_add_bridge_role(), ast_channel_set_bridge_role_option(), ast_strlen_zero, parking_lot::cfg, and parking_lot_cfg::mohclass.

Referenced by bridge_parking_push(), and park_common_setup().

58 {
59  if (ast_channel_add_bridge_role(chan, "holding_participant")) {
60  return -1;
61  }
62 
63  if (force_ringing) {
64  if (ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "ringing")) {
65  return -1;
66  }
67  } else {
68  if (ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "musiconhold")) {
69  return -1;
70  }
71  if (!ast_strlen_zero(lot->cfg->mohclass)) {
72  if (ast_channel_set_bridge_role_option(chan, "holding_participant", "moh_class", lot->cfg->mohclass)) {
73  return -1;
74  }
75  }
76  }
77 
78  return 0;
79 }
int ast_channel_add_bridge_role(struct ast_channel *chan, const char *role_name)
Adds a bridge role to a channel.
Definition: bridge_roles.c:317
#define ast_strlen_zero(foo)
Definition: strings.h:52
int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char *role_name, const char *option, const char *value)
Set a role option on a channel.
Definition: bridge_roles.c:379
const ast_string_field mohclass
Definition: res_parking.h:89
struct parking_lot_cfg * cfg
Definition: res_parking.h:96

◆ parking_lot_get_bridge()

struct ast_bridge* parking_lot_get_bridge ( struct parking_lot lot)

Get a reference to a parking lot's bridge. If it doesn't exist, create it and get a reference.

Since
12.0.0
Parameters
lotWhich parking lot we need the bridge from. This parking lot must be locked before calling this function.
Return values
Areference to the ast_bridge associated with the parking lot
NULLif it didn't already have a bridge and one couldn't be created
Note
This bridge will need to be unreffed if it ever falls out of scope.

Definition at line 36 of file parking_controller.c.

References ao2_ref, bridge_parking_new(), NULL, and parking_lot::parking_bridge.

Referenced by park_common_setup().

37 {
38  struct ast_bridge *lot_bridge;
39 
40  if (lot->parking_bridge) {
41  ao2_ref(lot->parking_bridge, +1);
42  return lot->parking_bridge;
43  }
44 
45  lot_bridge = bridge_parking_new(lot);
46  if (!lot_bridge) {
47  return NULL;
48  }
49 
50  /* The parking lot needs a reference to the bridge as well. */
51  lot->parking_bridge = lot_bridge;
52  ao2_ref(lot->parking_bridge, +1);
53 
54  return lot_bridge;
55 }
struct ast_bridge * parking_bridge
Definition: res_parking.h:94
#define NULL
Definition: resample.c:96
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Structure that contains information about a bridge.
Definition: bridge.h:357
struct ast_bridge * bridge_parking_new(struct parking_lot *bridge_lot)
Create a new parking bridge.

◆ parking_lot_get_space()

int parking_lot_get_space ( struct parking_lot lot,
int  target_override 
)

Get an available parking space within a parking lot.

Since
12.0.0
Parameters
lotWhich parking lot we are getting a space from
target_overrideIf there is a specific slot we want, provide it here and we'll start from that position
Return values
-1if No slot can be found
integervalue of parking space selected
Note
lot should be locked before this is called and unlocked only after a parked_user with the space returned has been added to the parking lot.

Definition at line 96 of file parking_controller.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, parking_lot::cfg, parking_lot::next_space, parking_lot::parked_users, parking_lot_cfg::parkfindnext, parked_user::parking_space, parking_lot_cfg::parking_start, and parking_limits_pvt::user.

Referenced by generate_parked_user().

97 {
98  int original_target;
99  int current_target;
100  struct ao2_iterator i;
101  struct parked_user *user;
102  int wrap;
103 
104  if (lot->cfg->parkfindnext) {
105  /* Use next_space if the lot already has next_space set; otherwise use lot start. */
106  original_target = lot->next_space ? lot->next_space : lot->cfg->parking_start;
107  } else {
108  original_target = lot->cfg->parking_start;
109  }
110 
111  if (target_override >= lot->cfg->parking_start && target_override <= lot->cfg->parking_stop) {
112  original_target = target_override;
113  }
114 
115  current_target = original_target;
116 
117  wrap = lot->cfg->parking_start;
118 
119  i = ao2_iterator_init(lot->parked_users, 0);
120  while ((user = ao2_iterator_next(&i))) {
121  /* Increment the wrap on each pass until we find an empty space */
122  if (wrap == user->parking_space) {
123  wrap += 1;
124  }
125 
126  if (user->parking_space < current_target) {
127  /* It's lower than the anticipated target, so we haven't reached the target yet. */
128  ao2_ref(user, -1);
129  continue;
130  }
131 
132  if (user->parking_space > current_target) {
133  /* The current target is usable because all items below have been read and the next target is higher than the one we want. */
134  ao2_ref(user, -1);
135  break;
136  }
137 
138  /* We found one already parked here. */
139  current_target += 1;
140  ao2_ref(user, -1);
141  }
143 
144  if (current_target <= lot->cfg->parking_stop) {
145  return current_target;
146  }
147 
148  if (wrap <= lot->cfg->parking_stop) {
149  return wrap;
150  }
151 
152  return -1;
153 }
static char user[512]
struct ao2_container * parked_users
Definition: res_parking.h:95
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int next_space
Definition: res_parking.h:93
int parking_space
Definition: res_parking.h:107
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
unsigned int parkfindnext
Definition: res_parking.h:71
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
struct parking_lot_cfg * cfg
Definition: res_parking.h:96

◆ parking_lot_inspect_parked_user()

struct parked_user* parking_lot_inspect_parked_user ( struct parking_lot lot,
int  target 
)

Determine if there is a parked user in a parking space and return it if there is.

Parameters
lotParking lot being pulled from
targetIf < 0 search for the first occupied space in the parking lot If >= 0 Only pull from the indicated target
Return values
NULLif no parked user could be pulled from the requested parking lot at the requested parking space
referenceto the requested parked user

Definition at line 166 of file parking_controller.c.

References ao2_callback, NULL, parking_lot::parked_users, retrieve_parked_user_targeted(), and parking_limits_pvt::user.

Referenced by func_get_parkingslot_channel().

167 {
168  struct parked_user *user;
169 
170  if (target < 0) {
171  user = ao2_callback(lot->parked_users, 0, NULL, NULL);
172  } else {
173  user = ao2_callback(lot->parked_users, 0, retrieve_parked_user_targeted, &target);
174  }
175 
176  if (!user) {
177  return NULL;
178  }
179 
180  return user;
181 }
static char user[512]
struct ao2_container * parked_users
Definition: res_parking.h:95
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
#define NULL
Definition: resample.c:96
static int retrieve_parked_user_targeted(void *obj, void *arg, int flags)

◆ parking_lot_retrieve_parked_user()

struct parked_user* parking_lot_retrieve_parked_user ( struct parking_lot lot,
int  target 
)

Determine if there is a parked user in a parking space and pull it from the parking lot if there is.

Since
12.0.0
Parameters
lotParking lot being pulled from
targetIf < 0 search for the first occupied space in the parking lot If >= 0 Only pull from the indicated target
Return values
NULLif no parked user could be pulled from the requested parking lot at the requested parking space
referenceto the requested parked user
Note
The parked user will be removed from parking lot as part of this process
Remove this reference with ao2_cleanup once it falls out of scope.

Definition at line 183 of file parking_controller.c.

References ao2_callback, ao2_cleanup, ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, NULL, PARK_ANSWERED, PARK_UNSET, parking_lot::parked_users, parking_lot_remove_if_unused(), RAII_VAR, retrieve_parked_user_targeted(), and parking_limits_pvt::user.

Referenced by AST_TEST_DEFINE(), and parked_call_app_exec().

184 {
186 
187  if (target < 0) {
188  user = ao2_callback(lot->parked_users, 0, NULL, NULL);
189  } else {
191  }
192 
193  if (!user) {
194  return NULL;
195  }
196 
197  ao2_lock(user);
198  if (user->resolution != PARK_UNSET) {
199  /* Abandon. Something else has resolved the parked user before we got to it. */
200  ao2_unlock(user);
201  return NULL;
202  }
203 
205  user->resolution = PARK_ANSWERED;
206  ao2_unlock(user);
207 
209 
210  /* Bump the ref count by 1 since the RAII_VAR will eat the reference otherwise */
211  ao2_ref(user, +1);
212  return user;
213 }
static char user[512]
struct ao2_container * parked_users
Definition: res_parking.h:95
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#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:911
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:400
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
static int retrieve_parked_user_targeted(void *obj, void *arg, int flags)
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
structure to hold users read from users.conf
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ retrieve_parked_user_targeted()

static int retrieve_parked_user_targeted ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 155 of file parking_controller.c.

References CMP_MATCH, and parked_user::parking_space.

Referenced by parking_lot_inspect_parked_user(), and parking_lot_retrieve_parked_user().

156 {
157  int *target = arg;
158  struct parked_user *user = obj;
159  if (user->parking_space == *target) {
160  return CMP_MATCH;
161  }
162 
163  return 0;
164 }
int parking_space
Definition: res_parking.h:107
structure to hold users read from users.conf

◆ unpark_parked_user()

int unpark_parked_user ( struct parked_user user)

Pull a parked user out of its parking lot. Use this when you don't want to use the parked user afterwards.

Since
12.0.0
Parameters
userThe parked user being pulled.
Return values
0on success
-1if the user didn't have its parking lot set

Definition at line 85 of file parking_controller.c.

References ao2_unlink, parked_user::lot, parking_lot::parked_users, and parking_lot_remove_if_unused().

Referenced by bridge_parking_pull().

86 {
87  if (pu->lot) {
88  ao2_unlink(pu->lot->parked_users, pu);
90  return 0;
91  }
92 
93  return -1;
94 }
struct ao2_container * parked_users
Definition: res_parking.h:95
struct parking_lot * lot
Definition: res_parking.h:111
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:400
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598