Mostly cleanup of documentation to substitute the pipe with the comma, but a few...
[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 <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41
42 #include "asterisk/file.h"
43 #include "asterisk/logger.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/pbx.h"
46 #include "asterisk/module.h"
47 #include "asterisk/features.h"
48 #include "asterisk/options.h"
49 #include "asterisk/logger.h"
50 #include "asterisk/say.h"
51 #include "asterisk/lock.h"
52 #include "asterisk/utils.h"
53 #include "asterisk/app.h"
54
55 static char *app = "ParkAndAnnounce";
56
57 static char *synopsis = "Park and Announce";
58
59 static char *descrip =
60 "  ParkAndAnnounce(announce:template,timeout,dial[,return_context]):\n"
61 "Park a call into the parkinglot and announce the call to another channel.\n"
62 "\n"
63 "announce template: Colon-separated list of files to announce.  The word PARKED\n"
64 "                   will be replaced by a say_digits of the extension in which\n"
65 "                   the call is parked.\n"
66 "timeout:           Time in seconds before the call returns into the return\n"
67 "                   context.\n"
68 "dial:              The app_dial style resource to call to make the\n"
69 "                   announcement.  Console/dsp calls the console.\n"
70 "return_context:    The goto-style label to jump the call back into after\n"
71 "                   timeout.  Default <priority+1>.\n"
72 "\n"
73 "The variable ${PARKEDAT} will contain the parking extension into which the\n"
74 "call was placed.  Use with the Local channel to allow the dialplan to make\n"
75 "use of this information.\n";
76
77
78 static int parkandannounce_exec(struct ast_channel *chan, void *data)
79 {
80         int res = -1;
81         int lot, timeout = 0, dres;
82         char *dialtech, *tmp[100], buf[13];
83         int looptemp, i;
84         char *s;
85
86         struct ast_channel *dchan;
87         struct outgoing_helper oh = { 0, };
88         int outstate;
89         AST_DECLARE_APP_ARGS(args,
90                 AST_APP_ARG(template);
91                 AST_APP_ARG(timeout);
92                 AST_APP_ARG(dial);
93                 AST_APP_ARG(return_context);
94         );
95         if (ast_strlen_zero(data)) {
96                 ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce:template|timeout|dial|[return_context])\n");
97                 return -1;
98         }
99   
100         s = ast_strdupa(data);
101         AST_STANDARD_APP_ARGS(args, s);
102
103         if (args.timeout)
104                 timeout = atoi(args.timeout) * 1000;
105
106         if (ast_strlen_zero(args.dial)) {
107                 ast_log(LOG_WARNING, "PARK: A dial resource must be specified i.e: Console/dsp or Zap/g1/5551212\n");
108                 return -1;
109         }
110
111         dialtech = strsep(&args.dial, "/");
112         ast_verb(3, "Dial Tech,String: (%s,%s)\n", dialtech, args.dial);
113
114         if (!ast_strlen_zero(args.return_context))
115                 ast_parseable_goto(chan, args.return_context);
116
117         ast_verb(3, "Return Context: (%s,%s,%d) ID: %s\n", chan->context, chan->exten, chan->priority, chan->cid.cid_num);
118                 if (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
119                 ast_verb(3, "Warning: Return Context Invalid, call will return to default|s\n");
120                 }
121
122         /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
123         before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
124
125         ast_masq_park_call(chan, NULL, timeout, &lot);
126
127         ast_verb(3, "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, args.return_context);
128
129         /* Now place the call to the extension */
130
131         snprintf(buf, sizeof(buf), "%d", lot);
132         oh.parent_channel = chan;
133         oh.vars = ast_variable_new("_PARKEDAT", buf);
134         dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, args.dial, 30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh);
135
136         if (dchan) {
137                 if (dchan->_state == AST_STATE_UP) {
138                         ast_verb(4, "Channel %s was answered.\n", dchan->name);
139                 } else {
140                         ast_verb(4, "Channel %s was never answered.\n", dchan->name);
141                                 ast_log(LOG_WARNING, "PARK: Channel %s was never answered for the announce.\n", dchan->name);
142                         ast_hangup(dchan);
143                         return -1;
144                 }
145         } else {
146                 ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
147                 return -1; 
148         }
149
150         ast_stopstream(dchan);
151
152         /* now we have the call placed and are ready to play stuff to it */
153
154         ast_verb(4, "Announce Template:%s\n", args.template);
155
156         for (looptemp = 0, tmp[looptemp++] = strsep(&args.template, ":");
157                  looptemp < sizeof(tmp) / sizeof(tmp[0]);
158                  tmp[looptemp++] = strsep(&args.template, ":"));
159
160         for (i = 0; i < looptemp; i++) {
161                 ast_verb(4, "Announce:%s\n", tmp[i]);
162                 if (!strcmp(tmp[i], "PARKED")) {
163                         ast_say_digits(dchan, lot, "", dchan->language);
164                 } else {
165                         dres = ast_streamfile(dchan, tmp[i], dchan->language);
166                         if (!dres) {
167                                 dres = ast_waitstream(dchan, "");
168                         } else {
169                                 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], dchan->name);
170                                 dres = 0;
171                         }
172                 }
173         }
174
175         ast_stopstream(dchan);  
176         ast_hangup(dchan);
177         
178         return res;
179 }
180
181 static int unload_module(void)
182 {
183         return ast_unregister_application(app);
184 }
185
186 static int load_module(void)
187 {
188         /* return ast_register_application(app, park_exec); */
189         return ast_register_application(app, parkandannounce_exec, synopsis, descrip);
190 }
191
192 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Parking and Announce Application");