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

Generated on Thu Jul 9 13:40:35 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7