features: call pickup stasis refactoring
[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
394         if (!lot) {
395                 ast_log(LOG_ERROR, "Could not find parking lot: '%s'\n", lot_name);
396                 return NULL;
397         }
398
399         ao2_lock(lot);
400         parking_bridge = parking_lot_get_bridge(lot);
401         ao2_unlock(lot);
402
403         if (!parking_bridge) {
404                 return NULL;
405         }
406
407         /* Apply relevant bridge roles and such to the parking channel */
408         parking_channel_set_roles(parkee, lot, use_ringing);
409         setup_park_common_datastore(parkee, ast_channel_uniqueid(parker), comeback_override, randomize, time_limit,
410                 silence_announcements);
411         return parking_bridge;
412 }
413
414 struct ast_bridge *park_application_setup(struct ast_channel *parkee, struct ast_channel *parker, const char *app_data,
415                 int *silence_announcements)
416 {
417         int use_ringing = 0;
418         int randomize = 0;
419         int time_limit = -1;
420
421         RAII_VAR(char *, comeback_override, NULL, ast_free);
422         RAII_VAR(char *, lot_name_app_arg, NULL, ast_free);
423
424         if (app_data) {
425                 park_app_parse_data(app_data, silence_announcements, &use_ringing, &randomize, &time_limit, &comeback_override, &lot_name_app_arg);
426         }
427
428         return park_common_setup(parkee, parker, lot_name_app_arg, comeback_override, use_ringing,
429                 randomize, time_limit, silence_announcements ? *silence_announcements : 0);
430
431 }
432
433 /* XXX BUGBUG - determining the parker when transferred to deep park priority
434  *     Currently all parking by the park application is treated as calls parking themselves.
435  *     However, it's possible for calls to be transferred here when the Park application is
436  *     set after the first priority of an extension. In that case, there used to be a variable
437  *     (BLINDTRANSFER) set indicating which channel placed that call here.
438  *
439  *     If BLINDTRANSFER is set, this channel name will need to be referenced in Park events
440  *     generated by stasis. Ideally we would get a whole channel snapshot and use that for the
441  *     parker, but that would likely require applying the channel snapshot to a channel datastore
442  *     on all transfers. Alternatively just the name of the parking channel could be applied along
443  *     with an indication that it's dead.
444  */
445 int park_app_exec(struct ast_channel *chan, const char *data)
446 {
447         RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
448
449         struct ast_bridge_features chan_features;
450         int res;
451         int silence_announcements = 0;
452         const char *blind_transfer;
453
454         ast_channel_lock(chan);
455         if ((blind_transfer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"))) {
456                 blind_transfer = ast_strdupa(blind_transfer);
457         }
458         ast_channel_unlock(chan);
459
460         /* Handle the common parking setup stuff */
461         if (!(parking_bridge = park_application_setup(chan, chan, data, &silence_announcements))) {
462                 if (!silence_announcements && !blind_transfer) {
463                         ast_stream_and_wait(chan, "pbx-parkingfailed", "");
464                 }
465                 return 0;
466         }
467
468         /* Initialize bridge features for the channel. */
469         res = ast_bridge_features_init(&chan_features);
470         if (res) {
471                 ast_bridge_features_cleanup(&chan_features);
472                 return -1;
473         }
474
475         /* Now for the fun part... park it! */
476         ast_bridge_join(parking_bridge, chan, NULL, &chan_features, NULL, 0);
477
478         /*
479          * If the bridge was broken for a hangup that isn't real, then
480          * don't run the h extension, because the channel isn't really
481          * hung up.  This should only happen with AST_SOFTHANGUP_ASYNCGOTO.
482          */
483         res = -1;
484
485         ast_channel_lock(chan);
486         if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
487                 res = 0;
488         }
489         ast_channel_unlock(chan);
490
491         ast_bridge_features_cleanup(&chan_features);
492
493         return res;
494 }
495
496 /* Retrieve a parked call */
497
498 int parked_call_app_exec(struct ast_channel *chan, const char *data)
499 {
500         RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
501         RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup); /* Parked user being retrieved */
502         RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
503         struct ast_bridge *retrieval_bridge;
504         int res;
505         int target_space = -1;
506         struct ast_bridge_features chan_features;
507         char *parse;
508         char *lot_name;
509
510         AST_DECLARE_APP_ARGS(args,
511                 AST_APP_ARG(lot_name);
512                 AST_APP_ARG(parking_space);
513                 AST_APP_ARG(other);     /* Any remaining unused arguments */
514         );
515
516         parse = ast_strdupa(data);
517         AST_STANDARD_APP_ARGS(args, parse);
518
519         /* Answer the channel if needed */
520         if (ast_channel_state(chan) != AST_STATE_UP) {
521                 ast_answer(chan);
522         }
523
524         lot_name = args.lot_name;
525
526         /* If the name of the parking lot isn't in the arguments, find it based on the channel. */
527         if (ast_strlen_zero(lot_name)) {
528                 ast_channel_lock(chan);
529                 lot_name = ast_strdupa(find_channel_parking_lot_name(chan));
530                 ast_channel_unlock(chan);
531         }
532
533         lot = parking_lot_find_by_name(lot_name);
534
535         if (!lot) {
536                 ast_log(LOG_ERROR, "Could not find the requested parking lot\n");
537                 ast_stream_and_wait(chan, "pbx-invalidpark", "");
538                 return -1;
539         }
540
541         if (!ast_strlen_zero(args.parking_space)) {
542                 if (sscanf(args.parking_space, "%d", &target_space) != 1 || target_space < 0) {
543                         ast_stream_and_wait(chan, "pbx-invalidpark", "");
544                         ast_log(LOG_ERROR, "value '%s' for parking_space argument is invalid. Must be an integer greater than 0.\n", args.parking_space);
545                         return -1;
546                 }
547         }
548
549         /* Attempt to get the parked user from the parking lot */
550         pu = parking_lot_retrieve_parked_user(lot, target_space);
551         if (!pu) {
552                 ast_stream_and_wait(chan, "pbx-invalidpark", "");
553                 return -1;
554         }
555
556         /* The parked call needs to know who is retrieving it before we move it out of the parking bridge */
557         pu->retriever = ast_channel_snapshot_create(chan);
558
559         /* Create bridge */
560         retrieval_bridge = ast_bridge_basic_new();
561         if (!retrieval_bridge) {
562                 return -1;
563         }
564
565         /* Move the parkee into the new bridge */
566         if (ast_bridge_move(retrieval_bridge, lot->parking_bridge, pu->chan, NULL, 0)) {
567                 ast_bridge_destroy(retrieval_bridge);
568                 return -1;
569         }
570
571         /* Initialize our bridge features */
572         res = ast_bridge_features_init(&chan_features);
573         if (res) {
574                 ast_bridge_destroy(retrieval_bridge);
575                 ast_bridge_features_cleanup(&chan_features);
576                 return -1;
577         }
578
579         /* Set the features */
580         parked_call_retrieve_enable_features(chan, lot, AST_FEATURE_FLAG_BYCALLER);
581
582         /* If the parkedplay option is set for the caller to hear, play that tone now. */
583         if (lot->cfg->parkedplay & AST_FEATURE_FLAG_BYCALLER) {
584                 ast_stream_and_wait(chan, lot->cfg->courtesytone, NULL);
585         }
586
587         /* Now we should try to join the new bridge ourselves... */
588         ast_bridge_join(retrieval_bridge, chan, NULL, &chan_features, NULL, 1);
589
590         ast_bridge_features_cleanup(&chan_features);
591
592         return 0;
593 }
594
595 struct park_announce_subscription_data {
596         char *parkee_uuid;
597         char *dial_string;
598         char *announce_string;
599 };
600
601 static void park_announce_subscription_data_destroy(void *data)
602 {
603         struct park_announce_subscription_data *pa_data = data;
604         ast_free(pa_data->parkee_uuid);
605         ast_free(pa_data->dial_string);
606         ast_free(pa_data->announce_string);
607         ast_free(pa_data);
608 }
609
610 static struct park_announce_subscription_data *park_announce_subscription_data_create(const char *parkee_uuid,
611                 const char *dial_string,
612                 const char *announce_string)
613 {
614         struct park_announce_subscription_data *pa_data;
615
616         if (!(pa_data = ast_calloc(1, sizeof(*pa_data)))) {
617                 return NULL;
618         }
619
620         if (!(pa_data->parkee_uuid = ast_strdup(parkee_uuid))
621                 || !(pa_data->dial_string = ast_strdup(dial_string))
622                 || !(pa_data->announce_string = ast_strdup(announce_string))) {
623                 park_announce_subscription_data_destroy(pa_data);
624                 return NULL;
625         }
626
627         return pa_data;
628 }
629
630 static void announce_to_dial(char *dial_string, char *announce_string, int parkingspace, struct ast_channel_snapshot *parkee_snapshot)
631 {
632         struct ast_channel *dchan;
633         struct outgoing_helper oh = { 0, };
634         int outstate;
635         struct ast_format_cap *cap_slin = ast_format_cap_alloc_nolock();
636         char buf[13];
637         char *dial_tech;
638         char *cur_announce;
639         struct ast_format tmpfmt;
640
641         dial_tech = strsep(&dial_string, "/");
642         ast_verb(3, "Dial Tech,String: (%s,%s)\n", dial_tech, dial_string);
643
644         if (!cap_slin) {
645                 ast_log(LOG_WARNING, "PARK: Failed to announce park.\n");
646                 goto announce_cleanup;
647         }
648         ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
649
650         snprintf(buf, sizeof(buf), "%d", parkingspace);
651         oh.vars = ast_variable_new("_PARKEDAT", buf, "");
652         dchan = __ast_request_and_dial(dial_tech, cap_slin, NULL, dial_string, 30000,
653                 &outstate,
654                 parkee_snapshot->caller_number,
655                 parkee_snapshot->caller_name,
656                 &oh);
657
658         ast_variables_destroy(oh.vars);
659         if (!dchan) {
660                 ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
661                 goto announce_cleanup;
662         }
663
664         ast_verb(4, "Announce Template: %s\n", announce_string);
665
666         for (cur_announce = strsep(&announce_string, ":"); cur_announce; cur_announce = strsep(&announce_string, ":")) {
667                 ast_verb(4, "Announce:%s\n", cur_announce);
668                 if (!strcmp(cur_announce, "PARKED")) {
669                         ast_say_digits(dchan, parkingspace, "", ast_channel_language(dchan));
670                 } else {
671                         int dres = ast_streamfile(dchan, cur_announce, ast_channel_language(dchan));
672                         if (!dres) {
673                                 dres = ast_waitstream(dchan, "");
674                         } else {
675                                 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", cur_announce, ast_channel_name(dchan));
676                         }
677                 }
678         }
679
680         ast_stopstream(dchan);
681         ast_hangup(dchan);
682
683 announce_cleanup:
684         cap_slin = ast_format_cap_destroy(cap_slin);
685 }
686
687 static void park_announce_update_cb(void *data, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *message)
688 {
689         struct park_announce_subscription_data *pa_data = data;
690         char *dial_string = pa_data->dial_string;
691
692         struct ast_parked_call_payload *payload = stasis_message_data(message);
693
694         if (stasis_subscription_final_message(sub, message)) {
695                 park_announce_subscription_data_destroy(data);
696                 return;
697         }
698
699         if (payload->event_type != PARKED_CALL) {
700                 /* We are only concerned with calls parked */
701                 return;
702         }
703
704         if (strcmp(payload->parkee->uniqueid, pa_data->parkee_uuid)) {
705                 /* We are only concerned with the parkee we are subscribed for. */
706                 return;
707         }
708
709         if (!ast_strlen_zero(dial_string)) {
710                 announce_to_dial(dial_string, pa_data->announce_string, payload->parkingspace, payload->parkee);
711         }
712
713         *dial_string = '\0'; /* If we observe this dial string on a second pass, we don't want to do anything with it. */
714 }
715
716 int park_and_announce_app_exec(struct ast_channel *chan, const char *data)
717 {
718         struct ast_bridge_features chan_features;
719         char *parse;
720         int res;
721         int silence_announcements = 1;
722
723         struct stasis_subscription *parking_subscription;
724         struct park_announce_subscription_data *pa_data;
725
726         RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
727
728         AST_DECLARE_APP_ARGS(args,
729                 AST_APP_ARG(lot_name);
730                 AST_APP_ARG(options);
731                 AST_APP_ARG(announce_template);
732                 AST_APP_ARG(dial);
733                 AST_APP_ARG(others);/* Any remaining unused arguments */
734         );
735
736         if (ast_strlen_zero(data)) {
737                 ast_log(LOG_ERROR, "ParkAndAnnounce has required arguments. No arguments were provided.\n");
738                 return -1;
739         }
740
741         parse = ast_strdupa(data);
742         AST_STANDARD_APP_ARGS(args, parse);
743
744         if (ast_strlen_zero(args.announce_template)) {
745                 /* improperly configured arguments for the application */
746                 ast_log(LOG_ERROR, "ParkAndAnnounce requires the announce_template argument.\n");
747                 return -1;
748         }
749
750         if (ast_strlen_zero(args.dial)) {
751                 /* improperly configured arguments */
752                 ast_log(LOG_ERROR, "ParkAndAnnounce requires the dial argument.\n");
753                 return -1;
754         }
755
756         if (!strchr(args.dial, '/')) {
757                 ast_log(LOG_ERROR, "ParkAndAnnounce dial string '%s' is improperly formed.\n", args.dial);
758                 return -1;
759         }
760
761         /* Handle the common parking setup stuff */
762         if (!(parking_bridge = park_application_setup(chan, chan, data, &silence_announcements))) {
763                 return 0;
764         }
765
766         /* Initialize bridge features for the channel. */
767         res = ast_bridge_features_init(&chan_features);
768         if (res) {
769                 ast_bridge_features_cleanup(&chan_features);
770                 return -1;
771         }
772
773         /* subscribe to the parking message so that we can announce once it is parked */
774         pa_data = park_announce_subscription_data_create(ast_channel_uniqueid(chan), args.dial, args.announce_template);
775         if (!pa_data) {
776                 return -1;
777         }
778
779         if (!(parking_subscription = stasis_subscribe(ast_parking_topic(), park_announce_update_cb, pa_data))) {
780                 /* Failed to create subscription */
781                 park_announce_subscription_data_destroy(pa_data);
782                 return -1;
783         }
784
785         /* Now for the fun part... park it! */
786         ast_bridge_join(parking_bridge, chan, NULL, &chan_features, NULL, 0);
787
788         /* Toss the subscription since we aren't bridged at this point. */
789         stasis_unsubscribe(parking_subscription);
790
791         /*
792          * If the bridge was broken for a hangup that isn't real, then
793          * don't run the h extension, because the channel isn't really
794          * hung up.  This should only happen with AST_SOFTHANGUP_ASYNCGOTO.
795          */
796         res = -1;
797
798         ast_channel_lock(chan);
799         if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
800                 res = 0;
801         }
802         ast_channel_unlock(chan);
803
804         ast_bridge_features_cleanup(&chan_features);
805
806         return res;
807 }