SIP channel name uniqueness
[asterisk/asterisk.git] / funcs / func_env.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16
17 /*! \file
18  *
19  * \brief Environment related dialplan functions
20  * 
21  * \ingroup functions
22  */
23
24 #include "asterisk.h"
25
26 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
27
28 #include <sys/stat.h>
29
30 #include "asterisk/module.h"
31 #include "asterisk/channel.h"
32 #include "asterisk/pbx.h"
33 #include "asterisk/utils.h"
34 #include "asterisk/app.h"
35
36 /*** DOCUMENTATION
37         <function name="ENV" language="en_US">
38                 <synopsis>
39                         Gets or sets the environment variable specified.
40                 </synopsis>
41                 <syntax>
42                         <parameter name="varname" required="true">
43                                 <para>Environment variable name</para>
44                         </parameter>
45                 </syntax>
46                 <description>
47                 </description>
48         </function>
49         <function name="STAT" language="en_US">
50                 <synopsis>
51                         Does a check on the specified file.
52                 </synopsis>
53                 <syntax>
54                         <parameter name="flag" required="true">
55                                 <para>Flag may be one of the following:</para>
56                                 <para>d - Checks if the file is a directory.</para>
57                                 <para>e - Checks if the file exists.</para>
58                                 <para>f - Checks if the file is a regular file.</para>
59                                 <para>m - Returns the file mode (in octal)</para>
60                                 <para>s - Returns the size (in bytes) of the file</para>
61                                 <para>A - Returns the epoch at which the file was last accessed.</para>
62                                 <para>C - Returns the epoch at which the inode was last changed.</para>
63                                 <para>M - Returns the epoch at which the file was last modified.</para>
64                         </parameter>
65                         <parameter name="filename" required="true" />
66                 </syntax>
67                 <description>
68                 </description>
69         </function>
70         <function name="FILE" language="en_US">
71                 <synopsis>
72                         Obtains the contents of a file.
73                 </synopsis>
74                 <syntax>
75                         <parameter name="filename" required="true" />
76                         <parameter name="offset" required="true">
77                                 <para>Maybe specified as any number. If negative, <replaceable>offset</replaceable> specifies the number
78                                 of bytes back from the end of the file.</para>
79                         </parameter>
80                         <parameter name="length" required="true">
81                                 <para>If specified, will limit the length of the data read to that size. If negative,
82                                 trims <replaceable>length</replaceable> bytes from the end of the file.</para>
83                         </parameter>
84                 </syntax>
85                 <description>
86                 </description>
87         </function>
88  ***/
89
90 static int env_read(struct ast_channel *chan, const char *cmd, char *data,
91                     char *buf, size_t len)
92 {
93         char *ret = NULL;
94
95         *buf = '\0';
96
97         if (data)
98                 ret = getenv(data);
99
100         if (ret)
101                 ast_copy_string(buf, ret, len);
102
103         return 0;
104 }
105
106 static int env_write(struct ast_channel *chan, const char *cmd, char *data,
107                      const char *value)
108 {
109         if (!ast_strlen_zero(data)) {
110                 if (!ast_strlen_zero(value)) {
111                         setenv(data, value, 1);
112                 } else {
113                         unsetenv(data);
114                 }
115         }
116
117         return 0;
118 }
119
120 static int stat_read(struct ast_channel *chan, const char *cmd, char *data,
121                      char *buf, size_t len)
122 {
123         char *action;
124         struct stat s;
125
126         ast_copy_string(buf, "0", len);
127
128         action = strsep(&data, ",");
129         if (stat(data, &s)) {
130                 return 0;
131         } else {
132                 switch (*action) {
133                 case 'e':
134                         strcpy(buf, "1");
135                         break;
136                 case 's':
137                         snprintf(buf, len, "%d", (unsigned int) s.st_size);
138                         break;
139                 case 'f':
140                         snprintf(buf, len, "%d", S_ISREG(s.st_mode) ? 1 : 0);
141                         break;
142                 case 'd':
143                         snprintf(buf, len, "%d", S_ISDIR(s.st_mode) ? 1 : 0);
144                         break;
145                 case 'M':
146                         snprintf(buf, len, "%d", (int) s.st_mtime);
147                         break;
148                 case 'A':
149                         snprintf(buf, len, "%d", (int) s.st_mtime);
150                         break;
151                 case 'C':
152                         snprintf(buf, len, "%d", (int) s.st_ctime);
153                         break;
154                 case 'm':
155                         snprintf(buf, len, "%o", (int) s.st_mode);
156                         break;
157                 }
158         }
159
160         return 0;
161 }
162
163 static int file_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
164 {
165         AST_DECLARE_APP_ARGS(args,
166                 AST_APP_ARG(filename);
167                 AST_APP_ARG(offset);
168                 AST_APP_ARG(length);
169         );
170         int offset = 0, length, res = 0;
171         char *contents;
172         size_t contents_len;
173
174         AST_STANDARD_APP_ARGS(args, data);
175         if (args.argc > 1) {
176                 offset = atoi(args.offset);
177         }
178
179         if (args.argc > 2) {
180                 /* The +1/-1 in this code section is to accomodate for the terminating NULL. */
181                 if ((length = atoi(args.length) + 1) > len) {
182                         ast_log(LOG_WARNING, "Length %d is greater than the max (%d).  Truncating output.\n", length - 1, (int)len - 1);
183                         length = len;
184                 }
185         } else {
186                 length = len;
187         }
188
189         if (!(contents = ast_read_textfile(args.filename))) {
190                 return -1;
191         }
192
193         do {
194                 contents_len = strlen(contents);
195                 if (offset > contents_len) {
196                         res = -1;
197                         break;
198                 }
199
200                 if (offset >= 0) {
201                         if (length < 0) {
202                                 if (contents_len - offset + length < 0) {
203                                         /* Nothing left after trimming */
204                                         res = -1;
205                                         break;
206                                 }
207                                 ast_copy_string(buf, &contents[offset], contents_len + length);
208                         } else {
209                                 ast_copy_string(buf, &contents[offset], length);
210                         }
211                 } else {
212                         if (offset * -1 > contents_len) {
213                                 ast_log(LOG_WARNING, "Offset is larger than the file size.\n");
214                                 offset = contents_len * -1;
215                         }
216                         ast_copy_string(buf, &contents[contents_len + offset], length);
217                 }
218         } while (0);
219
220         ast_free(contents);
221
222         return res;
223 }
224
225 static struct ast_custom_function env_function = {
226         .name = "ENV",
227         .read = env_read,
228         .write = env_write
229 };
230
231 static struct ast_custom_function stat_function = {
232         .name = "STAT",
233         .read = stat_read,
234         .read_max = 12,
235 };
236
237 static struct ast_custom_function file_function = {
238         .name = "FILE",
239         .read = file_read
240         /*
241          * Some enterprising programmer could probably add write functionality
242          * to FILE(), although I'm not sure how useful it would be.  Hence why
243          * it's called FILE and not READFILE (like the app was).
244          */
245 };
246
247 static int unload_module(void)
248 {
249         int res = 0;
250
251         res |= ast_custom_function_unregister(&env_function);
252         res |= ast_custom_function_unregister(&stat_function);
253         res |= ast_custom_function_unregister(&file_function);
254
255         return res;
256 }
257
258 static int load_module(void)
259 {
260         int res = 0;
261
262         res |= ast_custom_function_register(&env_function);
263         res |= ast_custom_function_register(&stat_function);
264         res |= ast_custom_function_register(&file_function);
265
266         return res;
267 }
268
269 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Environment/filesystem dialplan functions");