fixes some coding guideline issue
[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                         <para>Variables starting with <literal>AST_</literal> are reserved to the system and may not be set.</para>
48                 </description>
49         </function>
50         <function name="STAT" language="en_US">
51                 <synopsis>
52                         Does a check on the specified file.
53                 </synopsis>
54                 <syntax>
55                         <parameter name="flag" required="true">
56                                 <para>Flag may be one of the following:</para>
57                                 <para>d - Checks if the file is a directory.</para>
58                                 <para>e - Checks if the file exists.</para>
59                                 <para>f - Checks if the file is a regular file.</para>
60                                 <para>m - Returns the file mode (in octal)</para>
61                                 <para>s - Returns the size (in bytes) of the file</para>
62                                 <para>A - Returns the epoch at which the file was last accessed.</para>
63                                 <para>C - Returns the epoch at which the inode was last changed.</para>
64                                 <para>M - Returns the epoch at which the file was last modified.</para>
65                         </parameter>
66                         <parameter name="filename" required="true" />
67                 </syntax>
68                 <description>
69                 </description>
70         </function>
71         <function name="FILE" language="en_US">
72                 <synopsis>
73                         Obtains the contents of a file.
74                 </synopsis>
75                 <syntax>
76                         <parameter name="filename" required="true" />
77                         <parameter name="offset" required="true">
78                                 <para>Maybe specified as any number. If negative, <replaceable>offset</replaceable> specifies the number
79                                 of bytes back from the end of the file.</para>
80                         </parameter>
81                         <parameter name="length" required="true">
82                                 <para>If specified, will limit the length of the data read to that size. If negative,
83                                 trims <replaceable>length</replaceable> bytes from the end of the file.</para>
84                         </parameter>
85                 </syntax>
86                 <description>
87                 </description>
88         </function>
89  ***/
90
91 static int env_read(struct ast_channel *chan, const char *cmd, char *data,
92                     char *buf, size_t len)
93 {
94         char *ret = NULL;
95
96         *buf = '\0';
97
98         if (data)
99                 ret = getenv(data);
100
101         if (ret)
102                 ast_copy_string(buf, ret, len);
103
104         return 0;
105 }
106
107 static int env_write(struct ast_channel *chan, const char *cmd, char *data,
108                      const char *value)
109 {
110         if (!ast_strlen_zero(data) && strncmp(data, "AST_", 4)) {
111                 if (!ast_strlen_zero(value)) {
112                         setenv(data, value, 1);
113                 } else {
114                         unsetenv(data);
115                 }
116         }
117
118         return 0;
119 }
120
121 static int stat_read(struct ast_channel *chan, const char *cmd, char *data,
122                      char *buf, size_t len)
123 {
124         char *action;
125         struct stat s;
126
127         ast_copy_string(buf, "0", len);
128
129         action = strsep(&data, ",");
130         if (stat(data, &s)) {
131                 return 0;
132         } else {
133                 switch (*action) {
134                 case 'e':
135                         strcpy(buf, "1");
136                         break;
137                 case 's':
138                         snprintf(buf, len, "%d", (unsigned int) s.st_size);
139                         break;
140                 case 'f':
141                         snprintf(buf, len, "%d", S_ISREG(s.st_mode) ? 1 : 0);
142                         break;
143                 case 'd':
144                         snprintf(buf, len, "%d", S_ISDIR(s.st_mode) ? 1 : 0);
145                         break;
146                 case 'M':
147                         snprintf(buf, len, "%d", (int) s.st_mtime);
148                         break;
149                 case 'A':
150                         snprintf(buf, len, "%d", (int) s.st_mtime);
151                         break;
152                 case 'C':
153                         snprintf(buf, len, "%d", (int) s.st_ctime);
154                         break;
155                 case 'm':
156                         snprintf(buf, len, "%o", (int) s.st_mode);
157                         break;
158                 }
159         }
160
161         return 0;
162 }
163
164 static int file_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
165 {
166         AST_DECLARE_APP_ARGS(args,
167                 AST_APP_ARG(filename);
168                 AST_APP_ARG(offset);
169                 AST_APP_ARG(length);
170         );
171         int offset = 0, length, res = 0;
172         char *contents;
173         size_t contents_len;
174
175         AST_STANDARD_APP_ARGS(args, data);
176         if (args.argc > 1) {
177                 offset = atoi(args.offset);
178         }
179
180         if (args.argc > 2) {
181                 /* The +1/-1 in this code section is to accomodate for the terminating NULL. */
182                 if ((length = atoi(args.length) + 1) > len) {
183                         ast_log(LOG_WARNING, "Length %d is greater than the max (%d).  Truncating output.\n", length - 1, (int)len - 1);
184                         length = len;
185                 }
186         } else {
187                 length = len;
188         }
189
190         if (!(contents = ast_read_textfile(args.filename))) {
191                 return -1;
192         }
193
194         do {
195                 contents_len = strlen(contents);
196                 if (offset > contents_len) {
197                         res = -1;
198                         break;
199                 }
200
201                 if (offset >= 0) {
202                         if (length < 0) {
203                                 if (contents_len - offset + length < 0) {
204                                         /* Nothing left after trimming */
205                                         res = -1;
206                                         break;
207                                 }
208                                 ast_copy_string(buf, &contents[offset], contents_len + length);
209                         } else {
210                                 ast_copy_string(buf, &contents[offset], length);
211                         }
212                 } else {
213                         if (offset * -1 > contents_len) {
214                                 ast_log(LOG_WARNING, "Offset is larger than the file size.\n");
215                                 offset = contents_len * -1;
216                         }
217                         ast_copy_string(buf, &contents[contents_len + offset], length);
218                 }
219         } while (0);
220
221         ast_free(contents);
222
223         return res;
224 }
225
226 static struct ast_custom_function env_function = {
227         .name = "ENV",
228         .read = env_read,
229         .write = env_write
230 };
231
232 static struct ast_custom_function stat_function = {
233         .name = "STAT",
234         .read = stat_read,
235         .read_max = 12,
236 };
237
238 static struct ast_custom_function file_function = {
239         .name = "FILE",
240         .read = file_read
241         /*
242          * Some enterprising programmer could probably add write functionality
243          * to FILE(), although I'm not sure how useful it would be.  Hence why
244          * it's called FILE and not READFILE (like the app was).
245          */
246 };
247
248 static int unload_module(void)
249 {
250         int res = 0;
251
252         res |= ast_custom_function_unregister(&env_function);
253         res |= ast_custom_function_unregister(&stat_function);
254         res |= ast_custom_function_unregister(&file_function);
255
256         return res;
257 }
258
259 static int load_module(void)
260 {
261         int res = 0;
262
263         res |= ast_custom_function_register(&env_function);
264         res |= ast_custom_function_register(&stat_function);
265         res |= ast_custom_function_register(&file_function);
266
267         return res;
268 }
269
270 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Environment/filesystem dialplan functions");