res_parking: Apply ringing role option on swap with a channel that rings
[asterisk/asterisk.git] / res / parking / parking_bridge.c
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 Parking Bridge Class
22  *
23  * \author Jonathan Rose <jrose@digium.com>
24  */
25
26 #include "asterisk.h"
27 #include "asterisk/logger.h"
28 #include "res_parking.h"
29 #include "asterisk/astobj2.h"
30 #include "asterisk/features.h"
31 #include "asterisk/say.h"
32 #include "asterisk/term.h"
33
34 struct ast_bridge_parking
35 {
36         struct ast_bridge base;
37
38         /* private stuff for parking */
39         struct parking_lot *lot;
40 };
41
42 /*!
43  * \internal
44  * \brief ast_bridge parking class destructor
45  * \since 12.0.0
46  *
47  * \param self Bridge to operate upon.
48  *
49  * \note XXX Stub... and it might go unused.
50  *
51  * \return Nothing
52  */
53 static void bridge_parking_destroy(struct ast_bridge_parking *self)
54 {
55         ast_bridge_base_v_table.destroy(&self->base);
56 }
57
58 static void bridge_parking_dissolving(struct ast_bridge_parking *self)
59 {
60         self->lot = NULL;
61         ast_bridge_base_v_table.dissolving(&self->base);
62 }
63
64 static void destroy_parked_user(void *obj)
65 {
66         struct parked_user *pu = obj;
67
68         ao2_cleanup(pu->lot);
69         ao2_cleanup(pu->retriever);
70         ast_free(pu->parker_dial_string);
71 }
72
73 /* Only call this on a parked user that hasn't had its parker_dial_string set already */
74 static int parked_user_set_parker_dial_string(struct parked_user *pu, struct ast_channel *parker)
75 {
76         char *dial_string = ast_strdupa(ast_channel_name(parker));
77
78         ast_channel_name_to_dial_string(dial_string);
79         pu->parker_dial_string = ast_strdup(dial_string);
80
81         if (!pu->parker_dial_string) {
82                 return -1;
83         }
84
85         return 0;
86 }
87
88 /*!
89  * \internal
90  * \since 12
91  * \brief Construct a parked_user struct assigned to the specified parking lot
92  *
93  * \param lot The parking lot we are assigning the user to
94  * \param parkee The channel being parked
95  * \param parker The channel performing the park operation (may be the same channel)
96  * \param parker_dial_string Takes priority over parker for setting the parker dial string if included
97  * \param use_random_space if true, prioritize using a random parking space instead
98  *        of ${PARKINGEXTEN} and/or automatic assignment from the parking lot
99  * \param time_limit If using a custom timeout, this should be supplied so that the
100  *        parked_user struct can provide this information for manager events. If <0,
101  *        use the parking lot limit instead.
102  *
103  * \retval NULL on failure
104  * \retval reference to the parked user
105  *
106  * \note ao2_cleanup this reference when you are done using it or you'll cause leaks.
107  */
108 static struct parked_user *generate_parked_user(struct parking_lot *lot, struct ast_channel *chan, struct ast_channel *parker, const char *parker_dial_string, int use_random_space, int time_limit)
109 {
110         struct parked_user *new_parked_user;
111         int preferred_space = -1; /* Initialize to use parking lot defaults */
112         int parking_space;
113         const char *parkingexten;
114
115         if (lot->mode == PARKINGLOT_DISABLED) {
116                 ast_log(LOG_NOTICE, "Tried to park in a parking lot that is no longer able to be parked to.\n");
117                 return NULL;
118         }
119
120         new_parked_user = ao2_alloc(sizeof(*new_parked_user), destroy_parked_user);
121         if (!new_parked_user) {
122                 return NULL;
123         }
124
125         if (use_random_space) {
126                 preferred_space = ast_random() % (lot->cfg->parking_stop - lot->cfg->parking_start + 1);
127                 preferred_space += lot->cfg->parking_start;
128         } else {
129                 ast_channel_lock(chan);
130                 if ((parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"))) {
131                         parkingexten = ast_strdupa(parkingexten);
132                 }
133                 ast_channel_unlock(chan);
134
135                 if (!ast_strlen_zero(parkingexten)) {
136                         if (sscanf(parkingexten, "%30d", &preferred_space) != 1 || preferred_space <= 0) {
137                                 ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n", parkingexten);
138                                 ao2_ref(new_parked_user, -1);
139                                 return NULL;
140                         }
141                 }
142         }
143
144         /* We need to keep the lot locked between parking_lot_get_space and actually placing it in the lot. Or until we decide not to. */
145         ao2_lock(lot);
146
147         parking_space = parking_lot_get_space(lot, preferred_space);
148         if (parking_space == -1) {
149                 ast_log(LOG_NOTICE, "Failed to get parking space in lot '%s'. All full.\n", lot->name);
150                 ao2_ref(new_parked_user, -1);
151                 ao2_unlock(lot);
152                 return NULL;
153         }
154
155         lot->next_space = ((parking_space + 1) - lot->cfg->parking_start) % (lot->cfg->parking_stop - lot->cfg->parking_start + 1) + lot->cfg->parking_start;
156         new_parked_user->chan = chan;
157         new_parked_user->parking_space = parking_space;
158
159         /* Have the parked user take a reference to the parking lot. This reference should be immutable and released at destruction */
160         new_parked_user->lot = lot;
161         ao2_ref(lot, +1);
162
163         new_parked_user->start = ast_tvnow();
164         new_parked_user->time_limit = (time_limit >= 0) ? time_limit : lot->cfg->parkingtime;
165
166         if (parker_dial_string) {
167                 new_parked_user->parker_dial_string = ast_strdup(parker_dial_string);
168         } else {
169                 if (parked_user_set_parker_dial_string(new_parked_user, parker)) {
170                         ao2_ref(new_parked_user, -1);
171                         ao2_unlock(lot);
172                         return NULL;
173                 }
174         }
175
176         if (!new_parked_user->parker_dial_string) {
177                 ao2_ref(new_parked_user, -1);
178                 ao2_unlock(lot);
179                 return NULL;
180         }
181
182         /* Insert into the parking lot's parked user list. We can unlock the lot now. */
183         ao2_link(lot->parked_users, new_parked_user);
184         ao2_unlock(lot);
185
186         return new_parked_user;
187 }
188
189 /* TODO CEL events for parking */
190
191 /*!
192  * \internal
193  * \brief ast_bridge parking push method.
194  * \since 12.0.0
195  *
196  * \param self Bridge to operate upon
197  * \param bridge_channel Bridge channel to push
198  * \param swap Bridge channel to swap places with if not NULL
199  *
200  * \note On entry, self is already locked
201  *
202  * \retval 0 on success
203  * \retval -1 on failure
204  */
205 static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
206 {
207         struct parked_user *pu;
208         const char *blind_transfer;
209         RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup); /* XXX replace with ast_channel_cleanup when available */
210         RAII_VAR(struct park_common_datastore *, park_datastore, NULL, park_common_datastore_free);
211
212         ast_bridge_base_v_table.push(&self->base, bridge_channel, swap);
213
214         ast_assert(self->lot != NULL);
215
216         /* Answer the channel if needed */
217         if (ast_channel_state(bridge_channel->chan) != AST_STATE_UP) {
218                 ast_answer(bridge_channel->chan);
219         }
220
221         if (swap) {
222                 int use_ringing = 0;
223                 ao2_lock(swap);
224                 pu = swap->bridge_pvt;
225                 if (!pu) {
226                         /* This should be impossible since the only way a channel can enter in the first place
227                          * is if it has a parked user associated with it */
228                         publish_parked_call_failure(bridge_channel->chan);
229                         ao2_unlock(swap);
230                         return -1;
231                 }
232
233                 /* Give the swap channel's parked user reference to the incoming channel */
234                 pu->chan = bridge_channel->chan;
235                 bridge_channel->bridge_pvt = pu;
236                 swap->bridge_pvt = NULL;
237
238                 /* TODO Add a parked call swap message type to relay information about parked channel swaps */
239
240                 if (ast_bridge_channel_has_role(swap, "holding_participant")) {
241                         const char *idle_mode = ast_bridge_channel_get_role_option(swap, "holding_participant", "idle_mode");
242                         if (!ast_strlen_zero(idle_mode) && !strcmp(idle_mode, "ringing")) {
243                                 use_ringing = 1;
244                         }
245                 }
246
247                 ao2_unlock(swap);
248
249                 parking_set_duration(bridge_channel->features, pu);
250
251                 if (parking_channel_set_roles(bridge_channel->chan, self->lot, use_ringing)) {
252                         ast_log(LOG_WARNING, "Failed to apply holding bridge roles to %s while joining the parking lot.\n",
253                                 ast_channel_name(bridge_channel->chan));
254                 }
255
256                 return 0;
257         }
258
259         if (!(park_datastore = get_park_common_datastore_copy(bridge_channel->chan))) {
260                 /* There was either a failure to apply the datastore when performing park common setup or else we had alloc failures while cloning. Abort. */
261                 return -1;
262         }
263         parker = ast_channel_get_by_name(park_datastore->parker_uuid);
264
265         /* If the parker and the parkee are the same channel pointer, then the channel entered using
266          * the park application. It's possible that the channel that transferred it is still alive (particularly
267          * when a multichannel bridge is parked), so try to get the real parker if possible. */
268         ast_channel_lock(bridge_channel->chan);
269         blind_transfer = S_OR(pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER"),
270                 ast_channel_name(bridge_channel->chan));
271         if (blind_transfer) {
272                 blind_transfer = ast_strdupa(blind_transfer);
273         }
274         ast_channel_unlock(bridge_channel->chan);
275
276         if (parker == bridge_channel->chan) {
277                 struct ast_channel *real_parker = ast_channel_get_by_name(blind_transfer);
278                 if (real_parker) {
279                         ao2_cleanup(parker);
280                         parker = real_parker;
281                 }
282         }
283
284         pu = generate_parked_user(self->lot, bridge_channel->chan, parker,
285                 park_datastore->parker_dial_string, park_datastore->randomize, park_datastore->time_limit);
286
287         if (!pu) {
288                 publish_parked_call_failure(bridge_channel->chan);
289                 return -1;
290         }
291
292         /* If a comeback_override was provided, set it for the parked user's comeback string. */
293         if (park_datastore->comeback_override) {
294                 strncpy(pu->comeback, park_datastore->comeback_override, sizeof(pu->comeback));
295                 pu->comeback[sizeof(pu->comeback) - 1] = '\0';
296         }
297
298         /* Generate ParkedCall Stasis Message */
299         publish_parked_call(pu, PARKED_CALL);
300
301         /* If the parkee and the parker are the same and silence_announce isn't set, play the announcement to the parkee */
302         if (!strcmp(blind_transfer, ast_channel_name(bridge_channel->chan)) && !park_datastore->silence_announce) {
303                 char saynum_buf[16];
304                 snprintf(saynum_buf, sizeof(saynum_buf), "%u %u", 0, pu->parking_space);
305                 ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
306         }
307
308         /* Apply parking duration limits */
309         parking_set_duration(bridge_channel->features, pu);
310
311         /* Set this to the bridge pvt so that we don't have to refind the parked user associated with this bridge channel again. */
312         bridge_channel->bridge_pvt = pu;
313
314         ast_verb(3, "Parking '" COLORIZE_FMT "' in '" COLORIZE_FMT "' at space %d\n",
315                 COLORIZE(COLOR_BRMAGENTA, 0, ast_channel_name(bridge_channel->chan)),
316                 COLORIZE(COLOR_BRMAGENTA, 0, self->lot->name),
317                 pu->parking_space);
318
319         parking_notify_metermaids(pu->parking_space, self->lot->cfg->parking_con, AST_DEVICE_INUSE);
320
321         return 0;
322 }
323
324 /*!
325  * \internal
326  * \brief ast_bridge parking pull method.
327  * \since 12.0.0
328  *
329  * \param self Bridge to operate upon.
330  * \param bridge_channel Bridge channel to pull.
331  *
332  * \note On entry, self is already locked.
333  *
334  * \return Nothing
335  */
336 static void bridge_parking_pull(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
337 {
338         RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
339         ast_bridge_base_v_table.pull(&self->base, bridge_channel);
340
341         /* Take over the bridge channel's pu reference. It will be released when we are done. */
342         pu = bridge_channel->bridge_pvt;
343         bridge_channel->bridge_pvt = NULL;
344
345         /* This should only happen if the exiting channel was swapped out */
346         if (!pu) {
347                 return;
348         }
349
350         /* If we got here without the resolution being set, that's because the call was hung up for some reason without
351          * timing out or being picked up. There may be some forcible park removals later, but the resolution should be
352          * handled in those cases */
353         ao2_lock(pu);
354         if (pu->resolution == PARK_UNSET) {
355                 pu->resolution = PARK_ABANDON;
356         }
357         ao2_unlock(pu);
358
359         parking_notify_metermaids(pu->parking_space, self->lot->cfg->parking_con, AST_DEVICE_NOT_INUSE);
360
361         switch (pu->resolution) {
362         case PARK_UNSET:
363                 /* This should be impossible now since the resolution is forcibly set to abandon if it was unset at this point. Resolution
364                    isn't allowed to be changed when it isn't currently PARK_UNSET. */
365                 return;
366         case PARK_ABANDON:
367                 /* Since the call was abandoned without additional handling, we need to issue the give up event and unpark the user. */
368                 publish_parked_call(pu, PARKED_CALL_GIVEUP);
369                 unpark_parked_user(pu);
370                 return;
371         case PARK_FORCED:
372                 /* PARK_FORCED is currently unused, but it is expected that it would be handled similar to PARK_ANSWERED.
373                  * There is currently no event related to forced parked calls either */
374                 return;
375         case PARK_ANSWERED:
376                 /* If answered or forced, the channel should be pulled from the bridge as part of that process and unlinked from
377                  * the parking lot afterwards. We do need to apply bridge features though and play the courtesy tone if set. */
378                 publish_parked_call(pu, PARKED_CALL_UNPARKED);
379                 parked_call_retrieve_enable_features(bridge_channel->chan, pu->lot, AST_FEATURE_FLAG_BYCALLEE);
380
381                 if (pu->lot->cfg->parkedplay & AST_FEATURE_FLAG_BYCALLEE) {
382                         ast_bridge_channel_queue_playfile(bridge_channel, NULL, pu->lot->cfg->courtesytone, NULL);
383                 }
384
385                 return;
386         case PARK_TIMEOUT:
387                 /* Timeout is similar to abandon because it simply sets the bridge state to end and doesn't
388                  * actually pull the channel. Because of that, unpark should happen in here. */
389                 publish_parked_call(pu, PARKED_CALL_TIMEOUT);
390                 unpark_parked_user(pu);
391                 return;
392         }
393 }
394
395 /*!
396  * \internal
397  * \brief ast_bridge parking notify_masquerade method.
398  * \since 12.0.0
399  *
400  * \param self Bridge to operate upon.
401  * \param bridge_channel Bridge channel that was masqueraded.
402  *
403  * \note On entry, self is already locked.
404  * \note XXX Stub... and it will probably go unused.
405  *
406  * \return Nothing
407  */
408 static void bridge_parking_notify_masquerade(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
409 {
410         ast_bridge_base_v_table.notify_masquerade(&self->base, bridge_channel);
411 }
412
413 static void bridge_parking_get_merge_priority(struct ast_bridge_parking *self)
414 {
415         ast_bridge_base_v_table.get_merge_priority(&self->base);
416 }
417
418 struct ast_bridge_methods ast_bridge_parking_v_table = {
419         .name = "parking",
420         .destroy = (ast_bridge_destructor_fn) bridge_parking_destroy,
421         .dissolving = (ast_bridge_dissolving_fn) bridge_parking_dissolving,
422         .push = (ast_bridge_push_channel_fn) bridge_parking_push,
423         .pull = (ast_bridge_pull_channel_fn) bridge_parking_pull,
424         .notify_masquerade = (ast_bridge_notify_masquerade_fn) bridge_parking_notify_masquerade,
425         .get_merge_priority = (ast_bridge_merge_priority_fn) bridge_parking_get_merge_priority,
426 };
427
428 static struct ast_bridge *ast_bridge_parking_init(struct ast_bridge_parking *self, struct parking_lot *bridge_lot)
429 {
430         if (!self) {
431                 return NULL;
432         }
433
434         /* If no lot is defined for the bridge, then we aren't allowing the bridge to be initialized. */
435         if (!bridge_lot) {
436                 ao2_ref(self, -1);
437                 return NULL;
438         }
439
440         /* It doesn't need to be a reference since the bridge only lives as long as the parking lot lives. */
441         self->lot = bridge_lot;
442
443         return &self->base;
444 }
445
446 struct ast_bridge *bridge_parking_new(struct parking_lot *bridge_lot)
447 {
448         void *bridge;
449
450         bridge = ast_bridge_alloc(sizeof(struct ast_bridge_parking), &ast_bridge_parking_v_table);
451         bridge = ast_bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING,
452                 AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
453                 | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM);
454         bridge = ast_bridge_parking_init(bridge, bridge_lot);
455         bridge = ast_bridge_register(bridge);
456         return bridge;
457 }