Fri Jul 24 00:40:56 2009

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

Generated on Fri Jul 24 00:40:56 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7