merging the zap_and_dahdi_trunk branch up to trunk
[asterisk/asterisk.git] / apps / app_parkandannounce.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * Author: Ben Miller <bgmiller@dccinc.com>
9  *    With TONS of help from Mark!
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU General Public License Version 2. See the LICENSE file
19  * at the top of the source tree.
20  */
21
22 /*! \file
23  *
24  * \brief ParkAndAnnounce application for Asterisk
25  *
26  * \author Ben Miller <bgmiller@dccinc.com>
27  * \arg With TONS of help from Mark!
28  *
29  * \ingroup applications
30  */
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include "asterisk/file.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/module.h"
40 #include "asterisk/features.h"
41 #include "asterisk/say.h"
42 #include "asterisk/lock.h"
43 #include "asterisk/utils.h"
44 #include "asterisk/app.h"
45
46 static char *app = "ParkAndAnnounce";
47
48 static char *synopsis = "Park and Announce";
49
50 static char *descrip =
51 "  ParkAndAnnounce(announce:template,timeout,dial[,return_context]):\n"
52 "Park a call into the parkinglot and announce the call to another channel.\n"
53 "\n"
54 "announce template: Colon-separated list of files to announce.  The word PARKED\n"
55 "                   will be replaced by a say_digits of the extension in which\n"
56 "                   the call is parked.\n"
57 "timeout:           Time in seconds before the call returns into the return\n"
58 "                   context.\n"
59 "dial:              The app_dial style resource to call to make the\n"
60 "                   announcement.  Console/dsp calls the console.\n"
61 "return_context:    The goto-style label to jump the call back into after\n"
62 "                   timeout.  Default <priority+1>.\n"
63 "\n"
64 "The variable ${PARKEDAT} will contain the parking extension into which the\n"
65 "call was placed.  Use with the Local channel to allow the dialplan to make\n"
66 "use of this information.\n";
67
68
69 static int parkandannounce_exec(struct ast_channel *chan, void *data)
70 {
71         int res = -1;
72         int lot, timeout = 0, dres;
73         char *dialtech, *tmp[100], buf[13];
74         int looptemp, i;
75         char *s;
76
77         struct ast_channel *dchan;
78         struct outgoing_helper oh = { 0, };
79         int outstate;
80         AST_DECLARE_APP_ARGS(args,
81                 AST_APP_ARG(template);
82                 AST_APP_ARG(timeout);
83                 AST_APP_ARG(dial);
84                 AST_APP_ARG(return_context);
85         );
86         if (ast_strlen_zero(data)) {
87                 ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce:template|timeout|dial|[return_context])\n");
88                 return -1;
89         }
90   
91         s = ast_strdupa(data);
92         AST_STANDARD_APP_ARGS(args, s);
93
94         if (args.timeout)
95                 timeout = atoi(args.timeout) * 1000;
96
97         if (ast_strlen_zero(args.dial)) {
98                 ast_log(LOG_WARNING, "PARK: A dial resource must be specified i.e: Console/dsp or Zap/g1/5551212\n");
99                 return -1;
100         }
101
102         dialtech = strsep(&args.dial, "/");
103         ast_verb(3, "Dial Tech,String: (%s,%s)\n", dialtech, args.dial);
104
105         if (!ast_strlen_zero(args.return_context))
106                 ast_parseable_goto(chan, args.return_context);
107
108         ast_verb(3, "Return Context: (%s,%s,%d) ID: %s\n", chan->context, chan->exten, chan->priority, chan->cid.cid_num);
109                 if (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
110                 ast_verb(3, "Warning: Return Context Invalid, call will return to default|s\n");
111                 }
112
113         /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
114         before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
115
116         res = ast_masq_park_call(chan, NULL, timeout, &lot);
117         if (res == -1)
118                 return res;
119
120         ast_verb(3, "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, args.return_context);
121
122         /* Now place the call to the extension */
123
124         snprintf(buf, sizeof(buf), "%d", lot);
125         oh.parent_channel = chan;
126         oh.vars = ast_variable_new("_PARKEDAT", buf, "");
127         dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, args.dial, 30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh);
128
129         if (dchan) {
130                 if (dchan->_state == AST_STATE_UP) {
131                         ast_verb(4, "Channel %s was answered.\n", dchan->name);
132                 } else {
133                         ast_verb(4, "Channel %s was never answered.\n", dchan->name);
134                         ast_log(LOG_WARNING, "PARK: Channel %s was never answered for the announce.\n", dchan->name);
135                         ast_hangup(dchan);
136                         return -1;
137                 }
138         } else {
139                 ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
140                 return -1; 
141         }
142
143         ast_stopstream(dchan);
144
145         /* now we have the call placed and are ready to play stuff to it */
146
147         ast_verb(4, "Announce Template:%s\n", args.template);
148
149         for (looptemp = 0; looptemp < ARRAY_LEN(tmp); looptemp++) {
150                 if ((tmp[looptemp] = strsep(&args.template, ":")) != NULL)
151                         continue;
152                 else
153                         break;
154         }
155
156         for (i = 0; i < looptemp; i++) {
157                 ast_verb(4, "Announce:%s\n", tmp[i]);
158                 if (!strcmp(tmp[i], "PARKED")) {
159                         ast_say_digits(dchan, lot, "", dchan->language);
160                 } else {
161                         dres = ast_streamfile(dchan, tmp[i], dchan->language);
162                         if (!dres) {
163                                 dres = ast_waitstream(dchan, "");
164                         } else {
165                                 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], dchan->name);
166                                 dres = 0;
167                         }
168                 }
169         }
170
171         ast_stopstream(dchan);  
172         ast_hangup(dchan);
173         
174         return res;
175 }
176
177 static int unload_module(void)
178 {
179         return ast_unregister_application(app);
180 }
181
182 static int load_module(void)
183 {
184         /* return ast_register_application(app, park_exec); */
185         return ast_register_application(app, parkandannounce_exec, synopsis, descrip);
186 }
187
188 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Parking and Announce Application");