func_enum.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  * Oleksiy Krivoshey <oleksiyk@gmail.com>
00008  * Russell Bryant <russelb@clemson.edu>
00009  * Brett Bryant <bbryant@digium.com>
00010  *
00011  * See http://www.asterisk.org for more information about
00012  * the Asterisk project. Please do not directly contact
00013  * any of the maintainers of this project for assistance;
00014  * the project provides a web site, mailing lists and IRC
00015  * channels for your use.
00016  *
00017  * This program is free software, distributed under the terms of
00018  * the GNU General Public License Version 2. See the LICENSE file
00019  * at the top of the source tree.
00020  */
00021 
00022 /*! \file
00023  *
00024  * \brief ENUM Functions
00025  *
00026  * \author Mark Spencer <markster@digium.com>
00027  * \author Oleksiy Krivoshey <oleksiyk@gmail.com>
00028  * \author Russell Bryant <russelb@clemson.edu>
00029  * \author Brett Bryant <bbryant@digium.com>
00030  *
00031  * \arg See also AstENUM
00032  *
00033  * \ingroup functions
00034  */
00035 
00036 /*** MODULEINFO
00037    <support_level>core</support_level>
00038  ***/
00039 
00040 #include "asterisk.h"
00041 
00042 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 331201 $")
00043 
00044 #include "asterisk/module.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/pbx.h"
00047 #include "asterisk/utils.h"
00048 #include "asterisk/lock.h"
00049 #include "asterisk/file.h"
00050 #include "asterisk/enum.h"
00051 #include "asterisk/app.h"
00052 
00053 /*** DOCUMENTATION
00054    <function name="ENUMQUERY" language="en_US">
00055       <synopsis>
00056          Initiate an ENUM query.
00057       </synopsis>
00058       <syntax>
00059          <parameter name="number" required="true" />
00060          <parameter name="method-type">
00061             <para>If no <replaceable>method-type</replaceable> is given, the default will be
00062             <literal>sip</literal>.</para>
00063          </parameter>
00064          <parameter name="zone-suffix">
00065             <para>If no <replaceable>zone-suffix</replaceable> is given, the default will be
00066             <literal>e164.arpa</literal></para>
00067          </parameter>
00068       </syntax>
00069       <description>
00070          <para>This will do a ENUM lookup of the given phone number.</para>
00071       </description>
00072    </function>
00073    <function name="ENUMRESULT" language="en_US">
00074       <synopsis>
00075          Retrieve results from a ENUMQUERY.
00076       </synopsis>
00077       <syntax>
00078          <parameter name="id" required="true">
00079             <para>The identifier returned by the ENUMQUERY function.</para>
00080          </parameter>
00081          <parameter name="resultnum" required="true">
00082             <para>The number of the result that you want to retrieve.</para>
00083             <para>Results start at <literal>1</literal>. If this argument is specified
00084             as <literal>getnum</literal>, then it will return the total number of results 
00085             that are available or -1 on error.</para>
00086          </parameter>
00087       </syntax>
00088       <description>
00089          <para>This function will retrieve results from a previous use
00090          of the ENUMQUERY function.</para>
00091       </description>
00092    </function> 
00093    <function name="ENUMLOOKUP" language="en_US">
00094       <synopsis>
00095          General or specific querying of NAPTR records for ENUM or ENUM-like DNS pointers.
00096       </synopsis>
00097       <syntax>
00098          <parameter name="number" required="true" />
00099          <parameter name="method-type">
00100             <para>If no <replaceable>method-type</replaceable> is given, the default will be
00101                                 <literal>sip</literal>.</para>
00102          </parameter>
00103          <parameter name="options">
00104             <optionlist>
00105                <option name="c">
00106                   <para>Returns an integer count of the number of NAPTRs of a certain RR type.</para>
00107                   <para>Combination of <literal>c</literal> and Method-type of <literal>ALL</literal> will
00108                   return a count of all NAPTRs for the record or -1 on error.</para>
00109                </option>
00110                <option name="u">
00111                   <para>Returns the full URI and does not strip off the URI-scheme.</para>
00112                </option>
00113                <option name="s">
00114                   <para>Triggers ISN specific rewriting.</para>
00115                </option>
00116                <option name="i">
00117                   <para>Looks for branches into an Infrastructure ENUM tree.</para>
00118                </option>
00119                <option name="d">
00120                   <para>for a direct DNS lookup without any flipping of digits.</para>
00121                </option>
00122             </optionlist>  
00123          </parameter>
00124          <parameter name="record#">
00125             <para>If no <replaceable>record#</replaceable> is given, 
00126             defaults to <literal>1</literal>.</para>
00127          </parameter>
00128          <parameter name="zone-suffix">
00129             <para>If no <replaceable>zone-suffix</replaceable> is given, the default will be
00130             <literal>e164.arpa</literal></para>
00131          </parameter>
00132       </syntax>
00133       <description>
00134          <para>For more information see <filename>doc/AST.pdf</filename>.</para>
00135       </description>
00136    </function>
00137    <function name="TXTCIDNAME" language="en_US">
00138       <synopsis>
00139          TXTCIDNAME looks up a caller name via DNS.
00140       </synopsis>
00141       <syntax>
00142          <parameter name="number" required="true" />
00143          <parameter name="zone-suffix">
00144             <para>If no <replaceable>zone-suffix</replaceable> is given, the default will be
00145             <literal>e164.arpa</literal></para>
00146          </parameter>
00147       </syntax>
00148       <description>
00149          <para>This function looks up the given phone number in DNS to retrieve
00150          the caller id name.  The result will either be blank or be the value
00151          found in the TXT record in DNS.</para>
00152       </description>
00153    </function>
00154  ***/
00155 
00156 static char *synopsis = "Syntax: ENUMLOOKUP(number[,Method-type[,options[,record#[,zone-suffix]]]])\n";
00157 
00158 static int function_enum(struct ast_channel *chan, const char *cmd, char *data,
00159           char *buf, size_t len)
00160 {
00161    AST_DECLARE_APP_ARGS(args,
00162       AST_APP_ARG(number);
00163       AST_APP_ARG(tech);
00164       AST_APP_ARG(options);
00165       AST_APP_ARG(record);
00166       AST_APP_ARG(zone);
00167    );
00168    char tech[80];
00169    char dest[256] = "", tmp[2] = "", num[AST_MAX_EXTENSION] = "";
00170    char *s, *p;
00171    unsigned int record = 1;
00172 
00173    buf[0] = '\0';
00174 
00175    if (ast_strlen_zero(data)) {
00176       ast_log(LOG_WARNING, "%s", synopsis);
00177       return -1;
00178    }
00179 
00180    AST_STANDARD_APP_ARGS(args, data);
00181 
00182    if (args.argc < 1) {
00183       ast_log(LOG_WARNING, "%s", synopsis);
00184       return -1;
00185    }
00186 
00187    if (args.tech && !ast_strlen_zero(args.tech)) {
00188       ast_copy_string(tech,args.tech, sizeof(tech));
00189    } else {
00190       ast_copy_string(tech,"sip",sizeof(tech));
00191    }
00192 
00193    if (!args.zone) {
00194       args.zone = "e164.arpa";
00195    }
00196    if (!args.options) {
00197       args.options = "";
00198    }
00199    if (args.record) {
00200       record = atoi(args.record) ? atoi(args.record) : record;
00201    }
00202 
00203    /* strip any '-' signs from number */
00204    for (s = p = args.number; *s; s++) {
00205       if (*s != '-') {
00206          snprintf(tmp, sizeof(tmp), "%c", *s);
00207          strncat(num, tmp, sizeof(num) - strlen(num) - 1);
00208       }
00209 
00210    }
00211    ast_get_enum(chan, num, dest, sizeof(dest), tech, sizeof(tech), args.zone, args.options, record, NULL);
00212 
00213    p = strchr(dest, ':');
00214    if (p && strcasecmp(tech, "ALL") && !strchr(args.options, 'u')) {
00215       ast_copy_string(buf, p + 1, len);
00216    } else {
00217       ast_copy_string(buf, dest, len);
00218    }
00219    return 0;
00220 }
00221 
00222 static unsigned int enum_datastore_id;
00223 
00224 struct enum_result_datastore {
00225    struct enum_context *context;
00226    unsigned int id;
00227 };
00228 
00229 static void erds_destroy(struct enum_result_datastore *data) 
00230 {
00231    int k;
00232 
00233    for (k = 0; k < data->context->naptr_rrs_count; k++) {
00234       ast_free(data->context->naptr_rrs[k].result);
00235       ast_free(data->context->naptr_rrs[k].tech);
00236    }
00237 
00238    ast_free(data->context->naptr_rrs);
00239    ast_free(data->context);
00240    ast_free(data);
00241 }
00242 
00243 static void erds_destroy_cb(void *data) 
00244 {
00245    struct enum_result_datastore *erds = data;
00246    erds_destroy(erds);
00247 }
00248 
00249 static const struct ast_datastore_info enum_result_datastore_info = {
00250    .type = "ENUMQUERY",
00251    .destroy = erds_destroy_cb,
00252 }; 
00253 
00254 static int enum_query_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00255 {
00256    struct enum_result_datastore *erds;
00257    struct ast_datastore *datastore;
00258    char *parse, tech[128], dest[128];
00259    int res = -1;
00260 
00261    AST_DECLARE_APP_ARGS(args,
00262       AST_APP_ARG(number);
00263       AST_APP_ARG(tech);
00264       AST_APP_ARG(zone);
00265    );
00266 
00267    if (ast_strlen_zero(data)) {
00268       ast_log(LOG_WARNING, "ENUMQUERY requires at least a number as an argument...\n");
00269       goto finish;
00270    }
00271 
00272    parse = ast_strdupa(data);
00273     
00274    AST_STANDARD_APP_ARGS(args, parse);
00275 
00276    if (!chan) {
00277       ast_log(LOG_ERROR, "ENUMQUERY cannot be used without a channel!\n");
00278       goto finish;
00279    }
00280 
00281    if (!args.zone)
00282       args.zone = "e164.zone";
00283 
00284    ast_copy_string(tech, args.tech ? args.tech : "sip", sizeof(tech));
00285 
00286    if (!(erds = ast_calloc(1, sizeof(*erds))))
00287       goto finish;
00288 
00289    if (!(erds->context = ast_calloc(1, sizeof(*erds->context)))) {
00290       ast_free(erds);
00291       goto finish;
00292    }
00293 
00294    erds->id = ast_atomic_fetchadd_int((int *) &enum_datastore_id, 1);
00295 
00296    snprintf(buf, len, "%u", erds->id);
00297 
00298    if (!(datastore = ast_datastore_alloc(&enum_result_datastore_info, buf))) {
00299       ast_free(erds->context);
00300       ast_free(erds);
00301       goto finish;
00302    }
00303 
00304    ast_get_enum(chan, args.number, dest, sizeof(dest), tech, sizeof(tech), args.zone, "", 1, &erds->context);
00305 
00306    datastore->data = erds;
00307 
00308    ast_channel_lock(chan);
00309    ast_channel_datastore_add(chan, datastore);
00310    ast_channel_unlock(chan);
00311    
00312    res = 0;
00313     
00314 finish:
00315 
00316    return res;
00317 }
00318 
00319 static int enum_result_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00320 {
00321    struct enum_result_datastore *erds;
00322    struct ast_datastore *datastore;
00323    char *parse, *p;
00324    unsigned int num;
00325    int res = -1, k;
00326    AST_DECLARE_APP_ARGS(args, 
00327       AST_APP_ARG(id);
00328       AST_APP_ARG(resultnum);
00329    );
00330 
00331    if (ast_strlen_zero(data)) {
00332       ast_log(LOG_WARNING, "ENUMRESULT requires two arguments (id and resultnum)\n");
00333       goto finish;
00334    }
00335 
00336    if (!chan) {
00337       ast_log(LOG_ERROR, "ENUMRESULT can not be used without a channel!\n");
00338       goto finish;
00339    }
00340    
00341    parse = ast_strdupa(data);
00342 
00343    AST_STANDARD_APP_ARGS(args, parse);
00344 
00345    if (ast_strlen_zero(args.id)) {
00346       ast_log(LOG_ERROR, "A result ID must be provided to ENUMRESULT\n");
00347       goto finish;
00348    }
00349 
00350    if (ast_strlen_zero(args.resultnum)) {
00351       ast_log(LOG_ERROR, "A result number must be given to ENUMRESULT!\n");
00352       goto finish;
00353    }
00354 
00355    ast_channel_lock(chan);
00356    datastore = ast_channel_datastore_find(chan, &enum_result_datastore_info, args.id);
00357    ast_channel_unlock(chan);
00358    if (!datastore) {
00359       ast_log(LOG_WARNING, "No ENUM results found for query id!\n");
00360       goto finish;
00361    }
00362 
00363    erds = datastore->data;
00364 
00365    if (!strcasecmp(args.resultnum, "getnum")) {
00366       snprintf(buf, len, "%d", erds->context->naptr_rrs_count);
00367       res = 0;
00368       goto finish;
00369    }
00370 
00371    if (sscanf(args.resultnum, "%30u", &num) != 1) {
00372       ast_log(LOG_ERROR, "Invalid value '%s' for resultnum to ENUMRESULT!\n", args.resultnum);
00373       goto finish;
00374    }
00375 
00376    if (!num || num > erds->context->naptr_rrs_count) {
00377       ast_log(LOG_WARNING, "Result number %u is not valid for ENUM query results for ID %s!\n", num, args.id);
00378       goto finish;
00379    }
00380 
00381    for (k = 0; k < erds->context->naptr_rrs_count; k++) {
00382       if (num - 1 != erds->context->naptr_rrs[k].sort_pos)
00383          continue;
00384 
00385       p = strchr(erds->context->naptr_rrs[k].result, ':');
00386               
00387       if (p && strcasecmp(erds->context->naptr_rrs[k].tech, "ALL"))
00388          ast_copy_string(buf, p + 1, len);
00389       else
00390          ast_copy_string(buf, erds->context->naptr_rrs[k].result, len);
00391 
00392       break;
00393    }
00394 
00395    res = 0;
00396 
00397 finish:
00398 
00399    return res;
00400 }
00401 
00402 static struct ast_custom_function enum_query_function = {
00403    .name = "ENUMQUERY",
00404    .read = enum_query_read,
00405 };
00406 
00407 static struct ast_custom_function enum_result_function = {
00408    .name = "ENUMRESULT",
00409    .read = enum_result_read,
00410 };
00411 
00412 static struct ast_custom_function enum_function = {
00413    .name = "ENUMLOOKUP",
00414    .read = function_enum,
00415 };
00416 
00417 static int function_txtcidname(struct ast_channel *chan, const char *cmd,
00418                 char *data, char *buf, size_t len)
00419 {
00420    AST_DECLARE_APP_ARGS(args,
00421       AST_APP_ARG(number);
00422       AST_APP_ARG(zone);
00423    );
00424 
00425    buf[0] = '\0';
00426 
00427    if (ast_strlen_zero(data)) {
00428       ast_log(LOG_WARNING, "Syntax: TXTCIDNAME(number[,zone-suffix])\n");
00429       return -1;
00430    }
00431 
00432    AST_STANDARD_APP_ARGS(args, data);
00433 
00434    if (args.argc < 1) {
00435       ast_log(LOG_WARNING, "Syntax: TXTCIDNAME(number[,zone-suffix])\n");
00436       return -1;
00437    }
00438 
00439    if (!args.zone) {
00440       args.zone = "e164.arpa";
00441    }
00442 
00443    ast_get_txt(chan, args.number, buf, len, args.zone);
00444 
00445    return 0;
00446 }
00447 
00448 static struct ast_custom_function txtcidname_function = {
00449    .name = "TXTCIDNAME",
00450    .read = function_txtcidname,
00451 };
00452 
00453 static int unload_module(void)
00454 {
00455    int res = 0;
00456 
00457    res |= ast_custom_function_unregister(&enum_result_function);
00458    res |= ast_custom_function_unregister(&enum_query_function);
00459    res |= ast_custom_function_unregister(&enum_function);
00460    res |= ast_custom_function_unregister(&txtcidname_function);
00461 
00462    return res;
00463 }
00464 
00465 static int load_module(void)
00466 {
00467    int res = 0;
00468 
00469    res |= ast_custom_function_register(&enum_result_function);
00470    res |= ast_custom_function_register(&enum_query_function);
00471    res |= ast_custom_function_register(&enum_function);
00472    res |= ast_custom_function_register(&txtcidname_function);
00473 
00474    return res;
00475 }
00476 
00477 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ENUM related dialplan functions");

Generated on Thu Apr 16 06:27:35 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6