Thu Apr 28 2011 17:15:22

Asterisk developer's documentation


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