00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
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
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");