Merge str_substitution branch.
[asterisk/asterisk.git] / funcs / func_timeout.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  * 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 Channel timeout related dialplan functions
22  *
23  * \author Mark Spencer <markster@digium.com> 
24  * \ingroup functions
25  */
26
27 #include "asterisk.h"
28
29 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30
31 #include "asterisk/module.h"
32 #include "asterisk/channel.h"
33 #include "asterisk/pbx.h"
34 #include "asterisk/utils.h"
35 #include "asterisk/app.h"
36
37 /*** DOCUMENTATION
38         <function name="TIMEOUT" language="en_US">
39                 <synopsis>
40                         Gets or sets timeouts on the channel. Timeout values are in seconds.
41                 </synopsis>
42                 <syntax>
43                         <parameter name="timeouttype" required="true">
44                                 <para>The timeout that will be manipulated. The possible timeout types
45                                 are: <literal>absolute</literal>, <literal>digit</literal> or 
46                                 <literal>response</literal></para>
47                         </parameter>
48                 </syntax>
49                 <description>
50                         <para>The timeouts that can be manipulated are:</para>
51                         <para><literal>absolute</literal>: The absolute maximum amount of time permitted for a call.
52                         Setting of 0 disables the timeout.</para>
53                         <para><literal>digit</literal>: The maximum amount of time permitted between digits when the
54                         user is typing in an extension.  When this timeout expires,
55                         after the user has started to type in an extension, the
56                         extension will be considered complete, and will be
57                         interpreted.  Note that if an extension typed in is valid,
58                         it will not have to timeout to be tested, so typically at
59                         the expiry of this timeout, the extension will be considered
60                         invalid (and thus control would be passed to the <literal>i</literal>
61                         extension, or if it doesn't exist the call would be
62                         terminated).  The default timeout is 5 seconds.</para>
63                         <para><literal>response</literal>: The maximum amount of time permitted after falling through a
64                         series of priorities for a channel in which the user may
65                         begin typing an extension.  If the user does not type an
66                         extension in this amount of time, control will pass to the
67                         <literal>t</literal> extension if it exists, and if not the call would be
68                         terminated.  The default timeout is 10 seconds.</para>
69                 </description>
70         </function>
71  ***/
72
73 static int timeout_read(struct ast_channel *chan, const char *cmd, char *data,
74                         char *buf, size_t len)
75 {
76         struct timeval myt;
77
78         if (!chan)
79                 return -1;
80
81         if (!data) {
82                 ast_log(LOG_ERROR, "Must specify type of timeout to get.\n");
83                 return -1;
84         }
85
86         switch (*data) {
87         case 'a':
88         case 'A':
89                 if (ast_tvzero(chan->whentohangup)) {
90                         ast_copy_string(buf, "0", len);
91                 } else {
92                         myt = ast_tvnow();
93                         snprintf(buf, len, "%.3f", ast_tvdiff_ms(myt, chan->whentohangup) / 1000.0);
94                 }
95                 break;
96
97         case 'r':
98         case 'R':
99                 if (chan->pbx) {
100                         snprintf(buf, len, "%.3f", chan->pbx->rtimeoutms / 1000.0);
101                 }
102                 break;
103
104         case 'd':
105         case 'D':
106                 if (chan->pbx) {
107                         snprintf(buf, len, "%.3f", chan->pbx->dtimeoutms / 1000.0);
108                 }
109                 break;
110
111         default:
112                 ast_log(LOG_ERROR, "Unknown timeout type specified.\n");
113                 return -1;
114         }
115
116         return 0;
117 }
118
119 static int timeout_write(struct ast_channel *chan, const char *cmd, char *data,
120                          const char *value)
121 {
122         double x = 0.0;
123         long sec = 0L;
124         char timestr[64];
125         struct ast_tm myt;
126         struct timeval when = {0,};
127         int res;
128
129         if (!chan)
130                 return -1;
131
132         if (!data) {
133                 ast_log(LOG_ERROR, "Must specify type of timeout to set.\n");
134                 return -1;
135         }
136
137         if (!value)
138                 return -1;
139
140         res = sscanf(value, "%ld%lf", &sec, &x);
141         if (res == 0 || sec < 0) {
142                 when.tv_sec = 0;
143                 when.tv_usec = 0;
144         } else if (res == 1) {
145                 when.tv_sec = sec;
146         } else if (res == 2) {
147                 when.tv_sec = sec;
148                 when.tv_usec = x * 1000000;
149         }
150
151         switch (*data) {
152         case 'a':
153         case 'A':
154                 ast_channel_setwhentohangup_tv(chan, when);
155                 if (VERBOSITY_ATLEAST(3)) {
156                         if (!ast_tvzero(chan->whentohangup)) {
157                                 when = ast_tvadd(when, ast_tvnow());
158                                 ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S.%3q %Z",
159                                         ast_localtime(&when, &myt, NULL));
160                                 ast_verbose("Channel will hangup at %s.\n", timestr);
161                         } else {
162                                 ast_verbose("Channel hangup cancelled.\n");
163                         }
164                 }
165                 break;
166
167         case 'r':
168         case 'R':
169                 if (chan->pbx) {
170                         chan->pbx->rtimeoutms = when.tv_sec * 1000 + when.tv_usec / 1000.0;
171                         ast_verb(3, "Response timeout set to %.3f\n", chan->pbx->rtimeoutms / 1000.0);
172                 }
173                 break;
174
175         case 'd':
176         case 'D':
177                 if (chan->pbx) {
178                         chan->pbx->dtimeoutms = when.tv_sec * 1000 + when.tv_usec / 1000.0;
179                         ast_verb(3, "Digit timeout set to %.3f\n", chan->pbx->dtimeoutms / 1000.0);
180                 }
181                 break;
182
183         default:
184                 ast_log(LOG_ERROR, "Unknown timeout type specified.\n");
185                 break;
186         }
187
188         return 0;
189 }
190
191 static struct ast_custom_function timeout_function = {
192         .name = "TIMEOUT",
193         .read = timeout_read,
194         .read_max = 22,
195         .write = timeout_write,
196 };
197
198 static int unload_module(void)
199 {
200         return ast_custom_function_unregister(&timeout_function);
201 }
202
203 static int load_module(void)
204 {
205         return ast_custom_function_register(&timeout_function);
206 }
207
208 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel timeout dialplan functions");