Mon Oct 8 12:39:02 2012

Asterisk developer's documentation


func_realtime.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2005-2006, BJ Weschke. All rights reserved.
00005  *
00006  * BJ Weschke <bweschke@btwtech.com>
00007  *
00008  * This code is released by the author with no restrictions on usage.
00009  *
00010  * See http://www.asterisk.org for more information about
00011  * the Asterisk project. Please do not directly contact
00012  * any of the maintainers of this project for assistance;
00013  * the project provides a web site, mailing lists and IRC
00014  * channels for your use.
00015  *
00016  */
00017 
00018 /*** MODULEINFO
00019    <support_level>core</support_level>
00020  ***/
00021 
00022 /*! \file
00023  *
00024  * \brief REALTIME dialplan function
00025  *
00026  * \author BJ Weschke <bweschke@btwtech.com>
00027  *
00028  * \ingroup functions
00029  */
00030 
00031 #include "asterisk.h"
00032 
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369937 $")
00034 
00035 #include "asterisk/file.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/pbx.h"
00038 #include "asterisk/config.h"
00039 #include "asterisk/module.h"
00040 #include "asterisk/lock.h"
00041 #include "asterisk/utils.h"
00042 #include "asterisk/app.h"
00043 
00044 /*** DOCUMENTATION
00045    <function name="REALTIME" language="en_US">
00046       <synopsis>
00047          RealTime Read/Write Functions.
00048       </synopsis>
00049       <syntax>
00050          <parameter name="family" required="true" />
00051          <parameter name="fieldmatch" required="true" />
00052          <parameter name="matchvalue" />
00053          <parameter name="delim1|field">
00054             <para>Use <replaceable>delim1</replaceable> with <replaceable>delim2</replaceable> on
00055             read and <replaceable>field</replaceable> without <replaceable>delim2</replaceable> on
00056             write</para>
00057             <para>If we are reading and <replaceable>delim1</replaceable> is not specified, defaults
00058             to <literal>,</literal></para>
00059          </parameter>
00060          <parameter name="delim2">
00061             <para>Parameter only used when reading, if not specified defaults to <literal>=</literal></para>
00062          </parameter>
00063       </syntax>
00064       <description>
00065          <para>This function will read or write values from/to a RealTime repository.
00066          REALTIME(....) will read names/values from the repository, and
00067          REALTIME(....)= will write a new value/field to the repository. On a
00068          read, this function returns a delimited text string. The name/value
00069          pairs are delimited by <replaceable>delim1</replaceable>, and the name and value are delimited
00070          between each other with delim2.
00071          If there is no match, NULL will be returned by the function.
00072          On a write, this function will always return NULL.</para>
00073       </description>
00074       <see-also>
00075          <ref type="function">REALTIME_STORE</ref>
00076          <ref type="function">REALTIME_DESTROY</ref>
00077          <ref type="function">REALTIME_FIELD</ref>
00078          <ref type="function">REALTIME_HASH</ref>
00079       </see-also>
00080    </function>
00081    <function name="REALTIME_STORE" language="en_US">
00082       <synopsis>
00083          RealTime Store Function.
00084       </synopsis>
00085       <syntax>
00086          <parameter name="family" required="true" />
00087          <parameter name="field1" required="true" />
00088          <parameter name="fieldN" required="true" multiple="true" />
00089          <parameter name="field30" required="true" />
00090       </syntax>
00091       <description>
00092          <para>This function will insert a new set of values into the RealTime repository.
00093          If RT engine provides an unique ID of the stored record, REALTIME_STORE(...)=..
00094          creates channel variable named RTSTOREID, which contains value of unique ID.
00095          Currently, a maximum of 30 field/value pairs is supported.</para>
00096       </description>
00097       <see-also>
00098          <ref type="function">REALTIME</ref>
00099          <ref type="function">REALTIME_DESTROY</ref>
00100          <ref type="function">REALTIME_FIELD</ref>
00101          <ref type="function">REALTIME_HASH</ref>
00102       </see-also>
00103    </function>
00104    <function name="REALTIME_DESTROY" language="en_US">
00105       <synopsis>
00106          RealTime Destroy Function.
00107       </synopsis>
00108       <syntax>
00109          <parameter name="family" required="true" />
00110          <parameter name="fieldmatch" required="true" />
00111          <parameter name="matchvalue" />
00112          <parameter name="delim1" />
00113          <parameter name="delim2" />
00114       </syntax>
00115       <description>
00116          <para>This function acts in the same way as REALTIME(....) does, except that
00117          it destroys the matched record in the RT engine.</para>
00118       </description>
00119       <see-also>
00120          <ref type="function">REALTIME</ref>
00121          <ref type="function">REALTIME_STORE</ref>
00122          <ref type="function">REALTIME_FIELD</ref>
00123          <ref type="function">REALTIME_HASH</ref>
00124       </see-also>
00125    </function>
00126    <function name="REALTIME_FIELD" language="en_US">
00127       <synopsis>
00128          RealTime query function.
00129       </synopsis>
00130       <syntax>
00131          <parameter name="family" required="true" />
00132          <parameter name="fieldmatch" required="true" />
00133          <parameter name="matchvalue" required="true" />
00134          <parameter name="fieldname" required="true" />
00135       </syntax>
00136       <description>
00137          <para>This function retrieves a single item, <replaceable>fieldname</replaceable>
00138          from the RT engine, where <replaceable>fieldmatch</replaceable> contains the value
00139          <replaceable>matchvalue</replaceable>.  When written to, the REALTIME_FIELD() function
00140          performs identically to the REALTIME() function.</para>
00141       </description>
00142       <see-also>
00143          <ref type="function">REALTIME</ref>
00144          <ref type="function">REALTIME_STORE</ref>
00145          <ref type="function">REALTIME_DESTROY</ref>
00146          <ref type="function">REALTIME_HASH</ref>
00147       </see-also>
00148    </function>
00149    <function name="REALTIME_HASH" language="en_US">
00150       <synopsis>
00151          RealTime query function.
00152       </synopsis>
00153       <syntax>
00154          <parameter name="family" required="true" />
00155          <parameter name="fieldmatch" required="true" />
00156          <parameter name="matchvalue" required="true" />
00157       </syntax>
00158       <description>
00159          <para>This function retrieves a single record from the RT engine, where
00160          <replaceable>fieldmatch</replaceable> contains the value
00161          <replaceable>matchvalue</replaceable> and formats the output suitably, such that
00162          it can be assigned to the HASH() function.  The HASH() function then provides
00163          a suitable method for retrieving each field value of the record.</para>
00164       </description>
00165       <see-also>
00166          <ref type="function">REALTIME</ref>
00167          <ref type="function">REALTIME_STORE</ref>
00168          <ref type="function">REALTIME_DESTROY</ref>
00169          <ref type="function">REALTIME_FIELD</ref>
00170       </see-also>
00171    </function>
00172  ***/
00173 
00174 AST_THREADSTORAGE(buf1);
00175 AST_THREADSTORAGE(buf2);
00176 AST_THREADSTORAGE(buf3);
00177 
00178 static int function_realtime_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00179 {
00180    struct ast_variable *var, *head;
00181    struct ast_str *out;
00182    size_t resultslen;
00183    int n;
00184    AST_DECLARE_APP_ARGS(args,
00185       AST_APP_ARG(family);
00186       AST_APP_ARG(fieldmatch);
00187       AST_APP_ARG(value);
00188       AST_APP_ARG(delim1);
00189       AST_APP_ARG(delim2);
00190    );
00191 
00192    if (ast_strlen_zero(data)) {
00193       ast_log(LOG_WARNING, "Syntax: REALTIME(family,fieldmatch[,matchvalue[,delim1[,delim2]]]) - missing argument!\n");
00194       return -1;
00195    }
00196 
00197    AST_STANDARD_APP_ARGS(args, data);
00198 
00199    if (!args.delim1)
00200       args.delim1 = ",";
00201    if (!args.delim2)
00202       args.delim2 = "=";
00203 
00204    if (chan)
00205       ast_autoservice_start(chan);
00206 
00207    head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, SENTINEL);
00208 
00209    if (!head) {
00210       if (chan)
00211          ast_autoservice_stop(chan);
00212       return -1;
00213    }
00214 
00215    resultslen = 0;
00216    n = 0;
00217    for (var = head; var; n++, var = var->next)
00218       resultslen += strlen(var->name) + strlen(var->value);
00219    /* add space for delimiters and final '\0' */
00220    resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
00221 
00222    out = ast_str_alloca(resultslen);
00223    for (var = head; var; var = var->next)
00224       ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
00225    ast_copy_string(buf, ast_str_buffer(out), len);
00226 
00227    ast_variables_destroy(head);
00228 
00229    if (chan)
00230       ast_autoservice_stop(chan);
00231 
00232    return 0;
00233 }
00234 
00235 static int function_realtime_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00236 {
00237    int res = 0;
00238    AST_DECLARE_APP_ARGS(args,
00239       AST_APP_ARG(family);
00240       AST_APP_ARG(fieldmatch);
00241       AST_APP_ARG(value);
00242       AST_APP_ARG(field);
00243    );
00244 
00245    if (ast_strlen_zero(data)) {
00246       ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,matchvalue,updatecol) - missing argument!\n", cmd);
00247       return -1;
00248    }
00249 
00250    AST_STANDARD_APP_ARGS(args, data);
00251 
00252    if (ast_strlen_zero(args.fieldmatch) || ast_strlen_zero(args.field)) {
00253       ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,matchvalue,updatecol) - missing argument!\n", cmd);
00254       return -1;
00255    }
00256 
00257    if (chan) {
00258       ast_autoservice_start(chan);
00259    }
00260 
00261    res = ast_update_realtime(args.family, args.fieldmatch, args.value, args.field, (char *)value, SENTINEL);
00262 
00263    if (res < 0) {
00264       ast_log(LOG_WARNING, "Failed to update. Check the debug log for possible data repository related entries.\n");
00265    }
00266 
00267    if (chan) {
00268       ast_autoservice_stop(chan);
00269    }
00270 
00271    return res;
00272 }
00273 
00274 static int realtimefield_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00275 {
00276    struct ast_variable *var, *head;
00277    struct ast_str *escapebuf = ast_str_thread_get(&buf1, 16);
00278    struct ast_str *fields = ast_str_thread_get(&buf2, 16);
00279    struct ast_str *values = ast_str_thread_get(&buf3, 16);
00280    int first = 0;
00281    enum { rtfield, rthash } which;
00282    AST_DECLARE_APP_ARGS(args,
00283       AST_APP_ARG(family);
00284       AST_APP_ARG(fieldmatch);
00285       AST_APP_ARG(value);
00286       AST_APP_ARG(fieldname);
00287    );
00288 
00289    if (!strcmp(cmd, "REALTIME_FIELD")) {
00290       which = rtfield;
00291    } else {
00292       which = rthash;
00293    }
00294 
00295    if (ast_strlen_zero(data)) {
00296       ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,matchvalue%s) - missing argument!\n", cmd, which == rtfield ? ",fieldname" : "");
00297       return -1;
00298    }
00299 
00300    AST_STANDARD_APP_ARGS(args, data);
00301 
00302    if ((which == rtfield && args.argc != 4) || (which == rthash && args.argc != 3)) {
00303       ast_log(LOG_WARNING, "Syntax: %s(family,fieldmatch,matchvalue%s) - missing argument!\n", cmd, which == rtfield ? ",fieldname" : "");
00304       return -1;
00305    }
00306 
00307    if (chan) {
00308       ast_autoservice_start(chan);
00309    }
00310 
00311    if (!(head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, SENTINEL))) {
00312       if (chan) {
00313          ast_autoservice_stop(chan);
00314       }
00315       return -1;
00316    }
00317 
00318    ast_str_reset(fields);
00319    ast_str_reset(values);
00320 
00321    for (var = head; var; var = var->next) {
00322       if (which == rtfield) {
00323          ast_debug(1, "Comparing %s to %s\n", var->name, args.fieldname);
00324          if (!strcasecmp(var->name, args.fieldname)) {
00325             ast_debug(1, "Match! Value is %s\n", var->value);
00326             ast_copy_string(buf, var->value, len);
00327             break;
00328          }
00329       } else if (which == rthash) {
00330          ast_debug(1, "Setting hash key %s to value %s\n", var->name, var->value);
00331          ast_str_append(&fields, 0, "%s%s", first ? "" : ",", ast_str_set_escapecommas(&escapebuf, 0, var->name, INT_MAX));
00332          ast_str_append(&values, 0, "%s%s", first ? "" : ",", ast_str_set_escapecommas(&escapebuf, 0, var->value, INT_MAX));
00333          first = 0;
00334       }
00335    }
00336    ast_variables_destroy(head);
00337 
00338    if (which == rthash) {
00339       pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
00340       ast_copy_string(buf, ast_str_buffer(values), len);
00341    }
00342 
00343    if (chan) {
00344       ast_autoservice_stop(chan);
00345    }
00346 
00347    return 0;
00348 }
00349 
00350 static int function_realtime_store(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00351 {
00352    int res = 0;
00353    char storeid[32];
00354    char *valcopy;
00355    AST_DECLARE_APP_ARGS(a,
00356       AST_APP_ARG(family);
00357       AST_APP_ARG(f)[30]; /* fields */
00358    );
00359 
00360    AST_DECLARE_APP_ARGS(v,
00361       AST_APP_ARG(v)[30]; /* values */
00362    );
00363 
00364    if (ast_strlen_zero(data)) {
00365       ast_log(LOG_WARNING, "Syntax: REALTIME_STORE(family,field1,field2,...,field30) - missing argument!\n");
00366       return -1;
00367    }
00368 
00369    if (chan)
00370       ast_autoservice_start(chan);
00371 
00372    valcopy = ast_strdupa(value);
00373    AST_STANDARD_APP_ARGS(a, data);
00374    AST_STANDARD_APP_ARGS(v, valcopy);
00375 
00376    res = ast_store_realtime(a.family,
00377       a.f[0], v.v[0], a.f[1], v.v[1], a.f[2], v.v[2], a.f[3], v.v[3], a.f[4], v.v[4],
00378       a.f[5], v.v[5], a.f[6], v.v[6], a.f[7], v.v[7], a.f[8], v.v[8], a.f[9], v.v[9],
00379       a.f[10], v.v[10], a.f[11], v.v[11], a.f[12], v.v[12], a.f[13], v.v[13], a.f[14], v.v[14],
00380       a.f[15], v.v[15], a.f[16], v.v[16], a.f[17], v.v[17], a.f[18], v.v[18], a.f[19], v.v[19],
00381       a.f[20], v.v[20], a.f[21], v.v[21], a.f[22], v.v[22], a.f[23], v.v[23], a.f[24], v.v[24],
00382       a.f[25], v.v[25], a.f[26], v.v[26], a.f[27], v.v[27], a.f[28], v.v[28], a.f[29], v.v[29], SENTINEL
00383    );
00384 
00385    if (res < 0) {
00386       ast_log(LOG_WARNING, "Failed to store. Check the debug log for possible data repository related entries.\n");
00387    } else {
00388       snprintf(storeid, sizeof(storeid), "%d", res);
00389       pbx_builtin_setvar_helper(chan, "RTSTOREID", storeid);
00390    }
00391 
00392    if (chan)
00393       ast_autoservice_stop(chan);
00394 
00395    return 0;
00396 }
00397 
00398 static int function_realtime_readdestroy(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00399 {
00400    struct ast_variable *var, *head;
00401    struct ast_str *out;
00402    size_t resultslen;
00403    int n;
00404    AST_DECLARE_APP_ARGS(args,
00405       AST_APP_ARG(family);
00406       AST_APP_ARG(fieldmatch);
00407       AST_APP_ARG(value);
00408       AST_APP_ARG(delim1);
00409       AST_APP_ARG(delim2);
00410    );
00411 
00412    if (ast_strlen_zero(data)) {
00413       ast_log(LOG_WARNING, "Syntax: REALTIME_DESTROY(family,fieldmatch[,matchvalue[,delim1[,delim2]]]) - missing argument!\n");
00414       return -1;
00415    }
00416 
00417    AST_STANDARD_APP_ARGS(args, data);
00418 
00419    if (!args.delim1)
00420       args.delim1 = ",";
00421    if (!args.delim2)
00422       args.delim2 = "=";
00423 
00424    if (chan)
00425       ast_autoservice_start(chan);
00426 
00427    head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, SENTINEL);
00428 
00429    if (!head) {
00430       if (chan)
00431          ast_autoservice_stop(chan);
00432       return -1;
00433    }
00434 
00435    resultslen = 0;
00436    n = 0;
00437    for (var = head; var; n++, var = var->next)
00438       resultslen += strlen(var->name) + strlen(var->value);
00439    /* add space for delimiters and final '\0' */
00440    resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
00441 
00442    out = ast_str_alloca(resultslen);
00443    for (var = head; var; var = var->next) {
00444       ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
00445    }
00446    ast_copy_string(buf, ast_str_buffer(out), len);
00447 
00448    ast_destroy_realtime(args.family, args.fieldmatch, args.value, SENTINEL);
00449    ast_variables_destroy(head);
00450 
00451    if (chan)
00452       ast_autoservice_stop(chan);
00453 
00454    return 0;
00455 }
00456 
00457 static struct ast_custom_function realtime_function = {
00458    .name = "REALTIME",
00459    .read = function_realtime_read,
00460    .write = function_realtime_write,
00461 };
00462 
00463 static struct ast_custom_function realtimefield_function = {
00464    .name = "REALTIME_FIELD",
00465    .read = realtimefield_read,
00466    .write = function_realtime_write,
00467 };
00468 
00469 static struct ast_custom_function realtimehash_function = {
00470    .name = "REALTIME_HASH",
00471    .read = realtimefield_read,
00472 };
00473 
00474 static struct ast_custom_function realtime_store_function = {
00475    .name = "REALTIME_STORE",
00476    .write = function_realtime_store,
00477 };
00478 
00479 static struct ast_custom_function realtime_destroy_function = {
00480    .name = "REALTIME_DESTROY",
00481    .read = function_realtime_readdestroy,
00482 };
00483 
00484 static int unload_module(void)
00485 {
00486    int res = 0;
00487    res |= ast_custom_function_unregister(&realtime_function);
00488    res |= ast_custom_function_unregister(&realtime_store_function);
00489    res |= ast_custom_function_unregister(&realtime_destroy_function);
00490    res |= ast_custom_function_unregister(&realtimefield_function);
00491    res |= ast_custom_function_unregister(&realtimehash_function);
00492    return res;
00493 }
00494 
00495 static int load_module(void)
00496 {
00497    int res = 0;
00498    res |= ast_custom_function_register(&realtime_function);
00499    res |= ast_custom_function_register(&realtime_store_function);
00500    res |= ast_custom_function_register(&realtime_destroy_function);
00501    res |= ast_custom_function_register(&realtimefield_function);
00502    res |= ast_custom_function_register(&realtimehash_function);
00503    return res;
00504 }
00505 
00506 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read/Write/Store/Destroy values from a RealTime repository");

Generated on Mon Oct 8 12:39:02 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7