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