Thu Apr 28 2011 17:15:22

Asterisk developer's documentation


func_env.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * See http://www.asterisk.org for more information about
00007  * the Asterisk project. Please do not directly contact
00008  * any of the maintainers of this project for assistance;
00009  * the project provides a web site, mailing lists and IRC
00010  * channels for your use.
00011  *
00012  * This program is free software, distributed under the terms of
00013  * the GNU General Public License Version 2. See the LICENSE file
00014  * at the top of the source tree.
00015  */
00016 
00017 /*! \file
00018  *
00019  * \brief Environment related dialplan functions
00020  * 
00021  * \ingroup functions
00022  */
00023 
00024 #include "asterisk.h"
00025 
00026 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 182278 $")
00027 
00028 #include <sys/stat.h>
00029 
00030 #include "asterisk/module.h"
00031 #include "asterisk/channel.h"
00032 #include "asterisk/pbx.h"
00033 #include "asterisk/utils.h"
00034 #include "asterisk/app.h"
00035 
00036 /*** DOCUMENTATION
00037    <function name="ENV" language="en_US">
00038       <synopsis>
00039          Gets or sets the environment variable specified.
00040       </synopsis>
00041       <syntax>
00042          <parameter name="varname" required="true">
00043             <para>Environment variable name</para>
00044          </parameter>
00045       </syntax>
00046       <description>
00047       </description>
00048    </function>
00049    <function name="STAT" language="en_US">
00050       <synopsis>
00051          Does a check on the specified file.
00052       </synopsis>
00053       <syntax>
00054          <parameter name="flag" required="true">
00055             <para>Flag may be one of the following:</para>
00056             <para>d - Checks if the file is a directory.</para>
00057             <para>e - Checks if the file exists.</para>
00058             <para>f - Checks if the file is a regular file.</para>
00059             <para>m - Returns the file mode (in octal)</para>
00060             <para>s - Returns the size (in bytes) of the file</para>
00061             <para>A - Returns the epoch at which the file was last accessed.</para>
00062             <para>C - Returns the epoch at which the inode was last changed.</para>
00063             <para>M - Returns the epoch at which the file was last modified.</para>
00064          </parameter>
00065          <parameter name="filename" required="true" />
00066       </syntax>
00067       <description>
00068       </description>
00069    </function>
00070    <function name="FILE" language="en_US">
00071       <synopsis>
00072          Obtains the contents of a file.
00073       </synopsis>
00074       <syntax>
00075          <parameter name="filename" required="true" />
00076          <parameter name="offset" required="true">
00077             <para>Maybe specified as any number. If negative, <replaceable>offset</replaceable> specifies the number
00078             of bytes back from the end of the file.</para>
00079          </parameter>
00080          <parameter name="length" required="true">
00081             <para>If specified, will limit the length of the data read to that size. If negative,
00082             trims <replaceable>length</replaceable> bytes from the end of the file.</para>
00083          </parameter>
00084       </syntax>
00085       <description>
00086       </description>
00087    </function>
00088  ***/
00089 
00090 static int env_read(struct ast_channel *chan, const char *cmd, char *data,
00091           char *buf, size_t len)
00092 {
00093    char *ret = NULL;
00094 
00095    *buf = '\0';
00096 
00097    if (data)
00098       ret = getenv(data);
00099 
00100    if (ret)
00101       ast_copy_string(buf, ret, len);
00102 
00103    return 0;
00104 }
00105 
00106 static int env_write(struct ast_channel *chan, const char *cmd, char *data,
00107            const char *value)
00108 {
00109    if (!ast_strlen_zero(data)) {
00110       if (!ast_strlen_zero(value)) {
00111          setenv(data, value, 1);
00112       } else {
00113          unsetenv(data);
00114       }
00115    }
00116 
00117    return 0;
00118 }
00119 
00120 static int stat_read(struct ast_channel *chan, const char *cmd, char *data,
00121            char *buf, size_t len)
00122 {
00123    char *action;
00124    struct stat s;
00125 
00126    ast_copy_string(buf, "0", len);
00127 
00128    action = strsep(&data, ",");
00129    if (stat(data, &s)) {
00130       return 0;
00131    } else {
00132       switch (*action) {
00133       case 'e':
00134          strcpy(buf, "1");
00135          break;
00136       case 's':
00137          snprintf(buf, len, "%d", (unsigned int) s.st_size);
00138          break;
00139       case 'f':
00140          snprintf(buf, len, "%d", S_ISREG(s.st_mode) ? 1 : 0);
00141          break;
00142       case 'd':
00143          snprintf(buf, len, "%d", S_ISDIR(s.st_mode) ? 1 : 0);
00144          break;
00145       case 'M':
00146          snprintf(buf, len, "%d", (int) s.st_mtime);
00147          break;
00148       case 'A':
00149          snprintf(buf, len, "%d", (int) s.st_mtime);
00150          break;
00151       case 'C':
00152          snprintf(buf, len, "%d", (int) s.st_ctime);
00153          break;
00154       case 'm':
00155          snprintf(buf, len, "%o", (int) s.st_mode);
00156          break;
00157       }
00158    }
00159 
00160    return 0;
00161 }
00162 
00163 static int file_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00164 {
00165    AST_DECLARE_APP_ARGS(args,
00166       AST_APP_ARG(filename);
00167       AST_APP_ARG(offset);
00168       AST_APP_ARG(length);
00169    );
00170    int offset = 0, length, res = 0;
00171    char *contents;
00172    size_t contents_len;
00173 
00174    AST_STANDARD_APP_ARGS(args, data);
00175    if (args.argc > 1) {
00176       offset = atoi(args.offset);
00177    }
00178 
00179    if (args.argc > 2) {
00180       /* The +1/-1 in this code section is to accomodate for the terminating NULL. */
00181       if ((length = atoi(args.length) + 1) > len) {
00182          ast_log(LOG_WARNING, "Length %d is greater than the max (%d).  Truncating output.\n", length - 1, (int)len - 1);
00183          length = len;
00184       }
00185    } else {
00186       length = len;
00187    }
00188 
00189    if (!(contents = ast_read_textfile(args.filename))) {
00190       return -1;
00191    }
00192 
00193    do {
00194       contents_len = strlen(contents);
00195       if (offset > contents_len) {
00196          res = -1;
00197          break;
00198       }
00199 
00200       if (offset >= 0) {
00201          if (length < 0) {
00202             if (contents_len - offset + length < 0) {
00203                /* Nothing left after trimming */
00204                res = -1;
00205                break;
00206             }
00207             ast_copy_string(buf, &contents[offset], contents_len + length);
00208          } else {
00209             ast_copy_string(buf, &contents[offset], length);
00210          }
00211       } else {
00212          if (offset * -1 > contents_len) {
00213             ast_log(LOG_WARNING, "Offset is larger than the file size.\n");
00214             offset = contents_len * -1;
00215          }
00216          ast_copy_string(buf, &contents[contents_len + offset], length);
00217       }
00218    } while (0);
00219 
00220    ast_free(contents);
00221 
00222    return res;
00223 }
00224 
00225 static struct ast_custom_function env_function = {
00226    .name = "ENV",
00227    .read = env_read,
00228    .write = env_write
00229 };
00230 
00231 static struct ast_custom_function stat_function = {
00232    .name = "STAT",
00233    .read = stat_read
00234 };
00235 
00236 static struct ast_custom_function file_function = {
00237    .name = "FILE",
00238    .read = file_read
00239    /*
00240     * Some enterprising programmer could probably add write functionality
00241     * to FILE(), although I'm not sure how useful it would be.  Hence why
00242     * it's called FILE and not READFILE (like the app was).
00243     */
00244 };
00245 
00246 static int unload_module(void)
00247 {
00248    int res = 0;
00249 
00250    res |= ast_custom_function_unregister(&env_function);
00251    res |= ast_custom_function_unregister(&stat_function);
00252    res |= ast_custom_function_unregister(&file_function);
00253 
00254    return res;
00255 }
00256 
00257 static int load_module(void)
00258 {
00259    int res = 0;
00260 
00261    res |= ast_custom_function_register(&env_function);
00262    res |= ast_custom_function_register(&stat_function);
00263    res |= ast_custom_function_register(&file_function);
00264 
00265    return res;
00266 }
00267 
00268 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Environment/filesystem dialplan functions");