res_parking: Dynamic Parking Lots
[asterisk/asterisk.git] / res / parking / parking_applications.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 Call Parking Applications
22  *
23  * \author Jonathan Rose <jrose@digium.com>
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include "res_parking.h"
31 #include "asterisk/config.h"
32 #include "asterisk/config_options.h"
33 #include "asterisk/event.h"
34 #include "asterisk/utils.h"
35 #include "asterisk/astobj2.h"
36 #include "asterisk/features.h"
37 #include "asterisk/module.h"
38 #include "asterisk/app.h"
39 #include "asterisk/say.h"
40 #include "asterisk/features.h"
41 #include "asterisk/bridging_basic.h"
42
43 /*** DOCUMENTATION
44         <application name="Park" language="en_US">
45                 <synopsis>
46                         Park yourself.
47                 </synopsis>
48                 <syntax>
49                         <parameter name="parking_lot_name">
50                                 <para>Specify in which parking lot to park a call.</para>
51                                 <para>The parking lot used is selected in the following order:</para>
52                                 <para>1) parking_lot_name option to this application</para>
53                                 <para>2) <variable>PARKINGLOT</variable> variable</para>
54                                 <para>3) <literal>CHANNEL(parkinglot)</literal> function
55                                 (Possibly preset by the channel driver.)</para>
56                                 <para>4) Default parking lot.</para>
57                         </parameter>
58                         <parameter name="options">
59                                 <para>A list of options for this parked call.</para>
60                                 <optionlist>
61                                         <option name="r">
62                                                 <para>Send ringing instead of MOH to the parked call.</para>
63                                         </option>
64                                         <option name="R">
65                                                 <para>Randomize the selection of a parking space.</para>
66                                         </option>
67                                         <option name="s">
68                                                 <para>Silence announcement of the parking space number.</para>
69                                         </option>
70                                         <option name="c" argsep=",">
71                                                 <argument name="context" required="false" />
72                                                 <argument name="extension" required="false" />
73                                                 <argument name="priority" required="true" />
74                                                 <para>If the parking times out, go to this place in the dialplan
75                                                         instead of where the parking lot defines the call should go.
76                                                 </para>
77                                         </option>
78                                         <option name="t">
79                                                 <argument name="duration" required="true" />
80                                                 <para>Use a timeout of <literal>duration</literal> seconds instead
81                                                         of the timeout specified by the parking lot.</para>
82                                         </option>
83                                 </optionlist>
84                         </parameter>
85                 </syntax>
86                 <description>
87                         <para>Used to park yourself (typically in combination with an attended
88                         transfer to know the parking space).</para>
89                         <para>If you set the <variable>PARKINGEXTEN</variable> variable to a
90                                 parking space extension in the parking lot, Park() will attempt to park the
91                                 call on that extension. If the extension is already in use then execution
92                                 will continue at the next priority.
93                         </para>
94                 </description>
95                 <see-also>
96                         <ref type="application">ParkedCall</ref>
97                 </see-also>
98         </application>
99
100         <application name="ParkedCall" language="en_US">
101                 <synopsis>
102                         Retrieve a parked call.
103                 </synopsis>
104                 <syntax>
105                         <parameter name="parking_lot_name">
106                                 <para>Specify from which parking lot to retrieve a parked call.</para>
107                                 <para>The parking lot used is selected in the following order:</para>
108                                 <para>1) parking_lot_name option</para>
109                                 <para>2) <variable>PARKINGLOT</variable> variable</para>
110                                 <para>3) <literal>CHANNEL(parkinglot)</literal> function
111                                 (Possibly preset by the channel driver.)</para>
112                                 <para>4) Default parking lot.</para>
113                         </parameter>
114                         <parameter name="parking_space">
115                                 <para>Parking space to retrieve a parked call from.
116                                 If not provided then the first available parked call in the
117                                 parking lot will be retrieved.</para>
118                         </parameter>
119                 </syntax>
120                 <description>
121                         <para>Used to retrieve a parked call from a parking lot.</para>
122                         <note>
123                                 <para>If a parking lot's parkext option is set, then Parking lots
124                                 will automatically create and manage dialplan extensions in
125                                 the parking lot context. If that is the case then you will not
126                                 need to manage parking extensions yourself, just include the
127                                 parking context of the parking lot.</para>
128                         </note>
129                 </description>
130                 <see-also>
131                         <ref type="application">Park</ref>
132                 </see-also>
133         </application>
134
135         <application name="ParkAndAnnounce" language="en_US">
136                 <synopsis>
137                         Park and Announce.
138                 </synopsis>
139                 <syntax>
140                         <parameter name="parking_lot_name">
141                                 <para>Specify in which parking lot to park a call.</para>
142                                 <para>The parking lot used is selected in the following order:</para>
143                                 <para>1) parking_lot_name option to this application</para>
144                                 <para>2) <variable>PARKINGLOT</variable> variable</para>
145                                 <para>3) <literal>CHANNEL(parkinglot)</literal> function
146                                 (Possibly preset by the channel driver.)</para>
147                                 <para>4) Default parking lot.</para>
148                         </parameter>
149                         <parameter name="options">
150                                 <para>A list of options for this parked call.</para>
151                                 <optionlist>
152                                         <option name="r">
153                                                 <para>Send ringing instead of MOH to the parked call.</para>
154                                         </option>
155                                         <option name="R">
156                                                 <para>Randomize the selection of a parking space.</para>
157                                         </option>
158                                         <option name="c" argsep=",">
159                                                 <argument name="context" required="false" />
160                                                 <argument name="extension" required="false" />
161                                                 <argument name="priority" required="true" />
162                                                 <para>If the parking times out, go to this place in the dialplan
163                                                         instead of where the parking lot defines the call should go.
164                                                 </para>
165                                         </option>
166                                         <option name="t">
167                                                 <argument name="duration" required="true" />
168                                                 <para>Use a timeout of <literal>duration</literal> seconds instead
169                                                         of the timeout specified by the parking lot.</para>
170                                         </option>
171                                 </optionlist>
172                         </parameter>
173                         <parameter name="announce_template" required="true" argsep=":">
174                                 <argument name="announce" required="true">
175                                         <para>Colon-separated list of files to announce. The word
176                                         <literal>PARKED</literal> will be replaced by a say_digits of the extension in which
177                                         the call is parked.</para>
178                                 </argument>
179                                 <argument name="announce1" multiple="true" />
180                         </parameter>
181                         <parameter name="dial" required="true">
182                                 <para>The app_dial style resource to call to make the
183                                 announcement. Console/dsp calls the console.</para>
184                         </parameter>
185                 </syntax>
186                 <description>
187                         <para>Park a call into the parkinglot and announce the call to another channel.</para>
188                         <para>The variable <variable>PARKEDAT</variable> will contain the parking extension
189                         into which the call was placed.  Use with the Local channel to allow the dialplan to make
190                         use of this information.</para>
191                 </description>
192                 <see-also>
193                         <ref type="application">Park</ref>
194                         <ref type="application">ParkedCall</ref>
195                 </see-also>
196         </application>
197  ***/
198
199 /* Park a call */
200
201 enum park_args {
202         OPT_ARG_COMEBACK,
203         OPT_ARG_TIMEOUT,
204         OPT_ARG_ARRAY_SIZE /* Always the last element of the enum */
205 };
206
207 enum park_flags {
208         MUXFLAG_RINGING = (1 << 0),
209         MUXFLAG_RANDOMIZE = (1 << 1),
210         MUXFLAG_NOANNOUNCE = (1 << 2),
211         MUXFLAG_COMEBACK_OVERRIDE = (1 << 3),
212         MUXFLAG_TIMEOUT_OVERRIDE = (1 << 4),
213 };
214
215 AST_APP_OPTIONS(park_opts, {
216         AST_APP_OPTION('r', MUXFLAG_RINGING),
217         AST_APP_OPTION('R', MUXFLAG_RANDOMIZE),
218         AST_APP_OPTION('s', MUXFLAG_NOANNOUNCE),
219         AST_APP_OPTION_ARG('c', MUXFLAG_COMEBACK_OVERRIDE, OPT_ARG_COMEBACK),
220         AST_APP_OPTION_ARG('t', MUXFLAG_TIMEOUT_OVERRIDE, OPT_ARG_TIMEOUT),
221 });
222
223 static int apply_option_timeout (int *var, char *timeout_arg)
224 {
225         if (ast_strlen_zero(timeout_arg)) {
226                 ast_log(LOG_ERROR, "No duration value provided for the timeout ('t') option.\n");
227                 return -1;
228         }
229
230         if (sscanf(timeout_arg, "%d", var) != 1 || *var < 0) {
231                 ast_log(LOG_ERROR, "Duration value provided for timeout ('t') option must be 0 or greater.\n");
232                 return -1;
233         }
234
235         return 0;
236 }
237
238 static int park_app_parse_data(const char *data, int *disable_announce, int *use_ringing, int *randomize, int *time_limit, char **comeback_override, char **lot_name)
239 {
240         char *parse;
241         struct ast_flags flags = { 0 };
242
243         AST_DECLARE_APP_ARGS(args,
244                 AST_APP_ARG(lot_name);
245                 AST_APP_ARG(options);
246                 AST_APP_ARG(other);     /* Any remaining unused arguments */
247         );
248
249         parse = ast_strdupa(data);
250         AST_STANDARD_APP_ARGS(args, parse);
251
252         if (args.options) {
253                 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
254                 ast_app_parse_options(park_opts, &flags, opts, args.options);
255                 if (ast_test_flag(&flags, MUXFLAG_TIMEOUT_OVERRIDE)) {
256                         if (apply_option_timeout(time_limit, opts[OPT_ARG_TIMEOUT])) {
257                                 return -1;
258                         }
259                 }
260
261                 if (ast_test_flag(&flags, MUXFLAG_COMEBACK_OVERRIDE)) {
262                         *comeback_override = ast_strdup(opts[OPT_ARG_COMEBACK]);
263                 }
264
265                 if (ast_test_flag(&flags, MUXFLAG_NOANNOUNCE)) {
266                         if (disable_announce) {
267                                 *disable_announce = 1;
268                         }
269                 }
270
271                 if (ast_test_flag(&flags, MUXFLAG_RINGING)) {
272                         *use_ringing = 1;
273                 }
274
275                 if (ast_test_flag(&flags, MUXFLAG_RANDOMIZE)) {
276                         *randomize = 1;
277                 }
278         }
279
280         if (!ast_strlen_zero(args.lot_name)) {
281                 *lot_name = ast_strdup(args.lot_name);
282         }
283
284         return 0;
285 }
286
287 static void park_common_datastore_destroy(void *data)
288 {
289         struct park_common_datastore *datastore = data;
290         ast_free(datastore->parker_uuid);
291         ast_free(datastore->comeback_override);
292         ast_free(datastore);
293 }
294
295 static const struct ast_datastore_info park_common_info = {
296         .type = "park entry data",
297         .destroy = park_common_datastore_destroy,
298 };
299
300 static void wipe_park_common_datastore(struct ast_channel *chan)
301 {
302         struct ast_datastore *datastore;
303
304         ast_channel_lock(chan);
305         datastore = ast_channel_datastore_find(chan, &park_common_info, NULL);
306         if (datastore) {
307                 ast_channel_datastore_remove(chan, datastore);
308                 ast_datastore_free(datastore);
309         }
310         ast_channel_unlock(chan);
311 }
312
313 static int setup_park_common_datastore(struct ast_channel *parkee, const char *parker_uuid, const char *comeback_override, int randomize, int time_limit, int silence_announce)
314 {
315         struct ast_datastore *datastore = NULL;
316         struct park_common_datastore *park_datastore;
317
318         wipe_park_common_datastore(parkee);
319
320         if (!(datastore = ast_datastore_alloc(&park_common_info, NULL))) {
321                 return -1;
322         }
323
324         if (!(park_datastore = ast_calloc(1, sizeof(*park_datastore)))) {
325                 ast_datastore_free(datastore);
326                 return -1;
327         }
328
329         park_datastore->parker_uuid = ast_strdup(parker_uuid);
330         park_datastore->randomize = randomize;
331         park_datastore->time_limit = time_limit;
332         park_datastore->silence_announce = silence_announce;
333
334         if (comeback_override) {
335                 park_datastore->comeback_override = ast_strdup(comeback_override);
336         }
337
338
339         datastore->data = park_datastore;
340         ast_channel_lock(parkee);
341         ast_channel_datastore_add(parkee, datastore);
342         ast_channel_unlock(parkee);
343
344         return 0;
345 }
346
347 void get_park_common_datastore_data(struct ast_channel *parkee, char **parker_uuid, char **comeback_override,
348                 int *randomize, int *time_limit, int *silence_announce)
349 {
350         struct ast_datastore *datastore;
351         struct park_common_datastore *data;
352
353         ast_channel_lock(parkee);
354         if (!(datastore = ast_channel_datastore_find(parkee, &park_common_info, NULL))) {
355                 ast_channel_unlock(parkee);
356                 return;
357         }
358
359         data = datastore->data;
360
361         if (!data) {
362                 /* This data should always be populated if this datastore was appended to the channel */
363                 ast_assert(0);
364         }
365
366         *parker_uuid = ast_strdup(data->parker_uuid);
367         *randomize = data->randomize;
368         *time_limit = data->time_limit;
369         *silence_announce = data->silence_announce;
370
371         if (data->comeback_override) {
372                 *comeback_override = ast_strdup(data->comeback_override);
373         }
374
375         ast_channel_unlock(parkee);
376 }
377
378 struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_channel *parker,
379                 const char *lot_name, const char *comeback_override,
380                 int use_ringing, int randomize, int time_limit, int silence_announcements)
381 {
382         struct ast_bridge *parking_bridge;
383         RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
384
385         /* If the name of the parking lot isn't specified in the arguments, find it based on the channel. */
386         if (ast_strlen_zero(lot_name)) {
387                 ast_channel_lock(parker);
388                 lot_name = ast_strdupa(find_channel_parking_lot_name(parker));
389                 ast_channel_unlock(parker);
390         }
391
392         lot = parking_lot_find_by_name(lot_name);
393         if (!lot) {
394                 lot = parking_create_dynamic_lot(lot_name, parkee);
395         }
396
397         if (!lot) {
398                 ast_log(LOG_ERROR, "Could not find parking lot: '%s'\n", lot_name);
399                 return NULL;
400         }
401
402         ao2_lock(lot);
403         parking_bridge = parking_lot_get_bridge(lot);
404         ao2_unlock(lot);
405
406         if (!parking_bridge) {
407                 return NULL;
408         }
409
410         /* Apply relevant bridge roles and such to the parking channel */
411         parking_channel_set_roles(parkee, lot, use_ringing);
412         setup_park_common_datastore(parkee, ast_channel_uniqueid(parker), comeback_override, randomize, time_limit,
413                 silence_announcements);
414         return parking_bridge;
415 }
416
417 struct ast_bridge *park_application_setup(struct ast_channel *parkee, struct ast_channel *parker, const char *app_data,
418                 int *silence_announcements)
419 {
420         int use_ringing = 0;
421         int randomize = 0;
422         int time_limit = -1;
423
424         RAII_VAR(char *, comeback_override, NULL, ast_free);
425         RAII_VAR(char *, lot_name_app_arg, NULL, ast_free);
426
427         if (app_data) {
428                 park_app_parse_data(app_data, silence_announcements, &use_ringing, &randomize, &time_limit, &comeback_override, &lot_name_app_arg);
429         }
430
431         return park_common_setup(parkee, parker, lot_name_app_arg, comeback_override, use_ringing,
432                 randomize, time_limit, silence_announcements ? *silence_announcements : 0);
433
434 }
435
436 /* XXX BUGBUG - determining the parker when transferred to deep park priority
437  *     Currently all parking by the park application is treated as calls parking themselves.
438  *     However, it's possible for calls to be transferred here when the Park application is
439  *     set after the first priority of an extension. In that case, there used to be a variable
440  *     (BLINDTRANSFER) set indicating which channel placed that call here.
441  *
442  *     If BLINDTRANSFER is set, this channel name will need to be referenced in Park events
443  *     generated by stasis. Ideally we would get a whole channel snapshot and use that for the
444  *     parker, but that would likely require applying the channel snapshot to a channel datastore
445  *     on all transfers. Alternatively just the name of the parking channel could be applied along
446  *     with an indication that it's dead.
447  */
448 int park_app_exec(struct ast_channel *chan, const char *data)
449 {
450         RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
451
452         struct ast_bridge_features chan_features;
453         int res;
454         int silence_announcements = 0;
455         const char *blind_transfer;
456
457         /* Answer the channel if needed */
458         if (ast_channel_state(chan) != AST_STATE_UP) {
459                 ast_answer(chan);
460         }
461
462         ast_channel_lock(chan);
463         if ((blind_transfer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"))) {
464                 blind_transfer = ast_strdupa(blind_transfer);
465         }
466         ast_channel_unlock(chan);
467
468         /* Handle the common parking setup stuff */
469         if (!(parking_bridge = park_application_setup(chan, chan, data, &silence_announcements))) {
470                 if (!silence_announcements && !blind_transfer) {
471                         ast_stream_and_wait(chan, "pbx-parkingfailed", "");
472                 }
473                 return 0;
474         }
475
476         /* Initialize bridge features for the channel. */
477         res = ast_bridge_features_init(&chan_features);
478         if (res) {
479                 ast_bridge_features_cleanup(&chan_features);
480                 return -1;
481         }
482
483         /* Now for the fun part... park it! */
484         ast_bridge_join(parking_bridge, chan, NULL, &chan_features, NULL, 0);
485
486         /*
487          * If the bridge was broken for a hangup that isn't real, then
488          * don't run the h extension, because the channel isn't really
489          * hung up.  This should only happen with AST_SOFTHANGUP_ASYNCGOTO.
490          */
491         res = -1;
492
493         ast_channel_lock(chan);
494         if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
495                 res = 0;
496         }
497         ast_channel_unlock(chan);
498
499         ast_bridge_features_cleanup(&chan_features);
500
501         return res;
502 }
503
504 /* Retrieve a parked call */
505
506 int parked_call_app_exec(struct ast_channel *chan, const char *data)
507 {
508         RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
509         RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup); /* Parked user being retrieved */
510         RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
511         struct ast_bridge *retrieval_bridge;
512         int res;
513         int target_space = -1;
514         struct ast_bridge_features chan_features;
515         char *parse;
516         char *lot_name;
517
518         AST_DECLARE_APP_ARGS(args,
519                 AST_APP_ARG(lot_name);
520                 AST_APP_ARG(parking_space);
521                 AST_APP_ARG(other);     /* Any remaining unused arguments */
522         );
523
524         parse = ast_strdupa(data);
525         AST_STANDARD_APP_ARGS(args, parse);
526
527         /* Answer the channel if needed */
528         if (ast_channel_state(chan) != AST_STATE_UP) {
529                 ast_answer(chan);
530         }
531
532         lot_name = args.lot_name;
533
534         /* If the name of the parking lot isn't in the arguments, find it based on the channel. */
535         if (ast_strlen_zero(lot_name)) {
536                 ast_channel_lock(chan);
537                 lot_name = ast_strdupa(find_channel_parking_lot_name(chan));
538                 ast_channel_unlock(chan);
539         }
540
541         lot = parking_lot_find_by_name(lot_name);
542
543         if (!lot) {
544                 ast_log(LOG_ERROR, "Could not find the requested parking lot\n");
545                 ast_stream_and_wait(chan, "pbx-invalidpark", "");
546                 return -1;
547         }
548
549         if (!ast_strlen_zero(args.parking_space)) {
550                 if (sscanf(args.parking_space, "%d", &target_space) != 1 || target_space < 0) {
551                         ast_stream_and_wait(chan, "pbx-invalidpark", "");
552                         ast_log(LOG_ERROR, "value '%s' for parking_space argument is invalid. Must be an integer greater than 0.\n", args.parking_space);
553                         return -1;
554                 }
555         }
556
557         /* Attempt to get the parked user from the parking lot */
558         pu = parking_lot_retrieve_parked_user(lot, target_space);
559         if (!pu) {
560                 ast_stream_and_wait(chan, "pbx-invalidpark", "");
561                 return -1;
562         }
563
564         /* The parked call needs to know who is retrieving it before we move it out of the parking bridge */
565         pu->retriever = ast_channel_snapshot_create(chan);
566
567         /* Create bridge */
568         retrieval_bridge = ast_bridge_basic_new();
569         if (!retrieval_bridge) {
570                 return -1;
571         }
572
573         /* Move the parkee into the new bridge */
574         if (ast_bridge_move(retrieval_bridge, lot->parking_bridge, pu->chan, NULL, 0)) {
575                 ast_bridge_destroy(retrieval_bridge);
576                 return -1;
577         }
578
579         /* Initialize our bridge features */
580         res = ast_bridge_features_init(&chan_features);
581         if (res) {
582                 ast_bridge_destroy(retrieval_bridge);
583                 ast_bridge_features_cleanup(&chan_features);
584                 return -1;
585         }
586
587         /* Set the features */
588         parked_call_retrieve_enable_features(chan, lot, AST_FEATURE_FLAG_BYCALLER);
589
590         /* If the parkedplay option is set for the caller to hear, play that tone now. */
591         if (lot->cfg->parkedplay & AST_FEATURE_FLAG_BYCALLER) {
592                 ast_stream_and_wait(chan, lot->cfg->courtesytone, NULL);
593         }
594
595         /* Now we should try to join the new bridge ourselves... */
596         ast_bridge_join(retrieval_bridge, chan, NULL, &chan_features, NULL, 1);
597
598         ast_bridge_features_cleanup(&chan_features);
599
600         return 0;
601 }
602
603 struct park_announce_subscription_data {
604         char *parkee_uuid;
605         char *dial_string;
606         char *announce_string;
607 };
608
609 static void park_announce_subscription_data_destroy(void *data)
610 {
611         struct park_announce_subscription_data *pa_data = data;
612         ast_free(pa_data->parkee_uuid);
613         ast_free(pa_data->dial_string);
614         ast_free(pa_data->announce_string);
615         ast_free(pa_data);
616 }
617
618 static struct park_announce_subscription_data *park_announce_subscription_data_create(const char *parkee_uuid,
619                 const char *dial_string,
620                 const char *announce_string)
621 {
622         struct park_announce_subscription_data *pa_data;
623
624         if (!(pa_data = ast_calloc(1, sizeof(*pa_data)))) {
625                 return NULL;
626         }
627
628         if (!(pa_data->parkee_uuid = ast_strdup(parkee_uuid))
629                 || !(pa_data->dial_string = ast_strdup(dial_string))
630                 || !(pa_data->announce_string = ast_strdup(announce_string))) {
631                 park_announce_subscription_data_destroy(pa_data);
632                 return NULL;
633         }
634
635         return pa_data;
636 }
637
638 static void announce_to_dial(char *dial_string, char *announce_string, int parkingspace, struct ast_channel_snapshot *parkee_snapshot)
639 {
640         struct ast_channel *dchan;
641         struct outgoing_helper oh = { 0, };
642         int outstate;
643         struct ast_format_cap *cap_slin = ast_format_cap_alloc_nolock();
644         char buf[13];
645         char *dial_tech;
646         char *cur_announce;
647         struct ast_format tmpfmt;
648
649         dial_tech = strsep(&dial_string, "/");
650         ast_verb(3, "Dial Tech,String: (%s,%s)\n", dial_tech, dial_string);
651
652         if (!cap_slin) {
653                 ast_log(LOG_WARNING, "PARK: Failed to announce park.\n");
654                 goto announce_cleanup;
655         }
656         ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
657
658         snprintf(buf, sizeof(buf), "%d", parkingspace);
659         oh.vars = ast_variable_new("_PARKEDAT", buf, "");
660         dchan = __ast_request_and_dial(dial_tech, cap_slin, NULL, dial_string, 30000,
661                 &outstate,
662                 parkee_snapshot->caller_number,
663                 parkee_snapshot->caller_name,
664                 &oh);
665
666         ast_variables_destroy(oh.vars);
667         if (!dchan) {
668                 ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
669                 goto announce_cleanup;
670         }
671
672         ast_verb(4, "Announce Template: %s\n", announce_string);
673
674         for (cur_announce = strsep(&announce_string, ":"); cur_announce; cur_announce = strsep(&announce_string, ":")) {
675                 ast_verb(4, "Announce:%s\n", cur_announce);
676                 if (!strcmp(cur_announce, "PARKED")) {
677                         ast_say_digits(dchan, parkingspace, "", ast_channel_language(dchan));
678                 } else {
679                         int dres = ast_streamfile(dchan, cur_announce, ast_channel_language(dchan));
680                         if (!dres) {
681                                 dres = ast_waitstream(dchan, "");
682                         } else {
683                                 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", cur_announce, ast_channel_name(dchan));
684                         }
685                 }
686         }
687
688         ast_stopstream(dchan);
689         ast_hangup(dchan);
690
691 announce_cleanup:
692         cap_slin = ast_format_cap_destroy(cap_slin);
693 }
694
695 static void park_announce_update_cb(void *data, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *message)
696 {
697         struct park_announce_subscription_data *pa_data = data;
698         char *dial_string = pa_data->dial_string;
699
700         struct ast_parked_call_payload *payload = stasis_message_data(message);
701
702         if (stasis_subscription_final_message(sub, message)) {
703                 park_announce_subscription_data_destroy(data);
704                 return;
705         }
706
707         if (payload->event_type != PARKED_CALL) {
708                 /* We are only concerned with calls parked */
709                 return;
710         }
711
712         if (strcmp(payload->parkee->uniqueid, pa_data->parkee_uuid)) {
713                 /* We are only concerned with the parkee we are subscribed for. */
714                 return;
715         }
716
717         if (!ast_strlen_zero(dial_string)) {
718                 announce_to_dial(dial_string, pa_data->announce_string, payload->parkingspace, payload->parkee);
719         }
720
721         *dial_string = '\0'; /* If we observe this dial string on a second pass, we don't want to do anything with it. */
722 }
723
724 int park_and_announce_app_exec(struct ast_channel *chan, const char *data)
725 {
726         struct ast_bridge_features chan_features;
727         char *parse;
728         int res;
729         int silence_announcements = 1;
730
731         struct stasis_subscription *parking_subscription;
732         struct park_announce_subscription_data *pa_data;
733
734         RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
735
736         AST_DECLARE_APP_ARGS(args,
737                 AST_APP_ARG(lot_name);
738                 AST_APP_ARG(options);
739                 AST_APP_ARG(announce_template);
740                 AST_APP_ARG(dial);
741                 AST_APP_ARG(others);/* Any remaining unused arguments */
742         );
743
744         if (ast_strlen_zero(data)) {
745                 ast_log(LOG_ERROR, "ParkAndAnnounce has required arguments. No arguments were provided.\n");
746                 return -1;
747         }
748
749         parse = ast_strdupa(data);
750         AST_STANDARD_APP_ARGS(args, parse);
751
752         if (ast_strlen_zero(args.announce_template)) {
753                 /* improperly configured arguments for the application */
754                 ast_log(LOG_ERROR, "ParkAndAnnounce requires the announce_template argument.\n");
755                 return -1;
756         }
757
758         if (ast_strlen_zero(args.dial)) {
759                 /* improperly configured arguments */
760                 ast_log(LOG_ERROR, "ParkAndAnnounce requires the dial argument.\n");
761                 return -1;
762         }
763
764         if (!strchr(args.dial, '/')) {
765                 ast_log(LOG_ERROR, "ParkAndAnnounce dial string '%s' is improperly formed.\n", args.dial);
766                 return -1;
767         }
768
769         /* Handle the common parking setup stuff */
770         if (!(parking_bridge = park_application_setup(chan, chan, data, &silence_announcements))) {
771                 return 0;
772         }
773
774         /* Initialize bridge features for the channel. */
775         res = ast_bridge_features_init(&chan_features);
776         if (res) {
777                 ast_bridge_features_cleanup(&chan_features);
778                 return -1;
779         }
780
781         /* subscribe to the parking message so that we can announce once it is parked */
782         pa_data = park_announce_subscription_data_create(ast_channel_uniqueid(chan), args.dial, args.announce_template);
783         if (!pa_data) {
784                 return -1;
785         }
786
787         if (!(parking_subscription = stasis_subscribe(ast_parking_topic(), park_announce_update_cb, pa_data))) {
788                 /* Failed to create subscription */
789                 park_announce_subscription_data_destroy(pa_data);
790                 return -1;
791         }
792
793         /* Now for the fun part... park it! */
794         ast_bridge_join(parking_bridge, chan, NULL, &chan_features, NULL, 0);
795
796         /* Toss the subscription since we aren't bridged at this point. */
797         stasis_unsubscribe(parking_subscription);
798
799         /*
800          * If the bridge was broken for a hangup that isn't real, then
801          * don't run the h extension, because the channel isn't really
802          * hung up.  This should only happen with AST_SOFTHANGUP_ASYNCGOTO.
803          */
804         res = -1;
805
806         ast_channel_lock(chan);
807         if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
808                 res = 0;
809         }
810         ast_channel_unlock(chan);
811
812         ast_bridge_features_cleanup(&chan_features);
813
814         return res;
815 }