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
00037
00038
00039
00040 #include "asterisk.h"
00041
00042 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
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
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
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
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, "%u", 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");