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